Volume is now synced from car to phone

This commit is contained in:
Dreaded_X 2022-06-15 15:58:45 +02:00
parent 2f854ad54d
commit d05f767827
Signed by: Dreaded_X
GPG Key ID: 76BDEC4E165D8AD9
5 changed files with 122 additions and 92 deletions

View File

@ -1,5 +1,7 @@
#pragma once
#include <cstdint>
namespace avrcp {
void init();
bool is_playing();
@ -7,4 +9,6 @@ namespace avrcp {
void play_pause();
void forward();
void backward();
void set_volume(uint8_t volume);
}

View File

@ -3,26 +3,11 @@
#include <cstdint>
#include <stdint.h>
#define BUTTONS_ID 0x21f
#define RADIO_ID 0x165
#define VOLUME_ID 0x1A5
#define BUTTONS_ID 0x21f
namespace can {
#pragma pack(1)
struct Buttons {
uint8_t _1 : 1;
bool source : 1;
bool volume_down : 1;
bool volume_up : 1;
uint8_t _2 : 2;
bool backward : 1;
bool forward : 1;
uint8_t scroll : 8;
uint8_t _3 : 8;
};
#pragma pack()
enum Source : uint8_t {
Bluetooth = 0b111,
USB = 0b110,
@ -58,4 +43,31 @@ namespace can {
uint8_t _7 : 8;
};
#pragma pack()
#pragma pack(1)
struct Buttons {
uint8_t _1 : 1;
bool source : 1;
bool volume_down : 1;
bool volume_up : 1;
uint8_t _2 : 2;
bool backward : 1;
bool forward : 1;
uint8_t scroll : 8;
uint8_t _3 : 8;
};
#pragma pack()
#pragma pack(1)
struct Volume {
uint8_t _upper : 3;
uint8_t volume : 5;
bool scrolled() {
return _upper == 0b000;
}
};
#pragma pack()
}

View File

@ -9,6 +9,10 @@
static esp_avrc_rn_evt_cap_mask_t s_avrc_peer_rn_cap;
static esp_avrc_playback_stat_t playback_status = ESP_AVRC_PLAYBACK_STOPPED;
static uint8_t volume = 127;
static _lock_t volume_lock;
static bool volume_notify = false;
static void playback_changed() {
if (esp_avrc_rn_evt_bit_mask_operation(ESP_AVRC_BIT_MASK_OP_TEST, &s_avrc_peer_rn_cap, ESP_AVRC_RN_PLAY_STATUS_CHANGE)) {
esp_avrc_ct_send_register_notification_cmd(1, ESP_AVRC_RN_PLAY_STATUS_CHANGE, 0);
@ -29,6 +33,13 @@ static void notify_handler(uint8_t event_id, esp_avrc_rn_param_t *event_paramete
}
}
static void set_volume_value(uint8_t v) {
ESP_LOGI(AVRCP_TAG, "Setting internal volume value to %i", v);
_lock_acquire(&volume_lock);
volume = v;
_lock_release(&volume_lock);
}
static void rc_ct_callback(esp_avrc_ct_cb_event_t event, esp_avrc_ct_cb_param_t *param) {
ESP_LOGD(AVRCP_TAG, "%s event %d", __func__, event);
@ -71,6 +82,7 @@ static void rc_tg_callback(esp_avrc_tg_cb_event_t event, esp_avrc_tg_cb_param_t*
case ESP_AVRC_TG_SET_ABSOLUTE_VOLUME_CMD_EVT:
ESP_LOGI(AVRCP_TAG, "AVRC set absolute volume: %d%%", (int)param->set_abs_vol.volume * 100/ 0x7f);
// The phone want to change the volume
set_volume_value(param->set_abs_vol.volume);
break;
case ESP_AVRC_TG_REGISTER_NOTIFICATION_EVT:
@ -83,11 +95,14 @@ static void rc_tg_callback(esp_avrc_tg_cb_event_t event, esp_avrc_tg_cb_param_t*
// However for now it is not really relevant as the volume control is doen by the car
// In the future however it might be nice to sync the value on the phone, the esp and the car
// This will require some sort of CAN bus access
volume_notify = true;
esp_avrc_rn_param_t rn_param;
rn_param.volume = 127;
rn_param.volume = volume;
esp_avrc_tg_send_rn_rsp(ESP_AVRC_RN_VOLUME_CHANGE, ESP_AVRC_RN_RSP_INTERIM, &rn_param);
} else if (param->reg_ntf.event_id == ESP_AVRC_RN_PLAY_POS_CHANGED) {
ESP_LOGI(AVRCP_TAG, "We can change the play position?");
} else {
ESP_LOGW(AVRCP_TAG, "AVRC Volume Changes NOT Supported");
ESP_LOGI(AVRCP_TAG, "Something else!");
}
break;
@ -106,12 +121,23 @@ void avrcp::init() {
// Initialize AVRCP target
if (esp_avrc_tg_init() == ESP_OK) {
esp_avrc_tg_register_callback(rc_tg_callback);
esp_avrc_rn_evt_cap_mask_t evt_set = {0};
esp_avrc_rn_evt_bit_mask_operation(ESP_AVRC_BIT_MASK_OP_SET, &evt_set, ESP_AVRC_RN_VOLUME_CHANGE);
if (esp_avrc_tg_set_rn_evt_cap(&evt_set) != ESP_OK) {
ESP_LOGE(AVRCP_TAG, "esp_avrc_tg_set_rn_evt_cap failed");
{
esp_avrc_tg_register_callback(rc_tg_callback);
esp_avrc_rn_evt_cap_mask_t evt_set = {0};
esp_avrc_rn_evt_bit_mask_operation(ESP_AVRC_BIT_MASK_OP_SET, &evt_set, ESP_AVRC_RN_VOLUME_CHANGE);
if (esp_avrc_tg_set_rn_evt_cap(&evt_set) != ESP_OK) {
ESP_LOGE(AVRCP_TAG, "esp_avrc_tg_set_rn_evt_cap failed");
}
}
/* { */
/* esp_avrc_tg_register_callback(rc_tg_callback); */
/* esp_avrc_rn_evt_cap_mask_t evt_set = {0}; */
/* esp_avrc_rn_evt_bit_mask_operation(ESP_AVRC_BIT_MASK_OP_SET, &evt_set, ESP_AVRC_RN_PLAY_POS_CHANGED); */
/* if (esp_avrc_tg_set_rn_evt_cap(&evt_set) != ESP_OK) { */
/* ESP_LOGE(AVRCP_TAG, "esp_avrc_tg_set_rn_evt_cap failed"); */
/* } */
/* } */
} else {
ESP_LOGE(AVRCP_TAG, "esp_avrc_tg_init failed");
}
@ -150,3 +176,16 @@ void avrcp::backward() {
send_cmd(ESP_AVRC_PT_CMD_BACKWARD);
}
void avrcp::set_volume(uint8_t v) {
set_volume_value(v);
if (volume_notify) {
ESP_LOGI(AVRCP_TAG, "Setting remote volume value to %i", v);
esp_avrc_rn_param_t rn_param;
rn_param.volume = volume;
esp_avrc_tg_send_rn_rsp(ESP_AVRC_RN_VOLUME_CHANGE, ESP_AVRC_RN_RSP_CHANGED, &rn_param);
volume_notify = false;
}
}

View File

@ -1,5 +1,6 @@
#include <cstdint>
#include <string.h>
#include <cmath>
#include "esp_timer.h"
#include "freertos/FreeRTOS.h"
@ -364,32 +365,6 @@ static void read_can_msg(spi_device_handle_t spi, uint8_t buffer_load_addr, unsi
ESP_ERROR_CHECK(ret);
}
static void print_buttons(can::Buttons buttons) {
/* ESP_LOGI(CAN_TAG, "BUTTONS"); */
if (buttons.forward) {
ESP_LOGI(CAN_TAG, "Button: F");
}
if (buttons.backward) {
ESP_LOGI(CAN_TAG, "Button: B");
}
if (buttons.volume_up) {
ESP_LOGI(CAN_TAG, "Button: U");
}
if (buttons.volume_down) {
ESP_LOGI(CAN_TAG, "Button: D");
}
if (buttons.source) {
ESP_LOGI(CAN_TAG, "Button: S");
}
// Only print when scroll changes value
static uint8_t scroll = 0;
if (buttons.scroll != scroll) {
scroll = buttons.scroll;
ESP_LOGI(CAN_TAG, "Scroll: %i", buttons.scroll);
}
}
static void print_radio(can::Radio radio) {
ESP_LOGI(CAN_TAG, "RADIO");
if (radio.enabled) {
@ -444,33 +419,6 @@ static void print_radio(can::Radio radio) {
}
}
static void read_message(spi_device_handle_t spi) {
uint8_t status = read_rx_tx_status(spi);
unsigned long id;
uint8_t ext;
uint8_t rtr_bit;
uint8_t len;
uint8_t buf[8];
if (status & MCP_RX0IF) {
read_can_msg(spi, MCP_READ_RX0, &id, &ext, &rtr_bit, &len, buf);
} else if (status & MCP_RX1IF) {
read_can_msg(spi, MCP_READ_RX0, &id, &ext, &rtr_bit, &len, buf);
}
// @TODO Only do this if we actually are on AUX2
if (id == BUTTONS_ID) {
static MultiPurposeButton button_forward(avrcp::play_pause, avrcp::forward);
static MultiPurposeButton button_backward(nullptr, avrcp::backward);
can::Buttons buttons = *(can::Buttons*)buf;
button_forward.tick(buttons.forward);
button_backward.tick(buttons.backward);
}
}
static void id_to_buf(const uint8_t ext, const unsigned long id, uint8_t* buf) {
uint16_t canid = id & 0xFFFF;
@ -497,7 +445,39 @@ static void write_id(spi_device_handle_t spi, const uint8_t addr, const uint8_t
set_registers(spi, addr, buf, 4);
}
void can_task(void* params) {
static void read_message(spi_device_handle_t spi) {
uint8_t status = read_rx_tx_status(spi);
unsigned long id;
uint8_t ext;
uint8_t rtr_bit;
uint8_t len;
uint8_t buf[8];
if (status & MCP_RX0IF) {
read_can_msg(spi, MCP_READ_RX0, &id, &ext, &rtr_bit, &len, buf);
} else if (status & MCP_RX1IF) {
read_can_msg(spi, MCP_READ_RX0, &id, &ext, &rtr_bit, &len, buf);
}
// @TODO Only do this if we actually are on AUX2
if (id == BUTTONS_ID) {
static MultiPurposeButton button_forward(avrcp::play_pause, avrcp::forward);
static MultiPurposeButton button_backward(nullptr, avrcp::backward);
can::Buttons buttons = *(can::Buttons*)buf;
button_forward.tick(buttons.forward);
button_backward.tick(buttons.backward);
} else if (id == VOLUME_ID) {
can::Volume volume = *(can::Volume*)buf;
if (volume.scrolled()) {
avrcp::set_volume(ceil(volume.volume * 4.2f));
}
}
}
static void can_task(void* params) {
spi_device_handle_t spi = *(spi_device_handle_t*)params;
for (;;) {
@ -561,6 +541,7 @@ void can::init() {
ESP_LOGI(CAN_TAG, "Init filter");
/* write_id(*spi, MCP_RXF0SIDH, 0, 0x165); */
write_id(*spi, MCP_RXF1SIDH, 0, 0x1a5);
write_id(*spi, MCP_RXF1SIDH, 0, 0x21f);
ESP_LOGI(CAN_TAG, "Enter normal mode");

View File

@ -1,3 +1,5 @@
#include <cmath>
#include "esp_avrc_api.h"
#include "esp_log.h"
@ -18,21 +20,13 @@
void task(void*) {
for (;;) {
ESP_LOGI("TEST", "Pressing");
static uint8_t cmd = ESP_AVRC_PT_CMD_PLAY;
esp_err_t ret = esp_avrc_ct_send_passthrough_cmd(0, cmd, ESP_AVRC_PT_CMD_STATE_PRESSED);
ESP_ERROR_CHECK(ret);
ret = esp_avrc_ct_send_passthrough_cmd(1, cmd, ESP_AVRC_PT_CMD_STATE_RELEASED);
ESP_ERROR_CHECK(ret);
vTaskDelay(5000 / portTICK_PERIOD_MS);
if (cmd == ESP_AVRC_PT_CMD_PLAY) {
cmd = ESP_AVRC_PT_CMD_PAUSE;
} else {
cmd = ESP_AVRC_PT_CMD_PLAY;
}
static uint8_t volume = 0;
volume = (volume + 1) % 31;
ESP_LOGI(APP_TAG, "Emulation radio with volume: %i", volume);
avrcp::set_volume(ceil(volume * 4.2f));
}
}
@ -51,6 +45,6 @@ extern "C" void app_main() {
/* xTaskCreate(task, "Task", 2048, nullptr, 0, nullptr); */
can::init();
/* can::init(); */
}