mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2025-01-28 01:18:31 +00:00
d/wmr: Recover from bad camera transfers
Fix USB overflow problems when camera readout is delayed by rounding up the transfer size to always be a multiple of the endpoint transfer size, and by discarding invalid frames that happen when the headset ends up with too much data queued. Part-of: <https://gitlab.freedesktop.org/monado/monado/-/merge_requests/2394>
This commit is contained in:
parent
4a905bbb24
commit
d93e4b92a6
|
@ -99,6 +99,7 @@ struct wmr_camera
|
|||
int slam_cam_count; //!< Number of tracking cameras used for SLAM
|
||||
|
||||
size_t xfer_size;
|
||||
size_t frame_xfer_size;
|
||||
uint32_t frame_width, frame_height;
|
||||
uint8_t last_seq;
|
||||
uint64_t last_frame_ts;
|
||||
|
@ -172,6 +173,13 @@ compute_frame_size(struct wmr_camera *cam)
|
|||
|
||||
F = 26;
|
||||
|
||||
libusb_device *dev = libusb_get_device(cam->dev);
|
||||
int ep_pkt_size = libusb_get_max_packet_size(dev, CAM_ENDPOINT);
|
||||
if (ep_pkt_size < 0) {
|
||||
WMR_CAM_ERROR(cam, "Failed to retrieve endpoint descriptor: result %d", ep_pkt_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (i = 0; i < cam->tcam_count; i++) {
|
||||
const struct wmr_camera_config *config = &cam->tcam_confs[i];
|
||||
|
||||
|
@ -204,7 +212,14 @@ compute_frame_size(struct wmr_camera *cam)
|
|||
n_packets = F / (0x6000 - 32);
|
||||
leftover = F - n_packets * (0x6000 - 32);
|
||||
|
||||
cam->xfer_size = n_packets * 0x6000 + 32 + leftover;
|
||||
cam->frame_xfer_size = n_packets * 0x6000 + 32 + leftover;
|
||||
|
||||
// Round up to a multiple of the max packet size to avoid overflows
|
||||
// in case of stalls reading things out
|
||||
size_t round_up = ep_pkt_size - (cam->frame_xfer_size % ep_pkt_size);
|
||||
cam->xfer_size = cam->frame_xfer_size + round_up;
|
||||
WMR_CAM_DEBUG(cam, "Rounding up xfer size by %zu from frame size %zu to %zu", round_up, cam->frame_xfer_size,
|
||||
cam->xfer_size);
|
||||
|
||||
cam->frame_width = width;
|
||||
cam->frame_height = height;
|
||||
|
@ -288,8 +303,9 @@ img_xfer_cb(struct libusb_transfer *xfer)
|
|||
goto out;
|
||||
}
|
||||
|
||||
if (xfer->actual_length < xfer->length) {
|
||||
WMR_CAM_DEBUG(cam, "Camera transfer only delivered %d bytes", xfer->actual_length);
|
||||
if ((size_t)xfer->actual_length < cam->frame_xfer_size) {
|
||||
WMR_CAM_DEBUG(cam, "Camera transfer only delivered %d bytes of %zu per frame", xfer->actual_length,
|
||||
cam->frame_xfer_size);
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
@ -308,7 +324,7 @@ img_xfer_cb(struct libusb_transfer *xfer)
|
|||
const size_t chunk_size = 0x6000 - 32;
|
||||
|
||||
DRV_TRACE_BEGIN(copy_to_frame);
|
||||
while (dst_remain > 0) {
|
||||
while (dst_remain >= 0x20) {
|
||||
const size_t to_copy = dst_remain > chunk_size ? chunk_size : dst_remain;
|
||||
|
||||
/* 32 byte header seems to contain:
|
||||
|
@ -319,6 +335,11 @@ img_xfer_cb(struct libusb_transfer *xfer)
|
|||
* but repeat every 8 slices. They're different each boot
|
||||
* of the headset. Might just be uninitialised memory?
|
||||
*/
|
||||
uint32_t magic = __le32_to_cpu(*(__le32 *)(src));
|
||||
if (magic != WMR_MAGIC) {
|
||||
WMR_CAM_WARN(cam, "Invalid frame magic (got %x, expected %x). Dropping", magic, WMR_MAGIC);
|
||||
goto drop_frame;
|
||||
}
|
||||
src += 0x20;
|
||||
|
||||
memcpy(dst, src, to_copy);
|
||||
|
@ -328,8 +349,11 @@ img_xfer_cb(struct libusb_transfer *xfer)
|
|||
}
|
||||
DRV_TRACE_END(copy_to_frame);
|
||||
|
||||
/* There should be exactly a 26 byte footer left over */
|
||||
assert(xfer->buffer + xfer->length - src == 26);
|
||||
/* There should be exactly a 26 byte footer left over if we completely consumed the right amount of data */
|
||||
if (xfer->buffer + cam->frame_xfer_size - src != 26) {
|
||||
WMR_CAM_WARN(cam, "Invalid frame. Dropping");
|
||||
goto drop_frame;
|
||||
}
|
||||
|
||||
/* Footer contains:
|
||||
* __le64 start_ts; - 100ns unit timestamp, from same clock as video_timestamps on the IMU feed
|
||||
|
@ -401,6 +425,7 @@ img_xfer_cb(struct libusb_transfer *xfer)
|
|||
}
|
||||
}
|
||||
|
||||
drop_frame:
|
||||
xrt_frame_reference(&xf, NULL);
|
||||
|
||||
out:
|
||||
|
|
Loading…
Reference in a new issue