| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596 |
- #include "panel_uart.h"
- #include "dac_njw1195.h"
- #include "board_common.h"
- #include "playback_control.h"
- #include "settings.h"
- #include "dacp_client.h"
- #include "rtsp_events.h"
- #include "audio_prompt.h"
- #ifdef CONFIG_BT_A2DP_ENABLE
- #include "a2dp_sink.h"
- #endif
- #include "driver/uart.h"
- #include "driver/gpio.h"
- #include "esp_log.h"
- #include "esp_timer.h"
- #include "esp_wifi.h"
- #include "freertos/FreeRTOS.h"
- #include "freertos/task.h"
- #include "freertos/queue.h"
- static const char TAG[] = "PanelUart";
- #define UART_PORT UART_NUM_2
- #define UART_TX_GPIO 4
- #define UART_RX_GPIO 5
- #define UART_BAUD_RATE 115200
- #define UART_BUF_SIZE 256
- // 协议定义
- #define FRAME_HEAD_1 0x55
- #define FRAME_HEAD_2 0xAA
- #define CMD_READ 0x01
- #define CMD_WRITE 0x02
- #define CMD_REPORT 0x81
- // 功能监控项定义
- #define ITEM_SOURCE 0x01
- #define ITEM_BT_CONN 0x02
- #define ITEM_BT_AUDIO 0x03
- #define ITEM_DAC_MUTE 0x04
- #define ITEM_AUTO_RECONN 0x05
- #define ITEM_BATTERY 0x09
- #define ITEM_CHG_FULL 0x0A
- #define ITEM_CHG_ING 0x0B
- #define ITEM_VOL_LR 0x0C
- #define ITEM_VOL_BASS 0x0D
- #define ITEM_RESET 0x12
- #define ITEM_BASS_MUTE 0x13
- // 协议状态值定义 (归一化为 0 和 1)
- #define PROTO_VAL_OFF 0x00
- #define PROTO_VAL_ON 0x01
- #define CHG_FULL_GPIO 34
- #define CHG_ING_GPIO 35
- static TaskHandle_t s_charge_task_handle = NULL;
- static volatile bool s_bt_connected = false;
- static volatile bool s_bt_streaming = false;
- static volatile uint8_t s_battery_percent = 0;
- static volatile bool s_chg_full = false;
- static volatile bool s_chg_ing = false;
- static volatile bool s_chg_error = false;
- static uint8_t s_bass_before_mute = 100;
- extern bool s_in_panel_update; // 定义在 dac_njw1195.c 中
- // ----------------------------------------------------------------------------
- // 内部辅助函数
- // ----------------------------------------------------------------------------
- static const char* get_item_name(uint8_t item) {
- switch (item) {
- case ITEM_SOURCE: return "SOURCE";
- case ITEM_BT_CONN: return "BT_CONN";
- case ITEM_BT_AUDIO: return "BT_AUDIO";
- case ITEM_DAC_MUTE: return "DAC_MUTE";
- case ITEM_AUTO_RECONN: return "AUTO_RECONN";
- case ITEM_BATTERY: return "BATTERY";
- case ITEM_CHG_FULL: return "CHG_FULL";
- case ITEM_CHG_ING: return "CHG_ING";
- case ITEM_VOL_LR: return "VOL_LR";
- case ITEM_VOL_BASS: return "VOL_BASS";
- case ITEM_RESET: return "RESET";
- case ITEM_BASS_MUTE: return "BASS_MUTE";
- default: return "UNKNOWN";
- }
- }
- static void send_frame(uint8_t cmd, uint8_t item, uint8_t value) {
- uint8_t len = 2;
- uint8_t crc = cmd ^ len ^ item ^ value;
- uint8_t buf[7] = { FRAME_HEAD_1, FRAME_HEAD_2, cmd, len, item, value, crc };
- uart_write_bytes(UART_PORT, buf, 7);
- ESP_LOGI(TAG, "TX [%s]: %02X %02X %02X %02X %02X %02X %02X",
- get_item_name(item), buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6]);
- }
- static void send_ack(void) {
- uint8_t ack = 0xA0; // 成功响应应答,区别于帧头 0xAA
- uart_write_bytes(UART_PORT, &ack, 1);
- ESP_LOGI(TAG, "RX ACK: %02X", ack);
- }
- static void send_report_frame(uint8_t *items, uint8_t *values, uint8_t count) {
- uint8_t len = 1 + count * 2;
- uint8_t buf[5 + len]; // Header(2) + Cmd(1) + Len(1) + Payload(len) + CRC(1)
- int idx = 0;
- buf[idx++] = FRAME_HEAD_1;
- buf[idx++] = FRAME_HEAD_2;
- buf[idx++] = CMD_REPORT;
- buf[idx++] = len;
-
- uint8_t crc = CMD_REPORT ^ len ^ count;
- buf[idx++] = count;
- for (int i = 0; i < count; i++) {
- buf[idx++] = items[i];
- buf[idx++] = values[i];
- crc ^= items[i] ^ values[i];
- }
- buf[idx++] = crc;
- uart_write_bytes(UART_PORT, buf, idx);
- char hex_str[128] = {0};
- int offset = 0;
- for (int i = 0; i < idx; i++) {
- offset += snprintf(hex_str + offset, sizeof(hex_str) - offset, "%02X ", buf[i]);
- }
- ESP_LOGI(TAG, "TX_RAW: %s", hex_str);
- }
- void panel_uart_report(uint8_t item, uint8_t value) {
- send_frame(CMD_REPORT, item, value);
- }
- // ----------------------------------------------------------------------------
- // GPIO 充电状态中断处理与控制任务
- // ----------------------------------------------------------------------------
- static void IRAM_ATTR charge_isr_handler(void *arg) {
- BaseType_t need_yield = pdFALSE;
- if (s_charge_task_handle != NULL) {
- vTaskNotifyGiveFromISR(s_charge_task_handle, &need_yield);
- }
- if (need_yield) {
- portYIELD_FROM_ISR();
- }
- }
- static void read_charge_status(void) {
- int full = gpio_get_level(CHG_FULL_GPIO);
- int ing = gpio_get_level(CHG_ING_GPIO);
- // 新三极管电路逻辑 (平时上拉为1,触发有效为0):
- // 充满: full=0, ing=1
- // 充电中: full=1, ing=0
- // 异常: full=0, ing=0
- // 未接充电器: full=1, ing=1
- s_chg_full = (full == 0 && ing == 1);
- s_chg_ing = (full == 1 && ing == 0);
- s_chg_error = (full == 0 && ing == 0);
- }
- static void charge_status_task(void *arg) {
- vTaskDelay(pdMS_TO_TICKS(100));
- read_charge_status();
-
- // 面板在上报完整数据前会舍弃单项指令。
- // 因此开机不在这里单独上报,由 report_status_task 延迟 2s 后的 report_all_status 统一下发初始状态。
- int64_t last_edge_time = 0;
- int toggle_count = 0;
- while (1) {
- // 600ms 超时:若 600ms 内无引脚跳变,说明电平稳定,重置翻转计数器
- uint32_t notified = ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(600));
-
- if (notified > 0) {
- vTaskDelay(pdMS_TO_TICKS(30)); // 消抖
- int64_t now = esp_timer_get_time();
- int64_t delta_ms = (now - last_edge_time) / 1000;
- last_edge_time = now;
- // 芯片异常时引脚会以 250ms 周期反复翻转 (周期约 150ms ~ 400ms)
- if (delta_ms > 120 && delta_ms < 450) {
- toggle_count++;
- } else if (delta_ms > 600) {
- toggle_count = 0;
- }
- bool old_full = s_chg_full;
- bool old_ing = s_chg_ing;
- bool old_err = s_chg_error;
- if (toggle_count >= 2) {
- // 连续监测到 250ms 快速翻转,判定为充电异常
- s_chg_error = true;
- s_chg_full = false;
- s_chg_ing = false;
- } else if (toggle_count == 0) {
- read_charge_status();
- }
- if (s_chg_full != old_full || s_chg_ing != old_ing || s_chg_error != old_err) {
- if (s_chg_error) {
- send_frame(CMD_REPORT, ITEM_CHG_ING, 0xFE); // 充电异常错误码
- ESP_LOGE(TAG, "Chg: Error (250ms Toggling Detected)");
- } else if (s_chg_full) {
- send_frame(CMD_REPORT, ITEM_CHG_FULL, 1);
- ESP_LOGI(TAG, "Chg: Full");
- } else if (s_chg_ing) {
- send_frame(CMD_REPORT, ITEM_CHG_ING, 1);
- ESP_LOGI(TAG, "Chg: Charging");
- } else {
- send_frame(CMD_REPORT, ITEM_CHG_ING, 0);
- ESP_LOGI(TAG, "Chg: Discharging");
- }
- }
- } else {
- // 600ms 超时无新中断,判定电平已经稳定
- if (toggle_count > 0 || s_chg_error) {
- toggle_count = 0;
- bool old_full = s_chg_full;
- bool old_ing = s_chg_ing;
- bool old_err = s_chg_error;
- read_charge_status();
- if (s_chg_full != old_full || s_chg_ing != old_ing || s_chg_error != old_err) {
- if (s_chg_full) {
- send_frame(CMD_REPORT, ITEM_CHG_FULL, 1);
- ESP_LOGI(TAG, "Chg: Full (Recovered)");
- } else if (s_chg_ing) {
- send_frame(CMD_REPORT, ITEM_CHG_ING, 1);
- ESP_LOGI(TAG, "Chg: Charging (Recovered)");
- } else {
- send_frame(CMD_REPORT, ITEM_CHG_ING, 0);
- ESP_LOGI(TAG, "Chg: Discharging (Recovered)");
- }
- }
- }
- }
- }
- }
- // ----------------------------------------------------------------------------
- // 全部状态主动上报
- // ----------------------------------------------------------------------------
- static void report_all_status(void) {
- // 上报全部 10 项面板状态参数
- uint8_t rpt_items[] = {
- ITEM_SOURCE, ITEM_BT_CONN, ITEM_BT_AUDIO, ITEM_DAC_MUTE,
- ITEM_AUTO_RECONN, ITEM_VOL_LR, ITEM_VOL_BASS,
- ITEM_BATTERY, ITEM_CHG_FULL, ITEM_CHG_ING
- };
- uint8_t rpt_values[] = {
- (dac_njw1195_get_source() == NJW_SOURCE_BT) ? PROTO_VAL_ON : PROTO_VAL_OFF,
- s_bt_connected ? PROTO_VAL_ON : PROTO_VAL_OFF,
- s_bt_streaming ? PROTO_VAL_ON : PROTO_VAL_OFF,
- PROTO_VAL_OFF, // DAC 硬件静音状态(默认不静音,为 0)
- PROTO_VAL_ON, // 自动连接默认开启
- dac_njw1195_get_vol_main(),
- dac_njw1195_get_vol_bass(),
- s_battery_percent,
- s_chg_full ? 1 : 0,
- s_chg_ing ? 1 : 0
- };
- send_report_frame(rpt_items, rpt_values, 10);
- ESP_LOGI(TAG, "主动上报 (10 项)");
- }
- // ----------------------------------------------------------------------------
- // 电池电量定期自动上报任务
- // ----------------------------------------------------------------------------
- static void report_status_task(void *arg) {
- // 开机等待 2 秒(等待各模块初始化稳定后),发送包含电量、连接等 10 项的完整状态报告
- vTaskDelay(pdMS_TO_TICKS(2000));
- int pct = 0;
- bool chg = false;
-
- // 初始化并读取真实电量
- if (board_battery_read(&pct, &chg)) {
- s_battery_percent = pct;
- }
-
- // 开机 2s 后主动推送全局初始化状态(包含正确的初始电量)
- report_all_status();
- uint8_t last_sent_pct = s_battery_percent;
- bool low_battery_played = false;
- while (1) {
- if (board_battery_read(&pct, &chg)) {
- s_chg_ing = chg;
- // 充电中只增不减,放电中只减不增
- if (chg) {
- if (pct > s_battery_percent) {
- s_battery_percent = pct;
- }
- } else { // 放电中:只允许容量值单调减少
- if (pct < s_battery_percent) {
- s_battery_percent = pct;
- }
- }
- }
- if (s_battery_percent != last_sent_pct) {
- panel_uart_report(ITEM_BATTERY, s_battery_percent);
- #ifdef CONFIG_BT_A2DP_ENABLE
- bt_a2dp_send_battery_level(s_battery_percent);
- #endif
- last_sent_pct = s_battery_percent;
- ESP_LOGI(TAG, "Bat: %d%%", s_battery_percent);
- }
- // 低电量报警逻辑
- if (s_battery_percent <= 10 && !low_battery_played && !chg) {
- ESP_LOGW(TAG, "触发低电量警告!");
- audio_prompt_play(PROMPT_LOW_BATTERY);
- low_battery_played = true;
- } else if (s_battery_percent > 15 || chg) {
- low_battery_played = false;
- }
- vTaskDelay(pdMS_TO_TICKS(2000));
- }
- }
- // ----------------------------------------------------------------------------
- // 协议接收和处理逻辑
- // ----------------------------------------------------------------------------
- static void protocol_handler(uint8_t *data, int len) {
- for (int i = 0; i < len; i++) {
- if (data[i] != FRAME_HEAD_1) continue;
- if (i + 1 < len && data[i+1] != FRAME_HEAD_2) continue;
- if (i + 4 > len) break; // 至少包含 55 AA CMD LEN
- uint8_t cmd = data[i+2];
- uint8_t pkt_len = data[i+3];
-
- if (i + 4 + pkt_len + 1 > len) break; // 等待完整包 (含 CRC)
- uint8_t *payload = &data[i+4];
- uint8_t expected_crc = cmd ^ pkt_len;
- for (int j = 0; j < pkt_len; j++) {
- expected_crc ^= payload[j];
- }
-
- uint8_t actual_crc = data[i + 4 + pkt_len];
- if (actual_crc != expected_crc) {
- ESP_LOGW(TAG, "CRC 校验错误: 预期 %02X, 实际 %02X", expected_crc, actual_crc);
- continue;
- }
- if (cmd == CMD_READ) {
- // Read expect LEN=2: [ITEM] [VALUE]
- if (pkt_len == 2) {
- uint8_t item = payload[0];
- if (item == 0x00) {
- report_all_status();
- } else {
- switch (item) {
- case ITEM_SOURCE:
- send_frame(CMD_READ, ITEM_SOURCE, (dac_njw1195_get_source() == NJW_SOURCE_BT) ? PROTO_VAL_ON : PROTO_VAL_OFF);
- break;
- case ITEM_BT_CONN:
- send_frame(CMD_READ, ITEM_BT_CONN, s_bt_connected ? PROTO_VAL_ON : PROTO_VAL_OFF);
- break;
- case ITEM_BT_AUDIO:
- send_frame(CMD_READ, ITEM_BT_AUDIO, s_bt_streaming ? PROTO_VAL_ON : PROTO_VAL_OFF);
- break;
- case ITEM_VOL_LR:
- send_frame(CMD_READ, ITEM_VOL_LR, dac_njw1195_get_vol_main());
- break;
- case ITEM_VOL_BASS:
- send_frame(CMD_READ, ITEM_VOL_BASS, dac_njw1195_get_vol_bass());
- break;
- case ITEM_DAC_MUTE:
- send_frame(CMD_READ, ITEM_DAC_MUTE, dac_njw1195_get_mute() ? PROTO_VAL_OFF : PROTO_VAL_ON);
- break;
- case ITEM_AUTO_RECONN:
- send_frame(CMD_READ, ITEM_AUTO_RECONN, PROTO_VAL_ON);
- break;
- case ITEM_BATTERY:
- send_frame(CMD_READ, ITEM_BATTERY, s_battery_percent);
- break;
- case ITEM_CHG_FULL:
- send_frame(CMD_READ, ITEM_CHG_FULL, s_chg_full ? 1 : 0);
- break;
- case ITEM_CHG_ING:
- send_frame(CMD_READ, ITEM_CHG_ING, s_chg_ing ? 1 : 0);
- break;
- default:
- send_frame(CMD_READ, item, 0xFF);
- break;
- }
- }
- }
- } else if (cmd == CMD_WRITE) {
- if (pkt_len == 2) {
- uint8_t item = payload[0];
- uint8_t value = payload[1];
- switch (item) {
- case ITEM_SOURCE:
- if (value == PROTO_VAL_ON) {
- dac_njw1195_set_source(NJW_SOURCE_BT);
- send_ack();
- } else if (value == PROTO_VAL_OFF) {
- dac_njw1195_set_source(NJW_SOURCE_AUX);
- send_ack();
- } else {
- send_frame(CMD_WRITE, ITEM_SOURCE, 0xFF);
- }
- break;
- case ITEM_BT_CONN:
- if (value == PROTO_VAL_OFF) {
- ESP_LOGI(TAG, "RX: Reset");
- #ifdef CONFIG_BT_A2DP_ENABLE
- settings_clear_last_bt_bda();
- bt_a2dp_sink_disconnect_current();
- #endif
- send_ack();
- } else {
- send_frame(CMD_WRITE, ITEM_BT_CONN, 0xFF);
- }
- break;
- case ITEM_DAC_MUTE:
- if (value == PROTO_VAL_ON || value == PROTO_VAL_OFF) {
- dac_njw1195_set_mute(value == PROTO_VAL_OFF);
- send_ack();
- } else {
- send_frame(CMD_WRITE, ITEM_DAC_MUTE, 0xFF);
- }
- break;
- case ITEM_AUTO_RECONN:
- if (value == PROTO_VAL_ON || value == PROTO_VAL_OFF) {
- // 如果有开启/关闭自动回连的需求,在这里处理
- send_ack();
- } else {
- send_frame(CMD_WRITE, ITEM_AUTO_RECONN, 0xFF);
- }
- break;
- case ITEM_VOL_LR:
- ESP_LOGD(TAG, "面板音量设置为: %d", value);
- s_in_panel_update = true;
- dac_njw1195_set_vol_main(value);
- ESP_LOGD(TAG, "同步音量到播放器...");
- playback_control_set_volume_percent(value);
- s_in_panel_update = false;
- ESP_LOGD(TAG, "音量已同步,发送 ACK 应答...");
- send_ack();
- break;
- case ITEM_VOL_BASS:
- dac_njw1195_set_vol_bass(value);
- send_ack();
- break;
- case ITEM_RESET:
- send_ack();
- vTaskDelay(pdMS_TO_TICKS(50));
- settings_clear_wifi_credentials();
- esp_wifi_restore(); // 清除 WiFi 信息
- esp_restart();
- break;
- case ITEM_BASS_MUTE:
- if (value == PROTO_VAL_ON) {
- dac_njw1195_set_vol_bass(s_bass_before_mute);
- send_ack();
- } else if (value == PROTO_VAL_OFF) {
- s_bass_before_mute = dac_njw1195_get_vol_bass();
- dac_njw1195_set_vol_bass(0);
- send_ack();
- } else {
- send_frame(CMD_WRITE, ITEM_BASS_MUTE, 0xFF);
- }
- break;
- default:
- send_frame(CMD_WRITE, item, 0xFF);
- break;
- }
- }
- }
- i += 4 + pkt_len; // 跳过已处理的字节帧
- }
- }
- // ----------------------------------------------------------------------------
- // 串口接收读取任务
- // ----------------------------------------------------------------------------
- static void uart_task(void *arg) {
- uint8_t rx_buf[UART_BUF_SIZE];
- while (1) {
- int len = uart_read_bytes(UART_PORT, rx_buf, sizeof(rx_buf), pdMS_TO_TICKS(50));
- if (len > 0) {
- char hex_str[256] = {0};
- int offset = 0;
- for (int i = 0; i < len && offset < sizeof(hex_str) - 4; i++) {
- offset += snprintf(hex_str + offset, sizeof(hex_str) - offset, "%02X ", rx_buf[i]);
- }
- ESP_LOGI(TAG, "RX_RAW: %s", hex_str);
-
- protocol_handler(rx_buf, len);
- }
- }
- }
- // RTSP 事件回调,统一处理蓝牙和 AirPlay 的连接与播放状态
- static void on_rtsp_event(rtsp_event_t event, const rtsp_event_data_t *data, void *user_data) {
- (void)data;
- (void)user_data;
- switch (event) {
- case RTSP_EVENT_CLIENT_CONNECTED:
- panel_uart_set_bt_state(true, s_bt_streaming);
- break;
- case RTSP_EVENT_DISCONNECTED:
- panel_uart_set_bt_state(false, false);
- break;
- case RTSP_EVENT_PLAYING:
- panel_uart_set_bt_state(s_bt_connected, true);
- break;
- case RTSP_EVENT_PAUSED:
- panel_uart_set_bt_state(s_bt_connected, false);
- break;
- default:
- break;
- }
- }
- // ----------------------------------------------------------------------------
- // 公共对外 API 接口
- // ----------------------------------------------------------------------------
- esp_err_t panel_uart_init(void) {
- // 1. 初始化串口端口 2
- uart_config_t uart_config = {
- .baud_rate = UART_BAUD_RATE,
- .data_bits = UART_DATA_8_BITS,
- .parity = UART_PARITY_DISABLE,
- .stop_bits = UART_STOP_BITS_1,
- .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
- .source_clk = UART_SCLK_DEFAULT,
- };
- ESP_ERROR_CHECK(uart_param_config(UART_PORT, &uart_config));
- ESP_ERROR_CHECK(uart_set_pin(UART_PORT, UART_TX_GPIO, UART_RX_GPIO, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
- ESP_ERROR_CHECK(uart_driver_install(UART_PORT, UART_BUF_SIZE * 2, UART_BUF_SIZE * 2, 0, NULL, 0));
- // 2. 初始化充电状态检测中断 GPIO
- gpio_config_t io_conf = {
- .pin_bit_mask = (1ULL << CHG_FULL_GPIO) | (1ULL << CHG_ING_GPIO),
- .mode = GPIO_MODE_INPUT,
- .pull_up_en = GPIO_PULLUP_DISABLE,
- .pull_down_en = GPIO_PULLDOWN_DISABLE,
- .intr_type = GPIO_INTR_ANYEDGE,
- };
- ESP_ERROR_CHECK(gpio_config(&io_conf));
-
- // 全局安装中断服务,如果已安装则安全跳过 (兼容 IDF)
- gpio_install_isr_service(0);
- ESP_ERROR_CHECK(gpio_isr_handler_add(CHG_FULL_GPIO, charge_isr_handler, NULL));
- ESP_ERROR_CHECK(gpio_isr_handler_add(CHG_ING_GPIO, charge_isr_handler, NULL));
- // 注册 RTSP 事件监听器 (自动上报蓝牙和 AirPlay 的连接及播放状态)
- rtsp_events_register(on_rtsp_event, NULL);
- // 3. 创建执行任务
- xTaskCreate(uart_task, "uart_task", 4096, NULL, 5, NULL);
- xTaskCreate(charge_status_task, "chg_stat", 4096, NULL, 3, &s_charge_task_handle);
- xTaskCreate(report_status_task, "rpt_stat", 4096, NULL, 2, NULL);
- ESP_LOGI(TAG, "UART init OK, TX=%d RX=%d", UART_TX_GPIO, UART_RX_GPIO);
- return ESP_OK;
- }
- void panel_uart_set_bt_state(bool connected, bool streaming) {
- if (s_bt_connected != connected) {
- s_bt_connected = connected;
- panel_uart_report(ITEM_BT_CONN, s_bt_connected ? PROTO_VAL_ON : PROTO_VAL_OFF);
- }
- if (s_bt_streaming != streaming) {
- s_bt_streaming = streaming;
- panel_uart_report(ITEM_BT_AUDIO, s_bt_streaming ? PROTO_VAL_ON : PROTO_VAL_OFF);
- }
- }
- uint8_t panel_uart_get_battery_percent(void) {
- return s_battery_percent;
- }
- bool panel_uart_get_charging_status(void) {
- return s_chg_ing;
- }
|