From 8cfe9ba705e869de25b6907b1aff02c2e30b8548 Mon Sep 17 00:00:00 2001 From: Daniel Date: Sat, 3 Feb 2024 18:43:04 -0500 Subject: [PATCH] Add r->response_wait_default, improve ptp_download_object --- src/bind.c | 4 +++- src/camlib.h | 7 +++++++ src/cl_ops.h | 2 +- src/lib.c | 16 ++++++++++++++++ src/operations.c | 33 ++++++++++++--------------------- src/transport.c | 6 +++--- 6 files changed, 42 insertions(+), 26 deletions(-) diff --git a/src/bind.c b/src/bind.c index 3a367de..72922a8 100644 --- a/src/bind.c +++ b/src/bind.c @@ -502,7 +502,9 @@ int bind_get_partial_object(struct BindReq *bind, struct PtpRuntime *r) { } int bind_download_file(struct BindReq *bind, struct PtpRuntime *r) { - int x = ptp_download_file(r, bind->params[0], bind->string); + FILE *f = fopen(bind->string, "wb"); + int x = ptp_download_object(r, bind->params[0],f, 0x100000); + fclose(f); if (x < 0) { return sprintf(bind->buffer, "{\"error\": %d}", -1); } else { diff --git a/src/camlib.h b/src/camlib.h index 8973793..94184e5 100644 --- a/src/camlib.h +++ b/src/camlib.h @@ -49,6 +49,9 @@ enum PtpGeneralError { PTP_CHECK_CODE = -8, }; +/// @brief Evaluates PtpGeneralError into string message +const char *ptp_perror(int rc); + enum PtpLiveViewType { PTP_LV_NONE = 0, PTP_LV_EOS = 1, @@ -134,8 +137,12 @@ struct PtpRuntime { pthread_mutex_t *mutex; /// @brief Optionally wait up to 256 seconds for a response. Some PTP operations require this, such as EOS capture. + /// @note Not thread safe. Will be reset after each operation. uint8_t wait_for_response; + /// @brief Default value for wait_for_response. + uint8_t response_wait_default; + /// @brief For devices that implement it, this will hold a linked list of properties and an array of their supported values. /// generic_ functions will reject set property calls if an invalid value is written. struct PtpPropAvail *avail; diff --git a/src/cl_ops.h b/src/cl_ops.h index a904c30..f0f28a1 100644 --- a/src/cl_ops.h +++ b/src/cl_ops.h @@ -45,7 +45,7 @@ int ptp_get_thumbnail(struct PtpRuntime *r, int handle); /// @note Not thread safe. int ptp_get_partial_object(struct PtpRuntime *r, uint32_t handle, int offset, int max); /// @brief Download an object from handle, to a local file (uses GetPartialObject) -int ptp_download_file(struct PtpRuntime *r, int handle, char *file); +int ptp_download_object(struct PtpRuntime *r, int handle, FILE *stream, size_t max); /// @brief Recieve a generic list of all properties received in DeviceInfo /// This is similar to getting all events, but for first startup when you know nothing. /// Some vendors do this, but this gets all the properties manually. diff --git a/src/lib.c b/src/lib.c index 81f8720..e376348 100644 --- a/src/lib.c +++ b/src/lib.c @@ -13,6 +13,7 @@ void ptp_reset(struct PtpRuntime *r) { r->transaction = 0; r->session = 0; r->connection_type = PTP_USB; + r->response_wait_default = 1; r->wait_for_response = 1; } @@ -281,6 +282,21 @@ int ptp_check_prop(struct PtpRuntime *r, int code) { return 0; } +const char *ptp_perror(int rc) { + switch (rc) { + case PTP_OK: return "OK"; + case PTP_NO_DEVICE: return "No device found"; + case PTP_NO_PERM: return "Lacking permissions"; + case PTP_OPEN_FAIL: return "Failed opening device"; + case PTP_OUT_OF_MEM: return "Out of memory"; + case PTP_IO_ERR: return "I/O Error"; + case PTP_RUNTIME_ERR: return "Runtime error"; + case PTP_UNSUPPORTED: return "Unsupported operation"; + case PTP_CHECK_CODE: return "Check code"; + default: return "?"; + } +} + int ptp_dump(struct PtpRuntime *r) { FILE *f = fopen("DUMP", "w"); fwrite(r->data, r->data_length, 1, f); diff --git a/src/operations.c b/src/operations.c index b32c7ec..9b94be8 100644 --- a/src/operations.c +++ b/src/operations.c @@ -322,40 +322,31 @@ int ptp_get_object(struct PtpRuntime *r, int handle) { return ptp_send(r, &cmd); } -int ptp_download_file(struct PtpRuntime *r, int handle, char *file) { - int max = ptp_get_payload_length(r); - - struct PtpObjectInfo oi; - if (ptp_get_object_info(r, handle, &oi)) { - return 0; - } - - max = oi.compressed_size; - - FILE *f = fopen(file, "w"); - if (f == NULL) { - return PTP_RUNTIME_ERR; - } - +int ptp_download_object(struct PtpRuntime *r, int handle, FILE *f, size_t max) { int read = 0; while (1) { + ptp_mutex_keep_locked(r); int x = ptp_get_partial_object(r, handle, read, max); if (x) { - fclose(f); + ptp_mutex_unlock(r); return x; } - if (ptp_get_payload_length(r) == 0) { + size_t partial_len = ptp_get_payload_length(r); + + if (partial_len == 0) { fclose(f); + ptp_mutex_unlock(r); return 0; } - fwrite(ptp_get_payload(r), 1, ptp_get_payload_length(r), f); + fwrite(ptp_get_payload(r), 1, partial_len, f); - read += ptp_get_payload_length(r); + ptp_mutex_unlock(r); - if (read == oi.compressed_size) { - fclose(f); + read += partial_len; + + if (partial_len != max) { return 0; } } diff --git a/src/transport.c b/src/transport.c index 2673079..9658313 100644 --- a/src/transport.c +++ b/src/transport.c @@ -55,7 +55,7 @@ int ptpip_read_packet(struct PtpRuntime *r, int of) { } } - r->wait_for_response = 1; + r->wait_for_response = r->response_wait_default; if (rc < 0) { ptp_verbose_log("Failed to read packet length: %d\n", rc); @@ -171,7 +171,7 @@ int ptpusb_read_all_packets(struct PtpRuntime *r) { CAMLIB_SLEEP(CAMLIB_WAIT_MS); } } - r->wait_for_response = 1; + r->wait_for_response = r->response_wait_default; if (rc < 0) { ptp_verbose_log("Failed to read packets: %d\n", rc); @@ -222,7 +222,7 @@ int ptpipusb_read_packet(struct PtpRuntime *r, int of) { } } - r->wait_for_response = 1; + r->wait_for_response = r->response_wait_default; if (rc < 0) { ptp_verbose_log("Failed to read packet length: %d\n", rc);