Refactored and current playstatus is now received from device
This commit is contained in:
parent
1c1ccf0a7a
commit
a92fe02c59
|
@ -2,4 +2,9 @@
|
|||
|
||||
namespace avrcp {
|
||||
void init();
|
||||
bool is_playing();
|
||||
|
||||
void play_pause();
|
||||
void forward();
|
||||
void backward();
|
||||
}
|
||||
|
|
|
@ -6,3 +6,17 @@
|
|||
const char* addr_to_str(esp_bd_addr_t bda);
|
||||
const char* connection_state_to_str(esp_a2d_connection_state_t state);
|
||||
|
||||
class MultiPurposeButton {
|
||||
public:
|
||||
MultiPurposeButton(void(*short_press)(), void(*long_press)(), uint8_t threshold = 5);
|
||||
|
||||
void tick(bool current);
|
||||
|
||||
private:
|
||||
void(*short_press)();
|
||||
void(*long_press)();
|
||||
uint8_t threshold = 5;
|
||||
bool previous = false;
|
||||
uint8_t counter = 0;
|
||||
bool acted = false;
|
||||
};
|
||||
|
|
|
@ -6,8 +6,66 @@
|
|||
|
||||
#define AVRCP_TAG "APP_AVRCP"
|
||||
|
||||
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 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);
|
||||
}
|
||||
}
|
||||
|
||||
static void notify_handler(uint8_t event_id, esp_avrc_rn_param_t *event_parameter) {
|
||||
switch (event_id) {
|
||||
case ESP_AVRC_RN_PLAY_STATUS_CHANGE:
|
||||
ESP_LOGI(AVRCP_TAG, "Playback status changed: 0x%x", event_parameter->playback);
|
||||
playback_status = event_parameter->playback;
|
||||
playback_changed();
|
||||
break;
|
||||
|
||||
default:
|
||||
ESP_LOGI(AVRCP_TAG, "unhandled event: %d", event_id);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
switch (event) {
|
||||
case ESP_AVRC_CT_CONNECTION_STATE_EVT: {
|
||||
uint8_t *bda = param->conn_stat.remote_bda;
|
||||
ESP_LOGI(AVRCP_TAG, "AVRC conn_state event: state %d, [%02x:%02x:%02x:%02x:%02x:%02x]",
|
||||
param->conn_stat.connected, bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);
|
||||
|
||||
if (param->conn_stat.connected) {
|
||||
/* get remote supported event_ids of peer AVRCP Target */
|
||||
esp_avrc_ct_send_get_rn_capabilities_cmd(0);
|
||||
} else {
|
||||
/* clear peer notification capability record */
|
||||
s_avrc_peer_rn_cap.bits = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ESP_AVRC_CT_CHANGE_NOTIFY_EVT:
|
||||
notify_handler(param->change_ntf.event_id, ¶m->change_ntf.event_parameter);
|
||||
break;
|
||||
|
||||
case ESP_AVRC_CT_GET_RN_CAPABILITIES_RSP_EVT:
|
||||
ESP_LOGI(AVRCP_TAG, "remote rn_cap: count %d, bitmask 0x%x", param->get_rn_caps_rsp.cap_count, param->get_rn_caps_rsp.evt_set.bits);
|
||||
s_avrc_peer_rn_cap.bits = param->get_rn_caps_rsp.evt_set.bits;
|
||||
playback_changed();
|
||||
break;
|
||||
|
||||
default:
|
||||
ESP_LOGE(AVRCP_TAG, "%s unhandled event %d", __func__, event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void rc_tg_callback(esp_avrc_tg_cb_event_t event, esp_avrc_tg_cb_param_t* param) {
|
||||
ESP_LOGD(AVRCP_TAG, "%s evt %d", __func__, event);
|
||||
ESP_LOGD(AVRCP_TAG, "%s event %d", __func__, event);
|
||||
|
||||
switch (event) {
|
||||
case ESP_AVRC_TG_SET_ABSOLUTE_VOLUME_CMD_EVT:
|
||||
|
@ -34,7 +92,7 @@ static void rc_tg_callback(esp_avrc_tg_cb_event_t event, esp_avrc_tg_cb_param_t*
|
|||
break;
|
||||
|
||||
default:
|
||||
ESP_LOGE(AVRCP_TAG, "%s unhandled evt %d", __func__, event);
|
||||
ESP_LOGE(AVRCP_TAG, "%s unhandled event %d", __func__, event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +100,10 @@ static void rc_tg_callback(esp_avrc_tg_cb_event_t event, esp_avrc_tg_cb_param_t*
|
|||
void avrcp::init() {
|
||||
ESP_LOGI(AVRCP_TAG, "Initializing AVRCP");
|
||||
|
||||
if (esp_avrc_ct_init() == ESP_OK) {
|
||||
esp_avrc_ct_register_callback(rc_ct_callback);
|
||||
}
|
||||
|
||||
// Initialize AVRCP target
|
||||
if (esp_avrc_tg_init() == ESP_OK) {
|
||||
esp_avrc_tg_register_callback(rc_tg_callback);
|
||||
|
@ -54,3 +116,37 @@ void avrcp::init() {
|
|||
ESP_LOGE(AVRCP_TAG, "esp_avrc_tg_init failed");
|
||||
}
|
||||
}
|
||||
|
||||
bool avrcp::is_playing() {
|
||||
return playback_status == ESP_AVRC_PLAYBACK_PLAYING;
|
||||
}
|
||||
|
||||
static void send_cmd(esp_avrc_pt_cmd_t cmd) {
|
||||
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);
|
||||
}
|
||||
|
||||
void avrcp::play_pause() {
|
||||
if (is_playing()) {
|
||||
ESP_LOGI(AVRCP_TAG, "Pausing");
|
||||
send_cmd(ESP_AVRC_PT_CMD_PAUSE);
|
||||
} else {
|
||||
ESP_LOGI(AVRCP_TAG, "Playing");
|
||||
send_cmd(ESP_AVRC_PT_CMD_PLAY);
|
||||
}
|
||||
}
|
||||
|
||||
void avrcp::forward() {
|
||||
ESP_LOGI(AVRCP_TAG, "Forward");
|
||||
|
||||
send_cmd(ESP_AVRC_PT_CMD_FORWARD);
|
||||
}
|
||||
|
||||
void avrcp::backward() {
|
||||
ESP_LOGI(AVRCP_TAG, "Backward");
|
||||
|
||||
send_cmd(ESP_AVRC_PT_CMD_BACKWARD);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#include <cstdint>
|
||||
#include <string.h>
|
||||
|
||||
#include "esp_avrc_api.h"
|
||||
#include "esp_timer.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/portmacro.h"
|
||||
|
@ -14,6 +13,8 @@
|
|||
|
||||
#include "can.h"
|
||||
#include "can_data.h"
|
||||
#include "avrcp.h"
|
||||
#include "helper.h"
|
||||
|
||||
#define CAN_TAG "APP_CAN"
|
||||
|
||||
|
@ -458,118 +459,15 @@ static void read_message(spi_device_handle_t spi) {
|
|||
read_can_msg(spi, MCP_READ_RX0, &id, &ext, &rtr_bit, &len, buf);
|
||||
}
|
||||
|
||||
/* ESP_LOGI(CAN_TAG, "Received: id=%lu, ext=%i, rtr_bit=%i, len=%i", id, ext, rtr_bit, len); */
|
||||
|
||||
// @TODO Implement the length check in a more elegant manner
|
||||
/* switch (id) { */
|
||||
/* case BUTTONS_ID: */
|
||||
/* print_buttons(*(can::Buttons*)buf); */
|
||||
/* break; */
|
||||
|
||||
/* case RADIO_ID: */
|
||||
/* print_radio(*(can::Radio*)buf); */
|
||||
/* break; */
|
||||
|
||||
/* default: */
|
||||
/* break; */
|
||||
/* } */
|
||||
|
||||
// @TODO Only do this if we actually are on AUX2
|
||||
if (id == BUTTONS_ID) {
|
||||
static can::Buttons previous;
|
||||
static MultiPurposeButton button_forward(avrcp::play_pause, avrcp::forward);
|
||||
static MultiPurposeButton button_backward(nullptr, avrcp::backward);
|
||||
|
||||
can::Buttons buttons = *(can::Buttons*)buf;
|
||||
|
||||
// Forward
|
||||
{
|
||||
static uint8_t counter = 0;
|
||||
static bool disabled = false;
|
||||
|
||||
if (buttons.forward && !disabled) {
|
||||
counter++;
|
||||
|
||||
ESP_LOGI(CAN_TAG, "Counter: %i", counter);
|
||||
|
||||
if (counter > 5) {
|
||||
ESP_LOGI(CAN_TAG, "Forward");
|
||||
// Fast forward
|
||||
esp_err_t ret = esp_avrc_ct_send_passthrough_cmd(0, ESP_AVRC_PT_CMD_FORWARD, ESP_AVRC_PT_CMD_STATE_PRESSED);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
|
||||
ret = esp_avrc_ct_send_passthrough_cmd(1, ESP_AVRC_PT_CMD_FORWARD, ESP_AVRC_PT_CMD_STATE_RELEASED);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
|
||||
// Disable actions from happening again until we release the button
|
||||
disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (previous.forward != buttons.forward && !buttons.forward) {
|
||||
if (counter <= 5) {
|
||||
// @TODO Get this from the actual device instead of assuming that on startup it is falce
|
||||
static bool play_status = false;
|
||||
play_status = !play_status;
|
||||
|
||||
ESP_LOGI(CAN_TAG, "Play button has been pressed");
|
||||
|
||||
if (play_status) {
|
||||
ESP_LOGI(CAN_TAG, "Playing");
|
||||
// @TODO Abstract this away so that we are not directly interfacing with AVRC things
|
||||
esp_err_t ret = esp_avrc_ct_send_passthrough_cmd(0, ESP_AVRC_PT_CMD_PLAY, ESP_AVRC_PT_CMD_STATE_PRESSED);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
|
||||
ret = esp_avrc_ct_send_passthrough_cmd(1, ESP_AVRC_PT_CMD_PLAY, ESP_AVRC_PT_CMD_STATE_RELEASED);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
} else {
|
||||
ESP_LOGI(CAN_TAG, "Pausing");
|
||||
esp_err_t ret = esp_avrc_ct_send_passthrough_cmd(0, ESP_AVRC_PT_CMD_PAUSE, ESP_AVRC_PT_CMD_STATE_PRESSED);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
|
||||
ret = esp_avrc_ct_send_passthrough_cmd(1, ESP_AVRC_PT_CMD_PAUSE, ESP_AVRC_PT_CMD_STATE_RELEASED);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
}
|
||||
}
|
||||
|
||||
counter = 0;
|
||||
disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Backwards
|
||||
{
|
||||
static uint8_t counter = 0;
|
||||
static bool disabled = false;
|
||||
|
||||
if (buttons.backward && !disabled) {
|
||||
counter++;
|
||||
|
||||
ESP_LOGI(CAN_TAG, "Counter: %i", counter);
|
||||
|
||||
if (counter > 5) {
|
||||
ESP_LOGI(CAN_TAG, "Backwards");
|
||||
// Fast forward
|
||||
esp_err_t ret = esp_avrc_ct_send_passthrough_cmd(0, ESP_AVRC_PT_CMD_BACKWARD, ESP_AVRC_PT_CMD_STATE_PRESSED);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
|
||||
ret = esp_avrc_ct_send_passthrough_cmd(1, ESP_AVRC_PT_CMD_BACKWARD, ESP_AVRC_PT_CMD_STATE_RELEASED);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
|
||||
// Disable actions from happening again until we release the button
|
||||
disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (previous.backward != buttons.backward && !buttons.backward) {
|
||||
if (counter <= 5) {
|
||||
// @TODO What do we do when we just press this button?
|
||||
// Might be nice to somehow trigger the google assistant, altough that requires Handsfree profile, which might interfere with the car itself
|
||||
}
|
||||
|
||||
counter = 0;
|
||||
disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
previous = buttons;
|
||||
button_forward.tick(buttons.forward);
|
||||
button_backward.tick(buttons.backward);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,3 +12,33 @@ const char* connection_state_to_str(esp_a2d_connection_state_t state) {
|
|||
const char* states[4] = {"Disconnected", "Connecting", "Connected", "Disconnecting"};
|
||||
return states[state];
|
||||
}
|
||||
|
||||
MultiPurposeButton::MultiPurposeButton(void(*short_press)(), void(*long_press)(), uint8_t threshold) : short_press(short_press), long_press(long_press), threshold(threshold) {}
|
||||
|
||||
void MultiPurposeButton::tick(bool current) {
|
||||
if (current && !acted) {
|
||||
if (counter >= threshold) {
|
||||
// Long press
|
||||
if (long_press) {
|
||||
ESP_LOGI("MPB", "Long press!");
|
||||
long_press();
|
||||
}
|
||||
acted = true;
|
||||
}
|
||||
|
||||
counter++;
|
||||
} else if (previous != current && !current) {
|
||||
// The button just got released
|
||||
|
||||
// Short press
|
||||
if (counter < threshold) {
|
||||
if (short_press) {
|
||||
ESP_LOGI("MPB", "Short press!");
|
||||
short_press();
|
||||
}
|
||||
}
|
||||
|
||||
counter = 0;
|
||||
acted = false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,23 +16,23 @@
|
|||
|
||||
#define APP_TAG "APP"
|
||||
|
||||
void play_task(void*) {
|
||||
void task(void*) {
|
||||
for (;;) {
|
||||
esp_err_t ret = esp_avrc_ct_send_passthrough_cmd(0, ESP_AVRC_PT_CMD_PAUSE, ESP_AVRC_PT_CMD_STATE_PRESSED);
|
||||
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);
|
||||
|
||||
ret = esp_avrc_ct_send_passthrough_cmd(1, ESP_AVRC_PT_CMD_PAUSE, ESP_AVRC_PT_CMD_STATE_RELEASED);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
vTaskDelay(5000 / portTICK_PERIOD_MS);
|
||||
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
|
||||
ret = esp_avrc_ct_send_passthrough_cmd(0, ESP_AVRC_PT_CMD_PLAY, ESP_AVRC_PT_CMD_STATE_PRESSED);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
|
||||
ret = esp_avrc_ct_send_passthrough_cmd(1, ESP_AVRC_PT_CMD_PLAY, ESP_AVRC_PT_CMD_STATE_RELEASED);
|
||||
ESP_ERROR_CHECK(ret);
|
||||
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
if (cmd == ESP_AVRC_PT_CMD_PLAY) {
|
||||
cmd = ESP_AVRC_PT_CMD_PAUSE;
|
||||
} else {
|
||||
cmd = ESP_AVRC_PT_CMD_PLAY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,16 +49,8 @@ extern "C" void app_main() {
|
|||
|
||||
a2dp::connect_to_last();
|
||||
|
||||
/* xTaskCreate(play_task, "Play task", 2048, nullptr, 0, nullptr); */
|
||||
/* xTaskCreate(task, "Task", 2048, nullptr, 0, nullptr); */
|
||||
|
||||
can::init();
|
||||
|
||||
/* uint8_t button_buffer[3] = { 0b01000110, 22, 0x00 }; */
|
||||
/* can::Buttons buttons = *(can::Buttons*)button_buffer; */
|
||||
/* print_buttons(buttons); */
|
||||
|
||||
/* uint8_t radio_buffer[4] = { 0b10100000, 0b01000000, 0b00110000, 0x00 }; */
|
||||
/* can::Radio radio = *(can::Radio*)radio_buffer; */
|
||||
/* print_radio(radio); */
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user