libgphoto2 icon indicating copy to clipboard operation
libgphoto2 copied to clipboard

Fuji X-T4: Local camera control / gp_camera_trigger_capture

Open trilader opened this issue 3 years ago • 27 comments

Describe the bug

I'm not sure if this is actually a bug report or either a feature request, development advice for a patch for me to submit or me just using libgphoto wrongly. By default libgphoto switches the camera to USB control which disables all local controls on the camera.

What I want to do I want to have a user of a software be able to locally control the camera (press the trigger, use the remote release via the 2,5mm TRS jack, change settings on the camera). As well as programatically trigger the camera from the software using gp_camera_trigger_capture.

What I've tried I found out that camera_prepare_capture DPC 0xd207 gets set to 2 which is USB mode. By default it's set to 1 which I assume is camera mode. It also gets set back to that in camera_unprepare_capture. When I remove the setting of it to 2 in camera_prepare_capture the local camera controls work as expected and when the camera gets triggered either by the remote shutter release input or the shutter button the camera takes a picture, libgphoto detects it and the software downloads it to the computer.

What doesn't work without USB control mode is gp_camera_trigger_capture. In it, after fixing the type of the wait for propval 0xd212 loop from UINT64 to UINT16, the ptp_initiatecapture after triggering the focus action fails with 'PTP Device Busy' (0x2019).

I've tried to work around that by setting 0xd207 to 2 before focusing the camera, which works and allows the rest of gp_camera_trigger_capture to work normally, and then resetting it at the end so the user can control the camera again, which failed with 'PTP Device Busy' (0x2019).

My current idea is that the issue with changing the mode back is because the camera just took an image and isn't ready to switch back before it was transferred/removed as the mode can be changed back in unprepare_capture after the image was removed from the camera.

~~It that is the case I think something like the uilock config option for Canon camera might be a good idea.~~ I've experimented with adding a configuration option for the control mode property. Manually changing it to USB works but changing it back directly after either triggering the camera or directly after downloading the image doesn't work but about 50ms to 100ms after the image was downloaded does work. It indeed looks like there is some process on the camera that needs to finish before the mode can be changed back.

I've also noticed that I'm having issues with gp_camera_trigger_capture when taking the first picture after camera power on (no mode changes have been done in this case):

