55 * SPDX-License-Identifier: Apache-2.0
66 */
77
8+ #include <zephyr/init.h>
89#include <zephyr/kernel.h>
10+ #include <stdio.h>
11+ #include <errno.h>
912#include <zephyr/device.h>
1013
1114#include <zephyr/drivers/display.h>
1215#include <zephyr/drivers/video.h>
1316#include <zephyr/drivers/video-controls.h>
14-
17+ #include <zephyr/usb/usbh.h>
1518#include <zephyr/logging/log.h>
1619
1720#ifdef CONFIG_TEST
@@ -22,9 +25,8 @@ LOG_MODULE_REGISTER(main, LOG_LEVEL_DBG);
2225LOG_MODULE_REGISTER (main , CONFIG_LOG_DEFAULT_LEVEL );
2326#endif
2427
25- #if !DT_HAS_CHOSEN (zephyr_camera )
26- #error No camera chosen in devicetree. Missing "--shield" or "--snippet video-sw-generator" flag?
27- #endif
28+ USBH_CONTROLLER_DEFINE (uhs_ctx , DEVICE_DT_GET (DT_NODELABEL (zephyr_uhc0 )));
29+ const struct device * const uvc_host = DEVICE_DT_GET (DT_NODELABEL (uvc_host ));
2830
2931#if DT_HAS_CHOSEN (zephyr_display )
3032static inline int display_setup (const struct device * const display_dev , const uint32_t pixfmt )
@@ -75,8 +77,8 @@ static inline int display_setup(const struct device *const display_dev, const ui
7577}
7678
7779static inline void video_display_frame (const struct device * const display_dev ,
78- const struct video_buffer * const vbuf ,
79- const struct video_format fmt )
80+ const struct video_buffer * const vbuf ,
81+ const struct video_format fmt )
8082{
8183 struct display_buffer_descriptor buf_desc = {
8284 .buf_size = vbuf -> bytesused ,
@@ -89,15 +91,22 @@ static inline void video_display_frame(const struct device *const display_dev,
8991}
9092#endif
9193
94+ /* TODO: handle disconnection,etc.. */
95+ static void video_uvc_device_signal_handler (void )
96+ {
97+ }
98+
9299int main (void )
93100{
94101 struct video_buffer * buffers [CONFIG_VIDEO_BUFFER_POOL_NUM_MAX ];
95102 struct video_buffer * vbuf = & (struct video_buffer ){};
96- const struct device * video_dev ;
97103 struct video_format fmt ;
98104 struct video_caps caps ;
99105 struct video_frmival frmival ;
100106 struct video_frmival_enum fie ;
107+ struct k_poll_signal sig ;
108+ struct k_poll_event evt [1 ];
109+ k_timeout_t timeout = K_FOREVER ;
101110 enum video_buf_type type = VIDEO_BUF_TYPE_OUTPUT ;
102111#if (CONFIG_VIDEO_SOURCE_CROP_WIDTH && CONFIG_VIDEO_SOURCE_CROP_HEIGHT ) || \
103112 CONFIG_VIDEO_FRAME_HEIGHT || CONFIG_VIDEO_FRAME_WIDTH
@@ -116,17 +125,58 @@ int main(void)
116125 return 0 ;
117126 }
118127
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 );
128+ if (!device_is_ready (uvc_host )) {
129+ LOG_ERR ("%s: USB host is not ready" , uvc_host -> name );
122130 return 0 ;
123131 }
132+ LOG_INF ("USB host: %s" , uvc_host -> name );
124133
125- LOG_INF ("Video device: %s" , video_dev -> name );
134+ err = usbh_init (& uhs_ctx );
135+ if (err ) {
136+ LOG_ERR ("Failed to initialize host support" );
137+ return err ;
138+ }
139+
140+ err = usbh_enable (& uhs_ctx );
141+ if (err ) {
142+ LOG_ERR ("Failed to enable USB host support" );
143+ return err ;
144+ }
145+
146+ k_poll_signal_init (& sig );
147+ k_poll_event_init (& evt [0 ], K_POLL_TYPE_SIGNAL , K_POLL_MODE_NOTIFY_ONLY , & sig );
148+
149+ err = video_set_signal (uvc_host , & sig );
150+ if (err != 0 ) {
151+ LOG_WRN ("Failed to setup the signal on %s output endpoint" , uvc_host -> name );
152+ timeout = K_MSEC (10 );
153+ }
154+
155+ /* Wait for UVC device connection event */
156+ while (true) {
157+ err = k_poll (evt , ARRAY_SIZE (evt ), timeout );
158+ if (err != 0 ) {
159+ LOG_WRN ("Poll failed with error %d, retrying..." , err );
160+ continue ;
161+ }
162+
163+ int signaled , result ;
164+ k_poll_signal_check (& sig , & signaled , & result );
165+
166+ if (signaled && result == USBH_DEVICE_CONNECTED ) {
167+ LOG_INF ("UVC device connected successfully!" );
168+ k_poll_signal_reset (& sig );
169+ break ;
170+ }
171+
172+ /* Received other signal, reset and continue waiting */
173+ k_poll_signal_reset (& sig );
174+ LOG_DBG ("Received signal %d, waiting for device connection..." , result );
175+ }
126176
127177 /* Get capabilities */
128178 caps .type = type ;
129- if (video_get_caps (video_dev , & caps )) {
179+ if (video_get_caps (uvc_host , & caps )) {
130180 LOG_ERR ("Unable to retrieve video capabilities" );
131181 return 0 ;
132182 }
@@ -144,7 +194,7 @@ int main(void)
144194
145195 /* Get default/native format */
146196 fmt .type = type ;
147- if (video_get_format (video_dev , & fmt )) {
197+ if (video_get_format (uvc_host , & fmt )) {
148198 LOG_ERR ("Unable to retrieve video format" );
149199 return 0 ;
150200 }
@@ -156,7 +206,7 @@ int main(void)
156206 sel .rect .top = CONFIG_VIDEO_SOURCE_CROP_TOP ;
157207 sel .rect .width = CONFIG_VIDEO_SOURCE_CROP_WIDTH ;
158208 sel .rect .height = CONFIG_VIDEO_SOURCE_CROP_HEIGHT ;
159- if (video_set_selection (video_dev , & sel )) {
209+ if (video_set_selection (uvc_host , & sel )) {
160210 LOG_ERR ("Unable to set selection crop" );
161211 return 0 ;
162212 }
@@ -178,7 +228,7 @@ int main(void)
178228 * and if compose is necessary
179229 */
180230 sel .target = VIDEO_SEL_TGT_CROP ;
181- err = video_get_selection (video_dev , & sel );
231+ err = video_get_selection (uvc_host , & sel );
182232 if (err < 0 && err != - ENOSYS ) {
183233 LOG_ERR ("Unable to get selection crop" );
184234 return 0 ;
@@ -190,7 +240,7 @@ int main(void)
190240 sel .rect .top = 0 ;
191241 sel .rect .width = fmt .width ;
192242 sel .rect .height = fmt .height ;
193- err = video_set_selection (video_dev , & sel );
243+ err = video_set_selection (uvc_host , & sel );
194244 if (err < 0 && err != - ENOSYS ) {
195245 LOG_ERR ("Unable to set selection compose" );
196246 return 0 ;
@@ -201,24 +251,31 @@ int main(void)
201251 if (strcmp (CONFIG_VIDEO_PIXEL_FORMAT , "" )) {
202252 fmt .pixelformat = VIDEO_FOURCC_FROM_STR (CONFIG_VIDEO_PIXEL_FORMAT );
203253 }
254+ #if CONFIG_VIDEO_FRAME_WIDTH > 0
255+ fmt .width = CONFIG_VIDEO_FRAME_WIDTH ;
256+ #endif
257+
258+ #if CONFIG_VIDEO_FRAME_HEIGHT > 0
259+ fmt .height = CONFIG_VIDEO_FRAME_HEIGHT ;
260+ #endif
204261
205262 LOG_INF ("- Video format: %s %ux%u" ,
206263 VIDEO_FOURCC_TO_STR (fmt .pixelformat ), fmt .width , fmt .height );
207264
208- if (video_set_format (video_dev , & fmt )) {
265+ if (video_set_format (uvc_host , & fmt )) {
209266 LOG_ERR ("Unable to set format" );
210267 return 0 ;
211268 }
212269
213- if (!video_get_frmival (video_dev , & frmival )) {
270+ if (!video_get_frmival (uvc_host , & frmival )) {
214271 LOG_INF ("- Default frame rate : %f fps" ,
215272 1.0 * frmival .denominator / frmival .numerator );
216273 }
217274
218275 LOG_INF ("- Supported frame intervals for the default format:" );
219276 memset (& fie , 0 , sizeof (fie ));
220277 fie .format = & fmt ;
221- while (video_enum_frmival (video_dev , & fie ) == 0 ) {
278+ while (video_enum_frmival (uvc_host , & fie ) == 0 ) {
222279 if (fie .type == VIDEO_FRMIVAL_TYPE_DISCRETE ) {
223280 LOG_INF (" %u/%u" , fie .discrete .numerator , fie .discrete .denominator );
224281 } else {
@@ -233,7 +290,7 @@ int main(void)
233290 /* Get supported controls */
234291 LOG_INF ("- Supported controls:" );
235292 const struct device * last_dev = NULL ;
236- struct video_ctrl_query cq = {.dev = video_dev , .id = VIDEO_CTRL_FLAG_NEXT_CTRL };
293+ struct video_ctrl_query cq = {.dev = uvc_host , .id = VIDEO_CTRL_FLAG_NEXT_CTRL };
237294
238295 while (!video_query_ctrl (& cq )) {
239296 if (cq .dev != last_dev ) {
@@ -249,17 +306,17 @@ int main(void)
249306 int tp_set_ret = - ENOTSUP ;
250307
251308 if (IS_ENABLED (CONFIG_VIDEO_CTRL_HFLIP )) {
252- video_set_ctrl (video_dev , & ctrl );
309+ video_set_ctrl (uvc_host , & ctrl );
253310 }
254311
255312 if (IS_ENABLED (CONFIG_VIDEO_CTRL_VFLIP )) {
256313 ctrl .id = VIDEO_CID_VFLIP ;
257- video_set_ctrl (video_dev , & ctrl );
314+ video_set_ctrl (uvc_host , & ctrl );
258315 }
259316
260317 if (IS_ENABLED (CONFIG_TEST )) {
261318 ctrl .id = VIDEO_CID_TEST_PATTERN ;
262- tp_set_ret = video_set_ctrl (video_dev , & ctrl );
319+ video_set_ctrl (uvc_host , & ctrl );
263320 }
264321
265322#if DT_HAS_CHOSEN (zephyr_display )
@@ -273,8 +330,10 @@ int main(void)
273330 err = display_setup (display_dev , fmt .pixelformat );
274331 if (err ) {
275332 LOG_ERR ("Unable to set up display" );
333+ /* TODO: Use the format that this display supported, then need to do format covertion when streaming */
276334 return err ;
277335 }
336+
278337#endif
279338
280339 /* Size to allocate for each buffer */
@@ -284,6 +343,12 @@ int main(void)
284343 bsize = fmt .pitch * caps .min_line_count ;
285344 }
286345
346+ /* Start video capture */
347+ if (video_stream_start (uvc_host , type )) {
348+ LOG_ERR ("Unable to start capture (interface)" );
349+ return 0 ;
350+ }
351+
287352 /* Alloc video buffers and enqueue for capture */
288353 for (i = 0 ; i < ARRAY_SIZE (buffers ); i ++ ) {
289354 /*
@@ -297,21 +362,20 @@ int main(void)
297362 return 0 ;
298363 }
299364 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 ;
365+ video_enqueue (uvc_host , buffers [i ]);
307366 }
308367
309368 LOG_INF ("Capture started" );
310369
311370 /* Grab video frames */
312371 vbuf -> type = type ;
313372 while (1 ) {
314- err = video_dequeue (video_dev , & vbuf , K_FOREVER );
373+ err = k_poll (evt , ARRAY_SIZE (evt ), timeout );
374+ if (err != 0 && err != - EAGAIN ) {
375+ LOG_ERR ("Poll exited with status %d" , err );
376+ return err ;
377+ }
378+ err = video_dequeue (uvc_host , & vbuf , K_FOREVER );
315379 if (err ) {
316380 LOG_ERR ("Unable to dequeue video buf" );
317381 return 0 ;
@@ -329,13 +393,15 @@ int main(void)
329393#endif
330394
331395#if DT_HAS_CHOSEN (zephyr_display )
396+ vbuf -> type = VIDEO_BUF_TYPE_INPUT ;
332397 video_display_frame (display_dev , vbuf , fmt );
333398#endif
334-
335- err = video_enqueue (video_dev , vbuf );
399+ err = video_enqueue (uvc_host , vbuf );
336400 if (err ) {
337401 LOG_ERR ("Unable to requeue video buf" );
338402 return 0 ;
339403 }
404+
405+ video_uvc_device_signal_handler ();
340406 }
341407}
0 commit comments