Skip to content

Commit 86ccf55

Browse files
Merge pull request #177 from espressif/fix/uvc_bulk_eof_check
fix(uvc): Relax bulk EoF flag check
2 parents 7aa147c + 613fde7 commit 86ccf55

File tree

4 files changed

+64
-58
lines changed

4 files changed

+64
-58
lines changed

host/class/uvc/usb_host_uvc/host_test/main/streaming/images/test_logo_jpg.hpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
11
/*
2-
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
6+
7+
#pragma once
68
#include <array>
9+
#include "usb/uvc_host.h"
10+
11+
constexpr uvc_host_stream_format_t logo_jpg_format = {
12+
.h_res = 46,
13+
.v_res = 46,
14+
.fps = 15,
15+
.format = UVC_VS_FORMAT_MJPEG,
16+
};
717

818
std::array<unsigned char, 7561> logo_jpg = {
919
0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01,

host/class/uvc/usb_host_uvc/host_test/main/streaming/test_streaming.cpp

Lines changed: 49 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,16 @@
1717
#include "images/test_logo_jpg.hpp"
1818
#include "test_streaming_helpers.hpp"
1919

20-
std::function<bool(const uvc_host_frame_t *, void *)> frame_callback; // Define a std::function to hold the lambda with captures
21-
std::function<void(const uvc_host_stream_event_data_t *, void *)> stream_callback; // Define a std::function to hold the lambda with captures
22-
2320
// `send_frame_function` is a generic std::function that acts as a wrapper for sending frames in the
2421
// test scenarios. By assigning it either `test_streaming_bulk_send_frame` or `test_streaming_isoc_send_frame`
2522
// before calling `run_streaming_frame_reconstruction_scenario()`, we avoid duplicating the entire scenario
2623
// code for each transfer type (bulk or isochronous). Instead, we can dynamically set the appropriate
2724
// frame-sending function, allowing `run_streaming_frame_reconstruction_scenario` to run identical tests
2825
// with either transfer method.
29-
std::function<void(size_t, void *, std::span<const uint8_t>, uint8_t, bool, bool)> send_frame_function;
30-
inline void send_function_wrapper(size_t transfer_size, void *transfer_context, std::span<const uint8_t> data, uint8_t frame_id = 0, bool error_in_sof = false, bool error_in_eof = false)
26+
std::function<void(size_t, void *, std::span<const uint8_t>, uint8_t, bool, bool, bool)> send_frame_function;
27+
inline void send_function_wrapper(size_t transfer_size, void *transfer_context, std::span<const uint8_t> data, uint8_t frame_id = 0, bool error_in_sof = false, bool error_in_eof = false, bool eof_in_sof = false)
3128
{
32-
send_frame_function(transfer_size, transfer_context, data, frame_id, error_in_sof, error_in_eof);
29+
send_frame_function(transfer_size, transfer_context, data, frame_id, error_in_sof, error_in_eof, eof_in_sof);
3330
}
3431

3532
void run_streaming_frame_reconstruction_scenario(void)
@@ -39,45 +36,31 @@ void run_streaming_frame_reconstruction_scenario(void)
3936
uvc_stream_t stream = {}; // Define mock stream
4037
stream.constant.cb_arg = (void *)&user_arg;
4138

42-
stream.constant.stream_cb = [](const uvc_host_stream_event_data_t *event, void *user_ctx) {
43-
return stream_callback(event, user_ctx);
44-
};
45-
stream.constant.frame_cb = [](const uvc_host_frame_t *frame, void *user_ctx) -> bool {
46-
// We cannot have catching lambdas here, so we must call this std::function...
47-
return frame_callback(frame, user_ctx);
48-
};
49-
5039
// We don't expect any stream events or frames by default
51-
stream_callback = [&](const uvc_host_stream_event_data_t *event, void *user_ctx) {
40+
stream.constant.stream_cb = [](const uvc_host_stream_event_data_t *event, void *user_ctx) {
5241
FAIL("Unexpected event " + std::to_string(event->type));
5342
};
54-
frame_callback = [&](const uvc_host_frame_t *frame, void *user_ctx) -> bool {
43+
stream.constant.frame_cb = [](const uvc_host_frame_t *frame, void *user_ctx) -> bool {
5544
FAIL("Got unexpected frame");
5645
return true;
5746
};
5847

5948
GIVEN("Streaming enabled") {
6049
REQUIRE(uvc_host_stream_unpause(&stream) == ESP_OK);
61-
const uvc_host_stream_format_t format = {
62-
.h_res = 46,
63-
.v_res = 46,
64-
.fps = 15,
65-
.format = UVC_VS_FORMAT_MJPEG,
66-
};
67-
6850
AND_GIVEN("Frame buffer is allocated") {
6951
int frame_callback_called;
7052
frame_callback_called = 0;
7153
// We expect valid frame data
72-
frame_callback = [&](const uvc_host_frame_t *frame, void *user_ctx) -> bool {
73-
frame_callback_called++;
54+
stream.constant.cb_arg = (void *)&frame_callback_called;
55+
stream.constant.frame_cb = [](const uvc_host_frame_t *frame, void *user_ctx) -> bool {
56+
int *frame_callback_called = static_cast<int *>(user_ctx);
57+
(*frame_callback_called)++;
7458

75-
REQUIRE(user_ctx == stream.constant.cb_arg); // Sanity check
76-
REQUIRE(frame->data_len == logo_jpg.size());
77-
REQUIRE(frame->vs_format.h_res == format.h_res);
78-
REQUIRE(frame->vs_format.v_res == format.v_res);
79-
REQUIRE(frame->vs_format.fps == format.fps);
80-
REQUIRE(frame->vs_format.format == format.format);
59+
REQUIRE(frame->data_len == logo_jpg.size());
60+
REQUIRE(frame->vs_format.h_res == logo_jpg_format.h_res);
61+
REQUIRE(frame->vs_format.v_res == logo_jpg_format.v_res);
62+
REQUIRE(frame->vs_format.fps == logo_jpg_format.fps);
63+
REQUIRE(frame->vs_format.format == logo_jpg_format.format);
8164

8265
std::vector<uint8_t> frame_data(frame->data, frame->data + frame->data_len);
8366
std::vector<uint8_t> original_data(logo_jpg.begin(), logo_jpg.end());
@@ -87,7 +70,7 @@ void run_streaming_frame_reconstruction_scenario(void)
8770
};
8871

8972
REQUIRE(uvc_frame_allocate(&stream, 1, 100 * 1024, 0) == ESP_OK);
90-
uvc_frame_format_update(&stream, &format);
73+
uvc_frame_format_update(&stream, &logo_jpg_format);
9174

9275
// Test
9376
for (size_t transfer_size = 512; transfer_size <= 8192; transfer_size += 512) {
@@ -157,12 +140,12 @@ void run_streaming_frame_reconstruction_scenario(void)
157140
}
158141

159142
AND_GIVEN("Frame buffer is too small") {
160-
161143
// We expect overflow stream event
162144
enum uvc_host_dev_event event_type = static_cast<enum uvc_host_dev_event>(-1); // Explicitly set to invalid value
163-
stream_callback = [&](const uvc_host_stream_event_data_t *event, void *user_ctx) {
164-
REQUIRE(user_ctx == stream.constant.cb_arg); // Sanity check
165-
event_type = event->type;
145+
stream.constant.cb_arg = (void *)&event_type;
146+
stream.constant.stream_cb = [](const uvc_host_stream_event_data_t *event, void *user_ctx) {
147+
enum uvc_host_dev_event *event_type = static_cast<enum uvc_host_dev_event *>(user_ctx);
148+
*event_type = event->type;
166149
};
167150
REQUIRE(uvc_frame_allocate(&stream, 1, logo_jpg.size() - 100, 0) == ESP_OK);
168151

@@ -180,9 +163,10 @@ void run_streaming_frame_reconstruction_scenario(void)
180163
AND_GIVEN("There is no free frame buffer") {
181164
// We expect overflow stream event
182165
enum uvc_host_dev_event event_type = static_cast<enum uvc_host_dev_event>(-1); // Explicitly set to invalid value
183-
stream_callback = [&](const uvc_host_stream_event_data_t *event, void *user_ctx) {
184-
REQUIRE(user_ctx == stream.constant.cb_arg); // Sanity check
185-
event_type = event->type;
166+
stream.constant.cb_arg = (void *)&event_type;
167+
stream.constant.stream_cb = [](const uvc_host_stream_event_data_t *event, void *user_ctx) {
168+
enum uvc_host_dev_event *event_type = static_cast<enum uvc_host_dev_event *>(user_ctx);
169+
*event_type = event->type;
186170
};
187171

188172
uvc_host_frame_t *temp_frame = nullptr;
@@ -236,15 +220,41 @@ void run_streaming_frame_reconstruction_scenario(void)
236220

237221
SCENARIO("Bulk stream frame reconstruction", "[streaming][bulk]")
238222
{
223+
/* Tests that are same for ISOC and BULK */
239224
send_frame_function = test_streaming_bulk_send_frame;
240225
run_streaming_frame_reconstruction_scenario();
226+
227+
/* BULK specific tests */
228+
int frame_callback_called = 0;
229+
uvc_stream_t stream = {}; // Define mock stream
230+
stream.constant.cb_arg = (void *)&frame_callback_called;
231+
stream.constant.frame_cb = [](const uvc_host_frame_t *frame, void *user_ctx) -> bool {
232+
int *fb_called = static_cast<int *>(user_ctx);
233+
(*fb_called)++;
234+
return true;
235+
};
236+
237+
GIVEN("Streaming enabled and frame allocated") {
238+
REQUIRE(uvc_host_stream_unpause(&stream) == ESP_OK);
239+
REQUIRE(uvc_frame_allocate(&stream, 1, 100 * 1024, 0) == ESP_OK);
240+
uvc_frame_format_update(&stream, &logo_jpg_format);
241+
242+
WHEN("Expected SoF but got EoF") {
243+
test_streaming_bulk_send_frame(512, &stream, std::span(logo_jpg), 0, false, false, true);
244+
THEN("The frame callback is called") {
245+
REQUIRE(frame_callback_called == 1);
246+
}
247+
}
248+
}
241249
}
242250

