1 /***************************************************************************
2  * Copyright (c) 2024 Microsoft Corporation
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the MIT License which is available at
6  * https://opensource.org/licenses/MIT.
7  *
8  * SPDX-License-Identifier: MIT
9  **************************************************************************/
10 
11 
12 /**************************************************************************/
13 /**************************************************************************/
14 /**                                                                       */
15 /** USBX Component                                                        */
16 /**                                                                       */
17 /**   Pictbridge Application                                              */
18 /**                                                                       */
19 /**************************************************************************/
20 /**************************************************************************/
21 
22 
23 /* Include necessary system files.  */
24 
25 #define UX_SOURCE_CODE
26 
27 #include "ux_api.h"
28 #include "ux_pictbridge.h"
29 #include "ux_host_class_pima.h"
30 
31 
32 /**************************************************************************/
33 /*                                                                        */
34 /*  FUNCTION                                               RELEASE        */
35 /*                                                                        */
36 /*    _ux_pictbridge_dpshost_input_object_send            PORTABLE C      */
37 /*                                                           6.1.12       */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Chaoqiong Xiao, Microsoft Corporation                               */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    This function creates an input report for the dpshost               */
45 /*                                                                        */
46 /*  INPUT                                                                 */
47 /*                                                                        */
48 /*    pictbridge                             Pictbridge instance          */
49 /*    input_function                         input tag                    */
50 /*                                                                        */
51 /*  OUTPUT                                                                */
52 /*                                                                        */
53 /*    Completion Status                                                   */
54 /*                                                                        */
55 /*  CALLS                                                                 */
56 /*                                                                        */
57 /*                                                                        */
58 /*  CALLED BY                                                             */
59 /*                                                                        */
60 /*                                                                        */
61 /*                                                                        */
62 /*  RELEASE HISTORY                                                       */
63 /*                                                                        */
64 /*    DATE              NAME                      DESCRIPTION             */
65 /*                                                                        */
66 /*  05-19-2020     Chaoqiong Xiao           Initial Version 6.0           */
67 /*  09-30-2020     Chaoqiong Xiao           Modified comment(s),          */
68 /*                                            verified memset and memcpy  */
69 /*                                            cases, used UX prefix to    */
70 /*                                            refer to TX symbols instead */
71 /*                                            of using them directly,     */
72 /*                                            resulting in version 6.1    */
73 /*  07-29-2022     Chaoqiong Xiao           Modified comment(s),          */
74 /*                                            cleared compile warning,    */
75 /*                                            used macros for RTOS calls, */
76 /*                                            resulting in version 6.1.12 */
77 /*                                                                        */
78 /**************************************************************************/
_ux_pictbridge_dpshost_input_object_send(UX_PICTBRIDGE * pictbridge,ULONG input_function)79 UINT  _ux_pictbridge_dpshost_input_object_send(UX_PICTBRIDGE *pictbridge, ULONG input_function)
80 {
81 UINT                                status;
82 ULONG                               object_length;
83 UCHAR                               *pima_object_buffer;
84 UX_HOST_CLASS_PIMA                  *pima;
85 UX_HOST_CLASS_PIMA_SESSION          *pima_session;
86 UX_HOST_CLASS_PIMA_OBJECT           *pima_object;
87 ULONG                               requested_length;
88 ULONG                               object_handle;
89 ULONG                               actual_flags;
90 
91     /* Check the state machine.  */
92     if (pictbridge -> ux_pictbridge_host_client_state_machine != UX_PICTBRIDGE_STATE_MACHINE_IDLE)
93     {
94 
95         /* Set the state machine to Host Request pending.  */
96         pictbridge -> ux_pictbridge_host_client_state_machine |= UX_PICTBRIDGE_STATE_MACHINE_HOST_REQUEST_PENDING;
97 
98         /* Wait for the client event pending request to be completed.  */
99         status =  _ux_system_event_flags_get(&pictbridge -> ux_pictbridge_event_flags_group,
100                                         UX_PICTBRIDGE_EVENT_FLAG_STATE_MACHINE_READY,
101                                         UX_AND_CLEAR, &actual_flags, UX_PICTBRIDGE_EVENT_TIMEOUT);
102 
103         /* Reset the state machine to not Host Request pending.  */
104         pictbridge -> ux_pictbridge_host_client_state_machine &= (UINT)~UX_PICTBRIDGE_STATE_MACHINE_HOST_REQUEST_PENDING;
105 
106         /* Check status.  */
107         if (status != UX_SUCCESS)
108             return(UX_ERROR);
109 
110         /* Status good means flag match, no need to check variable again, mark it unused.  */
111         (void)actual_flags;
112     }
113 
114     /* Change state machine to host request pending.  */
115     pictbridge -> ux_pictbridge_host_client_state_machine |=  UX_PICTBRIDGE_STATE_MACHINE_HOST_REQUEST;
116 
117     /* Get the pima instance from the pictbridge container.  */
118     pima = (UX_HOST_CLASS_PIMA *) pictbridge -> ux_pictbridge_pima;
119 
120     /* And now the session since we use it.  */
121     pima_session =  (UX_HOST_CLASS_PIMA_SESSION *)pictbridge -> ux_pictbridge_session;
122 
123     /* Get the address of the object container.  */
124     pima_object =  (UX_HOST_CLASS_PIMA_OBJECT *) pictbridge -> ux_pictbridge_object_host;
125 
126     /* Get the object buffer address.  */
127     pima_object_buffer = pima_object -> ux_host_class_pima_object_buffer;
128 
129     /* Reset the object length.  */
130     object_length =  0;
131 
132     /* Clear the object memory buffer.  */
133     _ux_utility_memory_set(pima_object_buffer, 0, UX_PICTBRIDGE_MAX_PIMA_OBJECT_BUFFER); /* Use case of memset is verified. */
134 
135     /* Add the line <?xml version="1.0"?>  */
136     status = _ux_pictbridge_object_tag_line_add(pima_object_buffer, object_length, _ux_pictbridge_xml_tag_line_xmlversion,
137                                                 UX_PICTBRIDGE_TAG_FLAG_BEGIN | UX_PICTBRIDGE_TAG_FLAG_FORCE_LF,
138                                                 UX_NULL, 0, UX_NULL, &pima_object_buffer, &object_length);
139     if (status != UX_SUCCESS)
140         return(status);
141 
142     /* Add the line <dps xmlns="http://www.cipa.jp/dps/schema/">  */
143     status = _ux_pictbridge_object_tag_line_add(pima_object_buffer, object_length, _ux_pictbridge_xml_tag_line_dpsxmlns,
144                                                 UX_PICTBRIDGE_TAG_FLAG_BEGIN | UX_PICTBRIDGE_TAG_FLAG_FORCE_LF,
145                                                 UX_NULL, 0, UX_NULL, &pima_object_buffer, &object_length);
146 
147     /* Add the line <input>  */
148     if (status == UX_SUCCESS)
149     {
150         status = _ux_pictbridge_object_tag_line_add(pima_object_buffer, object_length, _ux_pictbridge_xml_tag_line_input,
151                                                     UX_PICTBRIDGE_TAG_FLAG_BEGIN | UX_PICTBRIDGE_TAG_FLAG_FORCE_LF,
152                                                     UX_NULL, 0, UX_NULL, &pima_object_buffer, &object_length);
153     }
154 
155     /* Look into the tag code from the input object and proceed to individual functions.  */
156     if (status == UX_SUCCESS)
157     {
158         switch (input_function)
159         {
160 
161             case UX_PICTBRIDGE_IR_NOTIFY_JOB_STATUS                    :
162 
163                 /* Insert the notifyJobStatus tag lines.  */
164                 status = _ux_pictbridge_dpshost_input_object_notify_job_status(pictbridge, pima_object_buffer, object_length, &pima_object_buffer, &object_length);
165                 break;
166 
167             case UX_PICTBRIDGE_IR_NOTIFY_DEVICE_STATUS                 :
168 
169                 /* Insert the notifyDeviceStatus tag lines.  */
170                 status = _ux_pictbridge_dpshost_input_object_notify_device_status(pictbridge, pima_object_buffer, object_length, &pima_object_buffer, &object_length);
171                 break;
172 
173             default                                                    :
174 
175                 /* Function not yet supported.  We should never come here anyway. */
176                 status = UX_ERROR;
177 
178         }
179     }
180 
181     /* Add the line </input>  */
182     if (status == UX_SUCCESS)
183     {
184         status = _ux_pictbridge_object_tag_line_add(pima_object_buffer, object_length, _ux_pictbridge_xml_tag_line_input,
185                                                     UX_PICTBRIDGE_TAG_FLAG_END,
186                                                     UX_NULL, 0, UX_NULL, &pima_object_buffer, &object_length);
187     }
188 
189     /* Add the line </dps>  */
190     if (status == UX_SUCCESS)
191     {
192         status = _ux_pictbridge_object_tag_line_add(pima_object_buffer, object_length, _ux_pictbridge_xml_tag_line_dps,
193                                                     UX_PICTBRIDGE_TAG_FLAG_END,
194                                                     UX_NULL, 0, UX_NULL, &pima_object_buffer, &object_length);
195     }
196 
197     /* Handle error.  */
198     if (status != UX_SUCCESS)
199     {
200 
201         /* Do we have a pending client event ?  */
202         if (pictbridge -> ux_pictbridge_host_client_state_machine & UX_PICTBRIDGE_STATE_MACHINE_CLIENT_REQUEST_PENDING)
203         {
204 
205             /* Yes, so we need to set the event that advertise the completion of the host request.  */
206             _ux_system_event_flags_set(&pictbridge -> ux_pictbridge_event_flags_group,
207                                     UX_PICTBRIDGE_EVENT_FLAG_STATE_MACHINE_READY,
208                                     UX_AND);
209 
210         }
211 
212         /* Change state machine to idle.  */
213         pictbridge -> ux_pictbridge_host_client_state_machine &=  (UINT)~UX_PICTBRIDGE_STATE_MACHINE_HOST_REQUEST;
214         return(UX_ERROR);
215     }
216 
217     /* Store the length of the new object waiting to be sent out.
218        We do not store the length into the object itself since this function is
219        host\client agnostic.  */
220     pima_object -> ux_host_class_pima_object_length =  object_length;
221 
222     /* Get the length of the object and store it into the object data set.  */
223     pima_object -> ux_host_class_pima_object_compressed_size = object_length;
224 
225     /* We need to change the file name to HREQUEST.DPS. Encode the file name from ascii format into Unicode.  */
226     _ux_utility_string_to_unicode(_ux_pictbridge_hrequest_name, pima_object -> ux_host_class_pima_object_filename);
227 
228     /* Set the object handle.  */
229     object_handle = 1;
230 
231     /* Send a script info.  */
232     status = _ux_host_class_pima_object_info_send(pima, pima_session, 0, 0, pima_object);
233     if (status != UX_SUCCESS)
234     {
235 
236         /* Do we have a pending client event ?  */
237         if (pictbridge -> ux_pictbridge_host_client_state_machine & UX_PICTBRIDGE_STATE_MACHINE_CLIENT_REQUEST_PENDING)
238         {
239 
240             /* Yes, so we need to set the event that advertise the completion of the host request.  */
241             _ux_system_event_flags_set(&pictbridge -> ux_pictbridge_event_flags_group,
242                                     UX_PICTBRIDGE_EVENT_FLAG_STATE_MACHINE_READY,
243                                     UX_AND);
244 
245         }
246 
247         /* Change state machine to idle.  */
248         pictbridge -> ux_pictbridge_host_client_state_machine &=  (UINT)~UX_PICTBRIDGE_STATE_MACHINE_HOST_REQUEST;
249 
250         /* Return status.  */
251         return(status);
252     }
253 
254 
255 
256 
257     /* Open the object.  */
258     status = _ux_host_class_pima_object_open(pima, pima_session,
259                                              object_handle,
260                                              pima_object);
261     if (status != UX_SUCCESS)
262     {
263 
264         /* Do we have a pending client event ?  */
265         if (pictbridge -> ux_pictbridge_host_client_state_machine & UX_PICTBRIDGE_STATE_MACHINE_CLIENT_REQUEST_PENDING)
266         {
267 
268             /* Yes, so we need to set the event that advertise the completion of the host request.  */
269             _ux_system_event_flags_set(&pictbridge -> ux_pictbridge_event_flags_group,
270                                     UX_PICTBRIDGE_EVENT_FLAG_STATE_MACHINE_READY,
271                                     UX_AND);
272 
273         }
274 
275         /* Change state machine to idle.  */
276         pictbridge -> ux_pictbridge_host_client_state_machine &=  (UINT)~UX_PICTBRIDGE_STATE_MACHINE_HOST_REQUEST;
277 
278         /* Return status.  */
279         return(status);
280     }
281 
282     /* Get the object length.  */
283     object_length =  pima_object -> ux_host_class_pima_object_compressed_size;
284 
285     /* Recall the object buffer address.  */
286     pima_object_buffer = pima_object -> ux_host_class_pima_object_buffer;
287 
288     /* Send all the object data.  */
289     while(object_length != 0)
290     {
291 
292         /* Calculate what length to request.  */
293         if (object_length > UX_PICTBRIDGE_MAX_PIMA_OBJECT_BUFFER)
294 
295             /* Request maximum length.  */
296             requested_length = UX_PICTBRIDGE_MAX_PIMA_OBJECT_BUFFER;
297 
298         else
299 
300             /* Request remaining length.  */
301             requested_length = object_length;
302 
303 
304         /* Send the object data.  */
305         status = _ux_host_class_pima_object_send(pima, pima_session, pima_object,
306                                                     pima_object_buffer, requested_length);
307         if (status != UX_SUCCESS)
308         {
309 
310             /* Abort the transfer.  */
311             _ux_host_class_pima_object_transfer_abort(pima, pima_session, object_handle, pima_object);
312 
313             /* Do we have a pending client event ?  */
314             if (pictbridge -> ux_pictbridge_host_client_state_machine & UX_PICTBRIDGE_STATE_MACHINE_CLIENT_REQUEST_PENDING)
315             {
316 
317                 /* Yes, so we need to set the event that advertise the completion of the host request.  */
318                 _ux_system_event_flags_set(&pictbridge -> ux_pictbridge_event_flags_group,
319                                         UX_PICTBRIDGE_EVENT_FLAG_STATE_MACHINE_READY,
320                                         UX_AND);
321 
322             }
323 
324             /* Change state machine to idle.  */
325             pictbridge -> ux_pictbridge_host_client_state_machine &=  (UINT)~UX_PICTBRIDGE_STATE_MACHINE_HOST_REQUEST;
326 
327             /* Return status.  */
328             return(status);
329 
330         }
331 
332         /* We have sent some data, update the length remaining.  */
333     object_length -= requested_length;
334     }
335 
336     /* Close the object.  */
337     status = _ux_host_class_pima_object_close(pima, pima_session, object_handle, pima_object);
338 
339     /* Check the status.  */
340     if (status != UX_SUCCESS)
341     {
342 
343         /* Do we have a pending client event ?  */
344         if (pictbridge -> ux_pictbridge_host_client_state_machine & UX_PICTBRIDGE_STATE_MACHINE_CLIENT_REQUEST_PENDING)
345         {
346 
347             /* Yes, so we need to set the event that advertise the completion of the host request.  */
348             _ux_system_event_flags_set(&pictbridge -> ux_pictbridge_event_flags_group,
349                                     UX_PICTBRIDGE_EVENT_FLAG_STATE_MACHINE_READY,
350                                     UX_AND);
351 
352         }
353 
354         /* Change state machine to idle.  */
355         pictbridge -> ux_pictbridge_host_client_state_machine &=  (UINT)~UX_PICTBRIDGE_STATE_MACHINE_HOST_REQUEST;
356 
357         /* Return status.  */
358         return(status);
359     }
360 
361 
362     /* Wait for the response from the device.  */
363     status = _ux_pictbridge_dpshost_response_get(pictbridge);
364 
365 
366     /* Do we have a pending client event ?  */
367     if (pictbridge -> ux_pictbridge_host_client_state_machine & UX_PICTBRIDGE_STATE_MACHINE_CLIENT_REQUEST_PENDING)
368     {
369 
370         /* Yes, so we need to set the event that advertise the completion of the host request.  */
371         _ux_system_event_flags_set(&pictbridge -> ux_pictbridge_event_flags_group,
372                                 UX_PICTBRIDGE_EVENT_FLAG_STATE_MACHINE_READY,
373                                 UX_AND);
374 
375     }
376 
377     /* Change state machine to idle.  */
378     pictbridge -> ux_pictbridge_host_client_state_machine &=  (UINT)~UX_PICTBRIDGE_STATE_MACHINE_HOST_REQUEST;
379 
380     /* Return status.  */
381     return(status);
382 
383 }
384 
385