@@ -34,16 +34,21 @@ static struct tracker_report {
3434 .data = {0 }
3535};;
3636
37- uint8_t reports [MAX_TRACKERS * sizeof (report )];
38- uint8_t report_count = 0 ;
39- uint8_t report_sent = 0 ;
37+ struct tracker_report reports [MAX_TRACKERS ];
38+ atomic_t report_write_index = 0 ;
39+ atomic_t report_read_index = 0 ;
40+ // read_index == write_index -> empty fifo
41+ // (write_index + 1) % MAX_TRACKERS == read_index -> full fifo
4042
4143static bool configured ;
4244static const struct device * hdev ;
4345static ATOMIC_DEFINE (hid_ep_in_busy , 1 ) ;
4446
4547#define HID_EP_BUSY_FLAG 0
4648#define REPORT_PERIOD K_MSEC(1) // streaming reports
49+ #define HID_EP_REPORT_COUNT 4
50+
51+ struct tracker_report ep_report_buffer [HID_EP_REPORT_COUNT ];
4752
4853LOG_MODULE_REGISTER (hid_event , LOG_LEVEL_INF );
4954
@@ -80,30 +85,45 @@ static void send_report(struct k_work *work)
8085{
8186 if (!usb_enabled ) return ;
8287 if (!stored_trackers ) return ;
83- if (report_count == 0 && k_uptime_get () - 100 < last_registration_sent ) return ; // send registrations only every 100ms
88+
89+ // Get current FIFO status atomically
90+ size_t write_idx = (size_t )atomic_get (& report_write_index );
91+ size_t read_idx = (size_t )atomic_get (& report_read_index );
92+
93+ if (write_idx == read_idx && k_uptime_get () - 100 < last_registration_sent ) {
94+ return ; // send registrations only every 100ms
95+ }
96+
8497 int ret , wrote ;
8598
8699 last_registration_sent = k_uptime_get ();
87100
88101 if (!atomic_test_and_set_bit (hid_ep_in_busy , HID_EP_BUSY_FLAG )) {
89- // TODO: this really sucks, how can i send as much or as little as i want instead??
90- // for (int i = report_count; i < 4; i++) memcpy(&reports[sizeof(report) * (report_sent+i)], &reports[sizeof(report) * report_sent], sizeof(report)); // just duplicate first entry a bunch, this will definitely cause problems
91- // cycle through devices and send associated address for server to register
92- for (int i = report_count ; i < 4 ; i ++ ) {
93- packet_device_addr (& reports [sizeof (report ) * (report_sent + i )], sent_device_addr );
94- sent_device_addr ++ ;
95- sent_device_addr %= stored_trackers ;
102+ // Calculate how many reports we have available
103+ int available_reports = write_idx - read_idx ;
104+ if (available_reports < 0 ) available_reports += MAX_TRACKERS ;
105+ size_t reports_to_send = (size_t )((available_reports > HID_EP_REPORT_COUNT ) ? HID_EP_REPORT_COUNT : available_reports );
106+
107+ int epind ;
108+ // Copy existing data to buffer
109+ for (epind = 0 ; epind < reports_to_send ; epind ++ ) {
110+ ep_report_buffer [epind ] = reports [read_idx ];
111+ epind ++ ;
112+ read_idx ++ ;
113+ if (read_idx == MAX_TRACKERS ) read_idx = 0 ;
114+ atomic_set (& report_read_index , read_idx );
96115 }
97- // ret = hid_int_ep_write(hdev, &reports, sizeof(report) * report_count, &wrote);
98- ret = hid_int_ep_write (hdev , & reports [sizeof (report ) * report_sent ], sizeof (report ) * 4 , & wrote );
99- if (report_count > 4 ) {
100- dropped_reports += report_count - 4 ;
101- if (dropped_reports > max_dropped_reports ) max_dropped_reports = dropped_reports ;
116+
117+ // Pad remaining report slots with device addr
118+ for (; epind < HID_EP_REPORT_COUNT ; epind ++ ) {
119+ if (stored_trackers > 0 ) {
120+ packet_device_addr (ep_report_buffer [epind ].data , sent_device_addr );
121+ sent_device_addr = (sent_device_addr + 1 ) % stored_trackers ;
122+ }
102123 }
103- report_sent += report_count ;
104- report_sent += 3 ; // this is a hack to make sure the ep isnt reading the same bits as trackers write to
105- if (report_sent > MAX_TRACKERS / 2 ) report_sent = 0 ; // an attempt to make ringbuffer so the ep isnt reading the same bits as trackers write to // TODO: might be too small!
106- report_count = 0 ;
124+
125+ ret = hid_int_ep_write (hdev , (uint8_t * )ep_report_buffer , sizeof (report ) * HID_EP_REPORT_COUNT , & wrote );
126+
107127 if (ret != 0 ) {
108128 /*
109129 * Do nothing and wait until host has reset the device
@@ -332,20 +352,38 @@ void hid_write_packet_n(uint8_t *data, uint8_t rssi)
332352 }
333353#endif
334354
335- memcpy (& report .data , data , 16 ); // all data can be passed through
355+ memcpy (& report .data , data , sizeof ( report ) ); // all data can be passed through
336356 if (data [0 ] != 1 && data [0 ] != 4 ) // packet 1 and 4 are full precision quat and accel/mag, no room for rssi
337357 report .data [15 ] = rssi ;
338- // TODO: this sucks
339- for (int i = 0 ; i < report_count ; i ++ ) // replace existing entry instead
340- {
341- if (reports [sizeof (report ) * (report_sent + i ) + 1 ] == report .data [1 ])
342- {
343- memcpy (& reports [sizeof (report ) * (report_sent + i )], & report , sizeof (report ));
344- return ;
358+ // Get current FIFO status atomically
359+ size_t write_idx = (size_t )atomic_get (& report_write_index );
360+ size_t read_idx = (size_t )atomic_get (& report_read_index );
361+
362+ // Try to replace existing entry for the same tracker first
363+ if (write_idx != read_idx ) {
364+ // Start from read point + 1 to avoid hitting the entry being used
365+ size_t check_index = read_idx + 1 ;
366+ if (check_index == MAX_TRACKERS ) check_index = 0 ;
367+
368+ while (check_index != write_idx ) {
369+ if (reports [check_index ].data [1 ] == data [1 ]) {
370+ // Replace existing entry
371+ reports [check_index ] = report ;
372+ return ;
373+ }
374+ check_index = check_index + 1 ;
375+ if (check_index == MAX_TRACKERS ) check_index = 0 ;
345376 }
346377 }
347- if (report_count > 100 ) // overflow
378+ if (write_idx + 1 == read_idx || (write_idx == MAX_TRACKERS - 1 && read_idx == 0 )) { // overflow
379+ dropped_reports ++ ;
348380 return ;
349- memcpy (& reports [sizeof (report ) * (report_sent + report_count )], & report , sizeof (report ));
350- report_count ++ ;
381+ }
382+ // Write new packet into FIFO
383+ reports [write_idx ] = report ;
384+
385+ // Update write index atomically
386+ write_idx ++ ;
387+ if (write_idx == MAX_TRACKERS ) write_idx = 0 ;
388+ atomic_set (& report_write_index , write_idx );
351389}
0 commit comments