diff --git a/src/backend.c b/src/backend.c index fc8d30f..87211bd 100644 --- a/src/backend.c +++ b/src/backend.c @@ -40,30 +40,53 @@ int ptp_send_bulk_packets(struct PtpRuntime *r, int length) { } int ptpip_read_packet(struct PtpRuntime *r, int of) { + int rc = 0; int read = 0; - int rc = 0; while (rc <= 0 && r->wait_for_response) { - rc = ptp_cmd_read(r, r->data + of + read, r->max_packet_size); + rc = ptpip_cmd_read(r, r->data + of + read, 4); r->wait_for_response--; + if (rc > 0) break; + if (r->wait_for_response) { + ptp_verbose_log("Trying again..."); CAMLIB_SLEEP(CAMLIB_WAIT_MS); } } r->wait_for_response = 1; + if (rc < 0) { + ptp_verbose_log("Failed to read packet length: %d\n", rc); + return PTP_IO_ERR; + } + + if (rc < 4) { + ptp_verbose_log("Failed to read at least packet length: %d\n", rc); + return PTP_IO_ERR; + } + read += rc; struct PtpIpHeader *h = (struct PtpIpHeader *)(r->data + of); - printf("Got packet of %d bytes, type %X\n", h->length, h->type); + if (h->length - read == 0) { + return read; + } + + // Ensure data buffer is large enough for the rest of the packet + if (of + read + h->length >= r->data_length) { + rc = ptp_buffer_resize(r, of + read + h->length); + if (rc) return rc; + } while (1) { rc = ptpip_cmd_read(r, r->data + of + read, h->length - read); + if (rc < 0) { + ptp_verbose_log("Read error: %d\n", rc); return PTP_IO_ERR; } @@ -150,8 +173,14 @@ int ptpusb_read_all_packets(struct PtpRuntime *r) { } r->wait_for_response = 1; + if (rc < 0) { + ptp_verbose_log("Failed to read packets: %d\n"); + return PTP_IO_ERR; + } + read += rc; + // TODO: unsigned/unsigned compare if (read >= r->data_length - r->max_packet_size) { ptp_verbose_log("recieve_bulk_packets: Not enough memory\n"); return PTP_OUT_OF_MEM; @@ -175,7 +204,7 @@ int ptpusb_read_all_packets(struct PtpRuntime *r) { } } -// For USB packets over IP, we can't do any LibUSB/LibWPD performance tricks. +// For USB packets over IP, we can't do any LibUSB/LibWPD performance tricks. reads will just time out. int ptpipusb_read_packet(struct PtpRuntime *r, int of) { int rc = 0; int read = 0; @@ -214,14 +243,9 @@ int ptpipusb_read_packet(struct PtpRuntime *r, int of) { } // Ensure data buffer is large enough for the rest of the packet - // TODO: Have this as an external function if (of + read + h->length >= r->data_length) { - ptp_verbose_log("Extending IO buffer\n"); - r->data = realloc(r->data, of + read + h->length + 1000); - r->data_length = of + read + h->length + 1000; - if (r->data == NULL) { - return PTP_OUT_OF_MEM; - } + rc = ptp_buffer_resize(r, of + read + h->length); + if (rc) return rc; } while (1) { diff --git a/src/bind.c b/src/bind.c index 88519a7..bf0bc29 100644 --- a/src/bind.c +++ b/src/bind.c @@ -11,9 +11,10 @@ #include -int bind_connected = 0; -int bind_initialized = 0; -int bind_capture_type = 0; +// TODO: func to access these +static int bind_connected = 0; +static int bind_initialized = 0; +static int bind_capture_type = 0; int bind_status(struct BindReq *bind, struct PtpRuntime *r) { return sprintf(bind->buffer, "{\"error\": 0, \"initialized\": %d, \"connected\": %d, " diff --git a/src/camlib.h b/src/camlib.h index 91e3f0a..fb4fd18 100644 --- a/src/camlib.h +++ b/src/camlib.h @@ -21,7 +21,7 @@ // Max timeout for command read/writes #define PTP_TIMEOUT 1000 -// How much x to wait for when wait_for_response is greater than 1 +// How much ms to wait for wait_for_response #define CAMLIB_WAIT_MS 1000 // Conforms to POSIX 2001, some compilers may not have it @@ -170,6 +170,8 @@ void ptp_mutex_unlock(struct PtpRuntime *r); void ptp_mutex_keep_locked(struct PtpRuntime *r); void ptp_mutex_lock(struct PtpRuntime *r); +int ptp_buffer_resize(struct PtpRuntime *r, size_t size); + // Packet builder/unpacker helper functions. These accept a pointer-to-pointer // and will advance the dereferenced pointer by amount read. uint8_t ptp_read_uint8(void **dat); @@ -228,7 +230,7 @@ int ptp_check_opcode(struct PtpRuntime *r, int op); int ptp_check_prop(struct PtpRuntime *r, int code); // Duplicate array, return malloc'd buffer -struct UintArray * ptp_dup_uint_array(struct UintArray *arr); +struct UintArray *ptp_dup_uint_array(struct UintArray *arr); // Write r->data to a file called DUMP int ptp_dump(struct PtpRuntime *r); diff --git a/src/cl_data.h b/src/cl_data.h index 6c5615e..4d267ce 100644 --- a/src/cl_data.h +++ b/src/cl_data.h @@ -75,15 +75,6 @@ struct PtpStorageInfo { uint32_t free_objects; }; -struct ObjectRequest { - uint32_t storage_id; - uint32_t object_format; - uint32_t object_handle; - uint8_t all_storage_ids; - uint8_t all_formats; - uint8_t in_root; -}; - struct PtpObjectInfo { uint32_t storage_id; uint16_t obj_format; @@ -192,6 +183,13 @@ enum PtpMlBmpLvOption { PTP_ML_BMP_LV_GET_SPEC = 1, }; +enum PtpCHDKCommands { + PTP_CHDK_Version = 0, + PTP_CHDK_UploadFile = 5, +}; + +void *ptp_pack_chdk_upload_file(struct PtpRuntime *r, char *in, char *out, int *length); + // Response to struct FujiInitPacket struct PtpFujiInitResp { uint32_t x1; diff --git a/src/cl_ops.h b/src/cl_ops.h index a39190f..6c3be8f 100644 --- a/src/cl_ops.h +++ b/src/cl_ops.h @@ -83,6 +83,9 @@ int ptp_liveview_type(struct PtpRuntime *r); int ptp_ml_init_bmp_lv(struct PtpRuntime *r); int ptp_ml_get_bmp_lv(struct PtpRuntime *r, uint32_t **buffer_ptr); +int ptp_chdk_get_version(struct PtpRuntime *r); +int ptp_chdk_upload_file(struct PtpRuntime *r, char *input, char *dest); + // Fuji vendor version of SendObjectInfo - same as standard, but no parameters int ptp_fuji_send_object_info(struct PtpRuntime *r, struct PtpObjectInfo *oi); int ptp_fuji_send_object(struct PtpRuntime *r, struct PtpObjectInfo *oi, void *data, int length); diff --git a/src/data.c b/src/data.c index df5e98a..5dd2ee6 100644 --- a/src/data.c +++ b/src/data.c @@ -114,6 +114,7 @@ int ptp_parse_object_info(struct PtpRuntime *r, struct PtpObjectInfo *oi) { return 0; } +// TODO: Different API int ptp_pack_object_info(struct PtpRuntime *r, struct PtpObjectInfo *oi, void **dat, int max) { if (1024 > max) { return 0; @@ -139,6 +140,31 @@ int ptp_pack_object_info(struct PtpRuntime *r, struct PtpObjectInfo *oi, void ** return length; } +void *ptp_pack_chdk_upload_file(struct PtpRuntime *r, char *in, char *out, int *length) { + FILE *f = fopen(in, "rb"); + if (f == NULL) { + ptp_verbose_log("Unable to open %s\n", in); + return NULL; + } + + fseek(f, 0, SEEK_END); + long file_size = ftell(f); + fseek(f, 0, SEEK_SET); + + int size_all = 4 + strlen(out) + 1 + file_size; + *length = size_all; + char *data = malloc(size_all); + if (data == NULL) return NULL; + + void *d_ptr = (void *)data; + ptp_write_uint32(&d_ptr, strlen(out) + 1); + ptp_write_utf8_string(&d_ptr, out); + + fread(d_ptr, 1, file_size, f); + + return data; +} + int ptp_parse_device_info(struct PtpRuntime *r, struct PtpDeviceInfo *di) { // Skip packet header void *e = ptp_get_payload(r); diff --git a/src/ip.c b/src/ip.c index 722e8b0..ba1246e 100644 --- a/src/ip.c +++ b/src/ip.c @@ -98,7 +98,7 @@ int ptpip_new_timeout_socket(char *addr, int port) { if (so_error == 0) { ptp_verbose_log("Connection established %s:%d (%d)\n", addr, port, sockfd); - set_nonblocking_io(sockfd, 0); + set_nonblocking_io(sockfd, 0); // ???? return sockfd; } } diff --git a/src/libwpd.c b/src/libwpd.c index f1c04bd..aec229b 100644 --- a/src/libwpd.c +++ b/src/libwpd.c @@ -55,7 +55,7 @@ int ptp_device_open(struct PtpRuntime *r, struct PtpDeviceEntry *entry) { } int ptp_send_bulk_packets(struct PtpRuntime *r, int length) { - struct PtpCommand cmd; + struct LibWPDPtpCommand cmd; struct PtpBulkContainer *bulk = (struct PtpBulkContainer*)(r->data); if (bulk->type == PTP_PACKET_TYPE_COMMAND) { @@ -110,7 +110,7 @@ int ptp_receive_bulk_packets(struct PtpRuntime *r) { struct PtpBulkContainer *bulk = (struct PtpBulkContainer*)(r->data); if (bulk->type == PTP_PACKET_TYPE_COMMAND) { - struct PtpCommand cmd; + struct LibWPDPtpCommand cmd; int b = wpd_receive_do_data(&backend_wpd, &cmd, (uint8_t *)(r->data + 12), r->data_length - 12); if (b < 0) { return PTP_IO_ERR; diff --git a/src/libwpd.h b/src/libwpd.h index f183a28..29bddbd 100644 --- a/src/libwpd.h +++ b/src/libwpd.h @@ -16,6 +16,15 @@ typedef enum tagWPD_DEVICE_TYPES { WPD_DEVICE_TYPE_AUDIO_RECORDER = 6 }WPD_DEVICE_TYPES; +struct LibWPDPtpCommand { + int code; + + uint32_t params[5]; + int param_length; + + int data_length; +}; + // Initialize thread int wpd_init(int verbose, wchar_t *app_name); @@ -39,18 +48,18 @@ int wpd_get_device_type(struct WpdStruct *wpd); // Send command packet with no data packet, but expect data packet (device may not send data packet, that is fine) // Data packet should be recieved with wpd_receive_do_data -int wpd_receive_do_command(struct WpdStruct *wpd, struct PtpCommand *cmd); +int wpd_receive_do_command(struct WpdStruct *wpd, struct LibWPDPtpCommand *cmd); // Get data payload from device, if any. cmd struct will be filled with response packet. -int wpd_receive_do_data(struct WpdStruct *wpd, struct PtpCommand *cmd, uint8_t *buffer, int length); +int wpd_receive_do_data(struct WpdStruct *wpd, struct LibWPDPtpCommand *cmd, uint8_t *buffer, int length); // Send command packet with data phase, with no data packet response from device. Call wpd_send_do_data to get the response // and data packets -int wpd_send_do_command(struct WpdStruct* wpd, struct PtpCommand* cmd, int length); +int wpd_send_do_command(struct WpdStruct* wpd, struct LibWPDPtpCommand* cmd, int length); // Send the actual data packet, if wpd_send_do_command was called with length != 0 // cmd struct will be filled with the response packet -int wpd_send_do_data(struct WpdStruct* wpd, struct PtpCommand* cmd, uint8_t *buffer, int length); +int wpd_send_do_data(struct WpdStruct* wpd, struct LibWPDPtpCommand* cmd, uint8_t *buffer, int length); #endif diff --git a/src/packet.c b/src/packet.c index a94b7ff..6cd4176 100644 --- a/src/packet.c +++ b/src/packet.c @@ -233,7 +233,7 @@ int ptp_new_cmd_packet(struct PtpRuntime *r, struct PtpCommand *cmd) { } } -// Get data start packet, then data end packet, then response packet +// PTPIP: Get data start packet, then data end packet, then response packet static struct PtpIpResponseContainer *ptpip_get_response_packet(struct PtpRuntime *r) { struct PtpIpStartDataPacket *ds = (struct PtpIpStartDataPacket*)(r->data); if (ds->type == PTPIP_COMMAND_RESPONSE) { diff --git a/src/ptp.h b/src/ptp.h index be2d63b..c68d8fd 100644 --- a/src/ptp.h +++ b/src/ptp.h @@ -130,6 +130,7 @@ struct PtpIpEndDataPacket { #define PTP_OC_CANON_GetViewFinderImage 0x901D #define PTP_OC_CANON_LockUI 0x9004 #define PTP_OC_CANON_UnlockUI 0x9005 +#define PTP_OC_CANON_DoNothing 0x902F // EOS specific #define PTP_OC_EOS_GetStorageIDs 0x9101 @@ -157,6 +158,18 @@ struct PtpIpEndDataPacket { #define PTP_OC_EOS_AfCancel 0x9160 #define PTP_OC_EOS_SetDefaultSetting 0x91BE +#define PTP_OC_CANON_ceresCreateFileValue 0x91c1 +#define PTP_OC_CANON_ceresRemoveFileValue 0x91c2 +#define PTP_OC_CANON_ceresCloseFileValue 0x91c3 +#define PTP_OC_CANON_ceresGetWriteObject 0x91c4 +#define PTP_OC_CANON_ceresSEndReadObject 0x91c5 +#define PTP_OC_CANON_ceresFileAttributesValue 0x91c6 +#define PTP_OC_CANON_ceresFileTimeValue 0x91c7 +#define PTP_OC_CANON_ceresSeekFileValue 0x91c8 +#define PTP_OC_CANON_ceresCreateDirectoryValue 0x91c9 +#define PTP_OC_EOS_ceresSendFileInfo 0x91cb +#define PTP_OC_EOS_ceresSendFileInfoListEx 0x91cc + #define PTP_OC_EOS_EnableEventProc 0x9050 #define PTP_OC_EOS_ExecuteEventProc 0x9052 #define PTP_OC_EOS_GetEventProcReturnData 0x9053 @@ -609,6 +622,9 @@ struct PtpIpEndDataPacket { #define PTP_OC_ML_LiveBmpRam 0x9996 #define PTP_OC_ML_Live360x240 0x9997 +#define PTP_OC_MagicLantern 0x9998 +#define PTP_OC_CHDK 0x9999 + // Storage Types #define PTP_ST_Undefined 0x0 #define PTP_ST_FixedROM 0x1