@@ -51,9 +51,6 @@ LOG_MODULE_REGISTER(bt_rfcomm);
51
51
52
52
static struct bt_rfcomm_server * servers ;
53
53
54
- /* Pool for dummy buffers to wake up the tx threads */
55
- NET_BUF_POOL_DEFINE (dummy_pool , CONFIG_BT_MAX_CONN , 0 , 0 , NULL );
56
-
57
54
#define RFCOMM_SESSION (_ch ) CONTAINER_OF(_ch, \
58
55
struct bt_rfcomm_session, br_chan.chan)
59
56
@@ -235,13 +232,37 @@ int bt_rfcomm_server_register(struct bt_rfcomm_server *server)
235
232
return 0 ;
236
233
}
237
234
235
+ static void rfcomm_dlc_tx_trigger (struct bt_rfcomm_dlc * dlc )
236
+ {
237
+ int err ;
238
+
239
+ if ((dlc == NULL ) || (dlc -> tx_work .handler == NULL )) {
240
+ return ;
241
+ }
242
+
243
+ LOG_DBG ("DLC %p TX trigger" , dlc );
244
+
245
+ err = k_work_submit (& dlc -> tx_work );
246
+ if (err < 0 ) {
247
+ LOG_ERR ("Failed to submit tx work: %d" , err );
248
+ }
249
+ }
250
+
251
+ static void rfcomm_dlcs_tx_trigger (struct bt_rfcomm_dlc * dlcs )
252
+ {
253
+ for (struct bt_rfcomm_dlc * dlc = dlcs ; dlc != NULL ; dlc = dlc -> _next ) {
254
+ rfcomm_dlc_tx_trigger (dlc );
255
+ }
256
+ }
257
+
238
258
static void rfcomm_dlc_tx_give_credits (struct bt_rfcomm_dlc * dlc ,
239
259
uint8_t credits )
240
260
{
241
261
LOG_DBG ("dlc %p credits %u" , dlc , credits );
242
262
243
263
while (credits -- ) {
244
264
k_sem_give (& dlc -> tx_credits );
265
+ rfcomm_dlc_tx_trigger (dlc );
245
266
}
246
267
247
268
LOG_DBG ("dlc %p updated credits %u" , dlc , k_sem_count_get (& dlc -> tx_credits ));
@@ -252,6 +273,8 @@ static void rfcomm_dlc_destroy(struct bt_rfcomm_dlc *dlc)
252
273
LOG_DBG ("dlc %p" , dlc );
253
274
254
275
k_work_cancel_delayable (& dlc -> rtx_work );
276
+ k_work_cancel (& dlc -> tx_work );
277
+
255
278
dlc -> state = BT_RFCOMM_STATE_IDLE ;
256
279
dlc -> session = NULL ;
257
280
@@ -274,16 +297,7 @@ static void rfcomm_dlc_disconnect(struct bt_rfcomm_dlc *dlc)
274
297
275
298
switch (old_state ) {
276
299
case BT_RFCOMM_STATE_CONNECTED :
277
- /* Queue a dummy buffer to wake up and stop the
278
- * tx thread for states where it was running.
279
- */
280
- k_fifo_put (& dlc -> tx_queue , net_buf_alloc (& dummy_pool , K_NO_WAIT ));
281
-
282
- /* There could be a writer waiting for credits so return a
283
- * dummy credit to wake it up.
284
- */
285
- rfcomm_dlc_tx_give_credits (dlc , 1 );
286
- k_sem_give (& dlc -> session -> fc );
300
+ rfcomm_dlc_tx_trigger (dlc );
287
301
break ;
288
302
default :
289
303
rfcomm_dlc_destroy (dlc );
@@ -465,8 +479,17 @@ static void rfcomm_dlc_init(struct bt_rfcomm_dlc *dlc,
465
479
uint8_t dlci ,
466
480
bt_rfcomm_role_t role )
467
481
{
482
+ struct k_work_sync sync ;
483
+
468
484
LOG_DBG ("dlc %p" , dlc );
469
485
486
+ if (dlc -> tx_work .handler != NULL ) {
487
+ /* Make sure the tx_work is cancelled before reinitializing */
488
+ k_work_cancel_sync (& dlc -> tx_work , & sync );
489
+ /* Reset the work handler to NULL before the DLC connected */
490
+ dlc -> tx_work .handler = NULL ;
491
+ }
492
+
470
493
dlc -> dlci = dlci ;
471
494
dlc -> session = session ;
472
495
dlc -> rx_credit = RFCOMM_DEFAULT_CREDIT ;
@@ -533,19 +556,30 @@ static int rfcomm_send_dm(struct bt_rfcomm_session *session, uint8_t dlci)
533
556
return rfcomm_send (session , buf );
534
557
}
535
558
536
- static void rfcomm_check_fc (struct bt_rfcomm_dlc * dlc )
559
+ static bool rfcomm_check_fc (struct bt_rfcomm_dlc * dlc )
537
560
{
538
- LOG_DBG ( "%p" , dlc ) ;
561
+ int err ;
539
562
540
563
LOG_DBG ("Wait for credits or MSC FC %p" , dlc );
541
564
/* Wait for credits or MSC FC */
542
- k_sem_take (& dlc -> tx_credits , K_FOREVER );
565
+ err = k_sem_take (& dlc -> tx_credits , K_NO_WAIT );
566
+ if (err != 0 ) {
567
+ LOG_DBG ("Credits not available" );
568
+ return false;
569
+ }
543
570
571
+ LOG_DBG ("Credits available" );
544
572
if (dlc -> session -> cfc == BT_RFCOMM_CFC_SUPPORTED ) {
545
- return ;
573
+ LOG_DBG ("Credits available" );
574
+ return true;
546
575
}
547
576
548
- k_sem_take (& dlc -> session -> fc , K_FOREVER );
577
+ err = k_sem_take (& dlc -> session -> fc , K_NO_WAIT );
578
+ if (err != 0 ) {
579
+ k_sem_give (& dlc -> tx_credits );
580
+ LOG_DBG ("Flow control not available" );
581
+ return false;
582
+ }
549
583
550
584
/* Give the sems immediately so that sem will be available for all
551
585
* the bufs in the queue. It will be blocked only once all the bufs
@@ -554,6 +588,9 @@ static void rfcomm_check_fc(struct bt_rfcomm_dlc *dlc)
554
588
*/
555
589
k_sem_give (& dlc -> session -> fc );
556
590
k_sem_give (& dlc -> tx_credits );
591
+
592
+ LOG_DBG ("Flow control available" );
593
+ return true;
557
594
}
558
595
559
596
static void bt_rfcomm_tx_destroy (struct bt_rfcomm_dlc * dlc , struct net_buf * buf )
@@ -581,55 +618,60 @@ static void rfcomm_sent(struct bt_conn *conn, void *user_data, int err)
581
618
582
619
dlc = (struct bt_rfcomm_dlc * )user_data ;
583
620
621
+ rfcomm_dlc_tx_trigger (dlc );
622
+
584
623
if (dlc && dlc -> ops && dlc -> ops -> sent ) {
585
624
dlc -> ops -> sent (dlc , err );
586
625
}
587
626
}
588
627
589
- static void rfcomm_dlc_tx_thread ( void * p1 , void * p2 , void * p3 )
628
+ static void rfcomm_dlc_tx_worker ( struct k_work * work )
590
629
{
591
- struct bt_rfcomm_dlc * dlc = p1 ;
592
- k_timeout_t timeout = K_FOREVER ;
630
+ struct bt_rfcomm_dlc * dlc = CONTAINER_OF (work , struct bt_rfcomm_dlc , tx_work );
593
631
struct net_buf * buf ;
594
632
595
- LOG_DBG ("Started for dlc %p" , dlc );
596
-
597
- while (dlc -> state == BT_RFCOMM_STATE_CONNECTED ||
598
- dlc -> state == BT_RFCOMM_STATE_USER_DISCONNECT ) {
599
- /* Get next packet for dlc */
600
- LOG_DBG ("Wait for buf %p" , dlc );
601
- buf = k_fifo_get (& dlc -> tx_queue , timeout );
602
- /* If its dummy buffer or non user disconnect then break */
603
- if ((dlc -> state != BT_RFCOMM_STATE_CONNECTED &&
604
- dlc -> state != BT_RFCOMM_STATE_USER_DISCONNECT ) ||
605
- !buf || !buf -> len ) {
606
- if (buf ) {
607
- bt_rfcomm_tx_destroy (dlc , buf );
608
- net_buf_unref (buf );
609
- }
610
- break ;
633
+ LOG_DBG ("Work for dlc %p state %u" , dlc , dlc -> state );
634
+
635
+ if (dlc -> state < BT_RFCOMM_STATE_CONNECTED ) {
636
+ return ;
637
+ }
638
+
639
+ if (dlc -> state == BT_RFCOMM_STATE_CONNECTED ||
640
+ dlc -> state == BT_RFCOMM_STATE_USER_DISCONNECT ) {
641
+ if (k_fifo_is_empty (& dlc -> tx_queue ) == true) {
642
+ goto user_disconnect ;
611
643
}
612
644
613
- rfcomm_check_fc (dlc );
614
- if (dlc -> state != BT_RFCOMM_STATE_CONNECTED &&
615
- dlc -> state != BT_RFCOMM_STATE_USER_DISCONNECT ) {
616
- bt_rfcomm_tx_destroy (dlc , buf );
617
- net_buf_unref (buf );
618
- break ;
645
+ if (rfcomm_check_fc (dlc ) == false) {
646
+ LOG_DBG ("FC or credit not available" );
647
+ goto user_disconnect ;
619
648
}
620
649
650
+ buf = k_fifo_get (& dlc -> tx_queue , K_NO_WAIT );
651
+ LOG_DBG ("Tx buf %p" , buf );
621
652
if (rfcomm_send_cb (dlc -> session , buf , rfcomm_sent , dlc ) < 0 ) {
622
653
/* This fails only if channel is disconnected */
623
654
dlc -> state = BT_RFCOMM_STATE_DISCONNECTED ;
624
655
bt_rfcomm_tx_destroy (dlc , buf );
625
- break ;
656
+ LOG_ERR ("Failed to send buffer, disconnected" );
657
+ goto disconnect ;
658
+ }
659
+
660
+ if (k_fifo_is_empty (& dlc -> tx_queue ) == false) {
661
+ rfcomm_dlc_tx_trigger (dlc );
662
+ return ;
626
663
}
627
664
665
+ user_disconnect :
628
666
if (dlc -> state == BT_RFCOMM_STATE_USER_DISCONNECT ) {
629
- timeout = K_NO_WAIT ;
667
+ LOG_DBG ("Process user disconnect" );
668
+ goto disconnect ;
630
669
}
670
+
671
+ return ;
631
672
}
632
673
674
+ disconnect :
633
675
LOG_DBG ("dlc %p disconnected - cleaning up" , dlc );
634
676
635
677
/* Give back any allocated buffers */
@@ -844,11 +886,7 @@ static void rfcomm_dlc_connected(struct bt_rfcomm_dlc *dlc)
844
886
k_work_cancel_delayable (& dlc -> rtx_work );
845
887
846
888
k_fifo_init (& dlc -> tx_queue );
847
- k_thread_create (& dlc -> tx_thread , dlc -> stack ,
848
- K_KERNEL_STACK_SIZEOF (dlc -> stack ),
849
- rfcomm_dlc_tx_thread , dlc , NULL , NULL , K_PRIO_COOP (7 ),
850
- 0 , K_NO_WAIT );
851
- k_thread_name_set (& dlc -> tx_thread , "BT DLC" );
889
+ k_work_init (& dlc -> tx_work , rfcomm_dlc_tx_worker );
852
890
853
891
if (dlc -> ops && dlc -> ops -> connected ) {
854
892
dlc -> ops -> connected (dlc );
@@ -921,17 +959,7 @@ static int rfcomm_dlc_close(struct bt_rfcomm_dlc *dlc)
921
959
break ;
922
960
case BT_RFCOMM_STATE_CONNECTED :
923
961
dlc -> state = BT_RFCOMM_STATE_DISCONNECTING ;
924
-
925
- /* Queue a dummy buffer to wake up and stop the
926
- * tx thread.
927
- */
928
- k_fifo_put (& dlc -> tx_queue ,
929
- net_buf_alloc (& dummy_pool , K_NO_WAIT ));
930
-
931
- /* There could be a writer waiting for credits so return a
932
- * dummy credit to wake it up.
933
- */
934
- rfcomm_dlc_tx_give_credits (dlc , 1 );
962
+ rfcomm_dlc_tx_trigger (dlc );
935
963
break ;
936
964
case BT_RFCOMM_STATE_DISCONNECTING :
937
965
case BT_RFCOMM_STATE_DISCONNECTED :
@@ -1178,6 +1206,7 @@ static void rfcomm_handle_msc(struct bt_rfcomm_session *session,
1178
1206
* thread in sem_take().
1179
1207
*/
1180
1208
k_sem_give (& dlc -> tx_credits );
1209
+ rfcomm_dlc_tx_trigger (dlc );
1181
1210
}
1182
1211
}
1183
1212
@@ -1410,6 +1439,7 @@ static void rfcomm_handle_msg(struct bt_rfcomm_session *session,
1410
1439
*/
1411
1440
k_sem_give (& session -> fc );
1412
1441
rfcomm_send_fcon (session , BT_RFCOMM_MSG_RESP_CR );
1442
+ rfcomm_dlcs_tx_trigger (session -> dlcs );
1413
1443
break ;
1414
1444
case BT_RFCOMM_FCOFF :
1415
1445
if (session -> cfc == BT_RFCOMM_CFC_SUPPORTED ) {
@@ -1544,6 +1574,7 @@ int bt_rfcomm_dlc_send(struct bt_rfcomm_dlc *dlc, struct net_buf *buf)
1544
1574
net_buf_add_u8 (buf , fcs );
1545
1575
1546
1576
k_fifo_put (& dlc -> tx_queue , buf );
1577
+ rfcomm_dlc_tx_trigger (dlc );
1547
1578
1548
1579
return buf -> len ;
1549
1580
}
@@ -1802,9 +1833,7 @@ int bt_rfcomm_dlc_disconnect(struct bt_rfcomm_dlc *dlc)
1802
1833
* and stop the tx thread.
1803
1834
*/
1804
1835
dlc -> state = BT_RFCOMM_STATE_USER_DISCONNECT ;
1805
- k_fifo_put (& dlc -> tx_queue ,
1806
- net_buf_alloc (& dummy_pool , K_NO_WAIT ));
1807
-
1836
+ rfcomm_dlc_tx_trigger (dlc );
1808
1837
k_work_reschedule (& dlc -> rtx_work , RFCOMM_DISC_TIMEOUT );
1809
1838
1810
1839
return 0 ;
0 commit comments