@@ -64,7 +64,8 @@ struct subscriber {
6464 struct enqueued_reports enqueued_reports ;
6565 struct report_data out_reports [ARRAY_SIZE (output_reports )];
6666 uint32_t saved_out_reports_bm ;
67- bool busy ;
67+ uint8_t report_max ;
68+ uint8_t report_cnt ;
6869};
6970
7071struct hids_peripheral {
@@ -88,7 +89,6 @@ static bool suspended;
8889
8990static void hogp_out_rep_write_cb (struct bt_hogp * hogp , struct bt_hogp_rep_info * rep , uint8_t err );
9091static int send_hid_out_report (struct bt_hogp * hogp , const uint8_t * data , size_t size );
91- static void send_empty_hid_out_reports (struct hids_peripheral * per , struct subscriber * sub );
9292
9393#if CONFIG_DESKTOP_HID_DONGLE_BOND_COUNT > 1
9494static void verify_data (const struct bt_bond_info * info , void * user_data )
@@ -353,12 +353,12 @@ static void forward_hid_report(struct hids_peripheral *per, uint8_t report_id,
353353 report -> dyndata .data [0 ] = report_id ;
354354 memcpy (& report -> dyndata .data [1 ], data , size );
355355
356- if (! sub -> busy ) {
356+ if (sub -> report_cnt < sub -> report_max ) {
357357 __ASSERT_NO_MSG (!is_report_enqueued (& sub -> enqueued_reports , irep_idx ));
358358
359359 APP_EVENT_SUBMIT (report );
360360 sub -> enqueued_reports .last_idx = irep_idx ;
361- sub -> busy = true ;
361+ sub -> report_cnt ++ ;
362362 } else {
363363 enqueue_hid_report (& sub -> enqueued_reports , irep_idx , report );
364364 }
@@ -984,27 +984,7 @@ static void disable_subscription(struct subscriber *sub, uint8_t report_id)
984984 }
985985
986986 WRITE_BIT (sub -> enabled_reports_bm , report_id , 0 );
987- bool sub_disconnected = (sub -> enabled_reports_bm == 0 );
988-
989- /* For all peripherals connected to this subscriber. */
990- for (size_t per_id = 0 ; per_id < ARRAY_SIZE (peripherals ); per_id ++ ) {
991- struct hids_peripheral * per = & peripherals [per_id ];
992-
993- if ((sub != get_subscriber (per )) ||
994- (!is_peripheral_connected (per ))) {
995- continue ;
996- }
997-
998- if (sub_disconnected ) {
999- send_empty_hid_out_reports (per , sub );
1000- }
1001- }
1002-
1003987 drop_enqueued_reports (& sub -> enqueued_reports , irep_idx );
1004-
1005- if (sub_disconnected ) {
1006- sub -> saved_out_reports_bm = 0 ;
1007- }
1008988}
1009989
1010990static void hogp_ready (struct bt_hogp * hids_c )
@@ -1119,21 +1099,19 @@ static void init(void)
11191099
11201100static void send_enqueued_report (struct subscriber * sub )
11211101{
1122- if (sub -> busy ) {
1123- return ;
1124- }
1125-
1126- struct enqueued_report * item ;
1102+ __ASSERT_NO_MSG (sub -> report_cnt <= sub -> report_max );
11271103
1128- /* First try to send report left at subscriber. */
1129- item = get_next_enqueued_report (& sub -> enqueued_reports );
1104+ while ( sub -> report_cnt != sub -> report_max ) {
1105+ struct enqueued_report * item = get_next_enqueued_report (& sub -> enqueued_reports );
11301106
1131- if (item ) {
1132- APP_EVENT_SUBMIT (item -> report );
1107+ if (item ) {
1108+ APP_EVENT_SUBMIT (item -> report );
11331109
1134- k_free (item );
1135-
1136- sub -> busy = true;
1110+ k_free (item );
1111+ sub -> report_cnt ++ ;
1112+ } else {
1113+ break ;
1114+ }
11371115 }
11381116}
11391117
@@ -1196,27 +1174,6 @@ static void hogp_out_rep_write_cb(struct bt_hogp *hogp, struct bt_hogp_rep_info
11961174 WRITE_BIT (per -> enqueued_out_reports_bm , orep_idx , 0 );
11971175}
11981176
1199- static void send_empty_hid_out_reports (struct hids_peripheral * per , struct subscriber * sub )
1200- {
1201- struct bt_hogp * per_hogp = & per -> hogp ;
1202-
1203- for (size_t orep_idx = 0 ; orep_idx < ARRAY_SIZE (sub -> out_reports ); orep_idx ++ ) {
1204- if (sub -> saved_out_reports_bm & BIT (orep_idx )) {
1205- uint8_t report_id = sub -> out_reports [orep_idx ].report_id ;
1206- size_t size = get_output_report_size (report_id );
1207- uint8_t empty_data [size ];
1208-
1209- memset (empty_data , 0 , sizeof (empty_data ));
1210- empty_data [0 ] = report_id ;
1211- int err = send_hid_out_report (per_hogp , empty_data , size );
1212-
1213- if (err ) {
1214- LOG_ERR ("Failed to forward output report (err: %d)" , err );
1215- }
1216- }
1217- }
1218- }
1219-
12201177static void save_hid_out_report (struct subscriber * sub , const uint8_t * data , size_t size )
12211178{
12221179 uint8_t report_id = data [0 ];
@@ -1258,34 +1215,126 @@ static void forward_hid_out_report(const struct hid_report_event *event,
12581215 }
12591216}
12601217
1261- static bool handle_hid_report_event (const struct hid_report_event * event )
1218+ static struct subscriber * find_subscriber (const void * sub_id )
12621219{
1263- /* Ignore HID input events. */
1264- if (event -> subscriber ) {
1265- return false;
1220+ struct subscriber * sub = NULL ;
1221+
1222+ for (size_t i = 0 ; i < ARRAY_SIZE (subscribers ); i ++ ) {
1223+ if (subscribers [i ].id == sub_id ) {
1224+ sub = & subscribers [i ];
1225+ break ;
1226+ }
12661227 }
12671228
1268- size_t sub_idx ;
1229+ return sub ;
1230+ }
12691231
1270- for (sub_idx = 0 ; sub_idx < ARRAY_SIZE (subscribers ); sub_idx ++ ) {
1271- if (subscribers [sub_idx ].id == event -> source ) {
1272- break ;
1232+ static void send_empty_hid_out_reports (struct hids_peripheral * per , struct subscriber * sub )
1233+ {
1234+ struct bt_hogp * per_hogp = & per -> hogp ;
1235+
1236+ for (size_t orep_idx = 0 ; orep_idx < ARRAY_SIZE (sub -> out_reports ); orep_idx ++ ) {
1237+ if (sub -> saved_out_reports_bm & BIT (orep_idx )) {
1238+ uint8_t report_id = sub -> out_reports [orep_idx ].report_id ;
1239+ size_t size = get_output_report_size (report_id );
1240+ uint8_t empty_data [size ];
1241+
1242+ memset (empty_data , 0 , sizeof (empty_data ));
1243+ empty_data [0 ] = report_id ;
1244+ int err = send_hid_out_report (per_hogp , empty_data , size );
1245+
1246+ if (err ) {
1247+ LOG_ERR ("Failed to forward output report (err: %d)" , err );
1248+ }
12731249 }
12741250 }
1251+ }
1252+
1253+ static void clear_hid_out_reports (struct subscriber * sub )
1254+ {
1255+ /* Update HID peripherals. */
1256+ for (size_t per_id = 0 ; per_id < ARRAY_SIZE (peripherals ); per_id ++ ) {
1257+ struct hids_peripheral * per = & peripherals [per_id ];
1258+
1259+ if ((sub == get_subscriber (per )) && is_peripheral_connected (per )) {
1260+ send_empty_hid_out_reports (per , sub );
1261+ }
1262+
1263+ }
1264+
1265+ sub -> saved_out_reports_bm = 0 ;
1266+ }
12751267
1276- if (sub_idx == ARRAY_SIZE (subscribers )) {
1277- LOG_WRN ("No subscriber with ID: %p" , event -> source );
1268+ static bool handle_hid_report_subscriber_event (const struct hid_report_subscriber_event * event )
1269+ {
1270+ if (event -> connected ) {
1271+ /* The HID forward module forwards data received from HID peripherals connected over
1272+ * BLE and does not generate HID data pipeline.
1273+ */
1274+ ARG_UNUSED (event -> params .pipeline_size );
1275+ ARG_UNUSED (event -> params .priority );
1276+
1277+ /* Allocate new subscriber. */
1278+ struct subscriber * sub = find_subscriber (NULL );
1279+
1280+ __ASSERT_NO_MSG (sub );
1281+ sub -> id = event -> subscriber ;
1282+ sub -> report_max = event -> params .report_max ;
1283+ } else {
1284+ struct subscriber * sub = find_subscriber (event -> subscriber );
1285+
1286+ __ASSERT_NO_MSG (sub );
1287+
1288+ __ASSERT_NO_MSG (sub -> report_cnt == 0 );
1289+ __ASSERT_NO_MSG (sub -> enabled_reports_bm == 0 );
1290+ __ASSERT_NO_MSG (get_next_enqueued_report (& sub -> enqueued_reports ) == NULL );
1291+
1292+ sub -> report_max = 0 ;
1293+ clear_hid_out_reports (sub );
1294+ sub -> id = NULL ;
1295+ }
1296+
1297+ return false;
1298+ }
1299+
1300+ static bool handle_hid_report_subscription_event (const struct hid_report_subscription_event * event )
1301+ {
1302+ struct subscriber * sub = find_subscriber (event -> subscriber );
1303+
1304+ __ASSERT_NO_MSG (sub );
1305+ __ASSERT_NO_MSG (event -> report_id < __CHAR_BIT__ * sizeof (sub -> enabled_reports_bm ));
1306+ enum bt_hids_pm prev_pm = get_sub_protocol_mode (sub );
1307+
1308+ if (event -> enabled ) {
1309+ enable_subscription (sub , event -> report_id );
1310+ send_enqueued_report (sub );
1311+ } else {
1312+ disable_subscription (sub , event -> report_id );
1313+ }
1314+
1315+ if (prev_pm != get_sub_protocol_mode (sub )) {
1316+ update_sub_protocol_mode (sub , get_sub_protocol_mode (sub ));
1317+ }
1318+
1319+ return false;
1320+ }
1321+
1322+ static bool handle_hid_report_event (const struct hid_report_event * event )
1323+ {
1324+ /* Ignore HID input events. */
1325+ if (event -> subscriber ) {
12781326 return false;
12791327 }
12801328
1281- save_hid_out_report (& subscribers [sub_idx ],
1282- event -> dyndata .data ,
1283- event -> dyndata .size );
1329+ struct subscriber * sub = find_subscriber (event -> source );
1330+
1331+ __ASSERT_NO_MSG (sub );
1332+ save_hid_out_report (sub , event -> dyndata .data , event -> dyndata .size );
12841333
12851334 for (size_t i = 0 ; i < ARRAY_SIZE (peripherals ); i ++ ) {
12861335 struct hids_peripheral * per = & peripherals [i ];
12871336
1288- if ((per -> sub_id == sub_idx ) && is_peripheral_connected (per )) {
1337+ if ((get_subscriber ( per ) == sub ) && is_peripheral_connected (per )) {
12891338 forward_hid_out_report (event , per );
12901339 }
12911340 }
@@ -1296,19 +1345,11 @@ static bool handle_hid_report_event(const struct hid_report_event *event)
12961345static bool app_event_handler (const struct app_event_header * aeh )
12971346{
12981347 if (is_hid_report_sent_event (aeh )) {
1299- const struct hid_report_sent_event * event =
1300- cast_hid_report_sent_event (aeh );
1301- struct subscriber * sub = NULL ;
1348+ const struct hid_report_sent_event * event = cast_hid_report_sent_event (aeh );
1349+ struct subscriber * sub = find_subscriber (event -> subscriber );
13021350
1303- for (size_t i = 0 ; i < ARRAY_SIZE (subscribers ); i ++ ) {
1304- if (subscribers [i ].id == event -> subscriber ) {
1305- sub = & subscribers [i ];
1306- break ;
1307- }
1308- }
13091351 __ASSERT_NO_MSG (sub );
1310-
1311- sub -> busy = false;
1352+ sub -> report_cnt -- ;
13121353 send_enqueued_report (sub );
13131354
13141355 return false;
@@ -1342,44 +1383,13 @@ static bool app_event_handler(const struct app_event_header *aeh)
13421383 return false;
13431384 }
13441385
1345- if (is_hid_report_subscription_event (aeh )) {
1346- const struct hid_report_subscription_event * event =
1347- cast_hid_report_subscription_event (aeh );
1348-
1349- struct subscriber * sub = NULL ;
1350-
1351- for (size_t i = 0 ; i < ARRAY_SIZE (subscribers ); i ++ ) {
1352- if ((subscribers [i ].id == event -> subscriber ) ||
1353- (subscribers [i ].id == NULL )) {
1354- sub = & subscribers [i ];
1355- }
1356-
1357- if (subscribers [i ].id == event -> subscriber ) {
1358- break ;
1359- }
1360- }
1361- __ASSERT_NO_MSG (sub );
1362-
1363- if (!sub -> id ) {
1364- sub -> id = event -> subscriber ;
1365- }
1366-
1367- __ASSERT_NO_MSG (event -> report_id < __CHAR_BIT__ * sizeof (sub -> enabled_reports_bm ));
1368-
1369- enum bt_hids_pm prev_pm = get_sub_protocol_mode (sub );
1370-
1371- if (event -> enabled ) {
1372- enable_subscription (sub , event -> report_id );
1373- send_enqueued_report (sub );
1374- } else {
1375- disable_subscription (sub , event -> report_id );
1376- }
1377-
1378- if (prev_pm != get_sub_protocol_mode (sub )) {
1379- update_sub_protocol_mode (sub , get_sub_protocol_mode (sub ));
1380- }
1386+ if (is_hid_report_subscriber_event (aeh )) {
1387+ return handle_hid_report_subscriber_event (cast_hid_report_subscriber_event (aeh ));
1388+ }
13811389
1382- return false;
1390+ if (is_hid_report_subscription_event (aeh )) {
1391+ return handle_hid_report_subscription_event (
1392+ cast_hid_report_subscription_event (aeh ));
13831393 }
13841394
13851395 if (is_hid_report_event (aeh )) {
@@ -1446,6 +1456,7 @@ APP_EVENT_SUBSCRIBE_EARLY(MODULE, ble_discovery_complete_event);
14461456APP_EVENT_SUBSCRIBE (MODULE , ble_peer_event );
14471457APP_EVENT_SUBSCRIBE (MODULE , ble_peer_operation_event );
14481458APP_EVENT_SUBSCRIBE (MODULE , hid_report_event );
1459+ APP_EVENT_SUBSCRIBE (MODULE , hid_report_subscriber_event );
14491460APP_EVENT_SUBSCRIBE (MODULE , hid_report_subscription_event );
14501461APP_EVENT_SUBSCRIBE (MODULE , hid_report_sent_event );
14511462APP_EVENT_SUBSCRIBE (MODULE , power_down_event );
0 commit comments