Skip to content

Commit

Permalink
Implement PTP_COMMAND_IGNORED and command resending if ignored
Browse files Browse the repository at this point in the history
+ some docs
  • Loading branch information
petabyt committed Sep 14, 2024
1 parent a791aca commit 5d19935
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 51 deletions.
9 changes: 7 additions & 2 deletions src/camlib.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ enum ImageFormats {

/// @brief Tells lib what backend and packet style to use
enum PtpConnType {
// why this this a bitmask??
PTP_IP = (1 << 0),
PTP_IP_USB = (1 << 1), // TCP-based, but using USB-style packets (Fujifilm)
PTP_USB = (1 << 2),
Expand Down Expand Up @@ -141,7 +142,7 @@ struct PtpRuntime {
int device_type;

/// @brief For Windows compatibility, this is set to indicate lenth for a data packet
/// that will be sent after a command packet. Will be set to zero when ptp_send_bulk_packets is called.
/// that will be sent after a command packet. Will be set to zero when ptp_send_packet is called.
int data_phase_length;

/// @brief For session comm/io structures (holds backend instance pointers)
Expand Down Expand Up @@ -253,6 +254,10 @@ PUB int ptp_get_event(struct PtpRuntime *r, struct PtpEventContainer *ec);
/// @memberof PtpRuntime
PUB void ptp_mutex_unlock(struct PtpRuntime *r);

/// @brief Completely unlock the mutex for the current thread, to ensure there isn't a deadlock
/// @memberof PtpRuntime
PUB void ptp_mutex_unlock_thread(struct PtpRuntime *r);

/// @brief Keep the mutex locked one more time for the current thread
/// @note When calling a thread-safe function, this will garuntee the mutex locked, in the
/// case that you want to continue using the buffer. Must be unlocked or will cause deadlock.
Expand Down Expand Up @@ -318,7 +323,7 @@ void ptp_set_prop_avail_info(struct PtpRuntime *r, int code, int memb_size, int

void *ptp_dup_payload(struct PtpRuntime *r);

// Write r->data to a file called DUMP
/// @brief Write r->data to a file called DUMP
/// @note Debugging only
int ptp_dump(struct PtpRuntime *r);

Expand Down
6 changes: 4 additions & 2 deletions src/cl_backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,12 @@ int ptp_device_reset(struct PtpRuntime *r);

/// @brief Send packets in r->data
/// @memberof PTP/USB
int ptp_send_bulk_packets(struct PtpRuntime *r, int length);
int ptp_send_packet(struct PtpRuntime *r, int length);

/// @brief Receive all packets into r->data
/// @memberof PTP/USB
int ptp_receive_bulk_packets(struct PtpRuntime *r);
int ptp_receive_all_packets(struct PtpRuntime *r);

/// @brief Poll the interrupt endpoint
/// @memberof PTP/USB
int ptp_read_int(struct PtpRuntime *r, void *to, int length);
Expand Down
113 changes: 71 additions & 42 deletions src/lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,95 +146,124 @@ void ptp_mutex_unlock_thread(struct PtpRuntime *r) {
while (pthread_mutex_unlock(r->mutex) == 0);
}

// Perform a generic command transaction - no data phase
int ptp_send(struct PtpRuntime *r, struct PtpCommand *cmd) {
ptp_mutex_lock(r);
static int ptp_check_rc(struct PtpRuntime *r) {
if (ptp_get_return_code(r) != PTP_RC_OK) {
ptp_verbose_log("Invalid return code: %X\n", ptp_get_return_code(r));
return PTP_CHECK_CODE;
}

r->data_phase_length = 0;
return 0;
}

static int ptp_send_try(struct PtpRuntime *r, struct PtpCommand *cmd) {
int length = ptp_new_cmd_packet(r, cmd);
if (ptp_send_bulk_packets(r, length) != length) {
ptp_mutex_unlock_thread(r);
if (ptp_send_packet(r, length) != length) {
ptp_verbose_log("Didn't send all packets\n");
return PTP_IO_ERR;
}

int rc = ptp_receive_bulk_packets(r);
int rc = ptp_receive_all_packets(r);
if (rc < 0) {
ptp_mutex_unlock_thread(r);
ptp_verbose_log("Failed to receive packets: %d\n", rc);
return PTP_IO_ERR;
return rc;
}

r->transaction++;

if (ptp_get_return_code(r) != PTP_RC_OK) {
ptp_verbose_log("Invalid return code: %X\n", ptp_get_return_code(r));
ptp_mutex_unlock_thread(r);
return PTP_CHECK_CODE;
}

ptp_mutex_unlock(r);
return 0;
}

// Perform a command request with a data phase to the camera
int ptp_send_data(struct PtpRuntime *r, struct PtpCommand *cmd, void *data, int length) {
// Perform a generic command transaction - no data phase
int ptp_send(struct PtpRuntime *r, struct PtpCommand *cmd) {
ptp_mutex_lock(r);

// Required for libWPD and PTP/IP
r->data_phase_length = length;
r->data_phase_length = 0;

// Resize buffer if needed
if (length + 50 > r->data_length) {
ptp_buffer_resize(r, 100 + length);
int rc = ptp_send_try(r, cmd);
if (rc == PTP_COMMAND_IGNORED) {
ptp_verbose_log("Command ignored, trying again...\n");
rc = ptp_send_try(r, cmd);
if (rc) {
ptp_verbose_log("Command ignored again.\n");
ptp_mutex_unlock(r);
return PTP_IO_ERR;
}
} else if (rc) {
ptp_mutex_unlock_thread(r);
return PTP_IO_ERR;
}

// Send operation request (data phase later on)
r->transaction++;

rc = ptp_check_rc(r);
ptp_mutex_unlock(r);
return rc;
}

static int ptp_send_data_try(struct PtpRuntime *r, struct PtpCommand *cmd, void *data, int length) {
// Send operation request (data packet later on)
int plength = ptp_new_cmd_packet(r, cmd);
if (ptp_send_bulk_packets(r, plength) != plength) {
ptp_mutex_unlock_thread(r);
if (ptp_send_packet(r, plength) != plength) {
return PTP_IO_ERR;
}

if (r->connection_type == PTP_IP) {
// Send data start packet first (only has payload length)
plength = ptpip_data_start_packet(r, length);
if (ptp_send_bulk_packets(r, plength) != plength) {
ptp_mutex_unlock_thread(r);
if (ptp_send_packet(r, plength) != plength) {
return PTP_IO_ERR;
}

// Send data end packet, with payload
plength = ptpip_data_end_packet(r, data, length);
if (ptp_send_bulk_packets(r, plength) != plength) {
ptp_mutex_unlock_thread(r);
if (ptp_send_packet(r, plength) != plength) {
return PTP_IO_ERR;
}
} else {
// Single data packet
plength = ptp_new_data_packet(r, cmd, data, length);
if (ptp_send_bulk_packets(r, plength) != plength) {
ptp_mutex_unlock_thread(r);
if (ptp_send_packet(r, plength) != plength) {
ptp_verbose_log("Failed to send data packet (%d)\n", plength);
return PTP_IO_ERR;
}
}

if (ptp_receive_bulk_packets(r) < 0) {
ptp_mutex_unlock_thread(r);
int rc = ptp_receive_all_packets(r);
if (rc < 0) return rc;
return 0;
}

// Perform a command request with a data phase to the camera
int ptp_send_data(struct PtpRuntime *r, struct PtpCommand *cmd, void *data, int length) {
ptp_mutex_lock(r);

// Required for libWPD and PTP/IP
r->data_phase_length = length;

// Resize buffer if needed
if (length + 50 > r->data_length) {
ptp_buffer_resize(r, 100 + length);
}

// If our command is ignored (we get 0 bytes as a response), try sending the
// commands again.
int rc = ptp_send_data_try(r, cmd, data, length);
if (rc == PTP_COMMAND_IGNORED) {
ptp_verbose_log("Command ignored, trying again...\n");
rc = ptp_send_data_try(r, cmd, data, length);
if (rc) {
ptp_verbose_log("Command ignored again.\n");
ptp_mutex_unlock(r);
return PTP_IO_ERR;
}
} else if (rc) {
ptp_mutex_unlock(r);
return PTP_IO_ERR;
}

r->transaction++;

if (ptp_get_return_code(r) != PTP_RC_OK) {
ptp_mutex_unlock_thread(r);
return PTP_CHECK_CODE;
}

rc = ptp_check_rc(r);
ptp_mutex_unlock(r);
return 0;
return rc;
}

int ptp_device_type(struct PtpRuntime *r) {
Expand Down
2 changes: 1 addition & 1 deletion src/no_ip.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ int ptpip_new_timeout_socket(char *addr, int port) {
return -1;
}

int ptpip_connect(struct PtpRuntime *r, const char *addr, int port) {
int ptpip_connect(struct PtpRuntime *r, const char *addr, int port, int extra_tmout) {
return -1;
}

Expand Down
9 changes: 5 additions & 4 deletions src/transport.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ int ptpusb_send_bulk_packets(struct PtpRuntime *r, int length) {
}
}

int ptp_send_bulk_packets(struct PtpRuntime *r, int length) {
int ptp_send_packet(struct PtpRuntime *r, int length) {
if (r->connection_type == PTP_USB) {
return ptpusb_send_bulk_packets(r, length);
}
Expand Down Expand Up @@ -82,7 +82,7 @@ int ptpip_read_packet(struct PtpRuntime *r, int of) {

if (rc < 0) {
ptp_verbose_log("Failed to read packet length: %d\n", rc);
return PTP_IO_ERR;
return PTP_COMMAND_IGNORED;
}

if (rc < 4) {
Expand Down Expand Up @@ -258,7 +258,7 @@ int ptpipusb_read_packet(struct PtpRuntime *r, int of) {

if (rc < 0) {
ptp_verbose_log("Failed to read packet length: %d\n", rc);
return PTP_IO_ERR;
return PTP_COMMAND_IGNORED;
}

if (rc < 4) {
Expand Down Expand Up @@ -319,6 +319,7 @@ int ptpipusb_receive_bulk_packets(struct PtpRuntime *r) {
// Handle data phase
if (c->type == PTP_PACKET_TYPE_DATA) {
rc = ptpipusb_read_packet(r, read);
if (rc == PTP_COMMAND_IGNORED) rc = PTP_IO_ERR; // Command was not ignored as we got a data packet
if (rc < 0) return rc;

read += rc;
Expand All @@ -330,7 +331,7 @@ int ptpipusb_receive_bulk_packets(struct PtpRuntime *r) {
return read;
}

int ptp_receive_bulk_packets(struct PtpRuntime *r) {
int ptp_receive_all_packets(struct PtpRuntime *r) {
if (r->io_kill_switch) return -1;
if (r->connection_type == PTP_IP) {
return ptpip_receive_bulk_packets(r);
Expand Down

0 comments on commit 5d19935

Please sign in to comment.