Test program output
Debug: libgphoto2[camera_wait_for_event]: waiting for events timeout 250 ms
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1007 (Get object handles) (0xffffffff,0x0,0x0) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1007 (Get object handles) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1007 (Get object handles) response...
Debug: libgphoto2[gp_port_get_timeout]: Current port timeout is 20000 milliseconds.
Debug: libgphoto2[gp_port_set_timeout]: Setting port timeout to 150 milliseconds.
Debug: libgphoto2[gp_port_set_timeout]: Setting port timeout to 20000 milliseconds.
Debug: libgphoto2[camera_wait_for_event]: waiting for events timeout 250 ms
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1007 (Get object handles) (0xffffffff,0x0,0x0) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1007 (Get object handles) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1007 (Get object handles) response...
Debug: libgphoto2[gp_port_get_timeout]: Current port timeout is 20000 milliseconds.
Debug: libgphoto2[gp_port_set_timeout]: Setting port timeout to 150 milliseconds.
Debug: libgphoto2[gp_port_set_timeout]: Setting port timeout to 20000 milliseconds.
Debug: libgphoto2[camera_wait_for_event]: waiting for events timeout 250 ms
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1007 (Get object handles) (0xffffffff,0x0,0x0) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1007 (Get object handles) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1007 (Get object handles) response...
Debug: libgphoto2[gp_port_get_timeout]: Current port timeout is 20000 milliseconds.
Debug: libgphoto2[gp_port_set_timeout]: Setting port timeout to 150 milliseconds.
Debug: libgphoto2[gp_port_set_timeout]: Setting port timeout to 20000 milliseconds.
Debug: libgphoto2[camera_wait_for_event]: waiting for events timeout 250 ms
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1007 (Get object handles) (0xffffffff,0x0,0x0) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1007 (Get object handles) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1007 (Get object handles) response...
Debug: libgphoto2[gp_port_get_timeout]: Current port timeout is 20000 milliseconds.
Debug: libgphoto2[gp_port_set_timeout]: Setting port timeout to 150 milliseconds.
Debug: libgphoto2[gp_port_set_timeout]: Setting port timeout to 20000 milliseconds.
Debug: libgphoto2[camera_trigger_capture]: camera_trigger_capture
Debug: libgphoto2[camera_trigger_capture]: Triggering capture to , autofocus=0
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1016 (Set device property value) (0xd208) request...
Debug: libgphoto2[ptp_usb_senddata]: Sending PTP_OC 0x1016 (Set device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1016 (Set device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x100e (Initiate capture) (0x0,0x0) request...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x100e (Initiate capture) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd209) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd209) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd209) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd209) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd209) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd209) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd209) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd209) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd209) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd209) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd209) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd209) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd209) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd209) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd209) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd209) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd209) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd209) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd209) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd209) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd209) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd209) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd209) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd209) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd209) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1016 (Set device property value) (0xd208) request...
Debug: libgphoto2[ptp_usb_senddata]: Sending PTP_OC 0x1016 (Set device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1016 (Set device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x100e (Initiate capture) (0x0,0x0) request...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x100e (Initiate capture) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1015 (Get device property value) (0xd212) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1015 (Get device property value) data...
Debug: libgphoto2[_cb_irq]: 0x6110000285d8 with status 0
Debug: libgphoto2[_cb_irq]: Requeuing completed transfer 0x6110000285d8
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1015 (Get device property value) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x100e (Initiate capture) (0x0,0x0) request...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x100e (Initiate capture) response...
Warning: libgphoto2[ptp_usb_getresp [usb.c:515]]: PTP_OC 0x100e receiving resp failed: PTP General Error (0x2002)
Warning: libgphoto2[camera_trigger_capture [library.c:6398]]: 'ptp_initiatecapture(params, 0x00000000, 0x00000000)' failed: 'PTP General Error' (0x2002)
Warning: libgphoto2[gp_context_error]: PTP General Error
Warning: libgphoto2[gp_camera_trigger_capture [gphoto2-camera.c:1369]]: 'camera->functions->trigger_capture (camera, context)' failed: -1
Debug: libgphoto2[camera_wait_for_event]: waiting for events timeout 250 ms
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1007 (Get object handles) (0xffffffff,0x0,0x0) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1007 (Get object handles) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1007 (Get object handles) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1008 (Get object info) (0x1) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1008 (Get object info) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1008 (Get object info) response...
Debug: libgphoto2[get_folder_from_handle]: (10000001,0,/store_10000001/)
Debug: libgphoto2[gp_filesystem_append]: Append /store_10000001/DSCF0001.jpg to filesystem
Debug: libgphoto2[lookup_folder]: Lookup folder '/store_10000001'...
Debug: libgphoto2[lookup_folder]: Folder / is dirty. Listing folders in there to make folder clean...
Debug: libgphoto2[gp_filesystem_list_folders]: Listing folders in /
Debug: libgphoto2[lookup_folder]: Lookup folder '/'...
Debug: libgphoto2[lookup_folder]: Found! / is 0x60400000f550
Debug: libgphoto2[gp_filesystem_list_folders]: ... is dirty, getting from camera
Debug: libgphoto2[folder_list_func]: folder_list_func(/)
Debug: libgphoto2[delete_all_folders]: Internally deleting all folders from '/'...
Debug: libgphoto2[lookup_folder]: Lookup folder '/'...
Debug: libgphoto2[lookup_folder]: Found! / is 0x60400000f550
Debug: libgphoto2[recurse_delete_folder]: Recurse delete folder 0x60400000f550//
Debug: libgphoto2[append_folder_one]: Append one folder store_10000001
Debug: libgphoto2[append_folder_one]: Append one folder store_10000002
Debug: libgphoto2[gp_filesystem_list_folders]: Folder / contains 2 subfolders.
Debug: libgphoto2[lookup_folder]: Done making folder / clean...
Debug: libgphoto2[gp_filesystem_list_files]: Listing files in /store_10000001
Debug: libgphoto2[lookup_folder]: Lookup folder '/store_10000001'...
Debug: libgphoto2[gp_filesystem_list_files]: Querying folder /store_10000001...
Debug: libgphoto2[delete_all_files]: Delete all files in folder 0x6040000285d0/store_10000001
Debug: libgphoto2[file_list_func]: file_list_func(/store_10000001)
Debug: libgphoto2[file_list_func]: after list folder
Debug: libgphoto2[debug_objectinfo]: ObjectInfo for 'DSCF0001.jpg':
Debug: libgphoto2[debug_objectinfo]:   Object ID: 0x00000001
Debug: libgphoto2[debug_objectinfo]:   StorageID: 0x10000001
Debug: libgphoto2[debug_objectinfo]:   ObjectFormat: 0x3801
Debug: libgphoto2[debug_objectinfo]:   ProtectionStatus: 0x0000
Debug: libgphoto2[debug_objectinfo]:   ObjectCompressedSize: 10451723
Debug: libgphoto2[debug_objectinfo]:   ThumbFormat: 0x3801
Debug: libgphoto2[debug_objectinfo]:   ThumbCompressedSize: 29223
Debug: libgphoto2[debug_objectinfo]:   ThumbPixWidth: 0
Debug: libgphoto2[debug_objectinfo]:   ThumbPixHeight: 0
Debug: libgphoto2[debug_objectinfo]:   ImagePixWidth: 0
Debug: libgphoto2[debug_objectinfo]:   ImagePixHeight: 0
Debug: libgphoto2[debug_objectinfo]:   ImageBitDepth: 0
Debug: libgphoto2[debug_objectinfo]:   ParentObject: 0x00000000
Debug: libgphoto2[debug_objectinfo]:   AssociationType: 0x0007
Debug: libgphoto2[debug_objectinfo]:   AssociationDesc: 0x00000000
Debug: libgphoto2[debug_objectinfo]:   SequenceNumber: 0x00000000
Debug: libgphoto2[debug_objectinfo]:   ModificationDate: 0x00000000
Debug: libgphoto2[debug_objectinfo]:   CaptureDate: 0x6081428b
Debug: libgphoto2[gp_filesystem_list_files]: Added 'DSCF0001.jpg'
Debug: libgphoto2[internal_append]: Internal append DSCF0001.jpg to folder store_10000001
Debug: libgphoto2[gp_filesystem_list_files]: Listed 'DSCF0001.jpg'
Debug: libgphoto2[internal_append]: Internal append DSCF0001.jpg to folder store_10000001
Debug: libgphoto2[gp_camera_file_get]: Getting file 'DSCF0001.jpg' in folder '/store_10000001'...
Debug: libgphoto2[gp_filesystem_get_file_impl]: Getting file 'DSCF0001.jpg' from folder '/store_10000001' (type 1)...
Debug: libgphoto2[lookup_folder_file]: Lookup folder /store_10000001 file DSCF0001.jpg
Debug: libgphoto2[lookup_folder]: Lookup folder '/store_10000001'...
Debug: libgphoto2[gp_filesystem_get_file_impl]: Downloading 'DSCF0001.jpg' from folder '/store_10000001'...
Debug: libgphoto2[get_file_func]: Getting file 'DSCF0001.jpg'.
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x101b (Get partial object) (0x1,0x0,0x100000) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x101b (Get partial object) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x101b (Get partial object) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x101b (Get partial object) (0x1,0x100000,0x100000) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x101b (Get partial object) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x101b (Get partial object) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x101b (Get partial object) (0x1,0x200000,0x100000) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x101b (Get partial object) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x101b (Get partial object) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x101b (Get partial object) (0x1,0x300000,0x100000) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x101b (Get partial object) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x101b (Get partial object) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x101b (Get partial object) (0x1,0x400000,0x100000) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x101b (Get partial object) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x101b (Get partial object) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x101b (Get partial object) (0x1,0x500000,0x100000) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x101b (Get partial object) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x101b (Get partial object) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x101b (Get partial object) (0x1,0x600000,0x100000) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x101b (Get partial object) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x101b (Get partial object) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x101b (Get partial object) (0x1,0x700000,0x100000) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x101b (Get partial object) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x101b (Get partial object) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x101b (Get partial object) (0x1,0x800000,0x100000) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x101b (Get partial object) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x101b (Get partial object) response...
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x101b (Get partial object) (0x1,0x900000,0xf7b0b) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x101b (Get partial object) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x101b (Get partial object) response...
Debug: Camera: File /store_10000001DSCF0001.jpg added
Debug: Size: 10451723 bytes
Debug: libgphoto2[gp_camera_file_delete]: Deleting file 'DSCF0001.jpg' in folder '/store_10000001'...
Debug: libgphoto2[lookup_folder_file]: Lookup folder /store_10000001 file DSCF0001.jpg
Debug: libgphoto2[lookup_folder]: Lookup folder '/store_10000001'...
Debug: libgphoto2[gp_filesystem_delete_file]: Deleting 'DSCF0001.jpg' from folder '/store_10000001'...
Debug: libgphoto2[gp_port_get_timeout]: Current port timeout is 20000 milliseconds.
Debug: libgphoto2[gp_port_set_timeout]: Setting port timeout to 150 milliseconds.
Debug: libgphoto2[gp_port_set_timeout]: Setting port timeout to 20000 milliseconds.
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x100b (Delete object) (0x1,0x0) request...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x100b (Delete object) response...
Debug: libgphoto2[camera_wait_for_event]: waiting for events timeout 250 ms
Debug: libgphoto2[ptp_usb_sendreq]: Sending PTP_OC 0x1008 (Get object info) (0x1) request...
Debug: libgphoto2[ptp_usb_getdata]: Reading PTP_OC 0x1008 (Get object info) data...
Debug: libgphoto2[ptp_usb_getresp]: Reading PTP_OC 0x1008 (Get object info) response...
Warning: libgphoto2[ptp_usb_getresp [usb.c:515]]: PTP_OC 0x1008 receiving resp failed: PTP Invalid Object Handle (0x2009)
Warning: libgphoto2[camera_wait_for_event [library.c:7191]]: 'ptp_object_want (params, event.Param1, PTPOBJECT_OBJECTINFO_LOADED, &ob)' failed: 'PTP Invalid Object Handle' (0x2009)
Warning: libgphoto2[gp_context_error]: PTP Invalid Object Handle
Warning: libgphoto2[gp_camera_wait_for_event [gphoto2-camera.c:1450]]: 'camera->functions->wait_for_event ( camera, timeout, eventtype, eventdata, context)' failed: -1

After the that failure all future calls to gp_trigger_camera work as expected until the camera is rebooted.

Name the camera Fuji Fujifilm X-T4 usb:002,029 Bus 002 Device 029: ID 04cb:02e6 Fuji Photo Film Co., Ltd USB PTP Camera

libgphoto2 and gphoto2 version I'm using libgphoto2 on the master branch based of ff6013b.

To Reproduce I'm using a simple test program which opens the camera, starts polling events for 5 seconds and after 1 second of that calls gp_camera_trigger_capture and after the loop exits the camera. I can provide if it you think it's helpful.

trilader avatar Apr 21 '21 17:04 trilader

I've investigated some more and made some progress.

In the output of my test application you can see that the final ptp_initiatecapture inside camera_trigger_capture fails. I've noticed that (at least the X-T4) still works without the final ptp_initiatecapture call. I'm not sure if that is a quirk of my camera or if it's true for all Fuji cameras.

The "PTP Invalid Object Handle" was caused by libgphoto2 trying to deal with object 1 twice. The Fuji camera code in camera_wait_for_event says:

/* current strategy ... as the camera (currently) does not send us ObjectAdded events for some reason...
		 * we just synthesize them for the generic PTP event handler code */

Which is usually true except (at least the X-T4) for the very first capture after plugging the camera in by USB which sends such an event, resulting object 1 getting processed twice which fails the second time as the object isn't necessarily there anymore (my example code downloads and deletes it as soon as the first file added event gets to the application).

To work around the duplicate object added event I've set PTPBUG_DELETE_SENDS_EVENT for the X-T4 as a workaroud so the gp_file_delete in the file added handler drains the extra event without libgphoto2 trying to handle it later. That works with the way my application behaves but is very far from ideal and/or practical and especially not a general case solution.

Could anyone check if other Fuji cameras behave the same way?

What would be a good solution to implement these quirks?

trilader avatar Jun 09 '21 12:06 trilader

Hi @trilader I'm very interested in progressing X-T4 support for gphoto and would love to help you out on this. Are you working on a fork of libgphoto2? Could you share your code or invite me to your fork?

riccardolardi avatar Jun 15 '21 09:06 riccardolardi

Hi. I've added my workarounds / hacks to a branch in my repo. My goal is to get this merged upstream once it's not a pile of hacks anymore and someone has verified it doesn't break non X-T4 Fuji cameras. USB is mostly working, PTP/IP is not and has, from what I can tell by looking at Wireshark captures, changed a lot from what is implemented in libgphoto2 at the moment.

trilader avatar Jun 15 '21 10:06 trilader

I've also put the Wireshark dissector and a test driver program for the X-T4 into https://github.com/trilader/x-t4-hacking

trilader avatar Jun 15 '21 11:06 trilader

Hi. I've added my workarounds / hacks to a branch in my repo. My goal is to get this merged upstream once it's not a pile of hacks anymore and someone has verified it doesn't break non X-T4 Fuji cameras. USB is mostly working, PTP/IP is not and has, from what I can tell by looking at Wireshark captures, changed a lot from what is implemented in libgphoto2 at the moment.

Thanks a lot @trilader

  • Is there a list of broken stuff / todos for the X-T4?
  • Is there no way to only target the X-T4 specifically for your workarounds? I believe it could take a while to verify the fixes for every Fuji camera currently supported by gphoto. Maybe working on model specific fixes could speed up development progress

riccardolardi avatar Jun 15 '21 11:06 riccardolardi

I will see if i can help merging any changes.

I would need to rent a Fuji camera to test, currently lacking the time to do so.

msmeissn avatar Jun 15 '21 11:06 msmeissn

i went over your commits and merged the okay ones. I fixed up the initiatecapture one differetnly in a followup commit.

2 can be improved if you want to test:

+get_Fuji_CurrentState -> can be done simpler, just use this 1 line addition: { N("Current State"), "currentstate", PTP_DPC_FUJI_CurrentState, PTP_VENDOR_FUJI, PTP_DTC_UINT16, _get_INT, _put_None },

if you want to look at the integer value. (needs no seperate function)

In the HACK: patch

  •   if (DELETE_SENDS_EVENT(params) &&
    
  •   if (params->deviceinfo.VendorExtensionID == PTP_VENDOR_FUJI) ||
    
  •       DELETE_SENDS_EVENT(params) &&
    

you can add PTPBUG_DELETE_SENDS_EVENT to the Fuji X-T4 in the camera list line instead.

msmeissn avatar Jun 15 '21 11:06 msmeissn

@msmeissn Thanks a lot for merging some stuff already!

Regarding the "Current State" property: Not sure if that really needs to be exposed. I am/was using it to figure out when it is save to switch back from USB to camera control mode after using camera_trigger_capture which fails with local control active. I've tried to do it automatically in camera_trigger_capture but it looks like I can't switch it back with an image pending for download so it has to be done by the application. For now I'm just switching to USB before calling camera_trigger_capture and back to local after the file was downloaded.

Regarding the HACK patch: I don't think adding PTPBUG_DELETE_SENDS_EVENT would be a smart idea. The camera doesn't actually send the event on delete. It just fixes the issue I'm having in a way that fits with the pattern my application uses. The real fix would likely be to just ignore the real ObjectAdded event from the camera and only rely on the synthesized ones as they are reliable and don't depend on USB just being plugged in.

trilader avatar Jun 15 '21 12:06 trilader

@riccardolardi Regarding stuff being broken: I think it is mainly PTP/IP which seem to have completely changed from the way it is currently implemented. I don't know what was looked at for the old implementation. Looking at traffic from Fuji XAcquire in Wireshark shows it's not using the separate event and jpeg connections that the current libgphoto2 implementation uses but does everything (control, events and image transfer) over the control socket. The init commands that are currently being sent are no longer used and report operation not supported when you try to send them.

Regarding what is TODO: I've tested image capture/download and setting parameters such as ISO and fStop as well as White Balance. I've not tested movie recording or other things.

I don't know how much of that is X-T4 specific as I currently only have access to that Fuji camera. I assume the current PTP/IP implementation works with whatever camera/software combination it was developed with / modeled after.

trilader avatar Jun 15 '21 12:06 trilader

yeah fuji ptpip ... is very wild and weird. this was a wild ride to implement first :/ without camera problematic.

I think USB might be much safer to use

msmeissn avatar Jun 15 '21 12:06 msmeissn

@trilader I have an X-S10 that I'm trying to get working with gphoto2 (2.X version of the camera FW, which seems to have completely broken most of how things used to work) so I'll likely be able to provide a data point for what's X-T4 specific soon.

mdietz avatar Jul 14 '22 17:07 mdietz

What's the current state of these changes? I'm having the same issue where --capture-tethered leaves my XT-4 in an unresponsive state, I'm guessing due to the issues around local vs usb control discussed at the top of the thread.

I've built the current gphoto2 hoping that the merged changes would have helped, but alas. I would love to contribute, but am unsure where to pick up the work.

bocajnotnef avatar Nov 03 '23 03:11 bocajnotnef

Actually, I'm starting to get my bearings here.

It looks like the change @trilader was talking about to get local control working during tethering is here. If I change that constant to 0x0001 then I can start a capture with gphoto --capture-tethered and local camera controls (including the shutter!) work.

I also experience the problem where gphoto errors out and the camera's transfer light stays stuck blinking. I did successfully get a jpeg image, so I'm wondering if the camera also tries to send down the .raf RAW file and we're not set up to handle that, gphoto errors, and the camera gets stuck in a bad state trying to talk to someone who's no longer listening.

It's a little strange because when triggering a capture (e.g. in Darktable), I pulled the jpeg and the .raf, so I suspect we have the capability to handle both somewhere, I just have to find it.

(I also recognize that just blindly changing that constant isn't a total solution; it solves my use case, where I want to shoot and control with the camera buttons and just have everything automatically transfer to my laptop so I can review easily, but others will likely want remote control of settings to still work)

I'll continue investigating.

bocajnotnef avatar Nov 03 '23 04:11 bocajnotnef

If I set my camera to save raw only, no jpeg, I get a different error and nothing downloads:

*** Error ***              
PTP I/O Error
ERROR: Could not get image.
*** Error (-7: 'I/O problem') *** 

I'm taking this as confirmation of my theory that it's choking on the RAF transfer.

Attaching an excerpt of the log file, minus a ton of hex dumps, that seems to contain interesting info.

log_excerpt.txt

Notably, it's aware that it's trying to download the RAF; it reads almost as if there's an error transferring the file on the camera's end. I'm gonna have to go figure out what a -7 return from gp_filesystem_get_file means.

bocajnotnef avatar Nov 03 '23 04:11 bocajnotnef

I'm currently using gphoto (based on master, a bit outdated, at 48d9baf) with just this commit from my x-t4 branch applied on top of it. After opening the camera I set it to local control mode config_set_string_value("prioritymode", GP_WIDGET_MENU, "Camera");

To trigger the camera from the application I'm doing

if(is_fuji && !fuji_needs_controlmode_reset)
{
    fuji_needs_controlmode_reset = true;
    config_set_string_value("prioritymode", GP_WIDGET_MENU, "USB");
}
GP_CHECK(gp_camera_trigger_capture(cam, context));

to trigger it. After the file has been downloaded (by seeing the file added event and handling it) I reset the control mode back to camera control.

if(is_fuji && fuji_needs_controlmode_reset)
{
    fuji_needs_controlmode_reset = false;
    QThread::msleep(100);
    config_set_string_value("prioritymode", GP_WIDGET_MENU, "Camera");
}

I've not tested anything regarding capturing multiple files with one trigger (either by the application or the user pressing the button on the camera / using the TRS jack) and don't have access to the camera at the moment as it is from work and at another location.

trilader avatar Nov 03 '23 09:11 trilader

okay, another update; I suspect we're not properly handling the file download.

The source of that "I/O problem" is here in usb.c where we're validating the announced packet size vs the actual size we got. Here's the gdb output from within ptp_usb_getpacket:

(gdb) p *rlen
$1 = 1024
(gdb) p packet->length
$2 = 1048588
(gdb) p maxsize
$3 = 1024
(gdb) p packet->type
$4 = 2
(gdb) p packet->code
$5 = 4123

so apparently we're getting ~1MB of data when we're expecting a max of 1024 bytes. (there's notes at the top of ptp.h about max packet sizes, but I'm not certain how reliable they are vs what I'm seeing in Wireshark). I have no idea what the packet type or code params mean right now--I'll look them up in the morning.

My guess about what's happening is we're listening for a packet and we're being handed data. I'm not completely sure why that's happening; according to the log files we're expecting to be downloading the RAF file:

Download of 'DSCF0001.raf' from '/store_10000001' (type 1) failed. Reason: 'I/O problem'

I'm currently running my camera in RAW only, so there should only be the one file to download, which does away with my theory about it being the second file download that's causing problems. I don't know why we'd be choking on RAWs either, but I'll take another crack at it tomorrow.

I can share the pcap if it'd be useful for people, but I believe it's incomplete since the camera seems to hang with the transfer light still blinking.

bocajnotnef avatar Nov 04 '23 04:11 bocajnotnef

@trilader I've never used a custom dissector before in Wireshark--is there a trick to parsing my captured USB traffic with your dissector? online docs aren't proving as helpful as I'd hoped. I have the dissector loaded in Wireshark but am having difficulty convincing Wireshark to use it.

I also found this repo of dissectors that also claims to handle Fuji PTP--again, I can get them to load, and Wireshark will now annotate some of the USB packet as PTP data, but it doesn't continue to break it down as fujifilm ptp data. I'm at a loss.

image

notably, none of my custom dissectors are listed as an option when trying to "Decode as..." when selecting off the USB protocol.

As an aside, glancing through the dissectors they do agree that a packet type of 2 is a data packet, which supports my theory that we're parsing a data packet with a packet-packet parser and that's causing our I/O error.

bocajnotnef avatar Nov 04 '23 04:11 bocajnotnef

I've never used a custom dissector before in Wireshark--is there a trick to parsing my captured USB traffic with your dissector? online docs aren't proving as helpful as I'd hoped. I have the dissector loaded in Wireshark but am having difficulty convincing Wireshark to use it.

The reason the dissector in my x-t4-hacking repo fails to decode (or attach to) any of your USB capture is because it is for Fuji PTPIP which is spoken over TCP port 15740. I think the speak more or less the same protocol via USB though.

Here is some code from a different, USB based dissector I have laying around:

Part of a dissector for Logitech HID++ that could make a good base for adapting the dissector for USB
local function heuristic(tvbuf)
    -- The checks below are for Logitech HID++. NOT FOR FUJI USB
    --[[-- Checks the packet length and makes sure it's one of short, long, very_long
    if tvbuf:captured_len() ~= 20 then
        return false
    end

    -- Checks against the first byte (length descriptor)
    if not (tvbuf:range(0, 1):uint() == 0x11) then
        return false
    end

    return true--]]
    return false
end

local function heuristic_dissector_request(tvbuf, pktinfo, root)
    if tvbuf:captured_len() < 8 then
        return false
    end
    tvbuf = tvbuf:range(7):tvb()

    if not heuristic(tvbuf) then
        return false
    end

    -- Okay, it's our packet probably. Call the dissector.
    dissector_request(tvbuf, pktinfo, root)
    return true
end

local function heuristic_dissector_response(tvbuf, pktinfo, root)
    if not heuristic(tvbuf) then
        return false
    end

    -- Okay, it's our packet probably. Call the dissector.
    dissector_response(tvbuf, pktinfo, root)
    return true
end

fujiptpip:register_heuristic("usb.control", heuristic_dissector_request) -- Not sure which usb transfer types are correct
fujiptpip:register_heuristic("usb.interrupt", heuristic_dissector_response)

I hope this is useful to you.

trilader avatar Nov 04 '23 07:11 trilader

log_excerpt shows some 0 reads where they were unexpected, a bit more debugging above would be useful. (or a full log)

msmeissn avatar Nov 04 '23 09:11 msmeissn

@msmeissn apologies, here is a full log-level=all log (compressed to reduce size). Again, camera was configured to capture in raw-only, and I have some local changes to allow local release on the camera.

raw_only.zip

There's also someone experiencing similar issues reporting in the gphoto2 repository--they included a log in their comment as well, though I haven't verified it's the same exact behavior (issue with file download) as opposed to just issues with remote release.

I'll be free later today to do some more debugging, hopefully.

bocajnotnef avatar Nov 04 '23 16:11 bocajnotnef

okay, fired up the debugger and did some looking around:

Breakpoint 1, ptp_usb_getpacket (params=params@entry=0x5555555c3b00, packet=packet@entry=0x7fffffff95c0, rlen=rlen@entry=0x7fffffff95bc, maxsize=1024) at ptp2/usb.c:249
249				GP_LOG_D ( "wtf");
(gdb) bt
#0  ptp_usb_getpacket (params=params@entry=0x5555555c3b00, packet=packet@entry=0x7fffffff95c0, rlen=rlen@entry=0x7fffffff95bc, maxsize=1024) at ptp2/usb.c:249
#1  0x00007ffff7a74ba0 in ptp_usb_getdata (params=0x5555555c3b00, ptp=0x7fffffff9ab0, handler=0x7fffffff9a50) at ptp2/usb.c:279
#2  0x00007ffff7a43adc in ptp_transaction_new (params=params@entry=0x5555555c3b00, ptp=ptp@entry=0x7fffffff9ab0, flags=flags@entry=2, sendlen=sendlen@entry=0, 
    handler=handler@entry=0x7fffffff9a50) at ptp2/ptp.c:237
#3  0x00007ffff7a43cb9 in ptp_transaction (params=params@entry=0x5555555c3b00, ptp=ptp@entry=0x7fffffff9ab0, flags=flags@entry=2, sendlen=sendlen@entry=0, 
    data=data@entry=0x7fffffff9b70, recvlen=recvlen@entry=0x7fffffff9b60) at ptp2/ptp.c:475
#4  0x00007ffff7a48cfc in ptp_getpartialobject (params=params@entry=0x5555555c3b00, handle=handle@entry=1, offset=offset@entry=0, maxbytes=maxbytes@entry=1048576, 
    object=object@entry=0x7fffffff9b70, len=len@entry=0x7fffffff9b60) at ptp2/ptp.c:2457
#5  0x00007ffff7a70127 in get_file_func (fs=<optimized out>, folder=<optimized out>, filename=<optimized out>, type=<optimized out>, file=0x5555555c4e70, 
    data=<optimized out>, context=0x55555557c0b0) at ptp2/library.c:9044
#6  0x00007ffff7f4af84 in gp_filesystem_get_file_impl (context=0x55555557c0b0, file=0x5555555c4e70, type=GP_FILE_TYPE_NORMAL, filename=0x5555555c4360 "DSCF0001.raf", 
    folder=0x5555555c4e50 "/store_10000001", fs=0x55555557b650) at gphoto2-filesys.c:1580
