137 lines
6.8 KiB
C
137 lines
6.8 KiB
C
/* test_bt_ctl.c — meow_netmgrd 蓝牙 P1 权威收口 纯逻辑宿主自测(本程序非生产代码)。
|
||
*
|
||
* 通过 #include 生产源文件(meow_netmgrd.c,用 #define main 改名避免入口冲突),同一 TU 直接访问
|
||
* FILE-STATIC 函数/全局:bt_cmd_is_write / bt_write_authorize / bt_ctl_execute(connect/disconnect/
|
||
* pair/unpair/connected/a2dp/devices/status)。工具经桩脚本(g_bluetoothctl/g_hcitool/g_bluealsa_cli/
|
||
* g_bt_scan_cache 指向 $T/桩)覆盖,不依赖真实蓝牙栈。
|
||
*
|
||
* 用法:cc -Wall -Wextra -I../meow_launcherd test_bt_ctl.c -o test_bt_ctl && ./test_bt_ctl
|
||
*/
|
||
#define main meow_netmgrd_prod_main_unused
|
||
#include "meow_netmgrd.c"
|
||
#undef main
|
||
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
#include <stdlib.h>
|
||
#include <sys/stat.h>
|
||
#include <unistd.h>
|
||
|
||
static int g_fail = 0;
|
||
#define CHECK(cond) do { if (!(cond)) { printf(" FAIL: %s (line %d)\n", #cond, __LINE__); g_fail++; } \
|
||
else { printf(" ok : %s\n", #cond); } } while (0)
|
||
|
||
static void wf(const char *p, const char *s)
|
||
{
|
||
FILE *f = fopen(p, "w");
|
||
if (f) { fputs(s, f); fclose(f); }
|
||
}
|
||
|
||
int main(void)
|
||
{
|
||
static const char *T = "/tmp/nmg_bt";
|
||
char p[192];
|
||
mkdir(T, 0755);
|
||
/* 假 /sys/class/bluetooth/hci0(available/powered/address) */
|
||
{ snprintf(p, sizeof p, "%s/bt", T); mkdir(p, 0755);
|
||
snprintf(p, sizeof p, "%s/bt/hci0", T); mkdir(p, 0755);
|
||
snprintf(p, sizeof p, "%s/bt/hci0/address", T); wf(p, "00:1A:7D:DA:71:13\n");
|
||
snprintf(p, sizeof p, "%s/bt/hci0/power", T); wf(p, "on\n"); }
|
||
|
||
/* 桩:bluetoothctl(paired/devices/connect/remove)、hcitool con、bluealsa-cli a2dp、扫描缓存 */
|
||
snprintf(p, sizeof p, "%s/bluetoothctl", T); wf(p,
|
||
"#!/bin/sh\ncase \"$1\" in\n"
|
||
" paired|paired-devices|devices) echo 'Device 33:DE:2E:21:AD:30 Pudding'; echo 'Device 11:22:33:44:55:66 Speaker';;\n"
|
||
" connect|disconnect|pair|remove) echo 'Controller 00:1A:7D:DA:71:13'; echo 'Device 33:DE:2E:21:AD:30 Connected: yes';;\n"
|
||
"esac\nexit 0\n"); chmod(p, 0755);
|
||
snprintf(p, sizeof p, "%s/hcitool", T); wf(p,
|
||
"#!/bin/sh\necho '\t< ACL 33:DE:2E:21:AD:30 handle 12 state 1 lm MASTER'\n"
|
||
"echo '\t< ACL 11:22:33:44:55:66 handle 13 state 1 lm SLAVE'\nexit 0\n"); chmod(p, 0755);
|
||
snprintf(p, sizeof p, "%s/bluealsa-cli", T); wf(p,
|
||
"#!/bin/sh\nif [ \"${1:-}\" = \"a2dp\" ]; then\n"
|
||
"echo '/org/bluealsa/hci0/dev_33_DE_2E_21_AD_30/a2dpsrc:'\n"
|
||
"echo '\tCodec: SBC'\necho '\tSampling: 44100 Hz'\necho '\tChannels: 2'\n"
|
||
"echo '\tBits per Sample: 16'\necho '\tState: RUNNING'\necho '\tAcquired: yes'\nfi\nexit 0\n"); chmod(p, 0755);
|
||
snprintf(p, sizeof p, "%s/bt_scan.txt", T); wf(p,
|
||
"[NEW] Device 33:DE:2E:21:AD:30 Pudding\n[NEW] Device AA:BB:CC:DD:EE:FF Earbuds\n");
|
||
|
||
g_bluetoothctl = ""; { char x[160]; snprintf(x, sizeof x, "%s/bluetoothctl", T); static char s[160];
|
||
snprintf(s, sizeof s, "%s", x); g_bluetoothctl = s; }
|
||
g_hcitool = ""; { char x[160]; snprintf(x, sizeof x, "%s/hcitool", T); static char s[160];
|
||
snprintf(s, sizeof s, "%s", x); g_hcitool = s; }
|
||
g_bluealsa_cli = ""; { char x[160]; snprintf(x, sizeof x, "%s/bluealsa-cli", T); static char s[160];
|
||
snprintf(s, sizeof s, "%s", x); g_bluealsa_cli = s; }
|
||
g_bt_scan_cache = ""; { char x[160]; snprintf(x, sizeof x, "%s/bt_scan.txt", T); static char s[160];
|
||
snprintf(s, sizeof s, "%s", x); g_bt_scan_cache = s; }
|
||
g_bt_dir[0] = 0; snprintf(g_bt_dir, sizeof g_bt_dir, "%s/bt", T);
|
||
|
||
ctl_result_t r;
|
||
|
||
printf("== bt_cmd_is_write 分类(读/写级) ==\n");
|
||
CHECK(bt_cmd_is_write("status") == 0);
|
||
CHECK(bt_cmd_is_write("paired") == 0);
|
||
CHECK(bt_cmd_is_write("connected") == 0);
|
||
CHECK(bt_cmd_is_write("a2dp") == 0);
|
||
CHECK(bt_cmd_is_write("devices") == 0);
|
||
CHECK(bt_cmd_is_write("on") == 1);
|
||
CHECK(bt_cmd_is_write("off") == 1);
|
||
CHECK(bt_cmd_is_write("connect") == 1);
|
||
CHECK(bt_cmd_is_write("disconnect") == 1);
|
||
CHECK(bt_cmd_is_write("pair") == 1);
|
||
CHECK(bt_cmd_is_write("unpair") == 1);
|
||
CHECK(bt_cmd_is_write("scan") == 1);
|
||
|
||
printf("== bt_ctl_execute 写级(connect/disconnect/pair/unpair,经桩 bluetoothctl) ==\n");
|
||
bt_ctl_execute("connect", "33:DE:2E:21:AD:30", &r);
|
||
CHECK(r.code == MEOW_OK);
|
||
CHECK(strstr(r.text, "Connected") != NULL);
|
||
bt_ctl_execute("disconnect", "33:DE:2E:21:AD:30", &r);
|
||
CHECK(r.code == MEOW_OK);
|
||
bt_ctl_execute("pair", "33:DE:2E:21:AD:30", &r);
|
||
CHECK(r.code == MEOW_OK);
|
||
bt_ctl_execute("unpair", "33:DE:2E:21:AD:30", &r);
|
||
CHECK(r.code == MEOW_OK);
|
||
CHECK(strstr(r.text, "Connected") != NULL); /* remove 桩回 Connected: yes */
|
||
bt_ctl_execute("connect", "", &r);
|
||
CHECK(r.code == MEOW_ERR_INVAL); /* 缺 mac → INVAL */
|
||
bt_ctl_execute("scan", NULL, &r);
|
||
CHECK(r.code == MEOW_OK); /* scan on(默认) */
|
||
CHECK(strstr(r.text, "scan on") != NULL);
|
||
bt_ctl_execute("scan", "off", &r);
|
||
CHECK(r.code == MEOW_OK);
|
||
|
||
printf("== bt_ctl_execute 读级(connected/a2dp/devices/status,权威) ==\n");
|
||
bt_ctl_execute("connected", NULL, &r);
|
||
CHECK(r.code == MEOW_OK);
|
||
CHECK(strstr(r.text, "Device 33:DE:2E:21:AD:30") != NULL);
|
||
CHECK(strstr(r.text, "Pudding") != NULL);
|
||
bt_ctl_execute("a2dp", NULL, &r);
|
||
CHECK(r.code == MEOW_OK);
|
||
CHECK(strstr(r.text, "codec=SBC") != NULL);
|
||
CHECK(strstr(r.text, "rate=44100") != NULL);
|
||
CHECK(strstr(r.text, "acquired=1") != NULL);
|
||
CHECK(strstr(r.text, "role=src") != NULL);
|
||
snprintf(p, sizeof p, "%s/bt_scan.txt", T); wf(p, /* 重写(bt scan on 曾覆盖) */
|
||
"[NEW] Device 33:DE:2E:21:AD:30 Pudding\n[NEW] Device AA:BB:CC:DD:EE:FF Earbuds\n");
|
||
bt_ctl_execute("devices", NULL, &r);
|
||
CHECK(r.code == MEOW_OK);
|
||
CHECK(strstr(r.text, "Earbuds") != NULL);
|
||
CHECK(strstr(r.text, "Device 33:DE:2E:21:AD:30") != NULL);
|
||
bt_ctl_execute("status", NULL, &r);
|
||
CHECK(r.code == MEOW_OK);
|
||
CHECK(strstr(r.text, "connected=2") != NULL);
|
||
|
||
printf("== bt_write_authorize(系统身份 + MeowOS 才放行写级) ==\n");
|
||
caller_t other; memset(&other, 0, sizeof other); other.kind = CALL_OTHER;
|
||
caller_t sys; memset(&sys, 0, sizeof sys); sys.kind = CALL_SYS;
|
||
snprintf(sys.pkg, sizeof sys.pkg, "meow_net");
|
||
CHECK(bt_write_authorize(&other, 1, "connect") == MEOW_ERR_PERM); /* 非系统 → 拒 */
|
||
CHECK(bt_write_authorize(&sys, 1, "connect") == MEOW_OK); /* 系统+meow → 放 */
|
||
CHECK(bt_write_authorize(&sys, 0, "connect") == MEOW_ERR_PERM); /* 系统+hiby → 拒 */
|
||
CHECK(bt_write_authorize(&other, 1, "status") == MEOW_OK); /* 读级任意 → 放 */
|
||
|
||
if (g_fail) { printf("\nBT_CTL TEST: %d FAIL\n", g_fail); return 1; }
|
||
printf("\nBT_CTL TEST: ALL PASS\n");
|
||
return 0;
|
||
}
|