29
29
#include "host/shell/bt.h"
30
30
#include "common/bt_shell_private.h"
31
31
32
+ NET_BUF_POOL_DEFINE (avrcp_tx_pool , CONFIG_BT_MAX_CONN ,
33
+ BT_L2CAP_BUF_SIZE (CONFIG_BT_L2CAP_TX_MTU ),
34
+ CONFIG_BT_CONN_TX_USER_DATA_SIZE , NULL );
35
+
36
+ #define FOLDER_NAME_HEX_BUF_LEN 80
37
+
32
38
struct bt_avrcp_ct * default_ct ;
33
39
struct bt_avrcp_tg * default_tg ;
34
40
static bool avrcp_ct_registered ;
@@ -60,6 +66,16 @@ static void avrcp_ct_disconnected(struct bt_avrcp_ct *ct)
60
66
default_ct = NULL ;
61
67
}
62
68
69
+ static void avrcp_ct_browsing_connected (struct bt_conn * conn , struct bt_avrcp_ct * ct )
70
+ {
71
+ bt_shell_print ("AVRCP CT browsing connected" );
72
+ }
73
+
74
+ static void avrcp_ct_browsing_disconnected (struct bt_avrcp_ct * ct )
75
+ {
76
+ bt_shell_print ("AVRCP CT browsing disconnected" );
77
+ }
78
+
63
79
static void avrcp_get_cap_rsp (struct bt_avrcp_ct * ct , uint8_t tid ,
64
80
const struct bt_avrcp_get_cap_rsp * rsp )
65
81
{
@@ -115,13 +131,70 @@ static void avrcp_passthrough_rsp(struct bt_avrcp_ct *ct, uint8_t tid, bt_avrcp_
115
131
}
116
132
}
117
133
134
+ static void avrcp_browsed_player_rsp (struct bt_avrcp_ct * ct , uint8_t tid ,
135
+ struct net_buf * buf )
136
+ {
137
+ struct bt_avrcp_set_browsed_player_rsp * rsp ;
138
+ struct bt_avrcp_folder_name * folder_name ;
139
+
140
+ rsp = net_buf_pull_mem (buf , sizeof (* rsp ));
141
+ if (rsp -> status != BT_AVRCP_STATUS_OPERATION_COMPLETED ) {
142
+ bt_shell_print ("AVRCP set browsed player failed, tid = %d, status = 0x%02x" ,
143
+ tid , rsp -> status );
144
+ return ;
145
+ }
146
+
147
+ bt_shell_print ("AVRCP set browsed player success, tid = %d" , tid );
148
+ bt_shell_print (" UID Counter: %u" , sys_be16_to_cpu (rsp -> uid_counter ));
149
+ bt_shell_print (" Number of Items: %u" , sys_be32_to_cpu (rsp -> num_items ));
150
+ bt_shell_print (" Charset ID: 0x%04X" , sys_be16_to_cpu (rsp -> charset_id ));
151
+ bt_shell_print (" Folder Depth: %u" , rsp -> folder_depth );
152
+
153
+ while (buf -> len > 0 ) {
154
+ if (buf -> len < sizeof (struct bt_avrcp_folder_name )) {
155
+ bt_shell_print ("incompleted message" );
156
+ break ;
157
+ }
158
+ folder_name = net_buf_pull_mem (buf , sizeof (struct bt_avrcp_folder_name ));
159
+ folder_name -> folder_name_len = sys_be16_to_cpu (folder_name -> folder_name_len );
160
+ if (buf -> len < folder_name -> folder_name_len ) {
161
+ bt_shell_print ("incompleted message for folder_name" );
162
+ break ;
163
+ }
164
+ net_buf_pull_mem (buf , folder_name -> folder_name_len );
165
+
166
+ if (sys_be16_to_cpu (rsp -> charset_id ) == BT_AVRCP_CHARSET_UTF8 ) {
167
+ bt_shell_print ("Raw folder name:" );
168
+ for (int i = 0 ; i < folder_name -> folder_name_len ; i ++ ) {
169
+ bt_shell_print ("%c" , folder_name -> folder_name [i ]);
170
+ }
171
+ } else {
172
+ bt_shell_print (" Get folder Name : " );
173
+ bt_shell_hexdump (folder_name -> folder_name , folder_name -> folder_name_len );
174
+ }
175
+ if (rsp -> folder_depth > 0 ) {
176
+ rsp -> folder_depth -- ;
177
+ } else {
178
+ bt_shell_warn ("Folder depth is mismatched with received data" );
179
+ break ;
180
+ }
181
+ }
182
+
183
+ if (rsp -> folder_depth > 0 ) {
184
+ bt_shell_print ("folder depth mismatch: expected 0, got %u" , rsp -> folder_depth );
185
+ }
186
+ }
187
+
118
188
static struct bt_avrcp_ct_cb app_avrcp_ct_cb = {
119
189
.connected = avrcp_ct_connected ,
120
190
.disconnected = avrcp_ct_disconnected ,
191
+ .browsing_connected = avrcp_ct_browsing_connected ,
192
+ .browsing_disconnected = avrcp_ct_browsing_disconnected ,
121
193
.get_cap_rsp = avrcp_get_cap_rsp ,
122
194
.unit_info_rsp = avrcp_unit_info_rsp ,
123
195
.subunit_info_rsp = avrcp_subunit_info_rsp ,
124
196
.passthrough_rsp = avrcp_passthrough_rsp ,
197
+ .browsed_player_rsp = avrcp_browsed_player_rsp ,
125
198
};
126
199
127
200
static void avrcp_tg_connected (struct bt_conn * conn , struct bt_avrcp_tg * tg )
@@ -136,16 +209,36 @@ static void avrcp_tg_disconnected(struct bt_avrcp_tg *tg)
136
209
default_tg = NULL ;
137
210
}
138
211
212
+ static void avrcp_tg_browsing_connected (struct bt_conn * conn , struct bt_avrcp_tg * tg )
213
+ {
214
+ bt_shell_print ("AVRCP TG browsing connected" );
215
+ }
216
+
139
217
static void avrcp_unit_info_req (struct bt_avrcp_tg * tg , uint8_t tid )
140
218
{
141
219
bt_shell_print ("AVRCP unit info request received" );
142
220
tg_tid = tid ;
143
221
}
144
222
223
+ static void avrcp_tg_browsing_disconnected (struct bt_avrcp_tg * tg )
224
+ {
225
+ bt_shell_print ("AVRCP TG browsing disconnected" );
226
+ }
227
+
228
+ static void avrcp_set_browsed_player_req (struct bt_avrcp_tg * tg , uint8_t tid ,
229
+ uint16_t player_id )
230
+ {
231
+ bt_shell_print ("AVRCP set browsed player request received, player_id = %u" , player_id );
232
+ tg_tid = tid ;
233
+ }
234
+
145
235
static struct bt_avrcp_tg_cb app_avrcp_tg_cb = {
146
236
.connected = avrcp_tg_connected ,
147
237
.disconnected = avrcp_tg_disconnected ,
238
+ .browsing_connected = avrcp_tg_browsing_connected ,
239
+ .browsing_disconnected = avrcp_tg_browsing_disconnected ,
148
240
.unit_info_req = avrcp_unit_info_req ,
241
+ .set_browsed_player_req = avrcp_set_browsed_player_req ,
149
242
};
150
243
151
244
static int register_ct_cb (const struct shell * sh )
@@ -256,6 +349,53 @@ static int cmd_disconnect(const struct shell *sh, int32_t argc, char *argv[])
256
349
return 0 ;
257
350
}
258
351
352
+ static int cmd_browsing_connect (const struct shell * sh , int32_t argc , char * argv [])
353
+ {
354
+ int err ;
355
+
356
+ if (!avrcp_ct_registered && register_ct_cb (sh ) != 0 ) {
357
+ return - ENOEXEC ;
358
+ }
359
+
360
+ if (default_conn == NULL ) {
361
+ shell_error (sh , "BR/EDR not connected" );
362
+ return - ENOEXEC ;
363
+ }
364
+
365
+ err = bt_avrcp_browsing_connect (default_conn );
366
+ if (err < 0 ) {
367
+ shell_error (sh , "fail to connect AVRCP browsing" );
368
+ } else {
369
+ shell_print (sh , "AVRCP browsing connect request sent" );
370
+ }
371
+
372
+ return err ;
373
+ }
374
+
375
+ static int cmd_browsing_disconnect (const struct shell * sh , int32_t argc , char * argv [])
376
+ {
377
+ int err ;
378
+
379
+ if (default_conn == NULL ) {
380
+ shell_print (sh , "Not connected" );
381
+ return - ENOEXEC ;
382
+ }
383
+
384
+ if ((default_ct != NULL ) || (default_tg != NULL )) {
385
+ err = bt_avrcp_browsing_disconnect (default_conn );
386
+ if (err < 0 ) {
387
+ shell_error (sh , "fail to disconnect AVRCP browsing" );
388
+ } else {
389
+ shell_print (sh , "AVRCP browsing disconnect request sent" );
390
+ }
391
+ } else {
392
+ shell_error (sh , "AVRCP is not connected" );
393
+ err = - ENOEXEC ;
394
+ }
395
+
396
+ return err ;
397
+ }
398
+
259
399
static int cmd_get_unit_info (const struct shell * sh , int32_t argc , char * argv [])
260
400
{
261
401
if (!avrcp_ct_registered && register_ct_cb (sh ) != 0 ) {
@@ -364,6 +504,139 @@ static int cmd_get_cap(const struct shell *sh, int32_t argc, char *argv[])
364
504
return 0 ;
365
505
}
366
506
507
+ static int cmd_set_browsed_player (const struct shell * sh , int32_t argc , char * argv [])
508
+ {
509
+ uint16_t player_id ;
510
+ int err ;
511
+
512
+ if (!avrcp_ct_registered && register_ct_cb (sh ) != 0 ) {
513
+ return - ENOEXEC ;
514
+ }
515
+
516
+ if (default_ct == NULL ) {
517
+ shell_error (sh , "AVRCP is not connected" );
518
+ return - ENOEXEC ;
519
+ }
520
+
521
+ player_id = (uint16_t )strtoul (argv [1 ], NULL , 0 );
522
+
523
+ err = bt_avrcp_ct_set_browsed_player (default_ct , get_next_tid (), player_id );
524
+ if (err < 0 ) {
525
+ shell_error (sh , "fail to set browsed player" );
526
+ } else {
527
+ shell_print (sh , "AVRCP send set browsed player req" );
528
+ }
529
+
530
+ return 0 ;
531
+ }
532
+
533
+ static int cmd_send_set_browsed_player_rsp (const struct shell * sh , int32_t argc , char * argv [])
534
+ {
535
+ struct bt_avrcp_set_browsed_player_rsp * rsp ;
536
+ struct bt_avrcp_folder_name * folder_name ;
537
+ char * folder_name_str = "Music" ;
538
+ uint8_t folder_name_hex [FOLDER_NAME_HEX_BUF_LEN ];
539
+ uint16_t folder_name_len = 0 ;
540
+ struct net_buf * buf ;
541
+ uint16_t param_len ;
542
+ int err ;
543
+
544
+ if (!avrcp_tg_registered && register_tg_cb (sh ) != 0 ) {
545
+ return - ENOEXEC ;
546
+ }
547
+
548
+ if (default_tg == NULL ) {
549
+ shell_error (sh , "AVRCP TG is not connected" );
550
+ return - ENOEXEC ;
551
+ }
552
+
553
+ buf = bt_avrcp_create_pdu (& avrcp_tx_pool );
554
+ if (buf == NULL ) {
555
+ shell_error (sh , "Failed to allocate buffer for AVRCP browsing response" );
556
+ return - ENOMEM ;
557
+ }
558
+
559
+ if (net_buf_tailroom (buf ) < sizeof (struct bt_avrcp_set_browsed_player_rsp )) {
560
+ shell_error (sh , "Not enough tailroom in buffer for browsed player rsp" );
561
+ goto failed ;
562
+ }
563
+
564
+ rsp = net_buf_add (buf , sizeof (* rsp ));
565
+ /* Set default rsp */
566
+ rsp -> status = BT_AVRCP_STATUS_OPERATION_COMPLETED ;
567
+ rsp -> uid_counter = sys_cpu_to_be16 (0x0001U );
568
+ rsp -> num_items = sys_cpu_to_be32 (100U );
569
+ rsp -> charset_id = sys_cpu_to_be16 (BT_AVRCP_CHARSET_UTF8 );
570
+ rsp -> folder_depth = 1 ;
571
+
572
+ /* Parse command line arguments or use default values */
573
+ if (argc >= 2 ) {
574
+ rsp -> status = (uint8_t )strtoul (argv [1 ], NULL , 0 );
575
+ }
576
+
577
+ if (argc >= 3 ) {
578
+ rsp -> uid_counter = sys_cpu_to_be16 ((uint16_t )strtoul (argv [2 ], NULL , 0 ));
579
+ }
580
+
581
+ if (argc >= 4 ) {
582
+ rsp -> num_items = sys_cpu_to_be32 ((uint32_t )strtoul (argv [3 ], NULL , 0 ));
583
+ }
584
+
585
+ if (argc >= 5 ) {
586
+ rsp -> charset_id = sys_cpu_to_be16 ((uint16_t )strtoul (argv [4 ], NULL , 0 ));
587
+ }
588
+
589
+ if (rsp -> charset_id == sys_cpu_to_be16 (BT_AVRCP_CHARSET_UTF8 )) {
590
+ if (argc >= 6 ) {
591
+ folder_name_str = argv [5 ];
592
+ }
593
+ folder_name_len = strlen (folder_name_str );
594
+ } else {
595
+ if (argc >= 6 ) {
596
+ folder_name_len = hex2bin (argv [5 ], strlen (argv [5 ]), folder_name_hex ,
597
+ sizeof (folder_name_hex ));
598
+ if (folder_name_len == 0 ) {
599
+ shell_error (sh , "Failed to get folder_name from %s" , argv [5 ]);
600
+ }
601
+ } else {
602
+ shell_error (sh , "Please input hex string for folder_name" );
603
+ goto failed ;
604
+ }
605
+ }
606
+
607
+ param_len = folder_name_len + sizeof (struct bt_avrcp_folder_name );
608
+ if (net_buf_tailroom (buf ) < param_len ) {
609
+ shell_error (sh , "Not enough tailroom in buffer for param" );
610
+ goto failed ;
611
+ }
612
+
613
+ folder_name = net_buf_add (buf , sizeof (* folder_name ));
614
+ folder_name -> folder_name_len = sys_cpu_to_be16 (folder_name_len );
615
+ if (rsp -> charset_id == sys_cpu_to_be16 (BT_AVRCP_CHARSET_UTF8 )) {
616
+ net_buf_add_mem (buf , folder_name_str , folder_name_len );
617
+ } else {
618
+ net_buf_add_mem (buf , folder_name_hex , folder_name_len );
619
+ }
620
+
621
+ err = bt_avrcp_tg_send_set_browsed_player_rsp (default_tg , tg_tid , buf );
622
+ if (err == 0 ) {
623
+ shell_print (sh , "Send set browsed player response, status = 0x%02x" , rsp -> status );
624
+ } else {
625
+ shell_error (sh , "Failed to send set browsed player response, err = %d" , err );
626
+ goto failed ;
627
+ }
628
+
629
+ return 0 ;
630
+ failed :
631
+ net_buf_unref (buf );
632
+ return - ENOEXEC ;
633
+ }
634
+
635
+ #define HELP_BROWSED_PLAYER_RSP \
636
+ "Send SetBrowsedPlayer response\n" \
637
+ "Usage: send_browsed_player_rsp [status] [uid_counter] [num_items] " \
638
+ "[charset_id] [folder_name]"
639
+
367
640
SHELL_STATIC_SUBCMD_SET_CREATE (
368
641
ct_cmds ,
369
642
SHELL_CMD_ARG (register_cb , NULL , "register avrcp ct callbacks" , cmd_register_ct_cb , 1 , 0 ),
@@ -373,12 +646,16 @@ SHELL_STATIC_SUBCMD_SET_CREATE(
373
646
0 ),
374
647
SHELL_CMD_ARG (play , NULL , "request a play at the remote player" , cmd_play , 1 , 0 ),
375
648
SHELL_CMD_ARG (pause , NULL , "request a pause at the remote player" , cmd_pause , 1 , 0 ),
649
+ SHELL_CMD_ARG (set_browsed_player , NULL , "set browsed player <player_id>" ,
650
+ cmd_set_browsed_player , 2 , 0 ),
376
651
SHELL_SUBCMD_SET_END );
377
652
378
653
SHELL_STATIC_SUBCMD_SET_CREATE (
379
654
tg_cmds ,
380
655
SHELL_CMD_ARG (register_cb , NULL , "register avrcp tg callbacks" , cmd_register_tg_cb , 1 , 0 ),
381
656
SHELL_CMD_ARG (send_unit_rsp , NULL , "send unit info response" , cmd_send_unit_info_rsp , 1 , 0 ),
657
+ SHELL_CMD_ARG (send_browsed_player_rsp , NULL , HELP_BROWSED_PLAYER_RSP ,
658
+ cmd_send_set_browsed_player_rsp , 1 , 5 ),
382
659
SHELL_SUBCMD_SET_END );
383
660
384
661
static int cmd_avrcp (const struct shell * sh , size_t argc , char * * argv )
@@ -398,6 +675,9 @@ SHELL_STATIC_SUBCMD_SET_CREATE(
398
675
avrcp_cmds ,
399
676
SHELL_CMD_ARG (connect , NULL , "connect AVRCP" , cmd_connect , 1 , 0 ),
400
677
SHELL_CMD_ARG (disconnect , NULL , "disconnect AVRCP" , cmd_disconnect , 1 , 0 ),
678
+ SHELL_CMD_ARG (browsing_connect , NULL , "connect browsing AVRCP" , cmd_browsing_connect , 1 , 0 ),
679
+ SHELL_CMD_ARG (browsing_disconnect , NULL , "disconnect browsing AVRCP" ,
680
+ cmd_browsing_disconnect , 1 , 0 ),
401
681
SHELL_CMD (ct , & ct_cmds , "AVRCP CT shell commands" , cmd_avrcp ),
402
682
SHELL_CMD (tg , & tg_cmds , "AVRCP TG shell commands" , cmd_avrcp ),
403
683
SHELL_SUBCMD_SET_END );
0 commit comments