diff --git a/camlibs/ptp2/config.c b/camlibs/ptp2/config.c index 548747320..5d33065b3 100644 --- a/camlibs/ptp2/config.c +++ b/camlibs/ptp2/config.c @@ -4016,6 +4016,69 @@ _put_Canon_EOS_ZoomPosition(CONFIG_PUT_ARGS) { return GP_OK; } +static int +_get_Canon_CHDK_Reboot(CONFIG_GET_ARGS) { + int val; + + gp_widget_new (GP_WIDGET_TOGGLE, _(menu->label), widget); + gp_widget_set_name (*widget, menu->name); + val = 2; /* always changed, unless we can find out the state ... */ + gp_widget_set_value (*widget, &val); + return (GP_OK); +} + +static int +_put_Canon_CHDK_Reboot(CONFIG_PUT_ARGS) { + int val, ret; + PTPParams *params = &(camera->pl->params); + + ret = gp_widget_get_value (widget, &val); + if (ret != GP_OK) + return ret; + if (val != 1) + return GP_OK; + ret = ptp_chdk_reboot (params); + return translate_ptp_result (ret); +} + +static int +_get_Canon_CHDK_Script(CONFIG_GET_ARGS) { + gp_widget_new (GP_WIDGET_RADIO, _(menu->label), widget); + gp_widget_set_name (*widget, menu->name); + + gp_widget_add_choice (*widget, "cls();exit_alt();"); + gp_widget_add_choice (*widget, "shoot();cls();exit_alt();"); + gp_widget_set_value (*widget, "cls();exit_alt();"); + return (GP_OK); +} + +static int +_put_Canon_CHDK_Script(CONFIG_PUT_ARGS) { + int ret; + char *val; + PTPParams *params = &(camera->pl->params); + uint32_t output; + char *scriptoutput; + + ret = gp_widget_get_value (widget, &val); + if (ret != GP_OK) + return ret; + ret = ptp_chdk_switch_mode (params, 1); + if (ret != PTP_RC_OK) + return translate_ptp_result (ret); +#if 0 + ret = ptp_chdk_exec_lua (params, val, &output); + if (ret != PTP_RC_OK) + return translate_ptp_result (ret); + fprintf(stderr,"output: 0x%08x\n", output); +#endif + ret = ptp_chdk_get_script_output (params, &scriptoutput); + if (ret != PTP_RC_OK) + return translate_ptp_result (ret); + fprintf(stderr,"script output: %s\n", scriptoutput); + return PTP_RC_OK; +} + static int _get_STR_as_time(CONFIG_GET_ARGS) { @@ -4825,7 +4888,9 @@ static struct submenu camera_actions_menu[] = { { N_("Canon EOS Zoom"), "eoszoom", 0, PTP_VENDOR_CANON, PTP_OC_CANON_EOS_Zoom, _get_Canon_EOS_Zoom, _put_Canon_EOS_Zoom}, { N_("Canon EOS Zoom Position"), "eoszoomposition", 0, PTP_VENDOR_CANON, PTP_OC_CANON_EOS_ZoomPosition, _get_Canon_EOS_ZoomPosition, _put_Canon_EOS_ZoomPosition}, { N_("Canon EOS Viewfinder"), "eosviewfinder", 0, PTP_VENDOR_CANON, PTP_OC_CANON_EOS_GetViewFinderData, _get_Canon_EOS_ViewFinder, _put_Canon_EOS_ViewFinder}, - { N_("Canon EOS Remote Release"), "eosremoterelease", 0, PTP_VENDOR_CANON, PTP_OC_CANON_EOS_RemoteReleaseOn, _get_Canon_EOS_RemoteRelease, _put_Canon_EOS_RemoteRelease}, + { N_("Canon EOS Remote Release"), "eosremoterelease", 0, PTP_VENDOR_CANON, PTP_OC_CANON_EOS_RemoteReleaseOn, _get_Canon_EOS_RemoteRelease, _put_Canon_EOS_RemoteRelease}, + { N_("CHDK Reboot"), "chdk_reboot", 0, PTP_VENDOR_CANON, PTP_OC_CHDK, _get_Canon_CHDK_Reboot, _put_Canon_CHDK_Reboot}, + { N_("CHDK Script"), "chdk_script", 0, PTP_VENDOR_CANON, PTP_OC_CHDK, _get_Canon_CHDK_Script, _put_Canon_CHDK_Script}, { 0,0,0,0,0,0,0 }, }; diff --git a/camlibs/ptp2/ptp.c b/camlibs/ptp2/ptp.c index 817e913f0..9dad82f59 100644 --- a/camlibs/ptp2/ptp.c +++ b/camlibs/ptp2/ptp.c @@ -2810,6 +2810,338 @@ ptp_mtp_setobjectproplist (PTPParams* params, MTPProperties *props, int nrofprop return ret; } +/****** CHDK interface ******/ + +uint16_t +ptp_chdk_get_memory(PTPParams* params, int start, int num, unsigned char **buf ) +{ + PTPContainer ptp; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CHDK; + ptp.Nparam=3; + ptp.Param1=PTP_CHDK_GetMemory; + ptp.Param2=start; + ptp.Param3=num; + return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, buf, NULL); +} + + +uint16_t +ptp_chdk_call(PTPParams* params, int *args, int size, int *ret) +{ + uint16_t r; + PTPContainer ptp; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CHDK; + ptp.Nparam=1; + ptp.Param1=PTP_CHDK_CallFunction; + + /* FIXME: check int packing */ + r=ptp_transaction(params, &ptp, PTP_DP_SENDDATA, size*sizeof(int), (unsigned char **) &args, NULL); + if ( r == PTP_RC_OK ) + return r; + if ( ret ) + *ret = ptp.Param1; + return r; +} + +uint16_t +ptp_chdk_get_propcase(PTPParams* params, int start, int num, int* ints) +{ + PTPContainer ptp; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CHDK; + ptp.Nparam=3; + ptp.Param1=PTP_CHDK_GetPropCase; + ptp.Param2=start; + ptp.Param3=num; + /* FIXME: unpack ints correctly */ + return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, (unsigned char**)ints, NULL); +} + +uint16_t +ptp_chdk_get_paramdata(PTPParams* params, int start, int num, unsigned char **buf) +{ + PTPContainer ptp; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CHDK; + ptp.Nparam=3; + ptp.Param1=PTP_CHDK_GetParamData; + ptp.Param2=start; + ptp.Param3=num; + return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, buf, NULL); +} + +#if 0 +int ptp_chdk_upload(char *local_fn, char *remote_fn, PTPParams* params, PTPDeviceInfo* deviceinfo) +{ + uint16_t ret; + PTPContainer ptp; + char *buf = NULL; + FILE *f; + int s,l; + struct stat st_buf; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CHDK; + ptp.Nparam=2; + ptp.Param1=PTP_CHDK_UploadFile; + + if (stat(local_fn, &st_buf)==0) ptp.Param2=st_buf.st_mtime-_timezone-_daylight; else ptp.Param2=0; + + f = fopen(local_fn,"rb"); + if ( f == NULL ) + { + ptp_error(params,"could not open file \'%s\'",local_fn); + return 0; + } + + + fseek(f,0,SEEK_END); + s = ftell(f); + fseek(f,0,SEEK_SET); + + l = strlen(remote_fn); + buf = malloc(4+l+s); + memcpy(buf,&l,4); + memcpy(buf+4,remote_fn,l); + fread(buf+4+l,1,s,f); + + fclose(f); + + ret=ptp_transaction(params, &ptp, PTP_DP_SENDDATA, 4+l+s, &buf); + + free(buf); + + if ( ret != 0x2001 ) + { + ptp_error(params,"unexpected return code 0x%x",ret); + return 0; + } + return 1; +} + +int ptp_chdk_download(char *remote_fn, char *local_fn, PTPParams* params, PTPDeviceInfo* deviceinfo) +{ + uint16_t ret; + PTPContainer ptp; + char *buf = NULL; + FILE *f; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CHDK; + ptp.Nparam=1; + ptp.Param1=PTP_CHDK_TempData; + ret=ptp_transaction(params, &ptp, PTP_DP_SENDDATA, strlen(remote_fn), &remote_fn); + if ( ret != 0x2001 ) + { + ptp_error(params,"unexpected return code 0x%x",ret); + return 0; + } + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CHDK; + ptp.Nparam=1; + ptp.Param1=PTP_CHDK_DownloadFile; + + ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &buf); + if ( ret != 0x2001 ) + { + ptp_error(params,"unexpected return code 0x%x",ret); + return 0; + } + + f = fopen(local_fn,"wb"); + if ( f == NULL ) + { + ptp_error(params,"could not open file \'%s\'",local_fn); + free(buf); + return 0; + } + + fwrite(buf,1,ptp.Param1,f); + fclose(f); + + free(buf); + + return 1; +} +#endif + +uint16_t +ptp_chdk_exec_lua(PTPParams* params, char *script, uint32_t *ret) +{ + uint16_t r; + PTPContainer ptp; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CHDK; + ptp.Nparam=1; + ptp.Param1=PTP_CHDK_ExecuteLUA; + r=ptp_transaction(params, &ptp, PTP_DP_SENDDATA, strlen(script)+1, (unsigned char**)&script, NULL); + if ( r != PTP_RC_OK ) + return r; + *ret = ptp.Param1; + return r; +} + +uint16_t +ptp_chdk_get_script_output(PTPParams* params, char** scriptoutput) { + PTPContainer ptp; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CHDK; + ptp.Nparam=1; + ptp.Param1=PTP_CHDK_GetScriptOutput; + return ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, (unsigned char **)scriptoutput, NULL); +} + +#if 0 +void ptp_chdk_opendir(char *dir, PTPParams* params, PTPDeviceInfo* deviceinfo){ + uint16_t ret; + PTPContainer ptp; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CHDK; + ptp.Nparam=1; + ptp.Param1=PTP_CHDK_OpenDir; + ret=ptp_transaction(params, &ptp, PTP_DP_SENDDATA, strlen(dir)+1, (char*)&dir); + if ( ret != 0x2001 ) + { + ptp_error(params,"unexpected return code 0x%x",ret); + return; + } +} + +void ptp_chdk_closedir(PTPParams* params, PTPDeviceInfo* deviceinfo){ + uint16_t ret; + PTPContainer ptp; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CHDK; + ptp.Nparam=1; + ptp.Param1=PTP_CHDK_CloseDir; + ret=ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL); + if ( ret != 0x2001 ) + { + ptp_error(params,"unexpected return code 0x%x",ret); + return; + } +} + +struct fileinfo* ptp_chdk_readdir(PTPParams* params, PTPDeviceInfo* deviceinfo){ + uint16_t ret; + PTPContainer ptp; + char* buf=NULL; + static struct fileinfo fi; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CHDK; + ptp.Nparam=1; + ptp.Param1=PTP_CHDK_ReadDir; + ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &buf); + if ( ret != 0x2001 ) + { + ptp_error(params,"unexpected return code 0x%x",ret); + return NULL; + } + if (buf){ + memcpy(&fi, buf, sizeof(fi)); + free(buf); + } + + return &fi; + +} + +void ptp_chdk_download_alt_end(PTPParams* params, PTPDeviceInfo* deviceinfo){ // internal use + uint16_t ret; + PTPContainer ptp; + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CHDK; + ptp.Nparam=1; + ptp.Param1=PTP_CHDK_EndDownloadFile; + ret=ptp_transaction(params, &ptp, PTP_DP_NODATA, 0, NULL); + if ( ret != 0x2001 ) ptp_error(params,"unexpected return code 0x%x",ret); +} + +int ptp_chdk_download_alt(char *remote_fn, char *local_fn, PTPParams* params, PTPDeviceInfo* deviceinfo) +{ + uint16_t ret; + PTPContainer ptp; + char *buf = NULL; + FILE *f; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CHDK; + ptp.Nparam=1; + ptp.Param1=PTP_CHDK_StartDownloadFile; + ret=ptp_transaction(params, &ptp, PTP_DP_SENDDATA, strlen(remote_fn)+1, &remote_fn); + if ( ret != 0x2001 ) + { + ptp_error(params,"unexpected return code 0x%x",ret); + return 0; + } + f = fopen(local_fn,"wb"); + if ( f == NULL ) + { + ptp_error(params,"could not open file \'%s\'",local_fn); + return 0; + } + + while(1) { + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CHDK; + ptp.Nparam=1; + ptp.Param1=PTP_CHDK_ResumeDownloadFile; + buf=NULL; + ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &buf); + if ( ret != 0x2001 ) + { + ptp_error(params,"unexpected return code 0x%x",ret); + ptp_chdk_download_alt_end(params, deviceinfo); + fclose(f); + return 0; + } + + if (ptp.Param1<=0){free(buf); break;} + fwrite(buf, 1, ptp.Param1, f); + free(buf); + } + fclose(f); + ptp_chdk_download_alt_end(params, deviceinfo); + return 1; +} +#endif + +uint16_t +ptp_chdk_get_video_settings(PTPParams* params, ptp_chdk_videosettings* vsettings) +{ + uint16_t ret; + PTPContainer ptp; + unsigned char* buf=NULL; + + PTP_CNT_INIT(ptp); + ptp.Code=PTP_OC_CHDK; + ptp.Nparam=1; + ptp.Param1=PTP_CHDK_GetVideoSettings; + ret=ptp_transaction(params, &ptp, PTP_DP_GETDATA, 0, &buf, NULL); + if ( ret != PTP_RC_OK ) + return ret; + if (buf) { + /* FIXME: endian convert */ + memcpy(vsettings, buf, sizeof(ptp_chdk_videosettings)); + free(buf); + } + return ret; +} + + + /* Non PTP protocol functions */ /* devinfo testing functions */ diff --git a/camlibs/ptp2/ptp.h b/camlibs/ptp2/ptp.h index 130d38bfe..d1210e0be 100644 --- a/camlibs/ptp2/ptp.h +++ b/camlibs/ptp2/ptp.h @@ -2602,7 +2602,7 @@ uint16_t ptp_nikon_getfileinfoinblock (PTPParams* params, uint32_t p1, uint32_t uint16_t ptp_mtp_getobjectpropssupported (PTPParams* params, uint16_t ofc, uint32_t *propnum, uint16_t **props); /* Non PTP protocol functions */ -static int +static inline int ptp_operation_issupported(PTPParams* params, uint16_t operation) { int i=0; @@ -2651,6 +2651,64 @@ uint16_t ptp_object_find_or_insert (PTPParams *params, uint32_t handle, PTPObjec /* ptpip.c */ void ptp_nikon_getptpipguid (unsigned char* guid); +enum { + PTP_CHDK_Shutdown = 0, // param2 is 0 (hard), 1 (soft), 2 (reboot) or 3 (reboot fw update) + // if param2 == 3, then filename of fw update is send as data (empty for default) + PTP_CHDK_GetMemory, // param2 is base address (or 0 for live image buffer, 1 for bitmap buffer) + // param3 is size (in bytes) + // return data is memory block + PTP_CHDK_SetMemoryLong, // param2 is address + // param3 is value + PTP_CHDK_CallFunction, // data is array of function pointer and (long) arguments (max: 10 args) + // return param1 is return value + PTP_CHDK_GetPropCase, // param2 is base id + // param3 is number of properties + // return data is array of longs + PTP_CHDK_GetParamData, // param2 is base id + // param3 is number of parameters + // return data is sequence of strings prefixed by their length (as long) + PTP_CHDK_TempData, // data is data to be stored for later + PTP_CHDK_UploadFile, // data is 4-byte length of filename, followed by filename and contents + PTP_CHDK_DownloadFile, // preceded by PTP_CHDK_TempData with filename + // return data are file contents + PTP_CHDK_SwitchMode, // param2 is 0 (playback) or 1 (record) + PTP_CHDK_ExecuteLUA, // data is script to be executed + PTP_CHDK_GetVideoSettings, + PTP_CHDK_GetScriptOutput, // return script output in ASCIIZ + PTP_CHDK_OpenDir, // open directory listing, data is directory name + PTP_CHDK_ReadDir, // return data is next file info + PTP_CHDK_CloseDir, // close directory listing + PTP_CHDK_GetShootingModesList, // not used + PTP_CHDK_StartDownloadFile, + PTP_CHDK_ResumeDownloadFile, + PTP_CHDK_EndDownloadFile, +} PTP_CHDK_Command; + +#define PTP_OC_CHDK 0x9999 +typedef struct tagptp_chdk_videosettings { + long live_image_buffer_width; + long live_image_width; + long live_image_height; + long bitmap_buffer_width; + long bitmap_width; + long bitmap_height; + unsigned palette[16]; +} ptp_chdk_videosettings; + +#define ptp_chdk_shutdown_hard(params) ptp_generic_no_data(params,PTP_OC_CHDK,2,PTP_CHDK_Shutdown,0) +#define ptp_chdk_shutdown_soft(params) ptp_generic_no_data(params,PTP_OC_CHDK,2,PTP_CHDK_Shutdown,1) +#define ptp_chdk_reboot(params) ptp_generic_no_data(params,PTP_OC_CHDK,2,PTP_CHDK_Shutdown,2) +#define ptp_chdk_reboot_fw_update(params) ptp_generic_no_data(params,PTP_OC_CHDK,2,PTP_CHDK_Shutdown,3) +uint16_t ptp_chdk_get_memory(PTPParams* params, int start, int num, unsigned char**); +#define ptp_chdk_set_memory_long(params,addr,val) ptp_generic_no_data(params,PTP_OC_CHDK,3,PTP_CHDK_SetMemoryLong,addr,val) +uint16_t ptp_chdk_call(PTPParams* params, int *args, int size, int *ret); +uint16_t ptp_chdk_get_propcase(PTPParams* params, int start, int num, int* ints); +uint16_t ptp_chdk_get_paramdata(PTPParams* params, int start, int num, unsigned char** x); +#define ptp_chdk_switch_mode(params,mode) ptp_generic_no_data(params,PTP_OC_CHDK,2,PTP_CHDK_SwitchMode,mode) +uint16_t ptp_chdk_exec_lua(PTPParams *params, char *script, uint32_t* ret); +uint16_t ptp_chdk_get_script_output(PTPParams* params, char **output ); +uint16_t ptp_chdk_get_video_settings(PTPParams* params, ptp_chdk_videosettings* vsettings); + #ifdef __cplusplus } #endif /* __cplusplus */