diff --git a/software/main/include/avrcp.h b/software/main/include/avrcp.h index 37ead03..a59f7c7 100644 --- a/software/main/include/avrcp.h +++ b/software/main/include/avrcp.h @@ -1,5 +1,7 @@ #pragma once +#include + 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); } diff --git a/software/main/include/can_data.h b/software/main/include/can_data.h index 8955f80..bb2db90 100644 --- a/software/main/include/can_data.h +++ b/software/main/include/can_data.h @@ -3,26 +3,11 @@ #include #include -#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() } diff --git a/software/main/src/avrcp.cpp b/software/main/src/avrcp.cpp index 03bb082..2639c8b 100644 --- a/software/main/src/avrcp.cpp +++ b/software/main/src/avrcp.cpp @@ -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; + } +} + diff --git a/software/main/src/can.cpp b/software/main/src/can.cpp index b385f81..eb02245 100644 --- a/software/main/src/can.cpp +++ b/software/main/src/can.cpp @@ -1,5 +1,6 @@ #include #include +#include #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"); diff --git a/software/main/src/main.cpp b/software/main/src/main.cpp index cd9ab97..bf0a388 100644 --- a/software/main/src/main.cpp +++ b/software/main/src/main.cpp @@ -1,3 +1,5 @@ +#include + #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(); */ }