I've made some good progress and I think it's time to share some of what I've learned. I went ahead and purchased the Arduino board and USB host shield that I posted in my last post. The first thing I found out is that my test camera (an SD870) won't acknowledge a USB host unless it senses 5v on the VBUS line. That required a modification to the USB host shield, detailed here in the hardware manual for the USB host shield:
http://www.circuitsathome.com/usb-host-shield-hardware-manualFrom there, it doesn't take much modification at all to get the PTP code provided with the host shield to get the Arduino talking to CHDK. The only functionality I've added so far is the ability to send Lua to the camera to be executed. This will provide all of the functionality that I need for my project, but adding support for the other CHDK-specific PTP commands should be pretty trivial. I've now got functions written that put the camera into record mode and capture a photo by sending Lua instead of using PTP operations.
I started with canonps.cpp from the USB host shield PTP library and am modifying the CanonPS class. CHDK's ptp.h needs to be included (and probably renamed first so that it isn't named the same thing as the ptp lib's ptp.h) for any of this to work. A couple of functions were added:
//Captures an image
uint16_t CanonPSCHDK::Capture()
{
uint16_t ptp_error;
char script[] = "shoot();";
OperFlags flags = { 2, 2, 1, 1, 3, 0};
uint32_t params[2];
params[0] = PTP_CHDK_ExecuteScript;
params[1] = PTP_CHDK_SL_LUA;
flags.dataSize = 9;//script.length()+1;
ptp_error = Transaction(PTP_OC_CHDK, &flags, params, &script);
return ptp_error;
}
I intend to have this function set record or play mode based on the number passed to it. It's still a work in progress
//Puts the camera into record or play mode
uint16_t CanonPSCHDK::SetRecordMode(int mode)
{
uint16_t ptp_error;
char script[] = "switch_mode_usb(1);";
OperFlags flags = { 2, 2, 1, 1, 3, 0};
uint32_t params[2];
params[0] = PTP_CHDK_ExecuteScript;
params[1] = PTP_CHDK_SL_LUA;
flags.dataSize = 20;//script.length()+1;
ptp_error = Transaction(PTP_OC_CHDK, &flags, params, &script);
return ptp_error;
}
I also changed the Initialize function so that it uses Lua instead of straight PTP:
uint16_t CanonPSCHDK::Initialize(bool binit)
{
uint16_t ptp_error;
if (binit)
{
if ((ptp_error = SetRecordMode(1)) != PTP_RC_OK)
PTPTRACE2("StartShootingMode failed: ", ptp_error);
}
else
{
if ((ptp_error = SetRecordMode(0)) != PTP_RC_OK)
PTPTRACE2("EndShootingMode failed: ", ptp_error);
}
return ptp_error;
}
The meat-and-potatoes of this is the Transaction function, which is defined in ptp.cpp and ptp.h. The hard part of this was basically deciding how to call it and with what parameters. I'll break it down a little bit here.
uint16_t PTP::Transaction(uint16_t opcode, OperFlags *flags, uint32_t *params = NULL, void *pVoid = NULL)
opcode: The opcode of the function that you want to call. The supported ptp and CHDK ptp operations are defined in their respective ptp.h files.
OperFlags is a data type that contains a number of parameters for the operation you're running. Its submembers are:
- opParams: the number of parameters to involved in the operation
- rsParams: the number of parameters that are returned from the operation
- txOperation: defines whether you're the host or receiver is sending data
- typeOfVoid: defines the type of the operation's data. 3 means the data is a buffer
- dataSize: The number of bytes in your data buffer
params: This should be an array which contains the parameters of the operation. What these are depends on the operation. Operation parameters are defined in the PTP specification or in CHDK's ptp.h
pVoid: This should be a pointer to the first element of your data buffer. I've found that trying to pass an actual string type doesn't work. Use a character array instead. The operations on strings and char arrays are similar.
Some of this might require some knowledge of the PTP specification in order to make sense of it. I recommend finding a copy of PIMA15740-2000 on Google. This has the formal definition of all of the canonical PTP operations and should give you some idea of what's expected in a PTP transaction. I also found it very useful to look at the source code for chdkptp (
http://trac.assembla.com/chdkptp) for examples.
Sorry it's been so long between replies. I'm pretty busy with other stuff, this is just one of the projects on my plate right now. I need to figure out file transfers now. I intend to release the full source of everything once I'm finished adding new functionality, as well as some more formal documentation.
The timing of your post was almost uncanny, DavidBowman. I had actually just sat down to start writing this post when you replied.
Whew, I think that's everything. I'd be happy to attempt to answer questions about what I've learned so far if you're trying to do something similar.