avrcp: add all operation IDs, accept all valid operation IDs

This commit is contained in:
Milanka Ringwald 2021-05-21 16:20:44 +02:00
parent 7e3c67e67b
commit 0b578d060f
3 changed files with 99 additions and 42 deletions

View File

@ -111,19 +111,19 @@ const char * avrcp_event2str(uint16_t index){
}
static const char * avrcp_operation_name[] = {
NULL, // 0x3B
"SKIP", NULL, NULL, NULL, NULL,
"VOLUME_UP", "VOLUME_DOWN", "MUTE", "PLAY", "STOP", "PAUSE", NULL,
"REWIND", "FAST_FORWARD", NULL, "FORWARD", "BACKWARD" // 0x4C
};
const char * avrcp_operation2str(uint8_t index){
const char * avrcp_operation2str(uint8_t operation_id){
char * name = NULL;
if ((index >= 0x3B) && (index <= 0x4C)){
name = (char *)avrcp_operation_name[index - 0x3B];
if ((operation_id >= AVRCP_OPERATION_ID_SKIP) && (operation_id <= AVRCP_OPERATION_ID_BACKWARD)){
name = (char *)avrcp_operation_name[operation_id - AVRCP_OPERATION_ID_SKIP];
}
if (name == NULL){
static char buffer[13];
snprintf(buffer, sizeof(buffer), "Unknown 0x%02x", index);
snprintf(buffer, sizeof(buffer), "Unknown 0x%02x", operation_id);
buffer[sizeof(buffer)-1] = 0;
return buffer;
} else {

View File

@ -246,28 +246,80 @@ typedef enum {
} avrcp_command_opcode_t;
typedef enum {
AVRCP_OPERATION_ID_CHANNEL_UP = 0x30,
AVRCP_OPERATION_ID_CHANNEL_DOWN = 0x31,
AVRCP_OPERATION_ID_SELECT = 0x00,
AVRCP_OPERATION_ID_UP = 0x01,
AVRCP_OPERATION_ID_DOWN = 0x02,
AVRCP_OPERATION_ID_LEFT = 0x03,
AVRCP_OPERATION_ID_RIGHT = 0x04,
AVRCP_OPERATION_ID_RIGHT_UP = 0x05,
AVRCP_OPERATION_ID_RIGHT_DOWN = 0x06,
AVRCP_OPERATION_ID_LEFT_UP = 0x07,
AVRCP_OPERATION_ID_LEFT_DOWN = 0x07,
AVRCP_OPERATION_ID_ROOT_MENU = 0x09,
AVRCP_OPERATION_ID_SETUP_MENU = 0x0A,
AVRCP_OPERATION_ID_CONTENTS_MENU = 0x0B,
AVRCP_OPERATION_ID_FAVORITE_MENU = 0x0C,
AVRCP_OPERATION_ID_EXIT = 0x0D,
AVRCP_OPERATION_ID_RESERVED_1 = 0x0E,
AVRCP_OPERATION_ID_0 = 0x20,
AVRCP_OPERATION_ID_1 = 0x21,
AVRCP_OPERATION_ID_2 = 0x22,
AVRCP_OPERATION_ID_3 = 0x23,
AVRCP_OPERATION_ID_4 = 0x24,
AVRCP_OPERATION_ID_5 = 0x25,
AVRCP_OPERATION_ID_6 = 0x26,
AVRCP_OPERATION_ID_7 = 0x27,
AVRCP_OPERATION_ID_8 = 0x28,
AVRCP_OPERATION_ID_9 = 0x29,
AVRCP_OPERATION_ID_DOT = 0x2A,
AVRCP_OPERATION_ID_ENTER = 0x2B,
AVRCP_OPERATION_ID_CLEAR = 0x2C,
AVRCP_OPERATION_ID_RESERVED_2 = 0x2D,
AVRCP_OPERATION_ID_CHANNEL_UP = 0x30,
AVRCP_OPERATION_ID_CHANNEL_DOWN = 0x31,
AVRCP_OPERATION_ID_PREVIOUS_CHANNEL = 0x32,
AVRCP_OPERATION_ID_SOUND_SELECT = 0x33,
AVRCP_OPERATION_ID_INPUT_SELECT = 0x34,
AVRCP_OPERATION_ID_DISPLAY_INFORMATION = 0x35,
AVRCP_OPERATION_ID_HELP = 0x36,
AVRCP_OPERATION_ID_PAGE_UP = 0x37,
AVRCP_OPERATION_ID_PAGE_DOWN = 0x38,
AVRCP_OPERATION_ID_RESERVED_3 = 0x39,
AVRCP_OPERATION_ID_SKIP = 0x3C,
AVRCP_OPERATION_ID_POWER = 0x40,
AVRCP_OPERATION_ID_VOLUME_UP = 0x41,
AVRCP_OPERATION_ID_VOLUME_DOWN = 0x42,
AVRCP_OPERATION_ID_MUTE = 0x43,
AVRCP_OPERATION_ID_PLAY = 0x44,
AVRCP_OPERATION_ID_STOP = 0x45,
AVRCP_OPERATION_ID_PAUSE = 0x46,
AVRCP_OPERATION_ID_RECORD = 0x47,
AVRCP_OPERATION_ID_REWIND = 0x48,
AVRCP_OPERATION_ID_FAST_FORWARD = 0x49,
AVRCP_OPERATION_ID_EJECT = 0x4A,
AVRCP_OPERATION_ID_FORWARD = 0x4B,
AVRCP_OPERATION_ID_BACKWARD = 0x4C,
AVRCP_OPERATION_ID_UNDEFINED = 0xFF
AVRCP_OPERATION_ID_RESERVED_4 = 0x4D,
AVRCP_OPERATION_ID_ANGLE = 0x50,
AVRCP_OPERATION_ID_SUBPICTURE = 0x51,
AVRCP_OPERATION_ID_RESERVED_5 = 0x3D,
AVRCP_OPERATION_ID_F1 = 0xF1,
AVRCP_OPERATION_ID_F2 = 0xF2,
AVRCP_OPERATION_ID_F3 = 0xF3,
AVRCP_OPERATION_ID_F4 = 0xF4,
AVRCP_OPERATION_ID_F5 = 0xF5,
AVRCP_OPERATION_ID_RESERVED_6 = 0xF7
} avrcp_operation_id_t;
typedef enum{

View File

@ -741,6 +741,33 @@ static uint8_t avrcp_target_get_transaction_label_for_notification(avrcp_connect
return connection->notifications_transaction_label[notification];
}
static bool avcrp_operation_id_is_valid(avrcp_operation_id_t operation_id){
if (operation_id < AVRCP_OPERATION_ID_RESERVED_1) return true;
if (operation_id < AVRCP_OPERATION_ID_0) return false;
if (operation_id < AVRCP_OPERATION_ID_RESERVED_2) return true;
if (operation_id < AVRCP_OPERATION_ID_CHANNEL_UP) return false;
if (operation_id < AVRCP_OPERATION_ID_RESERVED_3) return true;
if (operation_id < AVRCP_OPERATION_ID_CHANNEL_UP) return false;
if (operation_id < AVRCP_OPERATION_ID_RESERVED_3) return true;
if (operation_id < AVRCP_OPERATION_ID_SKIP) return false;
if (operation_id == AVRCP_OPERATION_ID_SKIP) return true;
if (operation_id < AVRCP_OPERATION_ID_POWER) return false;
if (operation_id < AVRCP_OPERATION_ID_RESERVED_4) return true;
if (operation_id < AVRCP_OPERATION_ID_ANGLE) return false;
if (operation_id < AVRCP_OPERATION_ID_RESERVED_5) return true;
if (operation_id < AVRCP_OPERATION_ID_F1) return false;
if (operation_id < AVRCP_OPERATION_ID_RESERVED_6) return true;
return false;
}
static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connection_t * connection, uint8_t *packet, uint16_t size){
if (size < 6u) return;
@ -790,6 +817,7 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec
avrcp_pdu_id_t pdu_id;
connection->cmd_operands_length = 0;
uint8_t offset;
uint8_t operand;
switch (opcode){
case AVRCP_CMD_OPCODE_UNIT_INFO:
@ -804,49 +832,26 @@ static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connec
avrcp_target_subunit_info(connection, offset);
break;
case AVRCP_CMD_OPCODE_PASS_THROUGH:{
case AVRCP_CMD_OPCODE_PASS_THROUGH:
if (size < 8) return;
log_info("AVRCP_OPERATION_ID 0x%02x, operands length %d", packet[6], packet[7]);
avrcp_operation_id_t operation_id = (avrcp_operation_id_t) (packet[6] & 0x7f);
bool button_pressed = (packet[6] & 0x80) == 0;
uint8_t operand = 0;
operand = 0;
if ((packet[7] >= 1) && (size >= 9)){
operand = packet[8];
}
switch (operation_id){
case AVRCP_OPERATION_ID_PLAY:
case AVRCP_OPERATION_ID_PAUSE:
case AVRCP_OPERATION_ID_STOP:
case AVRCP_OPERATION_ID_VOLUME_UP:
case AVRCP_OPERATION_ID_VOLUME_DOWN:
case AVRCP_OPERATION_ID_REWIND:
case AVRCP_OPERATION_ID_FAST_FORWARD:
case AVRCP_OPERATION_ID_FORWARD:
case AVRCP_OPERATION_ID_BACKWARD:
case AVRCP_OPERATION_ID_SKIP:
case AVRCP_OPERATION_ID_MUTE:
case AVRCP_OPERATION_ID_CHANNEL_UP:
case AVRCP_OPERATION_ID_CHANNEL_DOWN:
case AVRCP_OPERATION_ID_SELECT:
case AVRCP_OPERATION_ID_UP:
case AVRCP_OPERATION_ID_DOWN:
case AVRCP_OPERATION_ID_LEFT:
case AVRCP_OPERATION_ID_RIGHT:
case AVRCP_OPERATION_ID_ROOT_MENU:
avrcp_target_operation_accepted(connection->avrcp_cid, (avrcp_operation_id_t) packet[6], packet[7], operand);
avrcp_target_emit_operation(avrcp_target_context.avrcp_callback, connection->avrcp_cid,
if (avcrp_operation_id_is_valid(operation_id)){
bool button_pressed = (packet[6] & 0x80) == 0;
avrcp_target_operation_accepted(connection->avrcp_cid, (avrcp_operation_id_t) packet[6], packet[7], operand);
avrcp_target_emit_operation(avrcp_target_context.avrcp_callback, connection->avrcp_cid,
operation_id, button_pressed, packet[7], operand);
break;
case AVRCP_OPERATION_ID_UNDEFINED:
avrcp_target_operation_not_implemented(connection->avrcp_cid, (avrcp_operation_id_t) packet[6], packet[7], operand);
return;
default:
avrcp_target_operation_not_implemented(connection->avrcp_cid, (avrcp_operation_id_t) packet[6], packet[7], operand);
return;
} else {
avrcp_target_operation_not_implemented(connection->avrcp_cid, (avrcp_operation_id_t) packet[6], packet[7], operand);
}
break;
}
case AVRCP_CMD_OPCODE_VENDOR_DEPENDENT: