avrcp: get capabilities draft

This commit is contained in:
Milanka Ringwald 2017-02-01 00:06:30 +01:00 committed by Matthias Ringwald
parent 7f535380ac
commit 49bbb6f27b
3 changed files with 132 additions and 43 deletions

View File

@ -290,8 +290,52 @@ static avrcp_connection_t * get_avrcp_connection_for_l2cap_signaling_cid(uint16_
static void avrcp_handle_l2cap_data_packet_for_signaling_connection(avrcp_connection_t * connection, uint8_t *packet, uint16_t size){
if (connection->state != AVCTP_W2_RECEIVE_RESPONSE) return;
connection->state = AVCTP_CONNECTION_OPENED;
avrcp_command_type_t ctype;
avrcp_subunit_type_t subunit_type;
avrcp_subunit_type_t subunit_id;
uint8_t operands[5];
uint8_t opcode;
uint8_t value;
int pos = 0;
uint8_t transport_header = packet[pos++];
uint8_t transaction_label = transport_header >> 4;
uint8_t packet_type = (transport_header & 0x0F) >> 2;
uint8_t frame_type = (transport_header & 0x03) >> 1;
uint8_t ipid = transport_header & 0x01;
value = packet[pos++];
uint16_t pid = (value << 8) | packet[pos++];
printf("L2CAP DATA, response: ");
printf_hexdump(packet, size);
printf(" Transport header 0x%02x (transaction_label %d, packet_type %d, frame_type %d, ipid %d), pid 0x%4x\n",
transport_header, transaction_label, packet_type, frame_type, ipid, pid);
switch (connection->cmd_to_send){
case AVRCP_CMD_OPCODE_UNIT_INFO:{
ctype = packet[pos++];
value = packet[pos++];
subunit_type = value >> 3;
subunit_id = value & 0x07;
opcode = packet[pos++];
// operands:
memcpy(operands, packet+pos, 5);
uint8_t unit_type = operands[1] >> 3;
uint8_t unit = operands[1] & 0x07;
uint32_t company_id = operands[2] << 16 | operands[3] << 8 | operands[4];
printf(" UNIT INFO response: ctype 0x%02x (0C), subunit_type 0x%02x (1F), subunit_id 0x%02x (07), opcode 0x%02x (30), unit_type 0x%02x, unit %d, company_id 0x%06x\n",
ctype, subunit_type, subunit_id, opcode, unit_type, unit, company_id );
break;
}
case AVRCP_CMD_OPCODE_VENDOR_DEPENDENT:
break;
default:
break;
}
}
static int avrcp_send_cmd(uint16_t cid, avrcp_connection_t * connection){
@ -316,20 +360,10 @@ static int avrcp_send_cmd(uint16_t cid, avrcp_connection_t * connection){
return l2cap_send(cid, command, sizeof(command));
}
static void avrcp_handle_can_send_now(avrcp_connection_t * connection, uint16_t l2cap_cid){
if (!connection->wait_to_send) return;
static void avrcp_handle_can_send_now(avrcp_connection_t * connection){
if (connection->state != AVCTP_W2_SEND_COMMAND) return;
if (connection->cmd_to_send){
connection->wait_to_send = 0;
connection->state = AVCTP_W2_RECEIVE_RESPONSE;
avrcp_send_cmd(connection->l2cap_signaling_cid, connection);
}
int more_to_send = connection->wait_to_send;
if (more_to_send){
l2cap_request_can_send_now_event(l2cap_cid);
}
}
static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){
@ -387,7 +421,7 @@ static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packe
case L2CAP_EVENT_CAN_SEND_NOW:
connection = get_avrcp_connection_for_l2cap_signaling_cid(channel);
if (!connection) break;
avrcp_handle_can_send_now(connection, channel);
avrcp_handle_can_send_now(connection);
break;
case L2CAP_EVENT_CHANNEL_CLOSED:
@ -464,12 +498,35 @@ void avrcp_unit_info(uint16_t con_handle){
if (connection->state != AVCTP_CONNECTION_OPENED) return;
connection->state = AVCTP_W2_SEND_COMMAND;
connection->cmd_to_send = AVRCP_UNIT_INFO;
connection->cmd_to_send = AVRCP_CMD_OPCODE_UNIT_INFO;
connection->cmd_operands_lenght = 5;
connection->subunit_type = 0x1F;
connection->subunit_id = 7;
connection->command_type = AVRCP_STATUS_COMMAND;
connection->subunit_type = AVRCP_SUBUNIT_TYPE_UNIT;
connection->subunit_id = AVRCP_SUBUNIT_ID_IGNORE;
connection->command_type = AVRCP_CTYPE_STATUS;
connection->transaction_label++;
memset(connection->cmd_operands, 0xFF, connection->cmd_operands_lenght);
avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
}
void avrcp_get_capabilities(uint16_t con_handle){
avrcp_connection_t * connection = get_avrcp_connection_for_con_handle(con_handle);
if (!connection){
log_error("avrcp_unit_info: coud not find a connection.");
return;
}
if (connection->state != AVCTP_CONNECTION_OPENED) return;
connection->state = AVCTP_W2_SEND_COMMAND;
connection->cmd_to_send = AVRCP_CMD_OPCODE_VENDOR_DEPENDENT;
connection->command_type = AVRCP_CTYPE_STATUS;
connection->subunit_type = AVRCP_SUBUNIT_TYPE_PANEL;
connection->subunit_id = 0;
connection->transaction_label++;
big_endian_store_24(connection->cmd_operands, 0, BT_SIG_COMPANY_ID);
connection->cmd_operands[3] = 0x10;
connection->cmd_operands[4] = 0;
big_endian_store_16(connection->cmd_operands, 5, 1);
connection->cmd_operands[7] = 0x02;
connection->cmd_operands_lenght = 8;
avrcp_request_can_send_now(connection, connection->l2cap_signaling_cid);
}

View File

@ -51,38 +51,58 @@
extern "C" {
#endif
#define BT_SIG_COMPANY_ID 0x001958
/* API_START */
typedef enum {
AVRCP_CONTROL_COMMAND = 0,
AVRCP_STATUS_COMMAND,
AVRCP_INQUIRY_COMMAND,
AVRCP_NOTIFY_COMMAND,
AVRCP_NOTIFY_RESERVED4_COMMAND,
AVRCP_NOTIFY_RESERVED5_COMMAND,
AVRCP_NOTIFY_RESERVED6_COMMAND,
AVRCP_NOTIFY_RESERVED7_COMMAND,
AVRCP_NOT_IMPLEMENTED_RESPONSE = 8,
AVRCP_ACCEPTED_RESPONSE,
AVRCP_REJECTED_RESPONSE,
AVRCP_IN_TRANSITION_RESPONSE,
AVRCP_IMPLEMENTED_STABLE_RESPONSE,
AVRCP_CHANGED_STABLE_RESPONSE,
AVRCP_RESERVED_RESPONSE,
AVRCP_INTERIM_RESPONSE
AVRCP_CTYPE_CONTROL = 0,
AVRCP_CTYPE_STATUS,
AVRCP_CTYPE_SPECIFIC_INQUIRY,
AVRCP_CTYPE_NOTIFY,
AVRCP_CTYPE_GENERAL_INQUIRY,
AVRCP_CTYPE_RESERVED5,
AVRCP_CTYPE_RESERVED6,
AVRCP_CTYPE_RESERVED7,
AVRCP_CTYPE_RESPONSE_NOT_IMPLEMENTED = 8,
AVRCP_CTYPE_RESPONSE_ACCEPTED,
AVRCP_CTYPE_RESPONSE_REJECTED,
AVRCP_CTYPE_RESPONSE_IN_TRANSITION,
AVRCP_CTYPE_RESPONSE_IMPLEMENTED_STABLE,
AVRCP_CTYPE_RESPONSE_CHANGED_STABLE,
AVRCP_CTYPE_RESPONSE_RESERVED,
AVRCP_CTYPE_RESPONSE_INTERIM
} avrcp_command_type_t;
typedef enum {
AVRCP_SUBUNIT_TYPE_VIDEO_MONITOR = 0,
AVRCP_SUBUNIT_TYPE_AVIDEO_CASSETTE_RECORDER = 4,
AVRCP_SUBUNIT_TYPE_TV_TUNER = 5,
AVRCP_SUBUNIT_TYPE_VIDEO_CAMERA = 7,
AVRCP_SUBUNIT_TYPE_MONITOR = 0,
AVRCP_SUBUNIT_TYPE_AUDIO = 1,
AVRCP_SUBUNIT_TYPE_PRINTER,
AVRCP_SUBUNIT_TYPE_DISC,
AVRCP_SUBUNIT_TYPE_TAPE_RECORDER_PLAYER,
AVRCP_SUBUNIT_TYPE_TUNER,
AVRCP_SUBUNIT_TYPE_CA,
AVRCP_SUBUNIT_TYPE_CAMERA,
AVRCP_SUBUNIT_TYPE_RESERVED,
AVRCP_SUBUNIT_TYPE_PANEL = 9,
AVRCP_SUBUNIT_TYPE_BULLETIN_BOARD,
AVRCP_SUBUNIT_TYPE_CAMERA_STORAGE,
AVRCP_SUBUNIT_TYPE_VENDOR_UNIQUE = 0x1C,
AVRCP_SUBUNIT_TYPE_RESERVED_FOR_ALL_SUBUNIT_TYPES,
AVRCP_SUBUNIT_TYPE_EXTENDED_TO_NEXT_BYTE,
AVRCP_SUBUNIT_TYPE_UNIT = 0x1F
} avrcp_subunit_type_t;
typedef enum {
AVRCP_SUBUNIT_ID = 0,
AVRCP_SUBUNIT_ID_IGNORE = 7
} avrcp_subunit_id_t;
typedef enum{
AVRCP_CMD_NONE = 0,
AVRCP_UNIT_INFO = 0x30
AVRCP_CMD_OPCODE_VENDOR_DEPENDENT = 0x00,
AVRCP_CMD_OPCODE_RESERVE = 0x01,
AVRCP_CMD_OPCODE_UNIT_INFO = 0x30,
AVRCP_CMD_OPCODE_SUBUNIT_INFO = 0x31,
AVRCP_CMD_OPCODE_VERSION = 0xB0,
AVRCP_CMD_OPCODE_POWER = 0xB2
} avrcp_command_opcode_t;
typedef enum {
@ -108,8 +128,8 @@ typedef struct {
avrcp_command_opcode_t cmd_to_send;
avrcp_command_type_t command_type;
avrcp_subunit_type_t subunit_type;
avrcp_subunit_type_t subunit_id;
uint8_t cmd_operands[5];
avrcp_subunit_id_t subunit_id;
uint8_t cmd_operands[20];
uint8_t cmd_operands_lenght;
} avrcp_connection_t;
@ -154,11 +174,17 @@ void avrcp_register_packet_handler(btstack_packet_handler_t callback);
void avrcp_connect(bd_addr_t bd_addr);
/**
* @brief Pause.
* @brief Unit info.
* @param con_handle
*/
void avrcp_unit_info(uint16_t con_handle);
/**
* @brief Unit info.
* @param con_handle
*/
void avrcp_get_capabilities(uint16_t con_handle);
/* API_END */
#if defined __cplusplus

View File

@ -114,6 +114,8 @@ static void show_usage(void){
printf("c - create connection to addr %s\n", bd_addr_to_str(remote));
printf("C - disconnect\n");
printf("u - get unit info\n");
printf("p - get capabilities\n");
printf("Ctrl-c - exit\n");
printf("---\n");
}
@ -133,6 +135,10 @@ static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callbac
printf("u - get unit info\n");
avrcp_unit_info(con_handle);
break;
case 'p':
printf("p - get capabilities\n");
avrcp_get_capabilities(con_handle);
break;
default:
show_usage();
break;