diff --git a/src/btstack_memory.c b/src/btstack_memory.c index c31714180..64823f930 100644 --- a/src/btstack_memory.c +++ b/src/btstack_memory.c @@ -554,6 +554,45 @@ void btstack_memory_avdtp_connection_free(avdtp_connection_t *avdtp_connection){ #endif + +// MARK: avrcp_connection_t +#if !defined(HAVE_MALLOC) && !defined(MAX_NR_AVRCP_CONNECTIONS) + #if defined(MAX_NO_AVRCP_CONNECTIONS) + #error "Deprecated MAX_NO_AVRCP_CONNECTIONS defined instead of MAX_NR_AVRCP_CONNECTIONS. Please update your btstack_config.h to use MAX_NR_AVRCP_CONNECTIONS." + #else + #define MAX_NR_AVRCP_CONNECTIONS 0 + #endif +#endif + +#ifdef MAX_NR_AVRCP_CONNECTIONS +#if MAX_NR_AVRCP_CONNECTIONS > 0 +static avrcp_connection_t avrcp_connection_storage[MAX_NR_AVRCP_CONNECTIONS]; +static btstack_memory_pool_t avrcp_connection_pool; +avrcp_connection_t * btstack_memory_avrcp_connection_get(void){ + return (avrcp_connection_t *) btstack_memory_pool_get(&avrcp_connection_pool); +} +void btstack_memory_avrcp_connection_free(avrcp_connection_t *avrcp_connection){ + btstack_memory_pool_free(&avrcp_connection_pool, avrcp_connection); +} +#else +avrcp_connection_t * btstack_memory_avrcp_connection_get(void){ + return NULL; +} +void btstack_memory_avrcp_connection_free(avrcp_connection_t *avrcp_connection){ + // silence compiler warning about unused parameter in a portable way + (void) avrcp_connection; +}; +#endif +#elif defined(HAVE_MALLOC) +avrcp_connection_t * btstack_memory_avrcp_connection_get(void){ + return (avrcp_connection_t*) malloc(sizeof(avrcp_connection_t)); +} +void btstack_memory_avrcp_connection_free(avrcp_connection_t *avrcp_connection){ + free(avrcp_connection); +} +#endif + + #ifdef ENABLE_BLE // MARK: gatt_client_t @@ -712,6 +751,9 @@ void btstack_memory_init(void){ #if MAX_NR_AVDTP_CONNECTIONS > 0 btstack_memory_pool_create(&avdtp_connection_pool, avdtp_connection_storage, MAX_NR_AVDTP_CONNECTIONS, sizeof(avdtp_connection_t)); #endif +#if MAX_NR_AVRCP_CONNECTIONS > 0 + btstack_memory_pool_create(&avrcp_connection_pool, avrcp_connection_storage, MAX_NR_AVRCP_CONNECTIONS, sizeof(avrcp_connection_t)); +#endif #ifdef ENABLE_BLE #if MAX_NR_GATT_CLIENTS > 0 btstack_memory_pool_create(&gatt_client_pool, gatt_client_storage, MAX_NR_GATT_CLIENTS, sizeof(gatt_client_t)); diff --git a/src/btstack_memory.h b/src/btstack_memory.h index f3d865f91..8920ddc7e 100644 --- a/src/btstack_memory.h +++ b/src/btstack_memory.h @@ -66,6 +66,7 @@ extern "C" { #include "classic/sdp_server.h" #include "classic/avdtp_sink.h" #include "classic/avdtp_source.h" +#include "../../test/avrcp/avrcp.h" // BLE #ifdef ENABLE_BLE @@ -126,6 +127,10 @@ void btstack_memory_avdtp_stream_endpoint_free(avdtp_stream_endpoint_t *avdtp_ avdtp_connection_t * btstack_memory_avdtp_connection_get(void); void btstack_memory_avdtp_connection_free(avdtp_connection_t *avdtp_connection); +// avrcp_connection +avrcp_connection_t * btstack_memory_avrcp_connection_get(void); +void btstack_memory_avrcp_connection_free(avrcp_connection_t *avrcp_connection); + #ifdef ENABLE_BLE // gatt_client, whitelist_entry, sm_lookup_entry gatt_client_t * btstack_memory_gatt_client_get(void); diff --git a/test/avrcp/.gitignore b/test/avrcp/.gitignore new file mode 100644 index 000000000..3c2ec8769 --- /dev/null +++ b/test/avrcp/.gitignore @@ -0,0 +1 @@ +avrcp_test \ No newline at end of file diff --git a/test/avrcp/Makefile b/test/avrcp/Makefile new file mode 100644 index 000000000..f29833c31 --- /dev/null +++ b/test/avrcp/Makefile @@ -0,0 +1,84 @@ +# Makefile for libusb based PTS tests +BTSTACK_ROOT = ../.. + +include ${BTSTACK_ROOT}/3rd-party/bluedroid/decoder/Makefile.inc +include ${BTSTACK_ROOT}/3rd-party/bluedroid/encoder/Makefile.inc + +CORE += \ + btstack_memory.c \ + btstack_linked_list.c \ + btstack_memory_pool.c \ + btstack_run_loop.c \ + btstack_util.c \ + main.c \ + stdin_support.c \ + + +COMMON += \ + hci.c \ + hci_cmd.c \ + hci_dump.c \ + l2cap.c \ + l2cap_signaling.c \ + hci_transport_h2_libusb.c \ + btstack_run_loop_posix.c \ + btstack_link_key_db_fs.c \ + le_device_db_fs.c \ + wav_util.c \ + sdp_util.c \ + sdp_server.c \ + +CFLAGS += -g -Wall -Wmissing-prototypes -Wstrict-prototypes -Wshadow -Wunused-variable -Wunused-parameter -Werror +CFLAGS += -I. +CFLAGS += -I${BTSTACK_ROOT}/src +CFLAGS += -I${BTSTACK_ROOT}/src/classic +CFLAGS += -I${BTSTACK_ROOT}/3rd-party/bluedroid/decoder/include -D OI_DEBUG +CFLAGS += -I${BTSTACK_ROOT}/3rd-party/bluedroid/encoder/include +CFLAGS += -I${BTSTACK_ROOT}/platform/posix +CFLAGS += -I${BTSTACK_ROOT}/platform/embedded +CFLAGS += -I${BTSTACK_ROOT}/port/libusb + +VPATH += ${BTSTACK_ROOT}/src +VPATH += ${BTSTACK_ROOT}/src/classic +VPATH += ${BTSTACK_ROOT}/platform/posix +VPATH += ${BTSTACK_ROOT}/platform/libusb +VPATH += ${BTSTACK_ROOT}/port/libusb +VPATH += ${BTSTACK_ROOT}/3rd-party/bluedroid/decoder/srce +VPATH += ${BTSTACK_ROOT}/3rd-party/bluedroid/encoder/srce + +# use pkg-config for libusb +CFLAGS += $(shell pkg-config libusb-1.0 --cflags) +LDFLAGS += $(shell pkg-config libusb-1.0 --libs) + +# use pkg-config for portaudio +CFLAGS += $(shell pkg-config portaudio-2.0 --cflags) -DHAVE_PORTAUDIO +LDFLAGS += $(shell pkg-config portaudio-2.0 --libs) + +SBC_DECODER += \ + ${BTSTACK_ROOT}/src/classic/btstack_sbc_plc.c \ + ${BTSTACK_ROOT}/src/classic/btstack_sbc_bludroid.c \ + +SBC_ENCODER += \ + ${BTSTACK_ROOT}/src/classic/btstack_sbc_bludroid.c \ + ${BTSTACK_ROOT}/src/classic/hfp_msbc.c \ + +AVRCP += \ + avrcp.c \ + +AVRCP_TESTS = avrcp_test + +CORE_OBJ = $(CORE:.c=.o) +COMMON_OBJ = $(COMMON:.c=.o) +SBC_DECODER_OBJ = $(SBC_DECODER:.c=.o) +SBC_ENCODER_OBJ = $(SBC_ENCODER:.c=.o) +AVRCP_OBJ = $(AVRCP:.c=.o) + +all: ${AVRCP_TESTS} + +avrcp_test: ${CORE_OBJ} ${COMMON_OBJ} ${SBC_DECODER_OBJ} ${SBC_ENCODER_OBJ} ${AVRCP_OBJ} avrcp_test.o + ${CC} $^ ${CFLAGS} ${LDFLAGS} -o $@ + +test: all + +clean: + rm -rf *.pyc *.o $(AVDTP_TESTS) *.dSYM *_test *.wav *.sbc diff --git a/test/avrcp/avrcp.c b/test/avrcp/avrcp.c new file mode 100644 index 000000000..b52f36e51 --- /dev/null +++ b/test/avrcp/avrcp.c @@ -0,0 +1,258 @@ +/* + * Copyright (C) 2016 BlueKitchen GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * 4. Any redistribution, use, or modification is done solely for + * personal benefit and not for any commercial purpose or for + * monetary gain. + * + * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS + * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Please inquire about commercial licensing options at + * contact@bluekitchen-gmbh.com + * + */ + +#include +#include +#include +#include +#include + +#include "btstack.h" +#include "avrcp.h" + +static const char * default_avrcp_controller_service_name = "BTstack AVRCP Controller Service"; +static const char * default_avrcp_controller_service_provider_name = "BTstack AVRCP Controller Service Provider"; + +static btstack_linked_list_t avrcp_connections; +static btstack_packet_handler_t avrcp_callback; + +static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size); + +void avrcp_controller_create_sdp_record(uint8_t * service, uint32_t service_record_handle, uint16_t supported_features, const char * service_name, const char * service_provider_name){ + uint8_t* attribute; + de_create_sequence(service); + + // 0x0000 "Service Record Handle" + de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ServiceRecordHandle); + de_add_number(service, DE_UINT, DE_SIZE_32, service_record_handle); + + // 0x0001 "Service Class ID List" + de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ServiceClassIDList); + attribute = de_push_sequence(service); + { + de_add_number(attribute, DE_UUID, DE_SIZE_16, AUDIO_SINK_GROUP); + } + de_pop_sequence(service, attribute); + + // 0x0004 "Protocol Descriptor List" + de_add_number(service, DE_UINT, DE_SIZE_16, SDP_ProtocolDescriptorList); + attribute = de_push_sequence(service); + { + uint8_t* l2cpProtocol = de_push_sequence(attribute); + { + de_add_number(l2cpProtocol, DE_UUID, DE_SIZE_16, SDP_L2CAPProtocol); + de_add_number(l2cpProtocol, DE_UINT, DE_SIZE_16, PSM_AVCTP); + } + de_pop_sequence(attribute, l2cpProtocol); + + uint8_t* avProtocol = de_push_sequence(attribute); + { + de_add_number(avProtocol, DE_UUID, DE_SIZE_16, PSM_AVCTP); // avProtocol_service + de_add_number(avProtocol, DE_UINT, DE_SIZE_16, 0x0103); // version + } + de_pop_sequence(attribute, avProtocol); + } + de_pop_sequence(service, attribute); + + // 0x0005 "Public Browse Group" + de_add_number(service, DE_UINT, DE_SIZE_16, SDP_BrowseGroupList); // public browse group + attribute = de_push_sequence(service); + { + de_add_number(attribute, DE_UUID, DE_SIZE_16, SDP_PublicBrowseGroup); + } + de_pop_sequence(service, attribute); + + // 0x0009 "Bluetooth Profile Descriptor List" + de_add_number(service, DE_UINT, DE_SIZE_16, SDP_BluetoothProfileDescriptorList); + attribute = de_push_sequence(service); + { + uint8_t *a2dProfile = de_push_sequence(attribute); + { + de_add_number(a2dProfile, DE_UUID, DE_SIZE_16, ADVANCED_AUDIO_DISTRIBUTION); + de_add_number(a2dProfile, DE_UINT, DE_SIZE_16, 0x0103); + } + de_pop_sequence(attribute, a2dProfile); + } + de_pop_sequence(service, attribute); + + + // 0x0100 "Service Name" + de_add_number(service, DE_UINT, DE_SIZE_16, 0x0100); + if (service_name){ + de_add_data(service, DE_STRING, strlen(service_name), (uint8_t *) service_name); + } else { + de_add_data(service, DE_STRING, strlen(default_avrcp_controller_service_name), (uint8_t *) default_avrcp_controller_service_name); + } + + // 0x0100 "Provider Name" + de_add_number(service, DE_UINT, DE_SIZE_16, 0x0102); + if (service_provider_name){ + de_add_data(service, DE_STRING, strlen(service_provider_name), (uint8_t *) service_provider_name); + } else { + de_add_data(service, DE_STRING, strlen(default_avrcp_controller_service_provider_name), (uint8_t *) default_avrcp_controller_service_provider_name); + } + + // 0x0311 "Supported Features" + de_add_number(service, DE_UINT, DE_SIZE_16, 0x0311); + de_add_number(service, DE_UINT, DE_SIZE_16, supported_features); +} + +static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ + bd_addr_t event_addr; + hci_con_handle_t con_handle; + uint16_t psm; + uint16_t local_cid; + +// avrcp_connection_t * connection = NULL; + + switch (packet_type) { + // case L2CAP_DATA_PACKET: + // connection = get_avdtp_connection_for_l2cap_signaling_cid(channel); + // if (connection){ + // handle_l2cap_data_packet_for_signaling_connection(connection, packet, size); + // break; + // } + + // stream_endpoint = get_avdtp_stream_endpoint_for_l2cap_cid(channel); + // if (!stream_endpoint){ + // if (!connection) break; + // handle_l2cap_data_packet_for_signaling_connection(connection, packet, size); + // break; + // } + + // if (channel == stream_endpoint->connection->l2cap_signaling_cid){ + // stream_endpoint_state_machine(stream_endpoint->connection, stream_endpoint, L2CAP_DATA_PACKET, 0, packet, size); + // break; + // } + + // if (channel == stream_endpoint->l2cap_media_cid){ + // (*handle_media_data)(stream_endpoint, packet, size); + // break; + // } + + // if (channel == stream_endpoint->l2cap_reporting_cid){ + // // TODO + // printf("L2CAP_DATA_PACKET for reporting: NOT IMPLEMENTED\n"); + // } else if (channel == stream_endpoint->l2cap_recovery_cid){ + // // TODO + // printf("L2CAP_DATA_PACKET for recovery: NOT IMPLEMENTED\n"); + // } else { + // log_error("avdtp packet handler L2CAP_DATA_PACKET: local cid 0x%02x not found", channel); + // } + // break; + + case HCI_EVENT_PACKET: + switch (hci_event_packet_get_type(packet)) { + case L2CAP_EVENT_INCOMING_CONNECTION: + l2cap_event_incoming_connection_get_address(packet, event_addr); + local_cid = l2cap_event_incoming_connection_get_local_cid(packet); + break; + + case L2CAP_EVENT_CHANNEL_OPENED: + l2cap_event_channel_opened_get_address(packet, event_addr); + + if (l2cap_event_channel_opened_get_status(packet)){ + log_error("L2CAP connection to connection %s failed. status code 0x%02x", + bd_addr_to_str(event_addr), l2cap_event_channel_opened_get_status(packet)); + break; + } + psm = l2cap_event_channel_opened_get_psm(packet); + if (psm != PSM_AVCTP){ + log_error("unexpected PSM - Not implemented yet, avdtp sink: L2CAP_EVENT_CHANNEL_OPENED"); + return; + } + + con_handle = l2cap_event_channel_opened_get_handle(packet); + local_cid = l2cap_event_channel_opened_get_local_cid(packet); + + printf("L2CAP_EVENT_CHANNEL_OPENED: Channel successfully opened: %s, handle 0x%02x, psm 0x%02x, local cid 0x%02x, remote cid 0x%02x\n", + bd_addr_to_str(event_addr), con_handle, psm, local_cid, l2cap_event_channel_opened_get_remote_cid(packet)); + printf("channel %d, size %d\n", channel, size); + break; + + default: + break; + } + break; + default: + break; + } +} + +void avrcp_init(void){ + avrcp_connections = NULL; + l2cap_register_service(&packet_handler, PSM_AVCTP, 0xffff, LEVEL_0); +} + +void avrcp_register_packet_handler(btstack_packet_handler_t callback){ + if (callback == NULL){ + log_error("avrcp_register_packet_handler called with NULL callback"); + return; + } + avrcp_callback = callback; +} + +static avrcp_connection_t * get_avrcp_connection_for_bd_addr(bd_addr_t addr){ + btstack_linked_list_iterator_t it; + btstack_linked_list_iterator_init(&it, (btstack_linked_list_t *) &avrcp_connections); + while (btstack_linked_list_iterator_has_next(&it)){ + avrcp_connection_t * connection = (avrcp_connection_t *)btstack_linked_list_iterator_next(&it); + if (memcmp(addr, connection->remote_addr, 6) != 0) continue; + return connection; + } + return NULL; +} + +static avrcp_connection_t * avrcp_create_connection(bd_addr_t remote_addr){ + avrcp_connection_t * connection = btstack_memory_avrcp_connection_get(); + memset(connection, 0, sizeof(avrcp_connection_t)); + connection->state = AVCTP_CONNECTION_IDLE; + connection->transaction_label++; + memcpy(connection->remote_addr, remote_addr, 6); + btstack_linked_list_add(&avrcp_connections, (btstack_linked_item_t *) connection); + return connection; +} + +void avrcp_connect(bd_addr_t bd_addr){ + avrcp_connection_t * connection = get_avrcp_connection_for_bd_addr(bd_addr); + if (!connection){ + connection = avrcp_create_connection(bd_addr); + } + if (connection->state != AVCTP_CONNECTION_IDLE) return; + connection->state = AVCTP_CONNECTION_W4_L2CAP_CONNECTED; + l2cap_create_channel(packet_handler, connection->remote_addr, PSM_AVCTP, 0xffff, NULL); +} \ No newline at end of file diff --git a/test/avrcp/avrcp.h b/test/avrcp/avrcp.h new file mode 100644 index 000000000..79371f47c --- /dev/null +++ b/test/avrcp/avrcp.h @@ -0,0 +1,118 @@ +/* + * Copyright (C) 2016 BlueKitchen GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * 4. Any redistribution, use, or modification is done solely for + * personal benefit and not for any commercial purpose or for + * monetary gain. + * + * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS + * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Please inquire about commercial licensing options at + * contact@bluekitchen-gmbh.com + * + */ + +/* + * avrcp.h + * + * Audio/Video Remote Control Profile + * + */ + +#ifndef __AVRCP_H +#define __AVRCP_H + +#include + +#if defined __cplusplus +extern "C" { +#endif + +// protocols +#define PSM_AVCTP 0x0017 + +/* API_START */ +typedef enum { + AVCTP_CONNECTION_IDLE, + AVCTP_CONNECTION_W4_L2CAP_CONNECTED, + AVCTP_CONNECTION_OPENED, + AVCTP_CONNECTION_W4_L2CAP_DISCONNECTED +} avctp_connection_state_t; + +typedef struct { + btstack_linked_item_t item; + bd_addr_t remote_addr; + hci_con_handle_t con_handle; + uint16_t l2cap_signaling_cid; + uint16_t transaction_label; + + avctp_connection_state_t state; +} avrcp_connection_t; + +/** + * @brief AVDTP Sink service record. + * @param service + * @param service_record_handle + * @param supported_features 16-bit bitmap, see AVDTP_SINK_SF_* values in avdtp.h + * @param service_name + * @param service_provider_name + */ +void avrcp_controller_create_sdp_record(uint8_t * service, uint32_t service_record_handle, uint16_t supported_features, const char * service_name, const char * service_provider_name); + +/** + * @brief AVDTP Sink service record. + * @param service + * @param service_record_handle + * @param supported_features 16-bit bitmap, see AVDTP_SINK_SF_* values in avdtp.h + * @param service_name + * @param service_provider_name + */ +void avrcp_target_create_sdp_record(uint8_t * service, uint32_t service_record_handle, uint16_t supported_features, const char * service_name, const char * service_provider_name); + + +/** + * @brief Set up AVDTP Sink device. + */ +void avrcp_init(void); + +/** + * @brief Register callback for the AVDTP Sink client. + * @param callback + */ +void avrcp_register_packet_handler(btstack_packet_handler_t callback); + +/** + * @brief Connect to device with a bluetooth address. + * @param bd_addr + */ +void avrcp_connect(bd_addr_t bd_addr); + +/* API_END */ +#if defined __cplusplus +} +#endif + +#endif // __AVRCP_H \ No newline at end of file diff --git a/test/avrcp/avrcp_test.c b/test/avrcp/avrcp_test.c new file mode 100644 index 000000000..192746053 --- /dev/null +++ b/test/avrcp/avrcp_test.c @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2017 BlueKitchen GmbH + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holders nor the names of + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * 4. Any redistribution, use, or modification is done solely for + * personal benefit and not for any commercial purpose or for + * monetary gain. + * + * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS + * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Please inquire about commercial licensing options at + * contact@bluekitchen-gmbh.com + * + */ + +#include +#include +#include +#include +#include + +#include "btstack_config.h" +#include "btstack_debug.h" +#include "btstack_event.h" +#include "btstack_memory.h" +#include "btstack_run_loop.h" +#include "gap.h" +#include "hci.h" +#include "hci_cmd.h" +#include "hci_dump.h" +#include "l2cap.h" +#include "stdin_support.h" +#include "avrcp.h" + +static btstack_packet_callback_registration_t hci_event_callback_registration; +// mac 2011: static bd_addr_t remote = {0x04, 0x0C, 0xCE, 0xE4, 0x85, 0xD3}; +// pts: static bd_addr_t remote = {0x00, 0x1B, 0xDC, 0x08, 0x0A, 0xA5}; +// mac 2013: static bd_addr_t remote = {0x84, 0x38, 0x35, 0x65, 0xd1, 0x15}; +static bd_addr_t remote = {0x84, 0x38, 0x35, 0x65, 0xd1, 0x15}; +// static uint16_t con_handle = 0; +static uint8_t sdp_avrcp_controller_service_buffer[150]; + +static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size){ + UNUSED(channel); + UNUSED(size); + // bd_addr_t event_addr; + switch (packet_type) { + case HCI_EVENT_PACKET: + switch (hci_event_packet_get_type(packet)) { + case HCI_EVENT_DISCONNECTION_COMPLETE: + // connection closed -> quit test app + printf("--- avrcp_test: HCI_EVENT_DISCONNECTION_COMPLETE\n"); + break; + case HCI_EVENT_AVDTP_META: + switch (packet[2]){ + // case AVRCP_SUBEVENT_CONNECTION_ESTABLISHED: + // con_handle = avrcp_subevent_connection_established_get_con_handle(packet); + // printf("AVRCP_SUBEVENT_CONNECTION_ESTABLISHED, con handle 0x%02x", con_handle); + // break; + default: + printf("--- avrcp_test: Not implemented\n"); + break; + } + break; + default: + break; + } + break; + default: + // other packet type + break; + } +} + + +static void show_usage(void){ + bd_addr_t iut_address; + gap_local_bd_addr(iut_address); + printf("\n--- Bluetooth AVRCP Test Console %s ---\n", bd_addr_to_str(iut_address)); + printf("c - create connection to addr %s\n", bd_addr_to_str(remote)); + printf("C - disconnect\n"); + printf("Ctrl-c - exit\n"); + printf("---\n"); +} + +static void stdin_process(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type){ + UNUSED(ds); + UNUSED(callback_type); + + int cmd = btstack_stdin_read(); + + switch (cmd){ + case 'c': + avrcp_connect(remote); + break; + default: + show_usage(); + break; + + } +} + +int btstack_main(int argc, const char * argv[]); +int btstack_main(int argc, const char * argv[]){ + UNUSED(argc); + (void)argv; + + /* Register for HCI events */ + hci_event_callback_registration.callback = &packet_handler; + hci_add_event_handler(&hci_event_callback_registration); + + l2cap_init(); + + // Initialize AVDTP Sink + avrcp_init(); + avrcp_register_packet_handler(&packet_handler); + + // Initialize SDP + sdp_init(); + memset(sdp_avrcp_controller_service_buffer, 0, sizeof(sdp_avrcp_controller_service_buffer)); + avrcp_controller_create_sdp_record(sdp_avrcp_controller_service_buffer, 0x10001, 1, NULL, NULL); + sdp_register_service(sdp_avrcp_controller_service_buffer); + + gap_set_local_name("BTstack AVRCP Test"); + gap_discoverable_control(1); + gap_set_class_of_device(0x200408); + + // turn on! + hci_power_control(HCI_POWER_ON); + + btstack_stdin_setup(stdin_process); + return 0; +} diff --git a/tool/btstack_memory_generator.py b/tool/btstack_memory_generator.py index 59608726d..1031a1acb 100755 --- a/tool/btstack_memory_generator.py +++ b/tool/btstack_memory_generator.py @@ -69,6 +69,7 @@ extern "C" { #include "classic/sdp_server.h" #include "classic/avdtp_sink.h" #include "classic/avdtp_source.h" +#include "../../test/avrcp/avrcp.h" // BLE #ifdef ENABLE_BLE @@ -179,7 +180,8 @@ list_of_structs = [ ["hfp_connection"], ["service_record_item"], ["avdtp_stream_endpoint"], - ["avdtp_connection"] + ["avdtp_connection"], + ["avrcp_connection"] ] list_of_le_structs = [["gatt_client", "whitelist_entry", "sm_lookup_entry"]]