diff --git a/makefile b/makefile index 9f731eaa3..f40bb80ee 100644 --- a/makefile +++ b/makefile @@ -97,6 +97,7 @@ ifeq ($(PLATFORM), tg5040) cp ./workspace/all/minarch/build/$(PLATFORM)/liblzma.* ./build/SYSTEM/$(PLATFORM)/lib/ cp ./workspace/all/minarch/build/$(PLATFORM)/libzstd.* ./build/SYSTEM/$(PLATFORM)/lib/ endif + cp ./workspace/all/bluetooth/build/$(PLATFORM)/bluetooth.elf ./build/EXTRAS/Tools/$(PLATFORM)/Bluetooth.pak/ cores: # TODO: can't assume every platform will have the same stock cores (platform should be responsible for copy too) diff --git a/skeleton/EXTRAS/Tools/tg5040/Bluetooth.pak/launch.sh b/skeleton/EXTRAS/Tools/tg5040/Bluetooth.pak/launch.sh new file mode 100644 index 000000000..730039e5b --- /dev/null +++ b/skeleton/EXTRAS/Tools/tg5040/Bluetooth.pak/launch.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +SDCARD_PATH="/mnt/SDCARD" +USERDATA_PATH="$SDCARD_PATH/.userdata" + + +#!/bin/bash + +# Check if bluetoothd is running +if pgrep -x "bluetoothd" > /dev/null; then + echo "Bluetooth daemon is already running." +else + echo "Starting Bluetooth daemon..." + /etc/bluetooth/bluetoothd & +fi + + +cd $(dirname "$0") + + +./bluetooth.elf > $USERDATA_PATH/tg5040/logs/bluetooth.log 2>&1 diff --git a/skeleton/EXTRAS/Tools/tg5040/Bluetooth.pak/main.ttf b/skeleton/EXTRAS/Tools/tg5040/Bluetooth.pak/main.ttf new file mode 100644 index 000000000..f60bd41d3 Binary files /dev/null and b/skeleton/EXTRAS/Tools/tg5040/Bluetooth.pak/main.ttf differ diff --git a/skeleton/SYSTEM/tg5040/bin/suspend b/skeleton/SYSTEM/tg5040/bin/suspend index e1c348596..7d3d329b2 100755 --- a/skeleton/SYSTEM/tg5040/bin/suspend +++ b/skeleton/SYSTEM/tg5040/bin/suspend @@ -7,27 +7,30 @@ hciattach_running=0 bluetoothd_running=0 # shellcheck disable=SC2317 + +# honestly im kinda doubting if we even need to do all this because if i just disable everything bluetooth/wifi works perfect from suspend to wake up and all +# doesnt the internal firmware already take care of this?? When i enable all this stuff im just getting all kinds of reconnection errors and what not specially on bluetooth resume() { >&2 echo "Resuming from suspend..." - >&2 echo "Unblocking wireless..." - echo 1 >/sys/class/rfkill/rfkill0/state || true + # >&2 echo "Unblocking wireless..." + # echo 1 >/sys/class/rfkill/rfkill0/state || true - if [ "$wpa_running" -eq 1 ]; then - >&2 echo "Starting wpa_supplicant..." - wpa_supplicant -B -iwlan0 -Dnl80211 -c/etc/wifi/wpa_supplicant.conf -I/etc/wifi/wpa_supplicant_overlay.conf -O/etc/wifi/sockets || true - udhcpc -i wlan0 & - fi + # if [ "$wpa_running" -eq 1 ]; then + # >&2 echo "Starting wpa_supplicant..." + # wpa_supplicant -B -iwlan0 -Dnl80211 -c/etc/wifi/wpa_supplicant.conf -I/etc/wifi/wpa_supplicant_overlay.conf -O/etc/wifi/sockets || true + # udhcpc -i wlan0 & + # fi - if [ "$hciattach_running" -eq 1 ]; then - >&2 echo "Starting hciattach..." - /etc/init.d/hciattach start || true - fi - if [ "$bluetoothd_running" -eq 1 ]; then - >&2 echo "Starting bluetoothd..." - /etc/bluetooth/bluetoothd start || true - /usr/bin/bluetoothctl power on || true - fi + # if [ "$hciattach_running" -eq 1 ]; then + # >&2 echo "Starting hciattach..." + # /etc/init.d/hciattach start || true + # fi + # if [ "$bluetoothd_running" -eq 1 ]; then + # >&2 echo "Starting bluetoothd..." + # /etc/bluetooth/bluetoothd start || true + # /usr/bin/bluetoothctl power on || true + # fi } main() { @@ -35,30 +38,32 @@ main() { >&2 echo "Preparing for suspend..." - if pgrep wpa_supplicant; then - wpa_running=1 - >&2 echo "Stopping wpa_supplicant..." - killall -9 wpa_supplicant - fi - ifconfig wlan0 down + # if pgrep wpa_supplicant; then + # wpa_running=1 + # >&2 echo "Stopping wpa_supplicant..." + # killall -9 wpa_supplicant + # fi + # ifconfig wlan0 down + + # if pgrep hciattach; then + # hciattach_running=1 + # >&2 echo "Stopping hciattach..." + # /etc/init.d/hciattach stop + # fi + # if pgrep bluetoothd; then + # bluetoothd_running=1 + # >&2 echo "Stopping bluetoothd..." + # /etc/bluetooth/bluetoothd stop + # killall -15 bluealsa + # fi - if pgrep hciattach; then - hciattach_running=1 - >&2 echo "Stopping hciattach..." - /etc/init.d/hciattach stop - fi - if pgrep bluetoothd; then - bluetoothd_running=1 - >&2 echo "Stopping bluetoothd..." - /etc/bluetooth/bluetoothd stop - killall -15 bluealsa - fi + # >&2 echo "Blocking wireless..." + # echo 0 >/sys/class/rfkill/rfkill0/state - >&2 echo "Blocking wireless..." - echo 0 >/sys/class/rfkill/rfkill0/state >&2 echo "Suspending..." - echo mem >/sys/power/state + # this is really the only line we really need to activate suspend + echo mem >/sys/power/state exit 0 } diff --git a/skeleton/SYSTEM/tg5040/paks/MinUI.pak/launch.sh b/skeleton/SYSTEM/tg5040/paks/MinUI.pak/launch.sh index 1ca624bb1..225867ac2 100755 --- a/skeleton/SYSTEM/tg5040/paks/MinUI.pak/launch.sh +++ b/skeleton/SYSTEM/tg5040/paks/MinUI.pak/launch.sh @@ -104,18 +104,26 @@ CPU_PATH=/sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed CPU_SPEED_PERF=2000000 echo $CPU_SPEED_PERF > $CPU_PATH -# bt handling (todo, off for now) -rfkill block bluetooth -killall MtpDaemon # I dont think we need to micro manage this one - # BT handling # on by default, disable based on systemval setting -#bton=`/usr/trimui/bin/systemval bluetooth` -#if [ "$bton" != "1" ] ; then -# /etc/bluetooth/bluetoothd start -# /usr/bin/bluealsa -p a2dp-source& -# touch /tmp/bluetooth_ready -#fi +bton=`/usr/trimui/bin/systemval bluetooth` + + + +blon=$(nextval.elf wifi | sed -n 's/.*"wifi": \([0-9]*\).*/\1/p') +if [ "$blon" -eq 1 ]; then +# Start Bluetooth daemon +/etc/bluetooth/bluetoothd start +sleep 3 + +bluealsa --profile=a2dp-source --a2dp-volume > /mnt/SDCARD/.userdata/tg5040/logs/bluealsa.txt 2>&1 & +# Turn Bluetooth power on +bluetoothctl power on +touch /tmp/bluetooth_ready + +# Enable scanning for bluetooth devices +bluetoothctl scan on > /dev/null 2>&1 & +fi # wifi handling # on by default, disable based on systemval setting diff --git a/workspace/all/bluetooth/bluetooth.c b/workspace/all/bluetooth/bluetooth.c new file mode 100644 index 000000000..4039d9939 --- /dev/null +++ b/workspace/all/bluetooth/bluetooth.c @@ -0,0 +1,251 @@ +#include +#include +#include +#include +#include +#include +#include // For 'bool' type + +#include +#include +//#include +//#include +//#include +//#include +//#include // Required for ioctl() +//#define LOG_INFO(fmt, ...) printf(fmt, ##__VA_ARGS__) + +#include "defines.h" +#include "api.h" +#include "utils.h" +#include "msettings.h" + +#define MAX_DEVICES 10 // Maximum number of Bluetooth devices to store + +#define MAX_DEVICES 10 + +// Structure to hold device info +typedef struct { + char name[248]; + char address[18]; + int connected; + int paired; +} BluetoothDevice; + +// Array to store discovered Bluetooth devices +BluetoothDevice devices[MAX_DEVICES]; +int num_devices = 0; +static SDL_Surface *screen; +static bool quit = false; + +void pair_device(const char *device_address) { + char command[256]; + + printf("Pairing with device %s...\n", device_address); + + + // this needs to go in one line otherwise it will not be registerd under the agent and not reconnect automaticaly + snprintf(command, sizeof(command), "echo -e \"agent on\ndefault-agent\npair %s\ntrust %s\n\" | bluetoothctl",device_address); + + int result = system(command); + snprintf(command, sizeof(command), "bluetoothctl connect %s",device_address); + + result = system(command); + + if (result == 0) { + printf("Device %s paired successfully!\n", device_address); + } else { + printf("Failed to pair with device %s\n", device_address); + } + +} +void remove_device(const char *device_address) { + char command[256]; + + printf("Pairing with device %s...\n", device_address); + + + // this needs to go in one line otherwise it will not be registerd under the agent and not reconnect automaticaly + snprintf(command, sizeof(command), "echo -e \"remove %s\n\" | bluetoothctl",device_address); + + int result = system(command); + + if (result == 0) { + printf("Device %s remove successfully!\n", device_address); + } else { + printf("Failed to remove device %s\n", device_address); + } + +} + +// Function to scan for Bluetooth devices +void scan_bluetooth_devices() { + FILE *fp; + char path[1035]; + num_devices = 0; + LOG_info("test test\n"); + // Run bluetoothctl to list paired devices + fp = popen("bluetoothctl devices", "r"); + if (fp == NULL) { + perror("Failed to run bluetoothctl devices"); + return; + } +LOG_info("hiii test\n"); + // Process paired devices + printf("all devices:\n"); + while (fgets(path, sizeof(path)-1, fp) != NULL) { + // Each line will be something like: "Device XX:XX:XX:XX:XX:XX Device Name" + char *address = strtok(path, " "); // Get the "Device" token (we can discard this) + char *addr = strtok(NULL, " "); // Get the address token (XX:XX:XX:XX:XX:XX) + char *name = strtok(NULL, "\n"); // Get the remaining part as the name + + if (addr && name) { + // Add the device address and name to the devices array + strncpy(devices[num_devices].address, addr, sizeof(devices[num_devices].address) - 1); + strncpy(devices[num_devices].name, name, sizeof(devices[num_devices].name) - 1); + num_devices++; + } + } + fclose(fp); + fp = popen("bluetoothctl paired-devices", "r"); + if (fp == NULL) { + perror("Failed to run bluetoothctl paired-devices"); + return; + } + + // Process paired devices + printf("paired devices:\n"); + while (fgets(path, sizeof(path)-1, fp) != NULL) { + // Each line will be something like: "Device XX:XX:XX:XX:XX:XX Device Name" + char *address = strtok(path, " "); // Get the "Device" token (we can discard this) + char *addr = strtok(NULL, " "); // Get the address token (XX:XX:XX:XX:XX:XX) + char *name = strtok(NULL, "\n"); // Get the remaining part as the name + + if (addr && name) { + // Search for the device in the existing devices array and set paired = 1 + for (int i = 0; i < num_devices; i++) { + if (strcmp(devices[i].address, addr) == 0) { + // If the device is found, mark it as paired + devices[i].paired = 1; + break; + } + } + } + } + fclose(fp); + + // Run bluetoothctl to list connected devices + fp = popen("bluetoothctl connected", "r"); + if (fp == NULL) { + perror("Failed to run bluetoothctl connected"); + return; + } + + // Process connected devices + printf("\nConnected devices:\n"); + while (fgets(path, sizeof(path)-1, fp) != NULL) { + // Each line will be something like: "XX:XX:XX:XX:XX:XX" + char *address = strtok(path, " \n"); + + if (address) { + // Find the device in the paired devices list and mark it as connected + for (int i = 0; i < num_devices; i++) { + if (strcmp(devices[i].address, address) == 0) { + printf("Connected: %s %s\n", devices[i].address, devices[i].name); + break; + } + } + } + } + fclose(fp); +} + +int main(int argc, char *argv[]) { + InitSettings(); + + PWR_setCPUSpeed(CPU_SPEED_MENU); + + screen = GFX_init(MODE_MAIN); + PAD_init(); + PWR_init(); + + scan_bluetooth_devices(); + + int dirty = 1; + int show_setting = 0; + int selected_device = 0; + while (!quit) { + uint32_t frame_start = SDL_GetTicks(); + + PAD_poll(); + + // Check for quit or navigation inputs + if (PAD_justPressed(BTN_B)) { + quit = 1; + } else if (PAD_justPressed(BTN_UP)) { + selected_device = (selected_device - 1 + num_devices) % num_devices; + } else if (PAD_justPressed(BTN_DOWN)) { + selected_device = (selected_device + 1) % num_devices; + } else if (PAD_justPressed(BTN_A)) { + pair_device(devices[selected_device].address); + } else if (PAD_justPressed(BTN_X)) { + remove_device(devices[selected_device].address); + } + + PWR_update(&dirty, &show_setting, NULL, NULL); + + + GFX_clear(screen); + + int max_width = screen->w - SCALE1(PADDING * 2); + + char display_name[256]; + sprintf(display_name, "%s", "Bluetooth :D"); + char title[256]; + int text_width = GFX_truncateText(font.medium, display_name, title, max_width, SCALE1(BUTTON_PADDING * 2)); + max_width = MIN(max_width, text_width); + + SDL_Surface *text; + text = TTF_RenderUTF8_Blended(font.medium, title, COLOR_WHITE); + GFX_blitPill(ASSET_BLACK_PILL, screen, &(SDL_Rect){SCALE1(PADDING), SCALE1(PADDING), max_width, SCALE1(PILL_SIZE)}); + SDL_BlitSurface(text, &(SDL_Rect){0, 0, max_width - SCALE1(BUTTON_PADDING * 2), text->h}, screen, &(SDL_Rect){SCALE1(PADDING + BUTTON_PADDING), SCALE1(PADDING + 4)}); + SDL_FreeSurface(text); + + + for (int i = 0; i < num_devices; ++i) { + char device_text[256]; + snprintf(device_text, sizeof(device_text), "%s: %s", devices[i].name, devices[i].address); + + bool selected = (i == selected_device); + SDL_Color current_color = selected ? COLOR_BLACK : COLOR_WHITE; + + int y = SCALE1(PADDING + PILL_SIZE * (i + 1)); + + SDL_Surface *text = TTF_RenderUTF8_Blended(font.medium, device_text, current_color); + int text_width = text->w + SCALE1(BUTTON_PADDING * 2); + + GFX_blitPill(selected ? ASSET_WHITE_PILL : ASSET_BLACK_PILL, screen, &(SDL_Rect){SCALE1(PADDING), y, text_width, SCALE1(PILL_SIZE)}); + SDL_BlitSurface(text, &(SDL_Rect){0, 0, text->w, text->h}, screen, &(SDL_Rect){SCALE1(PADDING + BUTTON_PADDING), y + SCALE1(4)}); + SDL_FreeSurface(text); + } + + if (show_setting) + GFX_blitHardwareHints(screen, show_setting); + else + GFX_blitButtonGroup((char*[]){ "B","BACK", NULL }, 1, screen, 0); + + GFX_blitButtonGroup((char*[]){ "A","PAIR","X","UNPAIR", NULL }, 1, screen, 1); + + GFX_flip(screen); + dirty = 0; + + + } + + QuitSettings(); + PWR_quit(); + PAD_quit(); + GFX_quit(); + + return EXIT_SUCCESS; +} diff --git a/workspace/all/bluetooth/main.ttf b/workspace/all/bluetooth/main.ttf new file mode 100644 index 000000000..f60bd41d3 Binary files /dev/null and b/workspace/all/bluetooth/main.ttf differ diff --git a/workspace/all/bluetooth/makefile b/workspace/all/bluetooth/makefile new file mode 100644 index 000000000..765f2be0d --- /dev/null +++ b/workspace/all/bluetooth/makefile @@ -0,0 +1,41 @@ +########################################################### + +ifeq (,$(PLATFORM)) +PLATFORM=$(UNION_PLATFORM) +endif + +ifeq (,$(PLATFORM)) + $(error please specify PLATFORM, eg. PLATFORM=trimui make) +endif + +ifeq (,$(CROSS_COMPILE)) + $(error missing CROSS_COMPILE for this toolchain) +endif + +########################################################### + +include ../../$(PLATFORM)/platform/makefile.env +SDL?=SDL + +########################################################### + +TARGET = bluetooth +INCDIR = -I. -I../common/ -I../../$(PLATFORM)/platform/ +SOURCE = $(TARGET).c ../common/utils.c ../common/api.c ../common/config.c ../common/scaler.c ../../$(PLATFORM)/platform/platform.c + +CC = $(CROSS_COMPILE)gcc +CFLAGS += $(ARCH) -fomit-frame-pointer +CFLAGS += $(INCDIR) -DPLATFORM=\"$(PLATFORM)\" -std=gnu99 +LDFLAGS += -lmsettings -lbluetooth + +PRODUCT= build/$(PLATFORM)/$(TARGET).elf + +all: $(PREFIX)/include/msettings.h + mkdir -p build/$(PLATFORM) + $(CC) $(SOURCE) -o $(PRODUCT) $(CFLAGS) $(LDFLAGS) +clean: + rm -f $(PRODUCT) + +$(PREFIX)/include/msettings.h: + cd /root/workspace/$(PLATFORM)/libmsettings && make + diff --git a/workspace/all/common/api.c b/workspace/all/common/api.c index 0a4ac041f..ad30c7427 100644 --- a/workspace/all/common/api.c +++ b/workspace/all/common/api.c @@ -1750,7 +1750,7 @@ SDL_Color GFX_mapColor(uint32_t c) // to (try to) understand it // better -#define MAX_SAMPLE_RATE 48000 +#define MAX_SAMPLE_RATE 44100 #define BATCH_SIZE 100 #ifndef SAMPLES #define SAMPLES 512 // default @@ -1762,32 +1762,40 @@ SDL_Color GFX_mapColor(uint32_t c) pthread_mutex_t audio_mutex = PTHREAD_MUTEX_INITIALIZER; + // 1.0 = 100% volume, 0.0 = muted +int bluetoothEnabled = 0; static void SND_audioCallback(void *userdata, uint8_t *stream, int len) { - if (snd.frame_count == 0) - return; - - int16_t *out = (int16_t *)stream; - len /= (sizeof(int16_t) * 2); - - // Lock the mutex before accessing shared resources - - - while (snd.frame_out != snd.frame_in && len > 0) { - - *out++ = snd.buffer[snd.frame_out].left; - *out++ = snd.buffer[snd.frame_out].right; - pthread_mutex_lock(&audio_mutex); - snd.frame_out += 1; - len -= 1; - if (snd.frame_out >= snd.frame_count) - snd.frame_out = 0; - pthread_mutex_unlock(&audio_mutex); - } - + if (snd.frame_count == 0) + return; + float vol = bluetoothEnabled ? GetVolume()/20.0f:1.0f; + int16_t *out = (int16_t *)stream; + len /= (sizeof(int16_t) * 2); + + while (snd.frame_out != snd.frame_in && len > 0) { + // Apply volume control to left channel + int left = (int)(snd.buffer[snd.frame_out].left * vol); + if (left > 32767) left = 32767; + if (left < -32768) left = -32768; + + // Apply volume control to right channel + int right = (int)(snd.buffer[snd.frame_out].right * vol); + if (right > 32767) right = 32767; + if (right < -32768) right = -32768; + + *out++ = (int16_t)left; + *out++ = (int16_t)right; + + pthread_mutex_lock(&audio_mutex); + snd.frame_out += 1; + len -= 1; + if (snd.frame_out >= snd.frame_count) + snd.frame_out = 0; + pthread_mutex_unlock(&audio_mutex); + } - if (len > 0) { - memset(out, 0, len * (sizeof(int16_t) * 2)); - } + if (len > 0) { + memset(out, 0, len * (sizeof(int16_t) * 2)); + } } static void SND_resizeBuffer(void) { // plat_sound_resize_buffer @@ -2127,8 +2135,11 @@ size_t SND_batchSamples_fixed_rate(const SND_Frame *frames, size_t frame_count) void SND_init(double sample_rate, double frame_rate) { // plat_sound_init LOG_info("SND_init\n"); + SDL_CloseAudio(); + PLAT_setBluetoothaudio(); currentreqfps = frame_rate; SDL_InitSubSystem(SDL_INIT_AUDIO); + ; fps_counter = 0; fps_buffer_index = 0; @@ -2152,7 +2163,7 @@ void SND_init(double sample_rate, double frame_rate) { // plat_sound_init spec_in.channels = 2; spec_in.samples = SAMPLES; spec_in.callback = SND_audioCallback; - + if (SDL_OpenAudio(&spec_in, &spec_out)<0) LOG_info("SDL_OpenAudio error: %s\n", SDL_GetError()); snd.frame_count = ((float)spec_out.freq/SCREEN_FPS)*6; // buffer size based on sample rate out (with 6 frames headroom), ideally you want to use actual FPS but don't know it at this point yet @@ -2172,9 +2183,10 @@ void SND_init(double sample_rate, double frame_rate) { // plat_sound_init void SND_quit(void) { // plat_sound_finish if (!snd.initialized) return; + if(!bluetoothEnabled) { SDL_PauseAudio(1); SDL_CloseAudio(); - + } if (snd.buffer) { free(snd.buffer); snd.buffer = NULL; diff --git a/workspace/all/common/api.h b/workspace/all/common/api.h index 9db138a51..0b6e86d2f 100644 --- a/workspace/all/common/api.h +++ b/workspace/all/common/api.h @@ -99,7 +99,7 @@ extern double currentcpuse; extern int currentcputemp; extern int should_rotate; extern volatile int useAutoCpu; - +extern int bluetoothEnabled; enum { ASSET_WHITE_PILL, ASSET_BLACK_PILL, @@ -614,6 +614,7 @@ void PLAT_setLedBrightness(LightSettings *led); void PLAT_setLedInbrightness(LightSettings *led); void PLAT_setLedEffectSpeed(LightSettings *led); void PLAT_setLedEffectCycles(LightSettings *led); +void PLAT_setBluetoothaudio(); /////////////////// diff --git a/workspace/all/common/config.c b/workspace/all/common/config.c index b56b9ae91..d50b8cfdb 100644 --- a/workspace/all/common/config.c +++ b/workspace/all/common/config.c @@ -55,6 +55,7 @@ void CFG_defaults(NextUISettings *cfg) .stateFormat = CFG_DEFAULT_STATEFORMAT, .wifi = CFG_DEFAULT_WIFI, + .bluetooth = CFG_DEFAULT_BLUETOOTH, }; *cfg = defaults; @@ -209,6 +210,11 @@ void CFG_init(FontLoad_callback_t cb, ColorSet_callback_t ccb) CFG_setWifi((bool)temp_value); continue; } + if (sscanf(line, "bluetooth=%i", &temp_value) == 1) + { + CFG_setBluetooth((bool)temp_value); + continue; + } } fclose(file); } @@ -485,6 +491,15 @@ void CFG_setWifi(bool on) { settings.wifi = on; } +bool CFG_getBluetooth(void) +{ + return settings.bluetooth; +} + +void CFG_setBluetooth(bool isBl) +{ + settings.bluetooth = isBl; +} void CFG_get(const char *key, char *value) { @@ -588,6 +603,10 @@ void CFG_get(const char *key, char *value) { sprintf(value, "%i", (int)(CFG_getWifi())); } + else if (strcmp(key, "bluetooth") == 0) + { + sprintf(value, "%i", CFG_getBluetooth()); + } // meta, not a real setting else if (strcmp(key, "fontpath") == 0) @@ -643,6 +662,7 @@ void CFG_sync(void) fprintf(file, "muteLeds=%i\n", settings.muteLeds); fprintf(file, "artWidth=%i\n", (int)(settings.gameArtWidth * 100)); fprintf(file, "wifi=%i\n", settings.wifi); + fprintf(file, "bluetooth=%i\n", settings.bluetooth); fclose(file); } @@ -676,7 +696,7 @@ void CFG_print(void) printf("\t\"muteLeds\": %i,\n", settings.muteLeds); printf("\t\"artWidth\": %i,\n", (int)(settings.gameArtWidth * 100)); printf("\t\"wifi\": %i,\n", settings.wifi); - + printf("\t\"bluetooth\": %i,\n", settings.bluetooth); // meta, not a real setting if (settings.font == 1) printf("\t\"fontpath\": \"%s\"\n", RES_PATH "/chillroundm.ttf"); diff --git a/workspace/all/common/config.h b/workspace/all/common/config.h index 3c925f358..1132dbd61 100644 --- a/workspace/all/common/config.h +++ b/workspace/all/common/config.h @@ -85,6 +85,7 @@ typedef struct // Network bool wifi; + bool bluetooth; } NextUISettings; @@ -114,6 +115,7 @@ typedef struct #define CFG_DEFAULT_MUTELEDS false #define CFG_DEFAULT_GAMEARTWIDTH 0.45 #define CFG_DEFAULT_WIFI false +#define CFG_DEFAULT_BLUETOOTH false void CFG_init(FontLoad_callback_t fontCallback, ColorSet_callback_t ccb); void CFG_print(void); @@ -190,6 +192,10 @@ void CFG_setGameArtWidth(double zeroToOne); bool CFG_getWifi(void); void CFG_setWifi(bool on); +//bluetooth +bool CFG_getBluetooth(void); +void CFG_setBluetooth(bool); + void CFG_sync(void); void CFG_quit(void); diff --git a/workspace/all/minarch/minarch.c b/workspace/all/minarch/minarch.c index 42e6c1ec7..4e7ddf348 100644 --- a/workspace/all/minarch/minarch.c +++ b/workspace/all/minarch/minarch.c @@ -6137,6 +6137,7 @@ int save_screenshot_thread(void* data) { free(args->path); free(args->pixels); free(args); + LOG_info("returning\n"); return 0; } SDL_Thread* screenshotsavethread; @@ -6856,20 +6857,29 @@ int main(int argc , char* argv[]) { QuitSettings(); finish: - + LOG_info("quit\n"); Game_close(); + LOG_info("a\n"); Core_unload(); + LOG_info("b\n"); Core_quit(); + LOG_info("c\n"); Core_close(); + LOG_info("d\n"); Config_quit(); + LOG_info("2\n"); Special_quit(); MSG_quit(); PWR_quit(); VIB_quit(); + LOG_info("4\n"); // already happens on Core_unload - SND_quit(); + // SND_quit(); PAD_quit(); - GFX_quit(); + LOG_info("5\n"); + // GFX_quit(); + LOG_info("6\n"); SDL_WaitThread(screenshotsavethread, NULL); + LOG_info("done\n"); return EXIT_SUCCESS; } diff --git a/workspace/all/settings/settings.cpp b/workspace/all/settings/settings.cpp index 2da390b3b..a68beb1b1 100644 --- a/workspace/all/settings/settings.cpp +++ b/workspace/all/settings/settings.cpp @@ -212,6 +212,11 @@ int main(int argc, char *argv[]) auto systemMenu = new MenuList(MenuItemType::Fixed, "System", { + new MenuItem{ListItemType::Generic, "Bluetooth", "Blue", {false, true}, on_off, []() -> std::any + { return CFG_getBluetooth(); }, + [](const std::any &value) + { CFG_setBluetooth(std::any_cast(value)); }, + []() { CFG_setBluetooth(CFG_DEFAULT_BLUETOOTH);}}, new MenuItem{ListItemType::Generic, "Volume", "Speaker volume", {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}, {"Muted", "5%","10%","15%","20%","25%","30%","35%","40%","45%","50%","55%","60%","65%","70%","75%","80%","85%","90%","95%","100%"}, diff --git a/workspace/makefile b/workspace/makefile index c9f754ed0..92955dbaf 100644 --- a/workspace/makefile +++ b/workspace/makefile @@ -34,6 +34,7 @@ all: cd ./all/settings/ && make cd ./all/ledcontrol/ && make cd ./all/bootlogo/ && make + cd ./all/bluetooth/ && make # BUILDOPTION: don't forget to uncomment this to rebuild cores from # source, idk if this was left commented by mistake, but I actually # agree on leaving this commented out by default as they take a long @@ -73,4 +74,6 @@ clean: cd ./all/settings/ && make clean cd ./all/ledcontrol/ && make clean cd ./all/bootlogo/ && make clean + cd ./all/scraper/ && make clean + cd ./all/bluetooth/ && make clean cd ./$(PLATFORM) && make clean \ No newline at end of file diff --git a/workspace/tg5040/libmsettings/msettings.h b/workspace/tg5040/libmsettings/msettings.h index 1a109dcc0..eba835924 100644 --- a/workspace/tg5040/libmsettings/msettings.h +++ b/workspace/tg5040/libmsettings/msettings.h @@ -10,7 +10,6 @@ #define SETTINGS_DEFAULT_HEADPHONE_VOLUME 4 #define SETTINGS_DEFAULT_MUTE_NO_CHANGE -69 - void InitSettings(void); void QuitSettings(void); int InitializedSettings(void); @@ -61,4 +60,6 @@ void SetMutedSaturation(int); void SetMutedExposure(int); void SetMutedVolume(int); + + #endif // __msettings_h__ diff --git a/workspace/tg5040/platform/platform.c b/workspace/tg5040/platform/platform.c index 472c562b0..65c324302 100644 --- a/workspace/tg5040/platform/platform.c +++ b/workspace/tg5040/platform/platform.c @@ -2447,7 +2447,9 @@ void PLAT_setRumble(int strength) { } int PLAT_pickSampleRate(int requested, int max) { - return MIN(requested, max); + // return MIN(requested, max); + // temporary for bluetoth + return 44100; } char* PLAT_getModel(void) { @@ -3328,4 +3330,74 @@ void PLAT_wifiDisconnect() int ret = wifi.interface->disconnect_ap(42); LOG_info("wifi disconnect_ap returned %d\n", ret); -} \ No newline at end of file +} +///////////////////////// + +void PLAT_setBluetoothaudio() { + FILE *fp; + char path[1035]; + char mac_address[18]; // MAC addresses are 17 characters long (+1 for null terminator) + + // Run bluetoothctl devices to get a list of paired devices + fp = popen("bluetoothctl devices", "r"); + if (fp == NULL) { + perror("Failed to run bluetoothctl devices"); + } else { + // Read the output line by line to find the MAC addresses of all devices + while (fgets(path, sizeof(path)-1, fp) != NULL) { + // Check if the line contains the word "Device" + if (strstr(path, "Device") != NULL) { + // Extract the MAC address (it is the first part of the line) + sscanf(path, "Device %17s", mac_address); + + // Run bluetoothctl info to check if it's connected + char command[256]; + snprintf(command, sizeof(command), "bluetoothctl info %s", mac_address); + + FILE *info_fp = popen(command, "r"); + if (info_fp == NULL) { + perror("Failed to run bluetoothctl info"); + continue; // Skip this device and try the next one + } + + // Check if the device is connected + int is_connected = 0; + int is_audio_device = 0; + unsigned int class_value; + while (fgets(path, sizeof(path)-1, info_fp) != NULL) { + // Check for device class + if (sscanf(path, " Class: 0x%x", &class_value) == 1) { + if ((class_value & 0x1F00) == 0x0400) { // Check if major class is Audio/Video + is_audio_device = 1; + } + } + + // Check if the device is connected + if (strstr(path, "Connected: yes")) { + is_connected = 1; + } + } + fclose(info_fp); + + // If the device is connected, print its MAC address + if (is_connected && is_audio_device) { + printf("Connected device MAC address: %s\n", mac_address); + setenv("SDL_AUDIODRIVER", "alsa", 1); + char value[256]; // Adjust the size if needed + + + snprintf(value, sizeof(value), "bluealsa:HCI=hci0,DEV=%s", mac_address); + setenv("AUDIODEV", value, 1); + bluetoothEnabled = 1; + break; // Stop after finding the first connected device + } + } + } + + // Close the file pointer for device list + fclose(fp); + + + + } +}