static int get_file_func (CameraFilesystem *fs, const char *folder, const char *filename, CameraFileType type, CameraFile *file, void *data, GPContext *context) { Camera *camera = data; int result = GP_ERROR_IO; enum { START, DATA, ABORT } state; int r, pid = 0, update = 0; uint64_t byteCount = 0; struct utimbuf mod_utime_buf = { 0, 0 }; char *path; struct tf_packet reply; if (type != GP_FILE_TYPE_NORMAL) return GP_ERROR_NOT_SUPPORTED; do_cmd_turbo (camera, "ON", context); path = get_path(camera, folder, filename); r = send_cmd_hdd_file_send(camera, GET, path, context); free (path); if(r < 0) goto out; state = START; while(0 < (r = get_tf_packet(camera, &reply, context))) { update = (update + 1) % 4; switch (get_u32(&reply.cmd)) { case DATA_HDD_FILE_START: if(state == START) { struct typefile *tf = (struct typefile *) reply.data; byteCount = get_u64(&tf->size); pid = gp_context_progress_start (context, byteCount, _("Downloading %s..."), filename); mod_utime_buf.actime = mod_utime_buf.modtime = tfdt_to_time(&tf->stamp); send_success(camera,context); state = DATA; } else { gp_log (GP_LOG_ERROR, "topfield", "ERROR: Unexpected DATA_HDD_FILE_START packet in state %d\n", state); send_cancel(camera,context); state = ABORT; } break; case DATA_HDD_FILE_DATA: if(state == DATA) { uint64_t offset = get_u64(reply.data); uint16_t dataLen = get_u16(&reply.length) - (PACKET_HEAD_SIZE + 8); int w; if (!update) { /* avoid doing it too often */ gp_context_progress_update (context, pid, offset + dataLen); if (gp_context_cancel (context) == GP_CONTEXT_FEEDBACK_CANCEL) { send_cancel(camera,context); state = ABORT; } } if(r < get_u16(&reply.length)) { gp_log (GP_LOG_ERROR, "topfield", "ERROR: Short packet %d instead of %d\n", r, get_u16(&reply.length)); /* TODO: Fetch the rest of the packet */ } w = gp_file_append (file, (char*)&reply.data[8], dataLen); if(w < GP_OK) { /* Can't write data - abort transfer */ gp_log (GP_LOG_ERROR, "topfield", "ERROR: Can not write data: %d\n", w); send_cancel(camera,context); state = ABORT; } } else { gp_log (GP_LOG_ERROR, "topfield", "ERROR: Unexpected DATA_HDD_FILE_DATA packet in state %d\n", state); send_cancel(camera,context); state = ABORT; } break; case DATA_HDD_FILE_END: send_success(camera,context); result = GP_OK; goto out; break; case FAIL: gp_log (GP_LOG_ERROR, "topfield", "ERROR: Device reports %s\n", decode_error(&reply)); send_cancel(camera,context); state = ABORT; break; case SUCCESS: goto out; break; default: gp_log (GP_LOG_ERROR, "topfield", "ERROR: Unhandled packet (cmd 0x%x)\n", get_u32(&reply.cmd)); break; } } if (pid) gp_context_progress_stop (context, pid); out: do_cmd_turbo (camera, "OFF", context); return result; }
int main(int argc, char *argv[]) { struct usb_device_descriptor devDesc; int fd = -1; int r; /* Initialise timezone handling. */ tzset(); register_printf_function('W', quote_xml, quote_xml_arginfo); lockFd = open("/tmp/puppy", O_CREAT, S_IRUSR | S_IWUSR); if(lockFd < 0) { fprintf(stderr, "ERROR: Can not open lock file /tmp/puppy: %s\n", strerror(errno)); return E_LOCK_FILE; } r = parseArgs(argc, argv); if(r != 0) { return E_INVALID_ARGS; } /* Create a lock, so that other instances of puppy can detect this one. */ if(0 != flock(lockFd, LOCK_SH | LOCK_NB)) { fprintf(stderr, "ERROR: Can not obtain shared lock on /tmp/puppy: %s\n", strerror(errno)); return E_GLOBAL_LOCK; } trace(2, fprintf(stderr, "cmd %04x on %s\n", cmd, devPath)); fd = open(devPath, O_RDWR); if(fd < 0) { fprintf(stderr, "ERROR: Can not open %s for read/write: %s\n", devPath, strerror(errno)); return E_READ_DEVICE; } if(0 != flock(fd, LOCK_EX | LOCK_NB)) { fprintf(stderr, "ERROR: Can not get exclusive lock on %s\n", devPath); close(fd); return E_DEVICE_LOCK; } r = read_device_descriptor(fd, &devDesc); if(r < 0) { close(fd); return E_READ_DEVICE; } if(!isToppy(&devDesc)) { fprintf(stderr, "ERROR: Could not find a Topfield TF5000PVRt\n"); close(fd); return E_NOT_TF5000PVR; } trace(1, fprintf(stderr, "Found a Topfield TF5000PVRt\n")); trace(2, fprintf(stderr, "USBDEVFS_RESET\n")); r = ioctl(fd, USBDEVFS_RESET, NULL); if(r < 0) { fprintf(stderr, "ERROR: Can not reset device: %s\n", strerror(errno)); close(fd); return E_RESET_DEVICE; } { int interface = 0; trace(2, fprintf(stderr, "USBDEVFS_CLAIMINTERFACE\n")); r = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &interface); if(r < 0) { fprintf(stderr, "ERROR: Can not claim interface 0: %s\n", strerror(errno)); close(fd); return E_CLAIM_INTERFACE; } } { struct usbdevfs_setinterface interface0 = { 0, 0 }; trace(2, fprintf(stderr, "USBDEVFS_SETNTERFACE\n")); r = ioctl(fd, USBDEVFS_SETINTERFACE, &interface0); if(r < 0) { fprintf(stderr, "ERROR: Can not set interface zero: %s\n", strerror(errno)); close(fd); return E_SET_INTERFACE; } } switch (cmd) { case CANCEL: r = do_cancel(fd); break; case CMD_RESET: r = do_cmd_reset(fd); break; case CMD_HDD_SIZE: r = do_hdd_size(fd); break; case CMD_HDD_DIR: r = do_hdd_dir(fd, arg1); break; case CMD_HDD_FILE_SEND: if(sendDirection == PUT) { r = do_hdd_file_put(fd, arg1, arg2); } else { r = do_hdd_file_get(fd, arg1, arg2); } break; case CMD_HDD_DEL: r = do_hdd_del(fd, arg1); break; case CMD_HDD_RENAME: r = do_hdd_rename(fd, arg1, arg2); break; case CMD_HDD_CREATE_DIR: r = do_hdd_mkdir(fd, arg1); break; case CMD_TURBO: r = do_cmd_turbo(fd, arg1); break; default: fprintf(stderr, "BUG: Command 0x%08x not implemented\n", cmd); r = -EINVAL; } { int interface = 0; ioctl(fd, USBDEVFS_RELEASEINTERFACE, &interface); close(fd); } return r; }