Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1702 | - | 1 | /* Copyright (C) 2010-2011 Circuits At Home, LTD. All rights reserved. |
2 | |||
3 | This software may be distributed and modified under the terms of the GNU |
||
4 | General Public License version 2 (GPL2) as published by the Free Software |
||
5 | Foundation and appearing in the file GPL2.TXT included in the packaging of |
||
6 | this file. Please note that GPL2 Section 2[b] requires that all works based |
||
7 | on this software must also be made publicly available under the terms of |
||
8 | the GPL2 ("Copyleft"). |
||
9 | |||
10 | Contact information |
||
11 | ------------------- |
||
12 | |||
13 | Circuits At Home, LTD |
||
14 | Web : http://www.circuitsathome.com |
||
15 | e-mail : support@circuitsathome.com |
||
16 | */ |
||
17 | #include "ptpconst.h" |
||
18 | #include "ptp.h" |
||
19 | #include "ptpdebug.h" |
||
20 | |||
21 | void PTP::SetInitialState() |
||
22 | { |
||
23 | busyTime = 0; |
||
24 | hangTime = 0; |
||
25 | idSession = 0; |
||
26 | idTransaction = 0; |
||
27 | SetState(PTP_STATE_SESSION_NOT_OPENED); |
||
28 | } |
||
29 | |||
30 | void PTPStateHandlers::OnDeviceDisconnectedState(PTP *ptp) |
||
31 | { |
||
32 | } |
||
33 | |||
34 | void PTPStateHandlers::OnSessionNotOpenedState(PTP *ptp) |
||
35 | { |
||
36 | if (ptp->OpenSession() == PTP_RC_OK) |
||
37 | { |
||
38 | PTPTRACE("Session opened\r\n"); |
||
39 | ptp->SetState(PTP_STATE_SESSION_OPENED); |
||
40 | } |
||
41 | } |
||
42 | |||
43 | void PTPStateHandlers::OnSessionOpenedState(PTP *ptp) |
||
44 | { |
||
45 | ptp->SetState(PTP_STATE_DEVICE_INITIALIZED); |
||
46 | } |
||
47 | |||
48 | void PTPStateHandlers::OnDeviceInitializedState(PTP *ptp) |
||
49 | { |
||
50 | } |
||
51 | |||
52 | void PTPStateHandlers::OnDeviceNotRespondingState(PTP *ptp) |
||
53 | { |
||
54 | } |
||
55 | |||
56 | void PTPStateHandlers::OnDeviceBusyState(PTP *ptp) |
||
57 | { |
||
58 | } |
||
59 | |||
60 | void uint16_to_char(uint16_t integer, unsigned char *data) |
||
61 | { |
||
62 | data[0] = (integer & 0xff); |
||
63 | data[1] = ((integer >> 8) & 0xff); |
||
64 | } |
||
65 | |||
66 | void uint32_to_char(uint32_t integer, unsigned char *data) |
||
67 | { |
||
68 | data[0] = (integer & 0xff); |
||
69 | data[1] = ((integer >> 8) & 0xff); |
||
70 | data[2] = ((integer >> 16) & 0xff); |
||
71 | data[3] = ((integer >> 24) & 0xff); |
||
72 | } |
||
73 | |||
74 | void char_to_uint16(unsigned char *scan) |
||
75 | { |
||
76 | char c = scan[0]; |
||
77 | scan[0] = scan[1]; |
||
78 | scan[1] = c; |
||
79 | } |
||
80 | |||
81 | void char_to_uint32(unsigned char *scan) |
||
82 | { |
||
83 | char c = scan[0]; |
||
84 | scan[0] = scan[3]; |
||
85 | scan[3] = c; |
||
86 | c = scan[1]; |
||
87 | scan[1] = scan[2]; |
||
88 | scan[2] = c; |
||
89 | } |
||
90 | |||
91 | void UsbStringToASCII(uint8_t *str) |
||
92 | { |
||
93 | uint8_t i, j, len = (uint8_t)str[0]; |
||
94 | |||
95 | // length and descriptor type one byte each should be skipped |
||
96 | for (i=0, j=2; j<len; i++, j+=2) |
||
97 | str[i] = str[j]; |
||
98 | str[i] = 0; |
||
99 | } |
||
100 | |||
101 | void Notify(const char* msg) |
||
102 | { |
||
103 | if(!msg) return; |
||
104 | char c; |
||
105 | |||
106 | while((c = pgm_read_byte(msg++))) |
||
107 | Serial.print(c,BYTE); |
||
108 | } |
||
109 | |||
110 | void Message(const char* msg, uint16_t rcode = 0) |
||
111 | { |
||
112 | Notify(msg); |
||
113 | Notify(PSTR(": ")); |
||
114 | PrintHex<uint16_t>(rcode); |
||
115 | Notify(PSTR("\r\n")); |
||
116 | } |
||
117 | |||
118 | //void Message(const char* msg, uint16_t rcode = 0) |
||
119 | //{ |
||
120 | // Notify(msg); |
||
121 | // msg = PSTR(": 0x"); |
||
122 | // Notify(msg); |
||
123 | // |
||
124 | // uint16_t mask = 0x1000; |
||
125 | // |
||
126 | // while (mask > 1) |
||
127 | // { |
||
128 | // if (rcode < mask) |
||
129 | // Serial.print("0"); |
||
130 | // mask >>= 4; |
||
131 | // } |
||
132 | // Serial.println( rcode, HEX ); |
||
133 | //} |
||
134 | |||
135 | PTP::PTP(uint8_t addr, uint8_t epin, uint8_t epout, uint8_t epint, uint8_t nconf, PTPStateHandlers *s) : |
||
136 | theState(0), |
||
137 | busyTime(0), |
||
138 | hangTime(0), |
||
139 | idTransaction(0), |
||
140 | idSession(0), |
||
141 | devAddress(addr), |
||
142 | epDataIn(epin), |
||
143 | epDataOut(epout), |
||
144 | epInterrupt(epint), |
||
145 | numConf(nconf), |
||
146 | stateMachine(s) |
||
147 | { |
||
148 | }; |
||
149 | |||
150 | void PTP::Task2() |
||
151 | { |
||
152 | switch (theState) |
||
153 | { |
||
154 | //case PTP_STATE_DEVICE_DISCONNECTED: |
||
155 | // idSession = 0; |
||
156 | // idTransaction = 0; |
||
157 | // if (stateMachine) |
||
158 | // stateMachine->OnDeviceDisconnectedState(this); |
||
159 | // break; |
||
160 | case PTP_STATE_SESSION_NOT_OPENED: |
||
161 | if (stateMachine) |
||
162 | stateMachine->OnSessionNotOpenedState(this); |
||
163 | break; |
||
164 | case PTP_STATE_SESSION_OPENED: |
||
165 | if (stateMachine) |
||
166 | stateMachine->OnSessionOpenedState(this); |
||
167 | break; |
||
168 | case PTP_STATE_DEVICE_INITIALIZED: |
||
169 | if (stateMachine) |
||
170 | stateMachine->OnDeviceInitializedState(this); |
||
171 | break; |
||
172 | case PTP_STATE_DEVICE_NOT_RESPONDING: |
||
173 | if (stateMachine) |
||
174 | stateMachine->OnDeviceNotRespondingState(this); |
||
175 | break; |
||
176 | case PTP_STATE_DEVICE_BUSY: |
||
177 | if (stateMachine) |
||
178 | stateMachine->OnDeviceBusyState(this); |
||
179 | break; |
||
180 | // Error state |
||
181 | default: |
||
182 | ; |
||
183 | } |
||
184 | } |
||
185 | |||
186 | uint16_t PTP::Transaction(uint16_t opcode, OperFlags *flags, uint32_t *params = NULL, void *pVoid = NULL) |
||
187 | { |
||
188 | uint8_t rcode; |
||
189 | { |
||
190 | uint8_t cmd[PTP_USB_BULK_HDR_LEN + 12]; // header + 3 uint32_t parameters |
||
191 | |||
192 | ZerroMemory(PTP_USB_BULK_HDR_LEN + 12, cmd); |
||
193 | |||
194 | // Make command PTP container header |
||
195 | uint16_to_char(PTP_USB_CONTAINER_COMMAND, (unsigned char*)(cmd + PTP_CONTAINER_CONTYPE_OFF)); // type |
||
196 | uint16_to_char(opcode, (unsigned char*)(cmd + PTP_CONTAINER_OPCODE_OFF)); // code |
||
197 | uint32_to_char(idTransaction++, (unsigned char*)(cmd + PTP_CONTAINER_TRANSID_OFF)); // transaction id |
||
198 | |||
199 | uint8_t n = flags->opParams, len; |
||
200 | |||
201 | if (params && *params) |
||
202 | { |
||
203 | *((uint8_t*)cmd) = len = PTP_USB_BULK_HDR_LEN + (n << 2); |
||
204 | |||
205 | for (uint32_t *p1 = (uint32_t*)(cmd + PTP_CONTAINER_PAYLOAD_OFF), *p2 = (uint32_t*)params; n--; p1++, p2++) |
||
206 | uint32_to_char(*p2, (unsigned char*)p1); |
||
207 | } |
||
208 | else |
||
209 | *((uint8_t*)cmd) = len = PTP_USB_BULK_HDR_LEN; |
||
210 | |||
211 | rcode = Usb.outTransfer(devAddress, epDataOut, len, (char*)cmd); |
||
212 | |||
213 | if (rcode) |
||
214 | { |
||
215 | PTPTRACE2("Transaction: Command block send error", rcode); |
||
216 | return PTP_RC_GeneralError; |
||
217 | } |
||
218 | } |
||
219 | { |
||
220 | uint8_t data[PTP_MAX_RX_BUFFER_LEN]; |
||
221 | |||
222 | if (flags->txOperation) |
||
223 | { |
||
224 | if (flags->typeOfVoid && !pVoid) |
||
225 | { |
||
226 | PTPTRACE("Transaction: pVoid is NULL\n"); |
||
227 | return PTP_RC_GeneralError; |
||
228 | } |
||
229 | ZerroMemory(PTP_MAX_RX_BUFFER_LEN, data); |
||
230 | |||
231 | uint32_t bytes_left = (flags->typeOfVoid == 3) ? PTP_USB_BULK_HDR_LEN + flags->dataSize : |
||
232 | ((flags->typeOfVoid == 1) ? PTP_USB_BULK_HDR_LEN + ((PTPDataSupplier*)pVoid)->GetDataSize() : 12); |
||
233 | |||
234 | // Make data PTP container header |
||
235 | *((uint32_t*)data) = bytes_left; |
||
236 | uint16_to_char(PTP_USB_CONTAINER_DATA, (unsigned char*)(data + PTP_CONTAINER_CONTYPE_OFF)); // type |
||
237 | uint16_to_char(opcode, (unsigned char*)(data + PTP_CONTAINER_OPCODE_OFF)); // code |
||
238 | uint32_to_char(idTransaction, (unsigned char*)(data + PTP_CONTAINER_TRANSID_OFF)); // transaction id |
||
239 | |||
240 | uint16_t len; |
||
241 | |||
242 | if (flags->typeOfVoid == 1) |
||
243 | len = (bytes_left < PTP_MAX_RX_BUFFER_LEN) ? bytes_left : PTP_MAX_RX_BUFFER_LEN; |
||
244 | |||
245 | if (flags->typeOfVoid == 3) |
||
246 | { |
||
247 | uint8_t *p1 = (data + PTP_USB_BULK_HDR_LEN); |
||
248 | uint8_t *p2 = (uint8_t*)pVoid; |
||
249 | |||
250 | for (uint8_t i=flags->dataSize; i; i--, p1++, p2++) |
||
251 | *p1 = *p2; |
||
252 | |||
253 | len = PTP_USB_BULK_HDR_LEN + flags->dataSize; |
||
254 | } |
||
255 | bool first_time = true; |
||
256 | |||
257 | while (bytes_left) |
||
258 | { |
||
259 | if (flags->typeOfVoid == 1) |
||
260 | ((PTPDataSupplier*)pVoid)->GetData( (first_time) ? len - PTP_USB_BULK_HDR_LEN : len, |
||
261 | (first_time) ? (data + PTP_USB_BULK_HDR_LEN) : data); |
||
262 | |||
263 | rcode = Usb.outTransfer(devAddress, epDataOut, len, (char*)data); |
||
264 | |||
265 | if (rcode) |
||
266 | { |
||
267 | PTPTRACE2("Transaction: Data block send error.", rcode); |
||
268 | return PTP_RC_GeneralError; |
||
269 | } |
||
270 | |||
271 | bytes_left -= len; |
||
272 | |||
273 | len = (bytes_left < PTP_MAX_RX_BUFFER_LEN) ? bytes_left : PTP_MAX_RX_BUFFER_LEN; |
||
274 | |||
275 | first_time = false; |
||
276 | } |
||
277 | } |
||
278 | |||
279 | // Because inTransfer does not return the actual number of bytes recieved, it should be |
||
280 | // calculated here. |
||
281 | uint32_t total = 0, data_off = 0; // Total PTP data packet size, Data offset |
||
282 | uint8_t inbuffer = 0; // Number of bytes read into buffer |
||
283 | uint16_t loops = 0; // Number of loops necessary to get all the data from device |
||
284 | uint8_t timeoutcnt = 0; |
||
285 | |||
286 | while (1) |
||
287 | { |
||
288 | ZerroMemory(PTP_MAX_RX_BUFFER_LEN, data); |
||
289 | |||
290 | rcode = Usb.inTransfer(devAddress, epDataIn, PTP_MAX_RX_BUFFER_LEN, (char*)data); |
||
291 | |||
292 | if (rcode) |
||
293 | { |
||
294 | PTPTRACE("Fatal USB Error\r\n"); |
||
295 | |||
296 | // in some cases NAK handling might be necessary |
||
297 | PTPTRACE2("Transaction: Response recieve error", rcode); |
||
298 | return PTP_RC_GeneralError; |
||
299 | } |
||
300 | |||
301 | // This can occure in case of unsupported operation or successive response after data reception stage |
||
302 | if ((!loops || total == data_off) && *((uint16_t*)(data + PTP_CONTAINER_CONTYPE_OFF)) == PTP_USB_CONTAINER_RESPONSE) |
||
303 | { |
||
304 | uint16_t response = *((uint16_t*)(data + PTP_CONTAINER_OPCODE_OFF)); |
||
305 | |||
306 | if (response == PTP_RC_OK && *((uint32_t*)data) > PTP_USB_BULK_HDR_LEN) |
||
307 | { |
||
308 | // number of params = (container length - 12) / 4 |
||
309 | uint8_t n = (*((uint32_t*)data) - PTP_USB_BULK_HDR_LEN) >> 2; |
||
310 | |||
311 | // BUG: n should be checked!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! |
||
312 | flags->rsParams = n; |
||
313 | |||
314 | for (uint32_t *p1 = (uint32_t*)(data + PTP_USB_BULK_HDR_LEN), *p2 = (uint32_t*)params; n; n--, p1++, p2++) |
||
315 | p2 = p1; |
||
316 | } |
||
317 | if (response != PTP_RC_OK) |
||
318 | { |
||
319 | PTPTRACE2("Transaction: Response recieve error", response); |
||
320 | data_off = 0; |
||
321 | } |
||
322 | return response; |
||
323 | } |
||
324 | |||
325 | if (loops == 0) |
||
326 | { |
||
327 | total = *((uint32_t*)data); |
||
328 | inbuffer = (total < PTP_MAX_RX_BUFFER_LEN) ? (uint8_t)total : PTP_MAX_RX_BUFFER_LEN; |
||
329 | } |
||
330 | else |
||
331 | inbuffer = ((total - data_off) > PTP_MAX_RX_BUFFER_LEN) ? PTP_MAX_RX_BUFFER_LEN : (uint8_t)(total - data_off); |
||
332 | |||
333 | if (pVoid) |
||
334 | { |
||
335 | if (flags->typeOfVoid == 0x01) |
||
336 | ((PTPReadParser*)pVoid)->Parse(inbuffer, data, (const uint32_t&)data_off); |
||
337 | |||
338 | if (flags->typeOfVoid == 0x03) |
||
339 | for (uint32_t i=0, j=data_off; i<inbuffer && j<flags->dataSize; i++, j++) |
||
340 | ((uint8_t*)pVoid)[j] = data[i]; |
||
341 | } |
||
342 | data_off += inbuffer; |
||
343 | |||
344 | loops ++; |
||
345 | //delay(10); |
||
346 | } // while(1) |
||
347 | } // end of scope |
||
348 | } |
||
349 | |||
350 | |||
351 | uint16_t PTP::EventCheck(PTPReadParser *pParser) |
||
352 | { |
||
353 | uint8_t data[PTP_MAX_EV_BUFFER_LEN]; |
||
354 | uint8_t rcode; |
||
355 | |||
356 | // Because inTransfer does not return the actual number of bytes recieved, it should be |
||
357 | // calculated here. |
||
358 | uint32_t total = 0, data_off = 0; |
||
359 | uint8_t inbuffer = 0; |
||
360 | uint16_t loops = 0; |
||
361 | uint8_t timeoutcnt = 0; |
||
362 | |||
363 | while (1) |
||
364 | { |
||
365 | ZerroMemory(PTP_MAX_EV_BUFFER_LEN, data); |
||
366 | |||
367 | rcode = Usb.inTransfer(devAddress, epInterrupt, PTP_MAX_EV_BUFFER_LEN, (char*)data); |
||
368 | |||
369 | switch (rcode) |
||
370 | { |
||
371 | // In case of no event occured |
||
372 | case 0xFF: |
||
373 | return PTP_EC_Undefined; |
||
374 | |||
375 | default: |
||
376 | // in case of a usb error |
||
377 | PTPTRACE2("EventCheck USB error: ", rcode); |
||
378 | return PTP_RC_GeneralError; |
||
379 | } |
||
380 | |||
381 | if (loops == 0) |
||
382 | { |
||
383 | total = *((uint32_t*)data); |
||
384 | inbuffer = (total < PTP_MAX_EV_BUFFER_LEN) ? (uint8_t)total : PTP_MAX_EV_BUFFER_LEN; |
||
385 | } |
||
386 | else |
||
387 | inbuffer = ((total - data_off) > PTP_MAX_EV_BUFFER_LEN) ? PTP_MAX_EV_BUFFER_LEN : (uint8_t)(total - data_off); |
||
388 | |||
389 | if (pParser) |
||
390 | pParser->Parse(inbuffer, data, (const uint32_t&)data_off); |
||
391 | |||
392 | data_off += inbuffer; |
||
393 | |||
394 | loops ++; |
||
395 | delay(50); |
||
396 | } // while(1) |
||
397 | } |
||
398 | |||
399 | bool PTP::CheckEvent(uint8_t size, uint8_t *buf) |
||
400 | { |
||
401 | ZerroMemory(size, buf); |
||
402 | |||
403 | uint8_t rcode = Usb.inTransfer(devAddress, epInterrupt, size, (char*)buf); |
||
404 | |||
405 | // if no interrupts pending - return false |
||
406 | |||
407 | // there should be some error type checking involved i.e. timeout error |
||
408 | if (rcode) |
||
409 | return false; |
||
410 | |||
411 | return true; |
||
412 | } |
||
413 | |||
414 | bool PTP::EventWait(uint8_t size, uint8_t *event_buf, uint16_t timeout) |
||
415 | { |
||
416 | const uint16_t milisec = 0xA0; // must be polling interval for the interrupt pipe |
||
417 | bool occured = false; |
||
418 | |||
419 | while (!(occured = CheckEvent(size, event_buf)) && (timeout -= milisec)) |
||
420 | delay(milisec); |
||
421 | |||
422 | return occured; |
||
423 | } |
||
424 | |||
425 | uint16_t PTP::OpenSession() |
||
426 | { |
||
427 | uint32_t params[1]; |
||
428 | OperFlags flags = { 1, 0, 0, 0, 0, 0 }; |
||
429 | |||
430 | idSession = 1; |
||
431 | idTransaction = 1; |
||
432 | |||
433 | params[0] = idSession; |
||
434 | |||
435 | return Transaction(PTP_OC_OpenSession, &flags, params); |
||
436 | } |
||
437 | |||
438 | uint16_t PTP::ResetDevice() |
||
439 | { |
||
440 | OperFlags flags = { 0, 0, 0, 0, 0, 0 }; |
||
441 | return Transaction(PTP_OC_ResetDevice, &flags); |
||
442 | } |
||
443 | |||
444 | uint16_t PTP::GetNumObjects(uint32_t &retval, uint32_t storage_id, uint16_t format, uint32_t assoc) |
||
445 | { |
||
446 | uint16_t ptp_error = PTP_RC_GeneralError; |
||
447 | OperFlags flags = { 3, 1, 0, 0, 0, 0 }; |
||
448 | uint32_t params[3]; |
||
449 | |||
450 | if ( (ptp_error = Transaction(PTP_OC_GetNumObjects, &flags, params)) == PTP_RC_OK) |
||
451 | retval = params[0]; |
||
452 | |||
453 | return ptp_error; |
||
454 | } |
||
455 | |||
456 | uint16_t PTP::GetObject(uint32_t handle, PTPReadParser *parser) |
||
457 | { |
||
458 | OperFlags flags = { 1, 0, 0, 1, 1, 0 }; |
||
459 | uint32_t params[1]; |
||
460 | |||
461 | params[0] = handle; |
||
462 | |||
463 | return Transaction(PTP_OC_GetObject, &flags, params, parser); |
||
464 | } |
||
465 | |||
466 | uint16_t PTP::GetThumb(uint32_t handle, PTPReadParser *parser) |
||
467 | { |
||
468 | OperFlags flags = { 1, 0, 0, 1, 1, 0 }; |
||
469 | uint32_t params[1]; |
||
470 | |||
471 | params[0] = handle; |
||
472 | |||
473 | return Transaction(PTP_OC_GetThumb, &flags, params, parser); |
||
474 | } |
||
475 | |||
476 | uint16_t PTP::DeleteObject(uint32_t handle, uint16_t format) |
||
477 | { |
||
478 | OperFlags flags = { 2, 0, 0, 0, 0, 0 }; |
||
479 | uint32_t params[2]; |
||
480 | |||
481 | params[0] = handle; |
||
482 | params[1] = (uint32_t)format; |
||
483 | |||
484 | return Transaction(PTP_OC_DeleteObject, &flags, params); |
||
485 | } |
||
486 | |||
487 | uint16_t PTP::SetObjectProtection(uint32_t handle, uint16_t attrib) |
||
488 | { |
||
489 | OperFlags flags = { 2, 0, 0, 0, 0, 0 }; |
||
490 | uint32_t params[2]; |
||
491 | |||
492 | params[0] = handle; |
||
493 | params[1] = (uint32_t)attrib; |
||
494 | |||
495 | return Transaction(PTP_OC_SetObjectProtection, &flags, params); |
||
496 | } |
||
497 | |||
498 | uint16_t PTP::MoveObject(uint32_t handle, uint32_t storage_id, uint32_t parent) |
||
499 | { |
||
500 | OperFlags flags = { 3, 0, 0, 0, 0, 0 }; |
||
501 | uint32_t params[2]; |
||
502 | |||
503 | params[0] = handle; |
||
504 | params[1] = storage_id; |
||
505 | params[2] = parent; |
||
506 | |||
507 | return Transaction(PTP_OC_MoveObject, &flags, params); |
||
508 | } |
||
509 | |||
510 | uint16_t PTP::CopyObject(uint32_t handle, uint32_t storage_id, uint32_t parent, uint32_t &new_handle) |
||
511 | { |
||
512 | uint16_t ptp_error = PTP_RC_GeneralError; |
||
513 | OperFlags flags = { 3, 1, 0, 0, 0, 0 }; |
||
514 | uint32_t params[3]; |
||
515 | |||
516 | params[0] = handle; |
||
517 | params[1] = storage_id; |
||
518 | params[2] = parent; |
||
519 | |||
520 | if ( (ptp_error = Transaction(PTP_OC_CopyObject, &flags, params)) == PTP_RC_OK) |
||
521 | new_handle = params[0]; |
||
522 | |||
523 | return ptp_error; |
||
524 | } |
||
525 | |||
526 | uint16_t PTP::InitiateCapture(uint32_t storage_id, uint16_t format) |
||
527 | { |
||
528 | uint16_t ptp_error = PTP_RC_GeneralError; |
||
529 | OperFlags flags = { 2, 0, 0, 0, 0, 0 }; |
||
530 | uint32_t params[2]; |
||
531 | |||
532 | params[0] = storage_id; |
||
533 | params[1] = (uint32_t)format; |
||
534 | |||
535 | if ( (ptp_error = Transaction(PTP_OC_InitiateCapture, &flags, params)) == PTP_RC_OK) |
||
536 | {} |
||
537 | |||
538 | return ptp_error; |
||
539 | } |
||
540 | |||
541 | uint16_t PTP::InitiateOpenCapture(uint32_t storage_id, uint16_t format) |
||
542 | { |
||
543 | uint16_t ptp_error = PTP_RC_GeneralError; |
||
544 | OperFlags flags = { 2, 0, 0, 0, 0, 0 }; |
||
545 | uint32_t params[2]; |
||
546 | |||
547 | params[0] = storage_id; |
||
548 | params[1] = (uint32_t)format; |
||
549 | |||
550 | if ( (ptp_error = Transaction(PTP_OC_InitiateOpenCapture, &flags, params)) == PTP_RC_OK) |
||
551 | {} |
||
552 | |||
553 | return ptp_error; |
||
554 | } |
||
555 | |||
556 | uint16_t PTP::TerminateOpenCapture(uint32_t trans_id) |
||
557 | { |
||
558 | OperFlags flags = { 1, 0, 0, 0, 0, 0 }; |
||
559 | uint32_t params[1]; |
||
560 | |||
561 | params[0] = trans_id; |
||
562 | |||
563 | return Transaction(PTP_OC_TerminateOpenCapture, &flags, params); |
||
564 | } |
||
565 | |||
566 | uint16_t PTP::PowerDown() |
||
567 | { |
||
568 | OperFlags flags = { 0, 0, 0, 0, 0, 0 }; |
||
569 | return Transaction(PTP_OC_PowerDown, &flags); |
||
570 | } |
||
571 | |||
572 | uint16_t PTP::SelfTest(uint16_t type = 0) |
||
573 | { |
||
574 | OperFlags flags = { 1, 0, 0, 0 }; |
||
575 | uint32_t params[1]; |
||
576 | params[0] = type; |
||
577 | |||
578 | return Transaction(PTP_OC_SelfTest, &flags, params); |
||
579 | } |
||
580 | |||
581 | uint16_t PTP::CloseSession() |
||
582 | { |
||
583 | uint16_t ptp_error = PTP_RC_GeneralError; |
||
584 | OperFlags flags = { 0, 0, 0, 0, 0, 0 }; |
||
585 | |||
586 | if ( (ptp_error = Transaction(PTP_OC_CloseSession, &flags)) == PTP_RC_OK) |
||
587 | idSession = idTransaction = 0; |
||
588 | |||
589 | return ptp_error; |
||
590 | } |
||
591 | |||
592 | uint16_t PTP::GetDeviceInfo(PTPReadParser *parser) |
||
593 | { |
||
594 | OperFlags flags = { 0, 0, 0, 1, 1, 0 }; |
||
595 | return Transaction(PTP_OC_GetDeviceInfo, &flags, NULL, parser); |
||
596 | } |
||
597 | |||
598 | uint16_t PTP::GetObjectInfo(uint32_t handle, PTPReadParser *parser) |
||
599 | { |
||
600 | OperFlags flags = { 1, 0, 0, 1, 1, 0 }; |
||
601 | uint32_t params[1]; |
||
602 | params[0] = handle; |
||
603 | |||
604 | return Transaction(PTP_OC_GetObjectInfo, &flags, params, parser); |
||
605 | } |
||
606 | |||
607 | uint16_t PTP::GetDevicePropDesc(const uint16_t pcode, PTPReadParser *parser) |
||
608 | { |
||
609 | OperFlags flags = { 1, 0, 0, 1, 1, 0 }; |
||
610 | uint32_t params[1]; |
||
611 | |||
612 | params[0] = (uint32_t)pcode; |
||
613 | |||
614 | return Transaction(PTP_OC_GetDevicePropDesc, &flags, params, parser); |
||
615 | } |
||
616 | |||
617 | uint16_t PTP::GetDevicePropValue(const uint16_t pcode, PTPReadParser *parser) |
||
618 | { |
||
619 | OperFlags flags = { 1, 0, 0, 1, 1, 0 }; |
||
620 | uint32_t params[1]; |
||
621 | |||
622 | params[0] = (uint32_t)pcode; |
||
623 | |||
624 | return Transaction(PTP_OC_GetDevicePropValue, &flags, params, parser); |
||
625 | } |
||
626 | |||
627 | uint16_t PTP::GetDevicePropValue(const uint16_t pcode, uint8_t &val) |
||
628 | { |
||
629 | uint16_t ptp_error = PTP_RC_GeneralError; |
||
630 | OperFlags flags = { 1, 0, 0, 0, 3, 13 }; |
||
631 | uint32_t params[1]; |
||
632 | uint8_t buf[13]; |
||
633 | |||
634 | params[0] = (uint32_t)pcode; |
||
635 | |||
636 | if ( (ptp_error = Transaction(PTP_OC_GetDevicePropValue, &flags, params, buf)) == PTP_RC_OK) |
||
637 | val = buf[12]; |
||
638 | |||
639 | return ptp_error; |
||
640 | } |
||
641 | |||
642 | uint16_t PTP::GetDevicePropValue(const uint16_t pcode, uint16_t &val) |
||
643 | { |
||
644 | uint16_t ptp_error = PTP_RC_GeneralError; |
||
645 | OperFlags flags = { 1, 0, 0, 0, 3, 14 }; |
||
646 | uint32_t params[1]; |
||
647 | uint16_t buf[7]; |
||
648 | |||
649 | params[0] = pcode; |
||
650 | |||
651 | if ( (ptp_error = Transaction(PTP_OC_GetDevicePropValue, &flags, params, buf)) == PTP_RC_OK) |
||
652 | val = buf[6]; |
||
653 | |||
654 | return ptp_error; |
||
655 | } |
||
656 | |||
657 | uint16_t PTP::GetDevicePropValue(const uint16_t pcode, uint32_t &val) |
||
658 | { |
||
659 | uint16_t ptp_error = PTP_RC_GeneralError; |
||
660 | OperFlags flags = { 1, 0, 0, 0, 3, 16 }; |
||
661 | uint32_t params[1]; |
||
662 | uint32_t buf[4]; |
||
663 | |||
664 | params[0] = pcode; |
||
665 | |||
666 | if ( (ptp_error = Transaction(PTP_OC_GetDevicePropValue, &flags, params, buf)) == PTP_RC_OK) |
||
667 | val = buf[3]; |
||
668 | |||
669 | return ptp_error; |
||
670 | } |
||
671 | |||
672 | uint16_t PTP::SetDevicePropValue(uint16_t pcode, uint8_t val) |
||
673 | { |
||
674 | OperFlags flags = { 1, 0, 1, 1, 3, 1 }; |
||
675 | uint32_t params[1]; |
||
676 | uint8_t value; |
||
677 | |||
678 | params[0] = (uint32_t)pcode; |
||
679 | value = val; |
||
680 | |||
681 | return Transaction(PTP_OC_SetDevicePropValue, &flags, params, (void*)&value); |
||
682 | } |
||
683 | |||
684 | uint16_t PTP::SetDevicePropValue(uint16_t pcode, uint16_t val) |
||
685 | { |
||
686 | OperFlags flags = { 1, 0, 1, 1, 3, 2 }; |
||
687 | uint32_t params[1]; |
||
688 | uint16_t value; |
||
689 | |||
690 | params[0] = (uint32_t)pcode; |
||
691 | value = val; |
||
692 | |||
693 | return Transaction(PTP_OC_SetDevicePropValue, &flags, params, (void*)&value); |
||
694 | } |
||
695 | |||
696 | uint16_t PTP::SetDevicePropValue(uint16_t pcode, uint32_t val) |
||
697 | { |
||
698 | OperFlags flags = { 1, 0, 1, 1, 3, 4 }; |
||
699 | uint32_t params[1]; |
||
700 | uint32_t value; |
||
701 | |||
702 | params[0] = (uint32_t)pcode; |
||
703 | value = val; |
||
704 | |||
705 | return Transaction(PTP_OC_SetDevicePropValue, &flags, params, (void*)&value); |
||
706 | } |
||
707 | |||
708 | uint16_t PTP::ResetDevicePropValue(const uint16_t pcode) |
||
709 | { |
||
710 | OperFlags flags = { 1, 0, 0, 0 }; |
||
711 | uint32_t params[1]; |
||
712 | |||
713 | params[0] = (uint32_t)pcode; |
||
714 | |||
715 | return Transaction(PTP_OC_ResetDevicePropValue, &flags, params); |
||
716 | } |
||
717 | |||
718 | uint16_t PTP::Operation(uint16_t opcode, uint8_t nparams, uint32_t *params) |
||
719 | { |
||
720 | OperFlags flags = { 0, 0, 0, 0, 0, 0 }; |
||
721 | |||
722 | flags.opParams = nparams; |
||
723 | |||
724 | return Transaction(opcode, &flags, params); |
||
725 | } |
||
726 | |||
727 | uint16_t PTP::GetStorageInfo(uint32_t storage_id, PTPReadParser *parser) |
||
728 | { |
||
729 | OperFlags flags = { 1, 0, 0, 1, 1, 0 }; |
||
730 | |||
731 | uint32_t params[1]; |
||
732 | params[0] = storage_id; |
||
733 | |||
734 | return Transaction(PTP_OC_GetStorageInfo, &flags, params, parser); |
||
735 | } |
||
736 | |||
737 | uint16_t PTP::FormatStore(uint32_t storage_id, uint32_t fsformat) |
||
738 | { |
||
739 | OperFlags flags = { 2, 0, 0, 0, 0, 0 }; |
||
740 | |||
741 | uint32_t params[2]; |
||
742 | params[0] = storage_id; |
||
743 | params[1] = fsformat; |
||
744 | |||
745 | return Transaction(PTP_OC_FormatStore, &flags, params); |
||
746 | } |
||
747 | |||
748 | uint16_t PTP::CaptureImage() |
||
749 | { |
||
750 | uint16_t ptp_error = PTP_RC_GeneralError; |
||
751 | uint32_t params[2] = {0, 0x00003801}; |
||
752 | OperFlags flags = { 2, 0, 0, 0 }; |
||
753 | |||
754 | if ( (ptp_error = Transaction(PTP_OC_InitiateCapture, &flags, params)) != PTP_RC_OK) |
||
755 | { |
||
756 | PTPTRACE2("CaptureImage error", ptp_error); |
||
757 | return ptp_error; |
||
758 | } |
||
759 | PTPUSBEventContainer evnt; |
||
760 | bool occured; |
||
761 | |||
762 | // multiple objects can be added depending on current camera shooting mode |
||
763 | while ((occured = EventWait(sizeof(PTPUSBEventContainer), (uint8_t*)&evnt, 500)) && evnt.code == PTP_EC_ObjectAdded) |
||
764 | PTPTRACE("CaptureImage: New object added.\r\n"); |
||
765 | |||
766 | if (!occured) |
||
767 | { |
||
768 | PTPTRACE("CaptureImage: Timeout ellapsed.\r\n"); |
||
769 | return PTP_RC_Undefined; |
||
770 | } |
||
771 | switch (evnt.code) |
||
772 | { |
||
773 | case PTP_EC_CaptureComplete: |
||
774 | PTPTRACE("CaptureImage: Image captured.\r\n"); |
||
775 | return PTP_RC_OK; |
||
776 | |||
777 | case PTP_EC_StoreFull: |
||
778 | PTPTRACE("CaptureImage: Storage is full.\r\n"); |
||
779 | return PTP_RC_StoreFull; |
||
780 | |||
781 | default: |
||
782 | PTPTRACE2("CaptureImage: Unexpected event\r\n", evnt.code); |
||
783 | return PTP_RC_Undefined; |
||
784 | } |
||
785 | } |
||
786 | |||
787 | uint16_t PTP::GetStorageIDs(PTPReadParser *parser) |
||
788 | { |
||
789 | OperFlags flags = { 0, 0, 0, 1, 1, 0 }; |
||
790 | return Transaction(PTP_OC_GetStorageIDs, &flags, NULL, parser); |
||
791 | } |
||
792 | |||
793 | uint16_t PTP::GetStorageIDs(uint8_t bufsize, uint8_t *pbuf) |
||
794 | { |
||
795 | OperFlags flags = { 0, 0, 0, 1, 3, 0 }; |
||
796 | |||
797 | flags.dataSize = bufsize; |
||
798 | |||
799 | return Transaction(PTP_OC_GetStorageIDs, &flags, NULL, pbuf); |
||
800 | } |
||
801 | |||
802 | uint16_t PTP::GetObjectHandles(uint32_t storage_id, uint16_t format, uint16_t assoc, PTPReadParser *parser) |
||
803 | { |
||
804 | OperFlags flags = { 3, 0, 0, 1, 1, 0 }; |
||
805 | uint32_t params[3]; |
||
806 | |||
807 | params[0] = storage_id; |
||
808 | params[1] = (uint32_t)format; |
||
809 | params[2] = (uint32_t)assoc; |
||
810 | |||
811 | return Transaction(PTP_OC_GetObjectHandles, &flags, params, parser); |
||
812 | } |
||
813 | |||
814 | void PTP::Task() |
||
815 | { |
||
816 | Max.Task(); |
||
817 | Usb.Task(); |
||
818 | |||
819 | if( Usb.getUsbTaskState() == USB_DETACHED_SUBSTATE_WAIT_FOR_DEVICE ) |
||
820 | { |
||
821 | idSession = 0; |
||
822 | idTransaction = 0; |
||
823 | |||
824 | stateMachine->OnDeviceDisconnectedState(this); |
||
825 | } |
||
826 | //wait for addressing state |
||
827 | if( Usb.getUsbTaskState() == USB_STATE_CONFIGURING ) |
||
828 | { |
||
829 | /* Initialize data structures */ |
||
830 | epRecord[ 0 ] = *( Usb.getDevTableEntry( 0,0 )); //copy endpoint 0 parameters |
||
831 | |||
832 | // Data-In EP |
||
833 | epRecord[ 1 ].epAddr = epDataIn; |
||
834 | epRecord[ 1 ].Attr = 0x02; |
||
835 | epRecord[ 1 ].MaxPktSize = 0x0040; |
||
836 | epRecord[ 1 ].Interval = 0; |
||
837 | epRecord[ 1 ].sndToggle = bmSNDTOG0; |
||
838 | epRecord[ 1 ].rcvToggle = bmRCVTOG0; |
||
839 | |||
840 | // Data-Out EP |
||
841 | epRecord[ 2 ].epAddr = epDataOut; |
||
842 | epRecord[ 2 ].Attr = 0x02; |
||
843 | epRecord[ 2 ].MaxPktSize = 0x0040; |
||
844 | epRecord[ 2 ].Interval = 0; |
||
845 | epRecord[ 2 ].sndToggle = bmSNDTOG0; |
||
846 | epRecord[ 2 ].rcvToggle = bmRCVTOG0; |
||
847 | |||
848 | // Interrupt EP |
||
849 | epRecord[ 3 ].epAddr = epInterrupt; |
||
850 | epRecord[ 3 ].Attr = 0x03; |
||
851 | epRecord[ 3 ].MaxPktSize = 0x0008; |
||
852 | epRecord[ 3 ].Interval = 0x0A; |
||
853 | epRecord[ 3 ].sndToggle = bmSNDTOG0; |
||
854 | epRecord[ 3 ].rcvToggle = bmRCVTOG0; |
||
855 | |||
856 | Usb.setDevTableEntry( devAddress, epRecord ); |
||
857 | |||
858 | uint8_t rcode; |
||
859 | |||
860 | /* Configure device */ |
||
861 | if ((rcode = Usb.setConf( devAddress, 0, numConf ))) |
||
862 | HaltOnError(MsgErrDeviceConf, rcode); |
||
863 | |||
864 | Usb.setUsbTaskState( USB_STATE_RUNNING ); |
||
865 | |||
866 | SetInitialState(); |
||
867 | } |
||
868 | if( Usb.getUsbTaskState() == USB_STATE_RUNNING ) |
||
869 | { |
||
870 | Task2(); |
||
871 | } |
||
872 | } |
||
873 | |||
874 | uint8_t PTP::GetConfDescr( byte addr, byte conf ) |
||
875 | { |
||
876 | char buf[ PTP_MAX_RX_BUFFER_LEN ]; |
||
877 | byte rcode; |
||
878 | unsigned int total_length; |
||
879 | rcode = Usb.getConfDescr( addr, 0, 4, conf, buf ); //get total length |
||
880 | //LOBYTE( total_length ) = buf[ 2 ]; |
||
881 | //HIBYTE( total_length ) = buf[ 3 ]; |
||
882 | |||
883 | total_length = *((uint16_t*)(buf + 2)); |
||
884 | |||
885 | if( total_length > PTP_MAX_RX_BUFFER_LEN ) |
||
886 | { //check if total length is larger than buffer |
||
887 | //Serial.println("Total length truncated to 256 bytes"); |
||
888 | total_length = PTP_MAX_RX_BUFFER_LEN; |
||
889 | } |
||
890 | rcode = Usb.getConfDescr( addr, 0, total_length, conf, buf ); //get the whole descriptor |
||
891 | return( 0 ); |
||
892 | } |