diff --git a/data/config.txt b/data/config.txt index f29256d..0c08b4a 100644 --- a/data/config.txt +++ b/data/config.txt @@ -1,10 +1,8 @@ #nick=your nick, picked randomly on first run brightness=200 -msg_freq=1800 -msg_ms=20 -sys_freq=440 -sys_ms=10 +tones_msg=T300 O4 l8 D l4 A+ +tones_sys=T300 O4 l8 A l4 D+ touch_threshold=300 diff --git a/platformio.ini b/platformio.ini index 440f7cc..4a5bfe5 100644 --- a/platformio.ini +++ b/platformio.ini @@ -18,16 +18,21 @@ board_build.filesystem = littlefs monitor_speed = 115200 upload_speed = 921600 ;monitor_filters = send_on_enter -build_src_filter = + - +build_src_filter = + + + - lib_deps = lovyan03/LovyanGFX @ ^1.2 lvgl/lvgl @ ^9.0 ; t-vk/ESP32 BLE Keyboard@^0.3.2 https://github.com/sakul-the-one/sakuls-ESP32-BLE-Keyboard h2zero/NimBLE-Arduino + https://github.com/maxint-rd/MmlMusic build_flags = -DLV_CONF_INCLUDE_SIMPLE -I include + ; use strchr instead of strchr_P + -Dstrchr_P=strchr ; We only need HID peripheral from NimBLE ; saving some memory here. -DCONFIG_BT_NIMBLE_ROLE_CENTRAL_DISABLED @@ -39,7 +44,9 @@ board = esp32dev framework = arduino monitor_speed = 115200 upload_speed = 921600 -build_src_filter = - + ; ignores root +build_src_filter = + - + + ; ignores meshberry lib_deps = build_flags = -I include \ No newline at end of file diff --git a/src/meshberry/chat.cpp b/src/meshberry/chat.cpp index d8d4a7c..e8edb9b 100644 --- a/src/meshberry/chat.cpp +++ b/src/meshberry/chat.cpp @@ -403,8 +403,14 @@ void handleCommand(const char* in) { ui_push_message("", "Usage: /set color_bg ff0000", false, true); } else { *sp = '\0'; - if (settings_set_color(args, sp + 1)) + size_t klen = strlen(args); + bool is_tones = klen > 6 && !strcmp(args + klen - 6, "_tones"); + bool ok = is_tones ? settings_set_tones(args, sp + 1) + : settings_set_color(args, sp + 1); + if (ok) ui_push_message("", "Saved. Restart to apply.", false, true); + else if (is_tones) + ui_push_message("", "Unknown tones key.", false, true); else ui_push_message("", "Unknown color or bad hex value.", false, true); } @@ -435,7 +441,7 @@ void handleCommand(const char* in) { ui_push_message("", "/bt : toggle BT send mode", false, true); ui_push_message("", "/set color_bg ff0000 : set a color (restart to apply)", false, true); ui_push_message("", "/people : list connected", false, true); - ui_push_message("", "/sleep : sleep device", false, true); + ui_push_message("", "/sleep or /s : sleep device", false, true); ui_push_message("", "TAB : notes mode", false, true); //drawChatWindow(); diff --git a/src/meshberry/main.cpp b/src/meshberry/main.cpp index 97efc30..de6d223 100644 --- a/src/meshberry/main.cpp +++ b/src/meshberry/main.cpp @@ -45,5 +45,6 @@ void loop() { char key = Serial.available() ? (char)Serial.read() : cardkb_read(); chat_tick(key); // TODO: debug why a serial key does not show in the UI? ui_tick(); + sound_tick(); delay(5); } diff --git a/src/meshberry/settings.cpp b/src/meshberry/settings.cpp index e2d41f3..c84c028 100644 --- a/src/meshberry/settings.cpp +++ b/src/meshberry/settings.cpp @@ -1,16 +1,15 @@ #include "settings.h" #include #include +#include settings_t g_settings; static const settings_t DEFAULTS = { .nick = NICK_DEFAULT_PREFIX, .brightness = 200, - .msg_freq = 1800, - .msg_ms = 20, - .sys_freq = 440, - .sys_ms = 10, + .tones_msg = "T140 G", + .tones_sys = "T140 A", .touch_threshold = TOUCH_THRESHOLD, .color_bg = {.blue = 0x11, .green = 0x11, .red = 0x11}, .color_header_bg = {.blue = 0x1e, .green = 0x1e, .red = 0x1e}, @@ -43,10 +42,8 @@ static bool is_hex6(const char* s) { static bool apply_kv(const char* key, const char* val) { if (!strcmp(key, "nick")) { strncpy(g_settings.nick, val, CHAT_MAX_NICK_LEN - 1); } else if (!strcmp(key, "brightness")) { g_settings.brightness = (uint8_t)constrain(atoi(val), 0, 255); } - else if (!strcmp(key, "msg_freq")) { g_settings.msg_freq = (uint16_t)atoi(val); } - else if (!strcmp(key, "msg_ms")) { g_settings.msg_ms = (uint16_t)atoi(val); } - else if (!strcmp(key, "sys_freq")) { g_settings.sys_freq = (uint16_t)atoi(val); } - else if (!strcmp(key, "sys_ms")) { g_settings.sys_ms = (uint16_t)atoi(val); } + else if (!strcmp(key, "tones_msg")) { g_settings.tones_msg = String(val); } + else if (!strcmp(key, "tones_sys")) { g_settings.tones_sys = String(val); } else if (!strcmp(key, "touch_threshold")) { g_settings.touch_threshold = (uint16_t)atoi(val); } else if (!strcmp(key, "color_bg")) { if (!is_hex6(val)) return false; g_settings.color_bg = parse_color(val); } else if (!strcmp(key, "color_header_bg")) { if (!is_hex6(val)) return false; g_settings.color_header_bg = parse_color(val); } @@ -60,12 +57,12 @@ static bool apply_kv(const char* key, const char* val) { } static void dump_settings() { - Serial.println("[settings] ---- effective config ----"); + Serial.println("[settings]"); Serial.printf ("[settings] nick=%s brightness=%d\n", g_settings.nick, g_settings.brightness); - Serial.printf ("[settings] msg_freq=%u msg_ms=%u sys_freq=%u sys_ms=%u touch_threshold=%u\n", - g_settings.msg_freq, g_settings.msg_ms, g_settings.sys_freq, - g_settings.sys_ms, g_settings.touch_threshold); + Serial.printf ("[settings] tones_msg=%s tones_sys=%s\n", + g_settings.tones_msg.c_str(), g_settings.tones_sys.c_str()); + Serial.printf ("[settings] touch_threshold=%u\n", g_settings.touch_threshold); Serial.printf ("[settings] color_bg=%02x%02x%02x color_header_bg=%02x%02x%02x\n", g_settings.color_bg.red, g_settings.color_bg.green, g_settings.color_bg.blue, g_settings.color_header_bg.red, g_settings.color_header_bg.green, g_settings.color_header_bg.blue); @@ -76,7 +73,7 @@ static void dump_settings() { Serial.printf ("[settings] color_system=%02x%02x%02x color_input_prompt=%02x%02x%02x\n", g_settings.color_system.red, g_settings.color_system.green, g_settings.color_system.blue, g_settings.color_input_prompt.red, g_settings.color_input_prompt.green, g_settings.color_input_prompt.blue); - Serial.println("[settings] ----------------------------"); + Serial.println("[settings]"); } // Public @@ -170,3 +167,13 @@ bool settings_set_color(const char* key, const char* hex) { rewrite_config_line(key, hex); return true; } + + +bool settings_set_tones(const char* key, const char* tones) { + if (strlen(key) <= 6 || strcmp(key + strlen(key) - 6, "_tones") != 0) { + return false; + } + if (!apply_kv(key, tones)) return false; // unknown key or bad tones + rewrite_config_line(key, tones); + return true; +} \ No newline at end of file diff --git a/src/meshberry/settings.h b/src/meshberry/settings.h index 6651cb9..40c3094 100644 --- a/src/meshberry/settings.h +++ b/src/meshberry/settings.h @@ -1,16 +1,15 @@ #pragma once #include #include "config.h" +#include // All values read from /config.txt on LittleFS. struct settings_t { char nick[CHAT_MAX_NICK_LEN]; uint8_t brightness; - uint16_t msg_freq; // Hz, notification beep for incoming messages - uint16_t msg_ms; // duration in ms - uint16_t sys_freq; // Hz, beep for join / leave events - uint16_t sys_ms; // duration in ms - uint16_t touch_threshold; // touch7 (GPIO27) wake-from-sleep sensitivity + String tones_msg; // MML string for incoming message + String tones_sys; // MML string for system message + uint16_t touch_threshold; // touch7 (GPIO27) wake-from-sleep sensitivity lv_color_t color_bg; lv_color_t color_header_bg; lv_color_t color_msg; @@ -26,3 +25,4 @@ extern settings_t g_settings; void settings_load(); void settings_set_nick(const char* nick); bool settings_set_color(const char* key, const char* hex); +bool settings_set_tones(const char* key, const char* tones); diff --git a/src/meshberry/sound.cpp b/src/meshberry/sound.cpp index 16f4fd0..38f48cd 100644 --- a/src/meshberry/sound.cpp +++ b/src/meshberry/sound.cpp @@ -2,11 +2,35 @@ #include "config.h" #include "settings.h" #include +#include + +MmlMusic music; + +static bool sound_tone_callback(unsigned int frequency, unsigned long length, uint8_t nTrack, uint8_t nVolume) { + if (frequency > 0) { + tone(PIN_SPEAKER, frequency); + } else if (length == 0) { + noTone(PIN_SPEAKER); + } + return true; +} void sound_init() { pinMode(PIN_SPEAKER_EN, OUTPUT); digitalWrite(PIN_SPEAKER_EN, LOW); // LOW = amp enabled + music.setToneCallback(sound_tone_callback); } -void sound_msg_in() { tone(PIN_SPEAKER, g_settings.msg_freq, g_settings.msg_ms); } -void sound_system() { tone(PIN_SPEAKER, g_settings.sys_freq, g_settings.sys_ms); } +void sound_tick() { + music.continuePlaying(); +} + +void sound_msg_in() { + //tone(PIN_SPEAKER, g_settings.snd_msg_freq, g_settings.snd_msg_ms); + //music.play("T140 O5 O5 D L4 G L8 D G L4 B. G8 G. F#8 G. G#8 A2"); + music.play(g_settings.tones_msg.c_str()); +} +void sound_system() { + // tone(PIN_SPEAKER, g_settings.snd_sys_freq, g_settings.snd_sys_ms); + music.play(g_settings.tones_sys.c_str()); +} \ No newline at end of file diff --git a/src/meshberry/sound.h b/src/meshberry/sound.h index 79348eb..e3df084 100644 --- a/src/meshberry/sound.h +++ b/src/meshberry/sound.h @@ -1,5 +1,6 @@ #pragma once void sound_init(); +void sound_tick(); // call regularly from loop() to advance MML playback void sound_msg_in(); // short high beep, new chat message void sound_system(); // short low beep , join / leave