1111#include <zephyr/drivers/display.h>
1212#include <zephyr/drivers/video.h>
1313#include <zephyr/drivers/video-controls.h>
14-
14+ #include <zephyr/usb/usbh.h>
1515#include <zephyr/logging/log.h>
1616
1717#ifdef CONFIG_TEST
@@ -22,9 +22,8 @@ LOG_MODULE_REGISTER(main, LOG_LEVEL_DBG);
2222LOG_MODULE_REGISTER (main , CONFIG_LOG_DEFAULT_LEVEL );
2323#endif
2424
25- #if !DT_HAS_CHOSEN (zephyr_camera )
26- #error No camera chosen in devicetree. Missing "--shield" or "--snippet video-sw-generator" flag?
27- #endif
25+ USBH_CONTROLLER_DEFINE (uhs_ctx , DEVICE_DT_GET (DT_NODELABEL (zephyr_uhc0 )));
26+ const struct device * const uvc_host = DEVICE_DT_GET (DT_NODELABEL (uvc_host ));
2827
2928#if DT_HAS_CHOSEN (zephyr_display )
3029static inline int display_setup (const struct device * const display_dev , const uint32_t pixfmt )
@@ -75,8 +74,8 @@ static inline int display_setup(const struct device *const display_dev, const ui
7574}
7675
7776static inline void video_display_frame (const struct device * const display_dev ,
78- const struct video_buffer * const vbuf ,
79- const struct video_format fmt )
77+ const struct video_buffer * const vbuf ,
78+ const struct video_format fmt )
8079{
8180 struct display_buffer_descriptor buf_desc = {
8281 .buf_size = vbuf -> bytesused ,
@@ -89,15 +88,22 @@ static inline void video_display_frame(const struct device *const display_dev,
8988}
9089#endif
9190
91+ /* TODO: handle disconnection,etc.. */
92+ static void video_uvc_device_signal_handler (void )
93+ {
94+ }
95+
9296int main (void )
9397{
9498 struct video_buffer * buffers [CONFIG_VIDEO_BUFFER_POOL_NUM_MAX ];
9599 struct video_buffer * vbuf = & (struct video_buffer ){};
96- const struct device * video_dev ;
97100 struct video_format fmt ;
98101 struct video_caps caps ;
99102 struct video_frmival frmival ;
100103 struct video_frmival_enum fie ;
104+ struct k_poll_signal sig ;
105+ struct k_poll_event evt [1 ];
106+ k_timeout_t timeout = K_FOREVER ;
101107 enum video_buf_type type = VIDEO_BUF_TYPE_OUTPUT ;
102108#if (CONFIG_VIDEO_SOURCE_CROP_WIDTH && CONFIG_VIDEO_SOURCE_CROP_HEIGHT ) || \
103109 CONFIG_VIDEO_FRAME_HEIGHT || CONFIG_VIDEO_FRAME_WIDTH
@@ -116,17 +122,58 @@ int main(void)
116122 return 0 ;
117123 }
118124
119- video_dev = DEVICE_DT_GET (DT_CHOSEN (zephyr_camera ));
120- if (!device_is_ready (video_dev )) {
121- LOG_ERR ("%s: video device is not ready" , video_dev -> name );
125+ if (!device_is_ready (uvc_host )) {
126+ LOG_ERR ("%s: USB host is not ready" , uvc_host -> name );
122127 return 0 ;
123128 }
129+ LOG_INF ("USB host: %s" , uvc_host -> name );
124130
125- LOG_INF ("Video device: %s" , video_dev -> name );
131+ err = usbh_init (& uhs_ctx );
132+ if (err ) {
133+ LOG_ERR ("Failed to initialize host support" );
134+ return err ;
135+ }
136+
137+ err = usbh_enable (& uhs_ctx );
138+ if (err ) {
139+ LOG_ERR ("Failed to enable USB host support" );
140+ return err ;
141+ }
142+
143+ k_poll_signal_init (& sig );
144+ k_poll_event_init (& evt [0 ], K_POLL_TYPE_SIGNAL , K_POLL_MODE_NOTIFY_ONLY , & sig );
145+
146+ err = video_set_signal (uvc_host , & sig );
147+ if (err != 0 ) {
148+ LOG_WRN ("Failed to setup the signal on %s output endpoint" , uvc_host -> name );
149+ timeout = K_MSEC (10 );
150+ }
151+
152+ /* Wait for UVC device connection event */
153+ while (true) {
154+ err = k_poll (evt , ARRAY_SIZE (evt ), timeout );
155+ if (err != 0 ) {
156+ LOG_WRN ("Poll failed with error %d, retrying..." , err );
157+ continue ;
158+ }
159+
160+ int signaled , result ;
161+ k_poll_signal_check (& sig , & signaled , & result );
162+
163+ if (signaled && result == USBH_DEVICE_CONNECTED ) {
164+ LOG_INF ("UVC device connected successfully!" );
165+ k_poll_signal_reset (& sig );
166+ break ;
167+ }
168+
169+ /* Received other signal, reset and continue waiting */
170+ k_poll_signal_reset (& sig );
171+ LOG_DBG ("Received signal %d, waiting for device connection..." , result );
172+ }
126173
127174 /* Get capabilities */
128175 caps .type = type ;
129- if (video_get_caps (video_dev , & caps )) {
176+ if (video_get_caps (uvc_host , & caps )) {
130177 LOG_ERR ("Unable to retrieve video capabilities" );
131178 return 0 ;
132179 }
@@ -144,7 +191,7 @@ int main(void)
144191
145192 /* Get default/native format */
146193 fmt .type = type ;
147- if (video_get_format (video_dev , & fmt )) {
194+ if (video_get_format (uvc_host , & fmt )) {
148195 LOG_ERR ("Unable to retrieve video format" );
149196 return 0 ;
150197 }
@@ -156,7 +203,7 @@ int main(void)
156203 sel .rect .top = CONFIG_VIDEO_SOURCE_CROP_TOP ;
157204 sel .rect .width = CONFIG_VIDEO_SOURCE_CROP_WIDTH ;
158205 sel .rect .height = CONFIG_VIDEO_SOURCE_CROP_HEIGHT ;
159- if (video_set_selection (video_dev , & sel )) {
206+ if (video_set_selection (uvc_host , & sel )) {
160207 LOG_ERR ("Unable to set selection crop" );
161208 return 0 ;
162209 }
@@ -178,7 +225,7 @@ int main(void)
178225 * and if compose is necessary
179226 */
180227 sel .target = VIDEO_SEL_TGT_CROP ;
181- err = video_get_selection (video_dev , & sel );
228+ err = video_get_selection (uvc_host , & sel );
182229 if (err < 0 && err != - ENOSYS ) {
183230 LOG_ERR ("Unable to get selection crop" );
184231 return 0 ;
@@ -190,7 +237,7 @@ int main(void)
190237 sel .rect .top = 0 ;
191238 sel .rect .width = fmt .width ;
192239 sel .rect .height = fmt .height ;
193- err = video_set_selection (video_dev , & sel );
240+ err = video_set_selection (uvc_host , & sel );
194241 if (err < 0 && err != - ENOSYS ) {
195242 LOG_ERR ("Unable to set selection compose" );
196243 return 0 ;
@@ -201,24 +248,31 @@ int main(void)
201248 if (strcmp (CONFIG_VIDEO_PIXEL_FORMAT , "" )) {
202249 fmt .pixelformat = VIDEO_FOURCC_FROM_STR (CONFIG_VIDEO_PIXEL_FORMAT );
203250 }
251+ #if CONFIG_VIDEO_FRAME_WIDTH > 0
252+ fmt .width = CONFIG_VIDEO_FRAME_WIDTH ;
253+ #endif
254+
255+ #if CONFIG_VIDEO_FRAME_HEIGHT > 0
256+ fmt .height = CONFIG_VIDEO_FRAME_HEIGHT ;
257+ #endif
204258
205259 LOG_INF ("- Video format: %s %ux%u" ,
206260 VIDEO_FOURCC_TO_STR (fmt .pixelformat ), fmt .width , fmt .height );
207261
208- if (video_set_format (video_dev , & fmt )) {
262+ if (video_set_format (uvc_host , & fmt )) {
209263 LOG_ERR ("Unable to set format" );
210264 return 0 ;
211265 }
212266
213- if (!video_get_frmival (video_dev , & frmival )) {
267+ if (!video_get_frmival (uvc_host , & frmival )) {
214268 LOG_INF ("- Default frame rate : %f fps" ,
215269 1.0 * frmival .denominator / frmival .numerator );
216270 }
217271
218272 LOG_INF ("- Supported frame intervals for the default format:" );
219273 memset (& fie , 0 , sizeof (fie ));
220274 fie .format = & fmt ;
221- while (video_enum_frmival (video_dev , & fie ) == 0 ) {
275+ while (video_enum_frmival (uvc_host , & fie ) == 0 ) {
222276 if (fie .type == VIDEO_FRMIVAL_TYPE_DISCRETE ) {
223277 LOG_INF (" %u/%u" , fie .discrete .numerator , fie .discrete .denominator );
224278 } else {
@@ -233,7 +287,7 @@ int main(void)
233287 /* Get supported controls */
234288 LOG_INF ("- Supported controls:" );
235289 const struct device * last_dev = NULL ;
236- struct video_ctrl_query cq = {.dev = video_dev , .id = VIDEO_CTRL_FLAG_NEXT_CTRL };
290+ struct video_ctrl_query cq = {.dev = uvc_host , .id = VIDEO_CTRL_FLAG_NEXT_CTRL };
237291
238292 while (!video_query_ctrl (& cq )) {
239293 if (cq .dev != last_dev ) {
@@ -249,17 +303,17 @@ int main(void)
249303 int tp_set_ret = - ENOTSUP ;
250304
251305 if (IS_ENABLED (CONFIG_VIDEO_CTRL_HFLIP )) {
252- video_set_ctrl (video_dev , & ctrl );
306+ video_set_ctrl (uvc_host , & ctrl );
253307 }
254308
255309 if (IS_ENABLED (CONFIG_VIDEO_CTRL_VFLIP )) {
256310 ctrl .id = VIDEO_CID_VFLIP ;
257- video_set_ctrl (video_dev , & ctrl );
311+ video_set_ctrl (uvc_host , & ctrl );
258312 }
259313
260314 if (IS_ENABLED (CONFIG_TEST )) {
261315 ctrl .id = VIDEO_CID_TEST_PATTERN ;
262- tp_set_ret = video_set_ctrl (video_dev , & ctrl );
316+ video_set_ctrl (uvc_host , & ctrl );
263317 }
264318
265319#if DT_HAS_CHOSEN (zephyr_display )
@@ -273,8 +327,10 @@ int main(void)
273327 err = display_setup (display_dev , fmt .pixelformat );
274328 if (err ) {
275329 LOG_ERR ("Unable to set up display" );
330+ /* TODO: Use the format that this display supported, then need to do format covertion when streaming */
276331 return err ;
277332 }
333+
278334#endif
279335
280336 /* Size to allocate for each buffer */
@@ -284,6 +340,12 @@ int main(void)
284340 bsize = fmt .pitch * caps .min_line_count ;
285341 }
286342
343+ /* Start video capture */
344+ if (video_stream_start (uvc_host , type )) {
345+ LOG_ERR ("Unable to start capture (interface)" );
346+ return 0 ;
347+ }
348+
287349 /* Alloc video buffers and enqueue for capture */
288350 for (i = 0 ; i < ARRAY_SIZE (buffers ); i ++ ) {
289351 /*
@@ -297,21 +359,20 @@ int main(void)
297359 return 0 ;
298360 }
299361 buffers [i ]-> type = type ;
300- video_enqueue (video_dev , buffers [i ]);
301- }
302-
303- /* Start video capture */
304- if (video_stream_start (video_dev , type )) {
305- LOG_ERR ("Unable to start capture (interface)" );
306- return 0 ;
362+ video_enqueue (uvc_host , buffers [i ]);
307363 }
308364
309365 LOG_INF ("Capture started" );
310366
311367 /* Grab video frames */
312368 vbuf -> type = type ;
313369 while (1 ) {
314- err = video_dequeue (video_dev , & vbuf , K_FOREVER );
370+ err = k_poll (evt , ARRAY_SIZE (evt ), timeout );
371+ if (err != 0 && err != - EAGAIN ) {
372+ LOG_ERR ("Poll exited with status %d" , err );
373+ return err ;
374+ }
375+ err = video_dequeue (uvc_host , & vbuf , K_FOREVER );
315376 if (err ) {
316377 LOG_ERR ("Unable to dequeue video buf" );
317378 return 0 ;
@@ -329,13 +390,15 @@ int main(void)
329390#endif
330391
331392#if DT_HAS_CHOSEN (zephyr_display )
393+ vbuf -> type = VIDEO_BUF_TYPE_INPUT ;
332394 video_display_frame (display_dev , vbuf , fmt );
333395#endif
334-
335- err = video_enqueue (video_dev , vbuf );
396+ err = video_enqueue (uvc_host , vbuf );
336397 if (err ) {
337398 LOG_ERR ("Unable to requeue video buf" );
338399 return 0 ;
339400 }
401+
402+ video_uvc_device_signal_handler ();
340403 }
341404}
0 commit comments