1+ /*
2+ * Copyright (c) 2026, sakumisu
3+ *
4+ * SPDX-License-Identifier: Apache-2.0
5+ */
6+
7+ #include "usbd_core.h"
8+ #include "usbd_display.h"
9+ #include "chry_mempool.h"
10+
11+ struct usbd_disp_frame_header {
12+ uint16_t crc16 ; //payload crc16
13+ uint8_t type ; //raw rgb,yuv,jpg,other
14+ uint8_t cmd ;
15+ uint16_t x ; //32bit
16+ uint16_t y ;
17+ uint16_t width ; //32bit
18+ uint16_t height ;
19+ uint32_t frame_id : 10 ;
20+ uint32_t payload_total : 22 ; //payload max 4MB
21+ } __PACKED ;
22+
23+ struct usbd_display_priv {
24+ struct chry_mempool pool ;
25+ struct usbd_endpoint out_ep ;
26+ struct usbd_endpoint in_ep ;
27+ struct usbd_display_frame * current_frame ;
28+ } g_usbd_display ;
29+
30+ int usbd_display_frame_create (struct usbd_display_frame * frame , uint32_t count )
31+ {
32+ return chry_mempool_create (& g_usbd_display .pool , frame , sizeof (struct usbd_display_frame ), count );
33+ }
34+
35+ struct usbd_display_frame * usbd_display_frame_alloc (void )
36+ {
37+ return (struct usbd_display_frame * )chry_mempool_alloc (& g_usbd_display .pool );
38+ }
39+
40+ int usbd_display_frame_free (struct usbd_display_frame * frame )
41+ {
42+ return chry_mempool_free (& g_usbd_display .pool , (uintptr_t * )frame );
43+ }
44+
45+ int usbd_display_frame_send (struct usbd_display_frame * frame )
46+ {
47+ return chry_mempool_send (& g_usbd_display .pool , (uintptr_t * )frame );
48+ }
49+
50+ int usbd_display_frame_recv (struct usbd_display_frame * * frame , uint32_t timeout )
51+ {
52+ return chry_mempool_recv (& g_usbd_display .pool , (uintptr_t * * )frame , timeout );
53+ }
54+
55+ uint8_t usb_dispay_dummy [512 ];
56+ volatile uint32_t usb_display_buf_offset ;
57+ volatile bool usb_display_ignore_frame ;
58+
59+ static void display_notify_handler (uint8_t busid , uint8_t event , void * arg )
60+ {
61+ switch (event ) {
62+ case USBD_EVENT_RESET :
63+ break ;
64+ case USBD_EVENT_CONFIGURED :
65+ usb_display_buf_offset = 0 ;
66+ usb_display_ignore_frame = true;
67+ g_usbd_display .current_frame = NULL ;
68+ usbd_ep_start_read (busid , g_usbd_display .out_ep .ep_addr , usb_dispay_dummy , usbd_get_ep_mps (0 , g_usbd_display .out_ep .ep_addr ));
69+ break ;
70+ default :
71+ break ;
72+ }
73+ }
74+
75+ void usbd_display_bulk_out (uint8_t busid , uint8_t ep , uint32_t nbytes )
76+ {
77+ if (usb_display_ignore_frame ) {
78+ // alloc frame for next at the end of current frame
79+ if ((nbytes % usbd_get_ep_mps (0 , g_usbd_display .out_ep .ep_addr )) || (nbytes == 0 )) {
80+ if (g_usbd_display .current_frame == NULL ) {
81+ g_usbd_display .current_frame = usbd_display_frame_alloc ();
82+ if (g_usbd_display .current_frame ) {
83+ usb_display_ignore_frame = false;
84+ usb_display_buf_offset = 0 ;
85+
86+ goto get_frame ;
87+ } else {
88+ goto drop_frame ;
89+ }
90+ } else {
91+ usb_display_ignore_frame = false;
92+ usb_display_buf_offset = 0 ;
93+
94+ goto get_frame ;
95+ }
96+ } else {
97+ goto drop_frame ;
98+ }
99+ } else {
100+ struct usbd_disp_frame_header * header = (struct usbd_disp_frame_header * )& g_usbd_display .current_frame -> frame_buf [0 ];
101+ struct usbd_display_frame * frame ;
102+
103+ if (header -> payload_total > g_usbd_display .current_frame -> frame_bufsize ) {
104+ USB_LOG_ERR ("frame overflow, drop it\r\n" );
105+ usb_display_ignore_frame = true;
106+
107+ goto drop_frame ;
108+ }
109+
110+ usb_display_buf_offset += nbytes ;
111+
112+ if ((nbytes % usbd_get_ep_mps (0 , g_usbd_display .out_ep .ep_addr )) || (nbytes == 0 )) {
113+ frame = g_usbd_display .current_frame ;
114+ g_usbd_display .current_frame = NULL ;
115+
116+ frame -> frame_format = header -> type ;
117+ frame -> frame_size = header -> payload_total ;
118+ usbd_display_frame_send (frame );
119+
120+ g_usbd_display .current_frame = usbd_display_frame_alloc ();
121+ if (g_usbd_display .current_frame ) {
122+ usb_display_ignore_frame = false;
123+ usb_display_buf_offset = 0 ;
124+
125+ goto get_frame ;
126+ } else {
127+ usb_display_ignore_frame = true;
128+
129+ goto drop_frame ;
130+ }
131+ } else {
132+ goto get_frame ;
133+ }
134+ }
135+ return ;
136+
137+ drop_frame :
138+ // drop current frame
139+ usbd_ep_start_read (busid , g_usbd_display .out_ep .ep_addr , usb_dispay_dummy , usbd_get_ep_mps (0 , g_usbd_display .out_ep .ep_addr ));
140+ return ;
141+ get_frame :
142+ usbd_ep_start_read (busid , g_usbd_display .out_ep .ep_addr , & g_usbd_display .current_frame -> frame_buf [usb_display_buf_offset ], 16384 );
143+ return ;
144+ }
145+
146+ void usbd_display_bulk_in (uint8_t busid , uint8_t ep , uint32_t nbytes )
147+ {
148+ }
149+
150+ struct usbd_interface * usbd_display_init_intf (struct usbd_interface * intf ,
151+ const uint8_t out_ep ,
152+ const uint8_t in_ep ,
153+ struct usbd_display_frame * frame ,
154+ uint32_t count )
155+ {
156+ intf -> class_interface_handler = NULL ;
157+ intf -> class_endpoint_handler = NULL ;
158+ intf -> vendor_handler = NULL ;
159+ intf -> notify_handler = display_notify_handler ;
160+
161+ g_usbd_display .out_ep .ep_addr = out_ep ;
162+ g_usbd_display .out_ep .ep_cb = usbd_display_bulk_out ;
163+ g_usbd_display .in_ep .ep_addr = in_ep ;
164+ g_usbd_display .in_ep .ep_cb = usbd_display_bulk_in ;
165+ usbd_add_endpoint (0 , & g_usbd_display .out_ep );
166+ usbd_add_endpoint (0 , & g_usbd_display .in_ep );
167+
168+ for (uint32_t i = 0 ; i < count ; i ++ ) {
169+ USB_ASSERT_MSG (frame [i ].frame_bufsize % 16384 , "frame_bufsize must be the multiple of 16384" );
170+ }
171+
172+ usbd_display_frame_create (frame , count );
173+ return intf ;
174+ }
175+
176+ int usbd_display_dequeue (struct usbd_display_frame * * frame , uint32_t timeout )
177+ {
178+ return usbd_display_frame_recv (frame , timeout );
179+ }
180+
181+ int usbd_display_enqueue (struct usbd_display_frame * frame )
182+ {
183+ return usbd_display_frame_free (frame );
184+ }
0 commit comments