243251
SCENARIO("Isochronous stream frame reconstruction", "[streaming][isoc]")
244252
{
253+
/* Tests that are same for ISOC and BULK */
245254
send_frame_function = test_streaming_isoc_send_frame;
246255
run_streaming_frame_reconstruction_scenario();
247256

257+
/* ISOC specific tests */
248258
/*
249259
@todo ISOC test
250260
- Missed SoF

host/class/uvc/usb_host_uvc/host_test/main/streaming/test_streaming_helpers.hpp

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
2+
* SPDX-FileCopyrightText: 2024-2025 Espressif Systems (Shanghai) CO LTD
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -26,15 +26,8 @@ extern "C" {
2626
* @brief Send bulk frame to the UVC driver
2727
*
2828
* Only the first and last transfer contains header
29-
*
30-
* @param transfer_size
31-
* @param transfer_context
32-
* @param data
33-
* @param frame_id
34-
* @param error_in_sof
35-
* @param error_in_eof
3629
*/
37-
inline void test_streaming_bulk_send_frame(size_t transfer_size, void *transfer_context, std::span<const uint8_t> data, uint8_t frame_id = 0, bool error_in_sof = false, bool error_in_eof = false)
30+
inline void test_streaming_bulk_send_frame(size_t transfer_size, void *transfer_context, std::span<const uint8_t> data, uint8_t frame_id = 0, bool error_in_sof = false, bool error_in_eof = false, bool eof_in_sof = false)
3831
{
3932
assert(transfer_size > HEADER_LEN);
4033
assert(!data.empty());
@@ -64,6 +57,7 @@ inline void test_streaming_bulk_send_frame(size_t transfer_size, void *transfer_
6457
header_sof->bmHeaderInfo.end_of_header = 1;
6558
header_sof->bmHeaderInfo.frame_id = frame_id;
6659
header_sof->bmHeaderInfo.error = error_in_sof;
60+
header_sof->bmHeaderInfo.end_of_frame = eof_in_sof;
6761

6862

6963
// Add Frame data to first SoF transfer
@@ -107,15 +101,8 @@ inline void test_streaming_bulk_send_frame(size_t transfer_size, void *transfer_
107101
* @brief Send isoc frame to the UVC driver
108102
*
109103
* Each ISOC packet contains header
110-
*
111-
* @param transfer_size
112-
* @param transfer_context
113-
* @param data
114-
* @param frame_id
115-
* @param error_in_sof
116-
* @param error_in_eof
117104
*/
118-
inline void test_streaming_isoc_send_frame(size_t transfer_size, void *transfer_context, std::span<const uint8_t> data, uint8_t frame_id = 0, bool error_in_sof = false, bool error_in_eof = false)
105+
inline void test_streaming_isoc_send_frame(size_t transfer_size, void *transfer_context, std::span<const uint8_t> data, uint8_t frame_id = 0, bool error_in_sof = false, bool error_in_eof = false, bool eof_in_sof = false)
119106
{
120107
assert(transfer_size > HEADER_LEN);
121108
assert(!data.empty());

host/class/uvc/usb_host_uvc/uvc_bulk.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,6 @@ void bulk_transfer_callback(usb_transfer_t *transfer)
120120
}
121121
case UVC_STREAM_BULK_PACKET_SOF: {
122122
const uvc_payload_header_t *payload_header = (const uvc_payload_header_t *)payload;
123-
assert(!payload_header->bmHeaderInfo.end_of_frame);
124123

125124
// We detected start of new frame. Update Frame ID and start fetching this frame
126125
uvc_stream->single_thread.current_frame_id = payload_header->bmHeaderInfo.frame_id;

0 commit comments

Comments
 (0)