#7  gp_filesystem_get_file (fs=0x55555557b650, folder=folder@entry=0x5555555c4e50 "/store_10000001", filename=filename@entry=0x5555555c4360 "DSCF0001.raf", 
    type=type@entry=GP_FILE_TYPE_NORMAL, file=file@entry=0x5555555c4e70, context=context@entry=0x55555557c0b0) at gphoto2-filesys.c:1633
#8  0x00007ffff7f43752 in gp_camera_file_get (camera=camera@entry=0x55555557a340, folder=folder@entry=0x5555555c4e50 "/store_10000001", 
    file=file@entry=0x5555555c4360 "DSCF0001.raf", type=type@entry=GP_FILE_TYPE_NORMAL, camera_file=0x5555555c4e70, context=context@entry=0x55555557c0b0)
    at gphoto2-camera.c:1692
#9  0x0000555555566e5f in save_file_to_file (camera=0x55555557a340, context=0x55555557c0b0, flags=FLAGS_RECURSE, folder=folder@entry=0x5555555c4e50 "/store_10000001", 
    filename=filename@entry=0x5555555c4360 "DSCF0001.raf", type=type@entry=GP_FILE_TYPE_NORMAL) at main.c:660
#10 0x0000555555567225 in get_file_common (arg=arg@entry=0x5555555c45c0 "DSCF0001.raf", type=type@entry=GP_FILE_TYPE_NORMAL) at main.c:750
#11 0x000055555556173f in action_camera_wait_event (p=p@entry=0x555555579420 <gp_params>, downloadtype=downloadtype@entry=DT_DOWNLOAD, arg=arg@entry=0x0) at actions.c:1271
#12 0x0000555555568d5a in cb_arg_run (opt=<optimized out>, opt=<optimized out>, ctx=<optimized out>, reason=<optimized out>, params=0x7fffffffa7f4, arg=0x0) at main.c:1846
#13 cb_arg (ctx=<optimized out>, reason=<optimized out>, opt=<optimized out>, arg=0x0, data=0x7fffffffa7f4) at main.c:1887
#14 0x00007ffff7f01fa7 in ?? () from /lib/x86_64-linux-gnu/libpopt.so.0
#15 0x00007ffff7f02036 in ?? () from /lib/x86_64-linux-gnu/libpopt.so.0
#16 0x00007ffff7f062e8 in poptGetNextOpt () from /lib/x86_64-linux-gnu/libpopt.so.0
#17 0x000055555555ccd0 in main (argc=6, argv=0x7fffffffe018, envp=<optimized out>) at main.c:2570

what's currently of interest to me is we have a ptp_fujiptpip_getdata function, even with specific notes about the XT-4 and empty events, but we're invoking the generic ptp_usb_getdata one instead.

Continuing to dig, just gotta get more of my GDB legs back under me.

bocajnotnef avatar Nov 07 '23 03:11 bocajnotnef

Oh, I see, ptp_fujiptpip is the network shenanigans, hence why we're falling back to the ptp_usb_getdata routine since this is over USB. Of course.

bocajnotnef avatar Nov 07 '23 03:11 bocajnotnef

the partialobject read seems to fail.

you can try to disable that: in camlibs/ptp2/library.c look for line 9028 "We also need this for ... " and just comment out this if block to avoid a getpartialobject read here.

msmeissn avatar Nov 07 '23 10:11 msmeissn

@msmeissn @rheimbuch looks like your latest commits on master solved all my issues; I have local release on my xt4 and both JPG and RAW download following the shot. Thanks so much!

bocajnotnef avatar Nov 10 '23 01:11 bocajnotnef

@bocajnotnef @msmeissn oh funny, I didn't expect to see these commits show up here. It looks like you've incorporated most of the fixes I made for the xt-4. I pulled up my old notes for these issues, and I'll leave this bit here in case it's useful to anyone dealing with the xt-4:

the internal shot buffer is not a filesystem, and is incredibly fragile. You must always and only delete images from the shot buffer from first to last in lexicographic order by filename. If you delete in any other order the camera will hang requiring the complete removal of the battery to restore the camera to normal operation.

The commit to synthesize the object-added events in the correct order fixes this for triggered capture with immediate transfer, but you must still be aware of this behavior if you wish to separate triggering from image transfer and deletion.

rheimbuch avatar Nov 10 '23 05:11 rheimbuch

@rheimbuch i have rented and Xt4 for a day and currently merged NorthOfYou branch changes related to Fuji XT while able to test it, and took quite some of your code. I saw the ordering change you refered to and merged that. I did not yet see to Association tagging trouble, and that change was a bit too hacky for me so far.

msmeissn avatar Nov 10 '23 09:11 msmeissn

@msmeissn Agreed, the association tagging fix was a gross hack. My memory of the issue is incomplete, but I believe it arose primarily when attempting to walk the filesystem. However NoY’s usage was probably not typical, so this may not be an issue for most users, or (hopefully) it may have been fixed in later firmware versions.

rheimbuch avatar Nov 10 '23 15:11 rheimbuch