2121
2222#include "libhoth_device.h"
2323
24+ static libhoth_error libhoth_error_from_legacy (uint16_t context , int status ) {
25+ if (status == 0 ) {
26+ return HOTH_SUCCESS ;
27+ }
28+ if (status < 0 ) {
29+ return LIBHOTH_ERR_CONSTRUCT (context , HOTH_HOST_SPACE_POSIX , - status );
30+ }
31+ return LIBHOTH_ERR_CONSTRUCT (context , HOTH_HOST_SPACE_LIBHOTH , (uint32_t )status );
32+ }
33+
34+ static int libhoth_error_to_legacy (libhoth_error err ) {
35+ if (err == HOTH_SUCCESS ) {
36+ return 0 ;
37+ }
38+ uint32_t space = LIBHOTH_ERR_GET_SPACE (err );
39+ uint32_t code = LIBHOTH_ERR_GET_CODE (err );
40+
41+ if (space == HOTH_HOST_SPACE_LIBHOTH ) {
42+ return (int )code ;
43+ }
44+ if (space == HOTH_HOST_SPACE_POSIX || space == HOTH_HOST_SPACE_LIBUSB ) {
45+ return - (int )code ;
46+ }
47+ return LIBHOTH_ERR_FAIL ;
48+ }
49+
2450int libhoth_send_request (struct libhoth_device * dev , const void * request ,
2551 size_t request_size ) {
2652 if (dev == NULL ) {
2753 return LIBHOTH_ERR_INVALID_PARAMETER ;
2854 }
29- return dev -> send (dev , request , request_size );
55+ if (dev -> send != NULL ) {
56+ return dev -> send (dev , request , request_size );
57+ }
58+ if (dev -> send_v2 != NULL ) {
59+ libhoth_error err = dev -> send_v2 (dev , request , request_size );
60+ return libhoth_error_to_legacy (err );
61+ }
62+ return LIBHOTH_ERR_FAIL ;
3063}
3164
3265int libhoth_receive_response (struct libhoth_device * dev , void * response ,
@@ -35,36 +68,150 @@ int libhoth_receive_response(struct libhoth_device* dev, void* response,
3568 if (dev == NULL ) {
3669 return LIBHOTH_ERR_INVALID_PARAMETER ;
3770 }
38- return dev -> receive (dev , response , max_response_size , actual_size ,
39- timeout_ms );
71+ if (dev -> receive != NULL ) {
72+ return dev -> receive (dev , response , max_response_size , actual_size ,
73+ timeout_ms );
74+ }
75+ if (dev -> receive_v2 != NULL ) {
76+ libhoth_error err = dev -> receive_v2 (dev , response , max_response_size ,
77+ actual_size , timeout_ms );
78+ return libhoth_error_to_legacy (err );
79+ }
80+ return LIBHOTH_ERR_FAIL ;
4081}
4182
42- int libhoth_device_reconnect (struct libhoth_device * dev ) {
83+ libhoth_error libhoth_send_request_v2 (struct libhoth_device * dev ,
84+ const void * request ,
85+ size_t request_size ) {
4386 if (dev == NULL ) {
44- return LIBHOTH_ERR_INVALID_PARAMETER ;
87+ return LIBHOTH_ERR_CONSTRUCT (HOTH_CTX_INIT , HOTH_HOST_SPACE_LIBHOTH ,
88+ LIBHOTH_ERR_INVALID_PARAMETER );
89+ }
90+ if (dev -> send_v2 != NULL ) {
91+ return dev -> send_v2 (dev , request , request_size );
92+ }
93+ if (dev -> send != NULL ) {
94+ int status = dev -> send (dev , request , request_size );
95+ return libhoth_error_from_legacy (HOTH_CTX_NONE , status );
4596 }
97+ return LIBHOTH_ERR_CONSTRUCT (HOTH_CTX_INIT , HOTH_HOST_SPACE_LIBHOTH ,
98+ LIBHOTH_ERR_FAIL );
99+ }
46100
47- if (dev -> reconnect == NULL ) {
48- return LIBHOTH_ERR_UNSUPPORTED_VERSION ;
101+ libhoth_error libhoth_receive_response_v2 (struct libhoth_device * dev ,
102+ void * response ,
103+ size_t max_response_size ,
104+ size_t * actual_size ,
105+ int timeout_ms ) {
106+ if (dev == NULL ) {
107+ return LIBHOTH_ERR_CONSTRUCT (HOTH_CTX_INIT , HOTH_HOST_SPACE_LIBHOTH ,
108+ LIBHOTH_ERR_INVALID_PARAMETER );
49109 }
110+ if (dev -> receive_v2 != NULL ) {
111+ return dev -> receive_v2 (dev , response , max_response_size , actual_size ,
112+ timeout_ms );
113+ }
114+ if (dev -> receive != NULL ) {
115+ int status = dev -> receive (dev , response , max_response_size , actual_size ,
116+ timeout_ms );
117+ return libhoth_error_from_legacy (HOTH_CTX_NONE , status );
118+ }
119+ return LIBHOTH_ERR_CONSTRUCT (HOTH_CTX_INIT , HOTH_HOST_SPACE_LIBHOTH ,
120+ LIBHOTH_ERR_FAIL );
121+ }
50122
51- return dev -> reconnect (dev );
123+ int libhoth_device_reconnect (struct libhoth_device * dev ) {
124+ if (dev == NULL ) {
125+ return LIBHOTH_ERR_INVALID_PARAMETER ;
126+ }
127+ if (dev -> reconnect != NULL ) {
128+ return dev -> reconnect (dev );
129+ }
130+ if (dev -> reconnect_v2 != NULL ) {
131+ libhoth_error err = dev -> reconnect_v2 (dev );
132+ return libhoth_error_to_legacy (err );
133+ }
134+ return LIBHOTH_ERR_UNSUPPORTED_VERSION ;
52135}
53136
54137int libhoth_device_close (struct libhoth_device * dev ) {
55138 if (dev == NULL ) {
56139 return LIBHOTH_ERR_INVALID_PARAMETER ;
57140 }
58-
59- int status = dev -> close (dev );
141+ int status = 0 ;
142+ if (dev -> close != NULL ) {
143+ status = dev -> close (dev );
144+ } else if (dev -> close_v2 != NULL ) {
145+ libhoth_error err = dev -> close_v2 (dev );
146+ status = libhoth_error_to_legacy (err );
147+ } else {
148+ status = LIBHOTH_ERR_FAIL ;
149+ }
60150 free (dev );
61151 return status ;
62152}
63153
154+ libhoth_error libhoth_device_reconnect_v2 (struct libhoth_device * dev ) {
155+ if (dev == NULL ) {
156+ return LIBHOTH_ERR_CONSTRUCT (HOTH_CTX_INIT , HOTH_HOST_SPACE_LIBHOTH ,
157+ LIBHOTH_ERR_INVALID_PARAMETER );
158+ }
159+ if (dev -> reconnect_v2 != NULL ) {
160+ return dev -> reconnect_v2 (dev );
161+ }
162+ if (dev -> reconnect != NULL ) {
163+ int status = dev -> reconnect (dev );
164+ return libhoth_error_from_legacy (HOTH_CTX_NONE , status );
165+ }
166+ return LIBHOTH_ERR_CONSTRUCT (HOTH_CTX_INIT , HOTH_HOST_SPACE_LIBHOTH ,
167+ LIBHOTH_ERR_UNSUPPORTED_VERSION );
168+ }
169+
170+ libhoth_error libhoth_device_close_v2 (struct libhoth_device * dev ) {
171+ if (dev == NULL ) {
172+ return LIBHOTH_ERR_CONSTRUCT (HOTH_CTX_INIT , HOTH_HOST_SPACE_LIBHOTH ,
173+ LIBHOTH_ERR_INVALID_PARAMETER );
174+ }
175+ libhoth_error err = HOTH_SUCCESS ;
176+ if (dev -> close_v2 != NULL ) {
177+ err = dev -> close_v2 (dev );
178+ } else if (dev -> close != NULL ) {
179+ int status = dev -> close (dev );
180+ err = libhoth_error_from_legacy (HOTH_CTX_NONE , status );
181+ }
182+ free (dev );
183+ return err ;
184+ }
185+
64186int libhoth_claim_device (struct libhoth_device * dev , uint32_t timeout_us ) {
187+ if (dev == NULL ) {
188+ return LIBHOTH_ERR_INVALID_PARAMETER ;
189+ }
190+ libhoth_error err = libhoth_claim_device_v2 (dev , timeout_us );
191+ return libhoth_error_to_legacy (err );
192+ }
193+
194+ int libhoth_release_device (struct libhoth_device * dev ) {
195+ if (dev == NULL ) {
196+ return LIBHOTH_ERR_INVALID_PARAMETER ;
197+ }
198+ if (dev -> release != NULL ) {
199+ return dev -> release (dev );
200+ }
201+ if (dev -> release_v2 != NULL ) {
202+ libhoth_error err = dev -> release_v2 (dev );
203+ return libhoth_error_to_legacy (err );
204+ }
205+ return LIBHOTH_ERR_FAIL ;
206+ }
207+
208+ libhoth_error libhoth_claim_device_v2 (struct libhoth_device * dev , uint32_t timeout_us ) {
209+ if (dev == NULL ) {
210+ return LIBHOTH_ERR_CONSTRUCT (HOTH_CTX_INIT , HOTH_HOST_SPACE_LIBHOTH ,
211+ LIBHOTH_ERR_INVALID_PARAMETER );
212+ }
213+
65214 enum {
66- // The maximum time to sleep per attempt.
67- // Limited by `usleep()` to <1 second.
68215 MAX_SINGLE_SLEEP_US = 1000 * 1000 - 1 ,
69216 BACKOFF_FACTOR = 2 ,
70217 INITIAL_WAIT_US = 10 * 1000 ,
@@ -74,43 +221,61 @@ int libhoth_claim_device(struct libhoth_device* dev, uint32_t timeout_us) {
74221 uint32_t total_waiting_us = 0 ;
75222
76223 while (true) {
77- int status = dev -> claim (dev );
224+ libhoth_error err = HOTH_SUCCESS ;
225+ if (dev -> claim_v2 != NULL ) {
226+ err = dev -> claim_v2 (dev );
227+ } else if (dev -> claim != NULL ) {
228+ int status = dev -> claim (dev );
229+ err = libhoth_error_from_legacy (HOTH_CTX_NONE , status );
230+ } else {
231+ err = LIBHOTH_ERR_CONSTRUCT (HOTH_CTX_INIT , HOTH_HOST_SPACE_LIBHOTH ,
232+ LIBHOTH_ERR_FAIL );
233+ }
78234
79- if ( status != LIBHOTH_ERR_INTERFACE_BUSY ) {
80- // We either claimed the device or encountered an unexpected error. Let
81- // the caller know.
82- return status ;
235+ uint32_t space = LIBHOTH_ERR_GET_SPACE ( err );
236+ uint32_t code = LIBHOTH_ERR_GET_CODE ( err );
237+ if ( err == HOTH_SUCCESS || space != HOTH_HOST_SPACE_LIBHOTH || code != LIBHOTH_ERR_INTERFACE_BUSY ) {
238+ return err ;
83239 }
84240
85241 if (total_waiting_us >= timeout_us ) {
86- // We've exhausted our waiting budget. We couldn't claim the device
87- // within the configured timeout.
88242 fprintf (stderr , "libhoth: timed out claiming transport after %dus\n" ,
89243 timeout_us );
90- return LIBHOTH_ERR_INTERFACE_BUSY ;
244+ return LIBHOTH_ERR_CONSTRUCT (HOTH_CTX_INIT , HOTH_HOST_SPACE_LIBHOTH ,
245+ LIBHOTH_ERR_INTERFACE_BUSY );
91246 }
92247
93248 usleep (wait_us );
94249
95250 if (total_waiting_us <= UINT32_MAX - wait_us ) {
96251 total_waiting_us += wait_us ;
97252 } else {
98- // Saturate at integer upper bound to prevent overflow.
99253 total_waiting_us = UINT32_MAX ;
100254 }
101255
102256 if (wait_us <= MAX_SINGLE_SLEEP_US / BACKOFF_FACTOR ) {
103257 wait_us *= BACKOFF_FACTOR ;
104258 } else {
105- // Saturate at the `usleep()` max sleep bound.
106259 wait_us = MAX_SINGLE_SLEEP_US ;
107260 }
108261 }
109262
110- // Unreachable
111- return LIBHOTH_ERR_FAIL ;
263+ return LIBHOTH_ERR_CONSTRUCT ( HOTH_CTX_INIT , HOTH_HOST_SPACE_LIBHOTH ,
264+ LIBHOTH_ERR_FAIL ) ;
112265}
113266
114- int libhoth_release_device (struct libhoth_device * dev ) {
115- return dev -> release (dev );
267+ libhoth_error libhoth_release_device_v2 (struct libhoth_device * dev ) {
268+ if (dev == NULL ) {
269+ return LIBHOTH_ERR_CONSTRUCT (HOTH_CTX_INIT , HOTH_HOST_SPACE_LIBHOTH ,
270+ LIBHOTH_ERR_INVALID_PARAMETER );
271+ }
272+ if (dev -> release_v2 != NULL ) {
273+ return dev -> release_v2 (dev );
274+ }
275+ if (dev -> release != NULL ) {
276+ int status = dev -> release (dev );
277+ return libhoth_error_from_legacy (HOTH_CTX_NONE , status );
278+ }
279+ return LIBHOTH_ERR_CONSTRUCT (HOTH_CTX_INIT , HOTH_HOST_SPACE_LIBHOTH ,
280+ LIBHOTH_ERR_FAIL );
116281}
0 commit comments