"Fossies" - the Fresh Open Source Software Archive

Member "libgphoto2-2.5.27/camlibs/ptp2/chdk.c" (21 Feb 2021, 40566 Bytes) of package /linux/privat/libgphoto2-2.5.27.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "chdk.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.5.26_vs_2.5.27.

    1 /* chdk.c
    2  *
    3  * Copyright (C) 2015 Marcus Meissner <marcus@jet.franken.de>
    4  *
    5  * This library is free software; you can redistribute it and/or
    6  * modify it under the terms of the GNU Lesser General Public
    7  * License as published by the Free Software Foundation; either
    8  * version 2 of the License, or (at your option) any later version.
    9  *
   10  * This library is distributed in the hope that it will be useful,
   11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   13  * Lesser General Public License for more details.
   14  *
   15  * You should have received a copy of the GNU Lesser General Public
   16  * License along with this library; if not, write to the
   17  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   18  * Boston, MA  02110-1301  USA
   19  */
   20 
   21 #include "config.h"
   22 
   23 #include <stdlib.h>
   24 #include <math.h>
   25 #include <string.h>
   26 #include <stdio.h>
   27 #include <stdarg.h>
   28 #include <time.h>
   29 
   30 #ifdef HAVE_LIBJPEG
   31 #  include <jpeglib.h>
   32 #endif
   33 
   34 #include <gphoto2/gphoto2-library.h>
   35 #include <gphoto2/gphoto2-port-log.h>
   36 #include <gphoto2/gphoto2-setting.h>
   37 
   38 #ifdef ENABLE_NLS
   39 #  include <libintl.h>
   40 #  undef _
   41 #  define _(String) dgettext (GETTEXT_PACKAGE, String)
   42 #  ifdef gettext_noop
   43 #    define N_(String) gettext_noop (String)
   44 #  else
   45 #    define N_(String) (String)
   46 #  endif
   47 #else
   48 #  define textdomain(String) (String)
   49 #  define gettext(String) (String)
   50 #  define dgettext(Domain,Message) (Message)
   51 #  define dcgettext(Domain,Message,Type) (Message)
   52 #  define bindtextdomain(Domain,Directory) (Domain)
   53 #  define _(String) (String)
   54 #  define N_(String) (String)
   55 #endif
   56 
   57 #include "ptp.h"
   58 #include "ptp-bugs.h"
   59 #include "ptp-private.h"
   60 #include "ptp-pack.c"
   61 
   62 /* CHDK support */
   63 
   64 /* Include the rlibs.lua lua libs or try do it on our own? */
   65 
   66 /* capture:
   67  * send LUA:
   68  * init_usb_capture(0); is exiting capture
   69 
   70  * init_usb_capture(1,0,0)  1 = jpeg, 2 = raw, 4 = switch raw to dng
   71  *
   72  * ff_imglist(options)
   73 
   74  * return ls('path'[,'opts')
   75 
   76  * return ff_download(srcpaths[,ropts])
   77  *
   78  * return ff_mdelete(paths)
   79  *
   80  * return os.stat(path)
   81  * return os.utime(path)
   82  * return os.mkdir(path)
   83  * return os.remove(path)
   84  * return mkdir_m(path(s))
   85 
   86  * rs_init for starting usb shootinp
   87  */
   88 
   89 static int
   90 chdk_generic_script_run (
   91     PTPParams *params, const char *luascript,
   92     char **table, int *retint, GPContext *context
   93 ) {
   94     int         ret = GP_OK;
   95     int             scriptid = 0;
   96     unsigned int        status;
   97     int         luastatus;
   98     ptp_chdk_script_msg *msg = NULL;
   99     char            *xtable = NULL;
  100     int         xint = -1;
  101 
  102     if (!table) table = &xtable;
  103     if (!retint) retint = &xint;
  104 
  105     GP_LOG_D ("calling lua script %s", luascript);
  106     C_PTP (ptp_chdk_exec_lua(params, (char*)luascript, 0, &scriptid, &luastatus));
  107     GP_LOG_D ("called script. script id %d, status %d", scriptid, luastatus);
  108 
  109     *table = NULL;
  110     *retint = -1;
  111 
  112     while (1) {
  113         C_PTP (ptp_chdk_get_script_status(params, &status));
  114         GP_LOG_D ("script status %x", status);
  115 
  116         if (status & PTP_CHDK_SCRIPT_STATUS_MSG) {
  117             C_PTP (ptp_chdk_read_script_msg(params, &msg));
  118             GP_LOG_D ("message script id %d, type %d, subtype %d", msg->script_id, msg->type, msg->subtype);
  119             switch (msg->type) {
  120             case PTP_CHDK_S_MSGTYPE_RET:
  121             case PTP_CHDK_S_MSGTYPE_USER:
  122                 switch (msg->subtype) {
  123                 case PTP_CHDK_TYPE_UNSUPPORTED: GP_LOG_D("unsupported");break;
  124                 case PTP_CHDK_TYPE_NIL: GP_LOG_D("nil");break;
  125                 case PTP_CHDK_TYPE_BOOLEAN:
  126                     *retint = msg->data[0]; /* 3 more bytes, but rest are not interestng for bool */
  127                     GP_LOG_D("boolean %d", *retint);
  128                     break;
  129                 case PTP_CHDK_TYPE_INTEGER:
  130                     GP_LOG_D("int %02x %02x %02x %02x", msg->data[0], msg->data[1], msg->data[2], msg->data[3]);
  131                     *retint = le32atoh((unsigned char*)msg->data);
  132                     break;
  133                 case PTP_CHDK_TYPE_STRING:
  134                     GP_LOG_D("string %s", msg->data);
  135                     if (*table) {
  136                         *table = realloc(*table,strlen(*table)+strlen(msg->data)+1);
  137                         strcat(*table,msg->data);
  138                     } else {
  139                         *table = strdup(msg->data);
  140                     }
  141                     break;
  142                 case PTP_CHDK_TYPE_TABLE:
  143                     GP_LOG_D("table %s", msg->data);
  144                     if (*table) {
  145                         *table = realloc(*table,strlen(*table)+strlen(msg->data)+1);
  146                         strcat(*table,msg->data);
  147                     } else {
  148                         *table = strdup(msg->data);
  149                     }
  150                     break;
  151                 default: GP_LOG_E("unknown chdk msg->type %d", msg->subtype);break;
  152                 }
  153                 break;
  154             case PTP_CHDK_S_MSGTYPE_ERR:
  155                 GP_LOG_D ("error %d, message %s", msg->subtype, msg->data);
  156                 gp_context_error(context, _("CHDK lua engine reports error: %s"), msg->data);
  157                 ret = GP_ERROR_BAD_PARAMETERS;
  158                 break;
  159             default:
  160                 GP_LOG_E ("unknown msg->type %d", msg->type);
  161                 break;
  162             }
  163             free (msg);
  164         }
  165 
  166         if (!status) /* this means we read out all messages */
  167             break;
  168 
  169         /* wait for script to finish */
  170         if (status & PTP_CHDK_SCRIPT_STATUS_RUN)
  171             usleep(100*1000); /* 100 ms */
  172     }
  173     if (xtable)
  174         GP_LOG_E("a string return was unexpected, returned value: %s", xtable);
  175     if (xint != -1)
  176         GP_LOG_E("a int return was unexpected, returned value: %d", xint);
  177     return ret;
  178 }
  179 
  180 
  181 static int
  182 chdk_list_func (CameraFilesystem *fs, const char *folder, CameraList *list,
  183                 void *data, GPContext *context, int dirsonly)
  184 {
  185     Camera *camera = (Camera *)data;
  186     PTPParams       *params = &camera->pl->params;
  187     int         retint = FALSE;
  188     int         ret;
  189     int         tablecnt;
  190     /* return ls("A/path/"); */
  191     const char      *luascript = PTP_CHDK_LUA_LS"\nreturn ls('A%s',{\nstat='*',\n})";
  192     char            *lua = NULL;
  193     char            *t, *table = NULL;
  194     char            *xfolder;
  195 
  196     /* strip leading / of folders, except for the root folder */
  197     xfolder=strdup(folder);
  198     if (strlen(folder)>2 && (xfolder[strlen(xfolder)-1] == '/'))
  199         xfolder[strlen(xfolder)-1] = '\0';
  200 
  201     C_MEM (lua = malloc(strlen(luascript)+strlen(xfolder)+1));
  202 
  203     sprintf(lua,luascript,xfolder);
  204     free(xfolder);
  205 
  206     ret = chdk_generic_script_run (params, lua, &table, &retint, context);
  207     free (lua);
  208     if (ret != GP_OK)
  209         return ret;
  210     if (table) {
  211         t = table;
  212     /* table {[1]="NIKON001.DSC",[2]="DCIM",[3]="MISC",[4]="DISKBOOT.BIN",[5]="CHDK",[6]="changelog.txt",[7]="vers.req",[8]="readme.txt",[9]="PS.FI2",} */
  213 
  214     /* table {[1]={is_file=true,mtime=1402161416,name="NIKON001.DSC",ctime=1402161416,attrib=34,is_dir=false,size=512,},[2]={is_file=false,mtime=1402161416,name="DCIM",ctime=1402161416,attrib=16,is_dir=true,size=0,},[3]={is_file=false,mtime=1406460938,name="MISC",ctime=1406460938,attrib=16,is_dir=true,size=0,},[4]={is_file=true,mtime=1398564982,name="DISKBOOT.BIN",ctime=1423347896,attrib=32,is_dir=false,size=138921,},[5]={is_file=false,mtime=1423347900,name="CHDK",ctime=1423347900,attrib=16,is_dir=true,size=0,},[6]={is_file=true,mtime=1395026402,name="changelog.txt",ctime=1423347900,attrib=32,is_dir=false,size=2093,},[7]={is_file=true,mtime=1217623956,name="vers.req",ctime=1423347900,attrib=32,is_dir=false,size=107,},[8]={is_file=true,mtime=1398564982,name="readme.txt",ctime=1423347900,attrib=32,is_dir=false,size=10518,},[9]={is_file=true,mtime=1398564982,name="PS.FI2",ctime=1423347900,attrib=32,is_dir=false,size=80912,},}
  215 */
  216 
  217 nexttable:
  218         if (*t != '{')
  219             return GP_ERROR;
  220         t++;
  221         tablecnt = 0;
  222         while (*t) {
  223             int cnt;
  224             char *name = NULL;
  225             int isfile = 0, mtime = 0, attrib = -1, ctime = 0, size = -1;
  226             CameraFileInfo info;
  227 
  228             if (*t++ != '[') {
  229                 GP_LOG_E("expected [, have %c", t[-1]);
  230                 break;
  231             }
  232             if (!sscanf(t,"%d",&cnt)) {
  233                 GP_LOG_E("expected integer");
  234                 break;
  235             }
  236             GP_LOG_D("parsing entry %d", cnt);
  237             if (cnt != tablecnt + 1) {
  238                 GP_LOG_E("cnt %d, tablecnt %d, expected %d", cnt, tablecnt, tablecnt+1);
  239                 break;
  240             }
  241             tablecnt++;
  242             t = strchr(t,']');
  243             if (!t) {
  244                 GP_LOG_E("expected ]");
  245                 break;
  246             }
  247             t++;
  248             if (*t++ != '=') {
  249                 GP_LOG_E("expected =");
  250                 break;
  251             }
  252             /* {is_file=true,mtime=1402161416,name="NIKON001.DSC",ctime=1402161416,attrib=34,is_dir=false,size=512,} */
  253             if (*t++ != '{') {
  254                 GP_LOG_E("expected {");
  255                 break;
  256             }
  257             memset(&info,0,sizeof(info));
  258             while (*t && *t != '}') {
  259                 /* GP_LOG_D("parsing %s", t); */
  260                 if (t==strstr(t,"is_file=true")) { isfile = TRUE; }
  261                 if (t==strstr(t,"is_file=false")) { isfile = FALSE; }
  262                 if (t==strstr(t,"is_dir=true")) { isfile = FALSE; }
  263                 if (t==strstr(t,"is_dir=false")) { isfile = TRUE; }
  264                 if (t==strstr(t,"name=\"")) {
  265                     char *s;
  266                     name = t+strlen("name=.");
  267                     s = strchr(name,'"');
  268                     if (s) *s='\0';
  269                     name = strdup(name);
  270                     GP_LOG_D("name is %s", name);
  271                     *s = '"';
  272                 }
  273                 if (sscanf(t,"mtime=%d,", &mtime)) {
  274                     info.file.mtime = mtime;
  275                     info.file.fields |= GP_FILE_INFO_MTIME;
  276                 }
  277                 if (sscanf(t,"size=%d,", &size)) {
  278                     info.file.size = size;
  279                     info.file.fields |= GP_FILE_INFO_SIZE;
  280                 }
  281                 if (!sscanf(t,"ctime=%d,", &ctime)) { }
  282                 if (!sscanf(t,"attrib=%d,", &attrib)) { }
  283                 t = strchr(t,',');
  284                 if (t) t++;
  285             }
  286             if (*t)
  287                 t++;
  288             /* Directories: return as list. */
  289             if (dirsonly && !isfile)
  290                 gp_list_append (list, name, NULL);
  291 
  292             /* Files: Add directly to FS, including the meta info too. */
  293             if (!dirsonly && isfile) {
  294                 gp_filesystem_append(fs, folder, name, context);
  295                 gp_filesystem_set_info_noop(fs, folder, name, info, context);
  296             }
  297             free(name);
  298 
  299             if (*t++ != ',') {
  300                 GP_LOG_E("expected , got %c", t[-1]);
  301                 break;
  302             }
  303             if (*t == '}') { t++; break; }
  304         }
  305         if (*t) {
  306             if (*t == '{') goto nexttable;
  307             GP_LOG_E("expected end of string or { , got %s", t);
  308             return GP_ERROR;
  309         }
  310         free (table);
  311         table = NULL;
  312     }
  313     if (retint)
  314         return GP_OK;
  315     GP_LOG_E("boolean return from LUA ls was %d", retint);
  316     return GP_ERROR;
  317 }
  318 
  319 static int
  320 chdk_file_list_func (CameraFilesystem *fs, const char *folder, CameraList *list,
  321                 void *data, GPContext *context)
  322 {
  323     return chdk_list_func(fs,folder,list,data,context,FALSE);
  324 }
  325 
  326 
  327 static int
  328 chdk_folder_list_func (CameraFilesystem *fs, const char *folder, CameraList *list,
  329                   void *data, GPContext *context)
  330 {
  331     return chdk_list_func(fs,folder,list,data,context,TRUE);
  332 }
  333 
  334 static int
  335 chdk_get_info_func (CameraFilesystem *fs, const char *folder, const char *filename,
  336                CameraFileInfo *info, void *data, GPContext *context)
  337 {
  338     Camera *camera = (Camera *)data;
  339     PTPParams       *params = &camera->pl->params;
  340     int         retint = 0;
  341     int         ret;
  342     char            *table = NULL;
  343     const char      *luascript = "\nreturn os.stat('A%s/%s')";
  344     char            *lua = NULL;
  345 
  346     C_MEM (lua = malloc(strlen(luascript)+strlen(folder)+strlen(filename)+1));
  347     sprintf(lua,luascript,folder,filename);
  348     ret = chdk_generic_script_run (params, lua, &table, &retint, context);
  349     free (lua);
  350     if (table) {
  351         char *t = table;
  352         int x;
  353         while (*t) {
  354             if (sscanf(t,"mtime %d", &x)) {
  355                 info->file.fields |= GP_FILE_INFO_MTIME;
  356                 info->file.mtime = x;
  357             }
  358             if (sscanf(t,"size %d", &x)) {
  359                 info->file.fields |= GP_FILE_INFO_SIZE;
  360                 info->file.size = x;
  361             }
  362             t = strchr(t,'\n');
  363             if (t) t++;
  364         }
  365         free (table);
  366     }
  367     return ret;
  368 }
  369 
  370 static int
  371 chdk_delete_file_func (CameraFilesystem *fs, const char *folder,
  372                         const char *filename, void *data, GPContext *context)
  373 {
  374     Camera *camera = (Camera *)data;
  375     PTPParams       *params = &camera->pl->params;
  376     int         ret;
  377     const char      *luascript = "\nreturn os.remove('A%s/%s')";
  378     char            *lua = NULL;
  379 
  380     C_MEM (lua = malloc(strlen(luascript)+strlen(folder)+strlen(filename)+1));
  381     sprintf(lua,luascript,folder,filename);
  382     ret = chdk_generic_script_run (params, lua, NULL, NULL, context);
  383     free (lua);
  384     return ret;
  385 }
  386 
  387 static int
  388 chdk_get_file_func (CameraFilesystem *fs, const char *folder, const char *filename,
  389                CameraFileType type, CameraFile *file, void *data,
  390                GPContext *context)
  391 {
  392         Camera          *camera = data;
  393     PTPParams       *params = &camera->pl->params;
  394     uint16_t            ret;
  395     PTPDataHandler      handler;
  396     char            *fn;
  397 
  398     fn = malloc(1+strlen(folder)+1+strlen(filename)+1),
  399     sprintf(fn,"A%s/%s",folder,filename);
  400     ptp_init_camerafile_handler (&handler, file);
  401     ret = ptp_chdk_download(params, fn, &handler);
  402     free (fn);
  403     ptp_exit_camerafile_handler (&handler);
  404     if (ret == PTP_ERROR_CANCEL)
  405         return GP_ERROR_CANCEL;
  406     C_PTP_REP (ret);
  407     return GP_OK;
  408 }
  409 
  410 
  411 static CameraFilesystemFuncs chdk_fsfuncs = {
  412     .file_list_func         = chdk_file_list_func,
  413     .folder_list_func       = chdk_folder_list_func,
  414     .get_info_func          = chdk_get_info_func,
  415     .get_file_func          = chdk_get_file_func,
  416     .del_file_func          = chdk_delete_file_func,
  417 /*
  418     .set_info_func          = chdk_set_info_func,
  419     .read_file_func         = chdk_read_file_func,
  420     .put_file_func          = chdk_put_file_func,
  421     .make_dir_func          = chdk_make_dir_func,
  422     .remove_dir_func        = chdk_remove_dir_func,
  423     .storage_info_func      = chdk_storage_info_func
  424 */
  425 };
  426 
  427 static int
  428 camera_prepare_chdk_capture(Camera *camera, GPContext *context) {
  429     PTPParams       *params = &camera->pl->params;
  430     int         ret = 0, retint = 0;
  431     char            *table = NULL;
  432     char            *lua =
  433 PTP_CHDK_LUA_SERIALIZE
  434 "if not get_mode() then\n\
  435     switch_mode_usb(1)\n\
  436     local i=0\n\
  437     while not get_mode() and i < 300 do\n\
  438         sleep(10)\n\
  439         i=i+1\n\
  440     end\n\
  441     if not get_mode() then\n\
  442         return false, 'switch failed'\n\
  443     end\n\
  444     return true\n\
  445 end\n\
  446 return false,'already in rec'\n\
  447 ";
  448 
  449     ret = chdk_generic_script_run (params, lua, &table, &retint, context);
  450     if(table) GP_LOG_D("table returned: %s\n", table);
  451     free(table);
  452     return ret;
  453 }
  454 
  455 static int
  456 camera_unprepare_chdk_capture(Camera *camera, GPContext *context) {
  457     PTPParams       *params = &camera->pl->params;
  458     int             ret, retint;
  459     char            *table;
  460     char            *lua =
  461 PTP_CHDK_LUA_SERIALIZE
  462 "if get_mode() then\n\
  463     switch_mode_usb(0)\n\
  464     local i=0\n\
  465     while get_mode() and i < 300 do\n\
  466         sleep(10)\n\
  467         i=i+1\n\
  468     end\n\
  469     if get_mode() then\n\
  470         return false, 'switch failed'\n\
  471     end\n\
  472     return true\n\
  473 end\n\
  474 return false,'already in play'\n\
  475 ";
  476     ret = chdk_generic_script_run (params, lua, &table, &retint, context);
  477     if(table) GP_LOG_D("table returned: %s\n", table);
  478     free(table);
  479 
  480     return ret;
  481 }
  482 
  483 
  484 static int
  485 chdk_camera_about (Camera *camera, CameraText *text, GPContext *context)
  486 {
  487         snprintf (text->text, sizeof(text->text),
  488          _("PTP2 / CHDK driver\n"
  489            "(c) 2015-%d by Marcus Meissner <marcus@jet.franken.de>.\n"
  490            "This is a PTP subdriver that supports CHDK using Canon cameras.\n"
  491            "\n"
  492            "Enjoy!"), 2015);
  493         return GP_OK;
  494 }
  495 
  496 static int
  497 chdk_camera_summary (Camera *camera, CameraText *text, GPContext *context)
  498 {
  499     PTPParams   *params = &camera->pl->params;
  500     int         ret;
  501     char        *s = text->text;
  502     int     major, minor, retint;
  503 
  504     C_PTP (ptp_chdk_get_version (params, &major, &minor));
  505         sprintf (s, _("CHDK %d.%d Status:\n"), major, minor ); s += strlen(s);
  506 
  507     ret = chdk_generic_script_run (params, "return get_mode()", NULL, &retint, context);
  508     sprintf (s, _("Mode: %d\n"), retint); s += strlen(s);
  509     ret = chdk_generic_script_run (params, "return get_sv96()", NULL, &retint, context);
  510     sprintf (s, _("SV96: %d, ISO: %d\n"), retint, (int)(exp2(retint/96.0)*3.125)); s += strlen(s);
  511     ret = chdk_generic_script_run (params, "return get_tv96()", NULL, &retint, context);
  512     sprintf (s, _("TV96: %d, Shutterspeed: %f\n"), retint, 1.0/exp2(retint/96.0)); s += strlen(s);
  513     ret = chdk_generic_script_run (params, "return get_av96()", NULL, &retint, context);
  514     sprintf (s, _("AV96: %d, Aperture: %f\n"), retint, sqrt(exp2(retint/96.0))); s += strlen(s);
  515     ret = chdk_generic_script_run (params, "return get_focus()", NULL, &retint, context);
  516     sprintf (s, _("Focus: %d\n"), retint); s += strlen(s);
  517     ret = chdk_generic_script_run (params, "return get_iso_mode()", NULL, &retint, context);
  518     sprintf (s, _("ISO Mode: %d\n"), retint); s += strlen(s);
  519 
  520     ret = chdk_generic_script_run (params, "return get_zoom()", NULL, &retint, context);
  521     sprintf (s, _("Zoom: %d\n"), retint); s += strlen(s);
  522     ret = chdk_generic_script_run (params, "return get_temperature(0)", NULL, &retint, context);
  523     sprintf (s, _("Optical Temperature: %d\n"), retint); s += strlen(s);
  524     ret = chdk_generic_script_run (params, "return get_temperature(1)", NULL, &retint, context);
  525     sprintf (s, _("CCD Temperature: %d\n"), retint); s += strlen(s);
  526     ret = chdk_generic_script_run (params, "return get_temperature(2)", NULL, &retint, context);
  527     sprintf (s, _("Battery Temperature: %d\n"), retint); s += strlen(s);
  528 
  529     ret = chdk_generic_script_run (params, "return get_flash_mode()", NULL, &retint, context);
  530     sprintf (s, _("Flash Mode: %d\n"), retint); s += strlen(s);
  531         return ret;
  532 /*
  533 Mode: 256
  534 SV96: 603, ISO: 243
  535 TV96: 478, Shutterspeed: 0
  536 AV96: 294, Aperture: 2,890362
  537 ND Filter: -1
  538 Focus: 166
  539 ISO Mode: 0
  540 
  541 */
  542 
  543 }
  544 
  545 struct submenu;
  546 typedef int (*get_func) (PTPParams *, struct submenu*, CameraWidget **, GPContext *);
  547 #define CONFIG_GET_ARGS PTPParams *params, struct submenu *menu, CameraWidget **widget, GPContext *context
  548 typedef int (*put_func) (PTPParams *, CameraWidget *, GPContext *);
  549 #define CONFIG_PUT_ARGS PTPParams *params, CameraWidget *widget, GPContext *context
  550 
  551 struct submenu {
  552     char        *label;
  553     char        *name;
  554         get_func    getfunc;
  555         put_func    putfunc;
  556 };
  557 
  558 static int
  559 chdk_get_iso(CONFIG_GET_ARGS) {
  560     int retint = 0, iso = 0;
  561     char buf[20];
  562 
  563     CR (chdk_generic_script_run (params, "return get_iso_mode()", NULL, &retint, context));
  564     if (!retint) {
  565         CR(chdk_generic_script_run (params, "return get_sv96()", NULL, &retint, context));
  566         iso = (int)(exp2(retint/96.0)*3.125);
  567     } else {
  568         iso = retint;
  569     }
  570     CR (gp_widget_new (GP_WIDGET_TEXT, _(menu->label), widget));
  571     gp_widget_set_name (*widget, menu->name);
  572     sprintf(buf,"%d", iso);
  573     gp_widget_set_value (*widget, buf);
  574     return GP_OK;
  575 }
  576 
  577 static int
  578 chdk_put_iso(CONFIG_PUT_ARGS) {
  579     int iso = 0;
  580     char *val;
  581     char lua[100];
  582 
  583     gp_widget_get_value (widget, &val);
  584     if (!sscanf(val, "%d", &iso))
  585         return GP_ERROR_BAD_PARAMETERS;
  586 
  587     sprintf(lua,"return set_iso_mode(%d)\n", iso);
  588     CR (chdk_generic_script_run (params, lua, NULL, NULL, context));
  589     return GP_OK;
  590 }
  591 
  592 static int
  593 chdk_get_iso_market(CONFIG_GET_ARGS) {
  594     int retint = 0, iso = 0;
  595     char buf[20];
  596 
  597     CR (chdk_generic_script_run (params, "return get_iso_market()", NULL, &retint, context));
  598     if (!retint) {
  599         CR(chdk_generic_script_run (params, "return iso_real_to_market(get_sv96())", NULL, &retint, context));
  600         iso = (int)(exp2(retint/96.0)*3.125);
  601     } else {
  602         iso = retint;
  603     }
  604     CR (gp_widget_new (GP_WIDGET_TEXT, _(menu->label), widget));
  605     gp_widget_set_name (*widget, menu->name);
  606     sprintf(buf,"%d", iso);
  607     gp_widget_set_value (*widget, buf);
  608     return GP_OK;
  609 }
  610 
  611 static int
  612 chdk_put_iso_market(CONFIG_PUT_ARGS) {
  613     int iso = 0;
  614     char *val;
  615     char lua[100];
  616 
  617     gp_widget_get_value (widget, &val);
  618     if (!sscanf(val, "%d", &iso))
  619         return GP_ERROR_BAD_PARAMETERS;
  620 
  621     sprintf(lua,"return set_iso_real(iso_market_to_real(%d))\n", iso);
  622     CR (chdk_generic_script_run (params, lua, NULL, NULL, context));
  623     return GP_OK;
  624 }
  625 
  626 static int
  627 chdk_get_av(CONFIG_GET_ARGS) {
  628     int retint = 0;
  629     char buf[20];
  630     float f;
  631 
  632     CR (chdk_generic_script_run (params, "return get_av96()", NULL, &retint, context));
  633     f = sqrt(exp2(retint/96.0));
  634     CR (gp_widget_new (GP_WIDGET_TEXT, _(menu->label), widget));
  635     gp_widget_set_name (*widget, menu->name);
  636     sprintf(buf, "%d.%d", (int)f,((int)f*10)%10);
  637     gp_widget_set_value (*widget, buf);
  638     return GP_OK;
  639 }
  640 
  641 static int
  642 chdk_put_av(CONFIG_PUT_ARGS) {
  643     char *val;
  644     int av1,av2,sqav;
  645     char lua[100];
  646 
  647     gp_widget_get_value (widget, &val);
  648     if (2 != sscanf(val, "%d.%d", &av1,&av2)) {
  649         if (!sscanf(val, "%d", &av1)) {
  650             return GP_ERROR_BAD_PARAMETERS;
  651         }
  652         av2 = 0;
  653     }
  654 
  655     /* av96 = 96*log2(f^2) */
  656     sqav = (av1*1.0+av2/10.0)*(av1*1.0+av2/10.0);
  657     sprintf(lua,"return set_av96(%d)\n", (int)(96.0*log2(sqav)));
  658     return chdk_generic_script_run (params, lua, NULL, NULL, context);
  659 }
  660 
  661 static int
  662 chdk_get_tv(CONFIG_GET_ARGS) {
  663     int retint = 0;
  664     char buf[20];
  665 
  666     CR (chdk_generic_script_run (params, "return get_tv96()", NULL, &retint, context));
  667     CR (gp_widget_new (GP_WIDGET_TEXT, _(menu->label), widget));
  668     gp_widget_set_name (*widget, menu->name);
  669     sprintf(buf, "%f", 1.0/exp2(retint/96.0));
  670     gp_widget_set_value (*widget, buf);
  671     return GP_OK;
  672 }
  673 
  674 static int
  675 chdk_put_tv(CONFIG_PUT_ARGS) {
  676     char *val;
  677     float   f;
  678     char lua[100];
  679 
  680     gp_widget_get_value (widget, &val);
  681     if (!sscanf(val, "%f", &f))
  682         return GP_ERROR_BAD_PARAMETERS;
  683 
  684     sprintf(lua,"return set_tv96(%d)\n", (int)(96.0*(-log2(f))));
  685     return chdk_generic_script_run (params, lua, NULL, NULL, context);
  686 }
  687 
  688 static int
  689 chdk_get_focus(CONFIG_GET_ARGS) {
  690     int retint = 0;
  691     char buf[20];
  692 
  693     CR (chdk_generic_script_run (params, "return get_focus()", NULL, &retint, context));
  694     CR (gp_widget_new (GP_WIDGET_TEXT, _(menu->label), widget));
  695     sprintf(buf, "%dmm", retint);
  696     gp_widget_set_value (*widget, buf);
  697     return GP_OK;
  698 }
  699 
  700 static int
  701 chdk_put_focus(CONFIG_PUT_ARGS) {
  702     char *val;
  703     int focus;
  704     char lua[100];
  705 
  706     gp_widget_get_value (widget, &val);
  707     if (!sscanf(val, "%dmm", &focus))
  708         return GP_ERROR_BAD_PARAMETERS;
  709 
  710     sprintf(lua,"return set_focus(%d)\n", focus);
  711     return chdk_generic_script_run (params, lua, NULL, NULL, context);
  712 }
  713 
  714 static int
  715 chdk_get_zoom(CONFIG_GET_ARGS) {
  716     int retint = 0;
  717     char buf[20];
  718 
  719     CR (chdk_generic_script_run (params, "return get_zoom()", NULL, &retint, context));
  720     CR (gp_widget_new (GP_WIDGET_TEXT, _(menu->label), widget));
  721     sprintf(buf, "%d", retint);
  722     gp_widget_set_value (*widget, buf);
  723     return GP_OK;
  724 }
  725 
  726 static int
  727 chdk_put_zoom(CONFIG_PUT_ARGS) {
  728     char *val;
  729     int zoom;
  730     char lua[100];
  731 
  732     gp_widget_get_value (widget, &val);
  733     if (!sscanf(val, "%d", &zoom))
  734         return GP_ERROR_BAD_PARAMETERS;
  735 
  736     sprintf(lua,"return set_zoom(%d)\n", zoom);
  737     return chdk_generic_script_run (params, lua, NULL, NULL, context);
  738 }
  739 
  740 static int
  741 chdk_get_orientation(CONFIG_GET_ARGS) {
  742     int retint = 0;
  743     char buf[20];
  744 
  745     CR (chdk_generic_script_run (params, "return get_orientation_sensor()", NULL, &retint, context));
  746     CR (gp_widget_new (GP_WIDGET_TEXT, _(menu->label), widget));
  747     sprintf(buf, "%d'", retint);
  748     gp_widget_set_value (*widget, buf);
  749     return GP_OK;
  750 }
  751 
  752 static int
  753 chdk_put_none(CONFIG_PUT_ARGS) {
  754     return GP_ERROR_NOT_SUPPORTED;
  755 }
  756 
  757 static int
  758 chdk_get_ev(CONFIG_GET_ARGS) {
  759     int retint = 0;
  760     float val;
  761 
  762     CR (chdk_generic_script_run (params, "return get_ev()", NULL, &retint, context));
  763     CR (gp_widget_new (GP_WIDGET_RANGE, _(menu->label), widget));
  764         gp_widget_set_range (*widget,
  765                 -5.0,
  766                 5.0,
  767                 1.0/6.0
  768         );
  769     val = retint/96.0;
  770     return gp_widget_set_value (*widget, &val);
  771 }
  772 
  773 static int
  774 chdk_put_ev(CONFIG_PUT_ARGS) {
  775     float val;
  776     char lua[100];
  777 
  778     gp_widget_get_value (widget, &val);
  779     sprintf(lua,"return set_ev(%d)\n", (int)(val*96.0));
  780     return chdk_generic_script_run (params, lua, NULL, NULL, context);
  781 }
  782 
  783 static void
  784 add_buttons(CameraWidget *widget) {
  785     gp_widget_add_choice(widget, "shoot_half");
  786     gp_widget_add_choice(widget, "shoot_full");
  787     gp_widget_add_choice(widget, "shoot_full_only");
  788     gp_widget_add_choice(widget, "erase");
  789     gp_widget_add_choice(widget, "up");
  790     gp_widget_add_choice(widget, "print");
  791     gp_widget_add_choice(widget, "left");
  792     gp_widget_add_choice(widget, "set");
  793     gp_widget_add_choice(widget, "right");
  794     gp_widget_add_choice(widget, "disp");
  795     gp_widget_add_choice(widget, "down");
  796     gp_widget_add_choice(widget, "menu");
  797     gp_widget_add_choice(widget, "zoom_in");
  798     gp_widget_add_choice(widget, "zoom_out");
  799     gp_widget_add_choice(widget, "video");
  800     gp_widget_add_choice(widget, "shoot_full");
  801     gp_widget_add_choice(widget, "shoot_full_only");
  802     gp_widget_add_choice(widget, "wheel l");
  803     gp_widget_add_choice(widget, "wheel r");
  804     gp_widget_add_choice(widget, "zoom in");
  805     gp_widget_add_choice(widget, "zoom out");
  806     gp_widget_add_choice(widget, "iso");
  807     gp_widget_add_choice(widget, "flash");
  808     gp_widget_add_choice(widget, "mf");
  809     gp_widget_add_choice(widget, "macro");
  810     gp_widget_add_choice(widget, "video");
  811     gp_widget_add_choice(widget, "timer");
  812     gp_widget_add_choice(widget, "expo_corr");
  813     gp_widget_add_choice(widget, "fe");
  814     gp_widget_add_choice(widget, "face");
  815     gp_widget_add_choice(widget, "zoom_assist");
  816     gp_widget_add_choice(widget, "ae_lock");
  817     gp_widget_add_choice(widget, "metering_mode");
  818     gp_widget_add_choice(widget, "playback");
  819     gp_widget_add_choice(widget, "help");
  820 }
  821 
  822 static int
  823 chdk_get_press(CONFIG_GET_ARGS) {
  824     CR (gp_widget_new (GP_WIDGET_RADIO, _(menu->label), widget));
  825     gp_widget_set_value (*widget, "chdk buttonname");
  826     add_buttons(*widget);
  827     return GP_OK;
  828 }
  829 
  830 static int
  831 chdk_put_press(CONFIG_PUT_ARGS) {
  832     char *val;
  833     char lua[100];
  834 
  835     gp_widget_get_value (widget, &val);
  836     sprintf(lua,"press('%s')\n", val);
  837     return chdk_generic_script_run (params, lua, NULL, NULL, context);
  838 }
  839 
  840 static int
  841 chdk_get_release(CONFIG_GET_ARGS) {
  842     CR (gp_widget_new (GP_WIDGET_RADIO, _(menu->label), widget));
  843     gp_widget_set_value (*widget, "chdk buttonname");
  844     add_buttons(*widget);
  845     return GP_OK;
  846 }
  847 
  848 static int
  849 chdk_put_release(CONFIG_PUT_ARGS) {
  850     char *val;
  851     char lua[100];
  852 
  853     gp_widget_get_value (widget, &val);
  854     sprintf(lua,"release('%s')\n", val);
  855     return chdk_generic_script_run (params, lua, NULL, NULL, context);
  856 }
  857 
  858 static int
  859 chdk_get_click(CONFIG_GET_ARGS) {
  860     CR (gp_widget_new (GP_WIDGET_RADIO, _(menu->label), widget));
  861     gp_widget_set_value (*widget, "chdk buttonname");
  862     add_buttons(*widget);
  863     return GP_OK;
  864 }
  865 
  866 static int
  867 chdk_put_click(CONFIG_PUT_ARGS) {
  868     char *val;
  869     char lua[100];
  870 
  871     gp_widget_get_value (widget, &val);
  872     if (!strcmp(val,"wheel l"))
  873         strcpy(lua,"post_levent_to_ui(\"RotateJogDialLeft\",1)\n");
  874     else if (!strcmp(val,"wheel r"))
  875         strcpy(lua,"post_levent_to_ui(\"RotateJogDialRight\",1)\n");
  876     else
  877         sprintf(lua,"click('%s')\n", val);
  878     return chdk_generic_script_run (params, lua, NULL, NULL, context);
  879 }
  880 
  881 static int
  882 chdk_get_capmode(CONFIG_GET_ARGS) {
  883     char *s , *table = NULL;
  884     int retint = 0;
  885     const char *lua =
  886 PTP_CHDK_LUA_SERIALIZE \
  887 "capmode=require'capmode'\n"
  888 "str=''\n"
  889 "local l={}\n"
  890 "local i=1\n"
  891 "for id,name in ipairs(capmode.mode_to_name) do\n"
  892 "   if capmode.valid(id) then\n"
  893 "       str = str .. name .. '\\n'\n"
  894 "       l[i] = {name=name,id=id}\n"
  895 "       i = i + 1\n"
  896 "   end\n"
  897 "end\n"
  898 "str = str .. capmode.get_name()\n"
  899 "return str\n";
  900 
  901     CR (gp_widget_new (GP_WIDGET_RADIO, _(menu->label), widget));
  902 
  903     CR (chdk_generic_script_run (params,lua,&table,&retint,context));
  904 
  905     s = table;
  906     GP_LOG_D("table is %s", table);
  907     while (*s) {
  908         char *x = strchr(s,'\n');
  909 
  910         if (x) *x = 0;
  911         GP_LOG_D("line is %s", s);
  912         gp_widget_add_choice (*widget, s);
  913         if (!x || !strlen(x+1))
  914             gp_widget_set_value (*widget, s);
  915         if (!x)
  916             break;
  917         s = x+1;
  918     }
  919     free (table);
  920     return GP_OK;
  921 }
  922 
  923 static int
  924 chdk_put_capmode(CONFIG_PUT_ARGS) {
  925     char *val;
  926     char lua[200];
  927     const char *luastr =
  928 "capmode=require'capmode'\n"
  929 "str='%s'\n"
  930 "for id,name in ipairs(capmode.mode_to_name) do\n"
  931 "   if capmode.valid(id) and str == name then\n"
  932 "       set_capture_mode(id)\n"
  933 "   end\n"
  934 "end\n"
  935 "return\n";
  936 
  937     gp_widget_get_value (widget, &val);
  938     /* integer? should actually work ... according to CHDK/TEST/isobase.lua */
  939     sprintf(lua, luastr, val);
  940     return chdk_generic_script_run (params, lua, NULL, NULL, context);
  941 }
  942 
  943 static int
  944 chdk_get_aelock(CONFIG_GET_ARGS) {
  945     int val = 2;
  946     CR (gp_widget_new (GP_WIDGET_TOGGLE, _(menu->label), widget));
  947     gp_widget_set_value (*widget, &val);
  948     return GP_OK;
  949 }
  950 
  951 static int
  952 chdk_put_aelock(CONFIG_PUT_ARGS) {
  953     int val;
  954     char lua[100];
  955 
  956     gp_widget_get_value (widget, &val);
  957     sprintf(lua,"set_aelock(%d)\n", val);
  958     return chdk_generic_script_run (params, lua, NULL, NULL, context);
  959 }
  960 
  961 
  962 static int
  963 chdk_get_aflock(CONFIG_GET_ARGS) {
  964     int val = 2;
  965     CR (gp_widget_new (GP_WIDGET_TOGGLE, _(menu->label), widget));
  966     gp_widget_set_value (*widget, &val);
  967     return GP_OK;
  968 }
  969 
  970 static int
  971 chdk_put_aflock(CONFIG_PUT_ARGS) {
  972     int val;
  973     char lua[100];
  974 
  975     gp_widget_get_value (widget, &val);
  976     sprintf(lua,"set_aflock(%d)\n", val);
  977     return chdk_generic_script_run (params, lua, NULL, NULL, context);
  978 }
  979 
  980 
  981 static int
  982 chdk_get_mflock(CONFIG_GET_ARGS) {
  983     int val = 2;
  984     CR (gp_widget_new (GP_WIDGET_TOGGLE, _(menu->label), widget));
  985     gp_widget_set_value (*widget, &val);
  986     return GP_OK;
  987 }
  988 
  989 static int
  990 chdk_put_mflock(CONFIG_PUT_ARGS) {
  991     int val;
  992     char lua[100];
  993 
  994     gp_widget_get_value (widget, &val);
  995     sprintf(lua,"set_mf(%d)\n", val);
  996     return chdk_generic_script_run (params, lua, NULL, NULL, context);
  997 }
  998 
  999 static struct {
 1000         char    *name;
 1001         char    *label;
 1002 } chdkonoff[] = {
 1003         {"on", N_("On") },
 1004         {"off", N_("Off") },
 1005 };
 1006 
 1007 static int
 1008 chdk_get_onoff(CONFIG_GET_ARGS) {
 1009         unsigned int    i;
 1010         char        buf[1024];
 1011 
 1012         gp_widget_new (GP_WIDGET_RADIO, _(menu->label), widget);
 1013         gp_widget_set_name (*widget, menu->name);
 1014         if (GP_OK != gp_setting_get("ptp2","chdk", buf))
 1015                 strcpy(buf,"off");
 1016         for (i=0;i<sizeof (chdkonoff)/sizeof (chdkonoff[i]);i++) {
 1017                 gp_widget_add_choice (*widget, _(chdkonoff[i].label));
 1018                 if (!strcmp (buf,chdkonoff[i].name))
 1019                         gp_widget_set_value (*widget, _(chdkonoff[i].label));
 1020         }
 1021         return GP_OK;
 1022 }
 1023 
 1024 static int
 1025 chdk_put_onoff(CONFIG_PUT_ARGS) {
 1026         unsigned int    i;
 1027         char        *val;
 1028 
 1029         CR (gp_widget_get_value(widget, &val));
 1030         for (i=0;i<sizeof(chdkonoff)/sizeof(chdkonoff[i]);i++) {
 1031                 if (!strcmp( val, _(chdkonoff[i].label))) {
 1032                         gp_setting_set("ptp2","chdk",chdkonoff[i].name);
 1033                         break;
 1034                 }
 1035         }
 1036         return GP_OK;
 1037 }
 1038 
 1039 
 1040 struct submenu imgsettings[] = {
 1041     { N_("Raw ISO"),    "rawiso",   chdk_get_iso,       chdk_put_iso},
 1042     { N_("ISO"),        "iso",      chdk_get_iso_market,    chdk_put_iso_market},
 1043     { N_("Aperture"),   "aperture", chdk_get_av,        chdk_put_av},
 1044     { N_("Shutterspeed"),   "shutterspeed", chdk_get_tv,        chdk_put_tv},
 1045     { N_("Focus"),      "focus",    chdk_get_focus,     chdk_put_focus},
 1046     { N_("Zoom"),       "zoom",     chdk_get_zoom,      chdk_put_zoom},
 1047     { N_("Press"),      "press",    chdk_get_press,     chdk_put_press},
 1048     { N_("Release"),    "release",  chdk_get_release,   chdk_put_release},
 1049     { N_("Click"),      "click",    chdk_get_click,     chdk_put_click},
 1050     { N_("Capture Mode"),   "capmode",  chdk_get_capmode,   chdk_put_capmode},
 1051     { N_("AE Lock"),    "aelock",   chdk_get_aelock,    chdk_put_aelock},
 1052     { N_("AF Lock"),    "aflock",   chdk_get_aflock,    chdk_put_aflock},
 1053     { N_("MF Lock"),    "mflock",   chdk_get_mflock,    chdk_put_mflock},
 1054     { N_("Exposure Compensation"),  "exposurecompensation", chdk_get_ev, chdk_put_ev},
 1055     { N_("Orientation"),    "orientation",  chdk_get_orientation,   chdk_put_none},
 1056     { N_("CHDK"),       "chdk",     chdk_get_onoff,     chdk_put_onoff},
 1057     { NULL,         NULL,       NULL,       NULL},
 1058 };
 1059 
 1060 /* We have way less options than regular PTP now, but try to keep the same structure */
 1061 static int
 1062 chdk_camera_get_config (Camera *camera, CameraWidget **window, GPContext *context)
 1063 {
 1064     PTPParams   *params = &(camera->pl->params);
 1065     CameraWidget    *menu, *child;
 1066     int     i, ret;
 1067 
 1068     CR(camera_prepare_chdk_capture(camera, context));
 1069 
 1070         gp_widget_new (GP_WIDGET_WINDOW, _("Camera and Driver Configuration"), window);
 1071     gp_widget_set_name (*window, "main");
 1072     gp_widget_new (GP_WIDGET_SECTION, _("Image Settings"), &menu);
 1073     gp_widget_set_name (menu, "imgsettings");
 1074     gp_widget_append(*window, menu);
 1075 
 1076     for (i=0;imgsettings[i].name;i++) {
 1077         ret = imgsettings[i].getfunc(params,&imgsettings[i],&child,context);
 1078         if (ret != GP_OK) {
 1079             GP_LOG_E("error getting %s menu", imgsettings[i].name);
 1080             continue;
 1081         }
 1082         gp_widget_set_name (child, imgsettings[i].name);
 1083         gp_widget_append (menu, child);
 1084     }
 1085     return GP_OK;
 1086 }
 1087 
 1088 static int
 1089 chdk_camera_set_config (Camera *camera, CameraWidget *window, GPContext *context)
 1090 {
 1091     PTPParams   *params = &(camera->pl->params);
 1092     int     i, ret;
 1093 
 1094     for (i=0;imgsettings[i].name;i++) {
 1095         CameraWidget *widget;
 1096 
 1097         ret = gp_widget_get_child_by_label (window, _(imgsettings[i].label), &widget);
 1098         if (ret != GP_OK)
 1099             continue;
 1100         if (!gp_widget_changed (widget))
 1101             continue;
 1102             gp_widget_set_changed (widget, FALSE);
 1103         ret = imgsettings[i].putfunc(params,widget,context);
 1104         if (ret != GP_OK) {
 1105             GP_LOG_E("error putting %s menu", imgsettings[i].name);
 1106             continue;
 1107         }
 1108     }
 1109     return GP_OK;
 1110 }
 1111 
 1112 static int
 1113 chdk_camera_exit (Camera *camera, GPContext *context)
 1114 {
 1115     camera_unprepare_chdk_capture(camera, context);
 1116         return GP_OK;
 1117 }
 1118 
 1119 static int
 1120 chdk_camera_capture (Camera *camera, CameraCaptureType type, CameraFilePath *path,
 1121     GPContext *context)
 1122 {
 1123     int     ret, retint;
 1124     char        *table, *s;
 1125     PTPParams   *params = &camera->pl->params;
 1126     const char  *luascript = PTP_CHDK_LUA_SERIALIZE_MSGS_SIMPLEQUOTE \
 1127                 PTP_CHDK_LUA_RLIB_SHOOT \
 1128                 "return rlib_shoot({info=true});\n";
 1129 
 1130     ret =  camera_prepare_chdk_capture(camera, context);
 1131     if (ret != GP_OK) return ret;
 1132 
 1133     ret = chdk_generic_script_run (params, luascript, &table, &retint, context);
 1134     GP_LOG_D("rlib_shoot returned table %s, retint %d\n", table, retint);
 1135     s = strstr(table, "exp=");
 1136     if (s) {
 1137         int exp;
 1138         if (!sscanf(s,"exp=%d\n", &exp)) {
 1139             GP_LOG_E("%s did not parse for exp=NR?", s);
 1140             ret = GP_ERROR;
 1141         } else {
 1142             sprintf(path->name,"IMG_%04d.JPG", exp);
 1143         }
 1144     } else {
 1145         GP_LOG_E("no exp=nr found?\n");
 1146         ret = GP_ERROR;
 1147     }
 1148     s = strstr(table, "dir=\"A");
 1149     if (s) {
 1150         char *y = strchr(s+6,'"');
 1151         if (y) *y='\0';
 1152         strcpy(path->folder, s+6);
 1153     } else {
 1154         ret = GP_ERROR;
 1155     }
 1156     free (table);
 1157         return ret;
 1158 }
 1159 
 1160 #ifdef HAVE_LIBJPEG
 1161 static void yuv_live_to_jpeg(unsigned char *p_yuv,
 1162                  unsigned int buf_width, unsigned int width, unsigned int height,
 1163                  int fb_type, CameraFile *file
 1164 ) {
 1165     struct      jpeg_compress_struct cinfo;
 1166     struct      jpeg_error_mgr jerr;
 1167     JSAMPROW    row_ptr[1];
 1168     uint8_t     *outbuf = NULL, *tmprowbuf = NULL;
 1169     uint64_t    outlen = 0;
 1170     unsigned int    row_inc;
 1171     int     sshift, dshift, xshift, skip;
 1172 
 1173     /* Pre-Digic 6 cameras: 8 bit per element UYVYYY,
 1174      * 6 bytes used to encode 4 pixels, need 12 bytes raw YUV data for jpeg encoding */
 1175     if (fb_type == LV_FB_YUV8) {
 1176         row_inc = buf_width*1.5;
 1177         sshift = 6;
 1178         dshift = (width/height > 2) ? 6 : 12;
 1179         xshift = 4;
 1180     /* Digic 6 cameras: 8 bit per element UYVY,
 1181      * 4 bytes used to encode 2 pixels, need 6 bytes raw YUV data for jpeg encoding */
 1182     } else {
 1183         row_inc = buf_width*2;
 1184         sshift = 4;
 1185         dshift = 6;
 1186         xshift = 2;
 1187     }
 1188     /* Encode only 2 pixels from each UV pair either if it is a UYVY data
 1189      * (for Digic 6 cameras) or if the width to height ratio provided
 1190      * by camera is too large (typically width 720 for height 240), so that
 1191      * the resulting image would be stretched too much in the horizontal
 1192      * direction if all 4 Y values were used. */
 1193     skip  = (fb_type > LV_FB_YUV8) || (width/height > 2);
 1194 
 1195     cinfo.err = jpeg_std_error (&jerr);
 1196     jpeg_create_compress (&cinfo);
 1197 
 1198     cinfo.image_width = (width/height > 2) ? (width/2) & -1 : width & -1;
 1199     cinfo.image_height = height & -1;
 1200     cinfo.input_components = 3;
 1201     cinfo.in_color_space = JCS_YCbCr; // input color space
 1202 
 1203     jpeg_mem_dest (&cinfo, &outbuf, &outlen);
 1204     jpeg_set_defaults (&cinfo);
 1205     cinfo.dct_method = JDCT_IFAST; // DCT method
 1206     jpeg_set_quality (&cinfo, 70, TRUE);
 1207 
 1208     jpeg_start_compress (&cinfo, TRUE);
 1209 
 1210     tmprowbuf = calloc (cinfo.image_width , 3);
 1211     row_ptr[0] = &tmprowbuf[0];
 1212 
 1213     while (cinfo.next_scanline < cinfo.image_height) {
 1214         unsigned int x, i, j;
 1215         /* offset to the correct row */
 1216         unsigned int offset = cinfo.next_scanline * row_inc;
 1217 
 1218         for (x = 0, i = 0, j = 0; x < width; i += sshift, j += dshift, x += xshift) {
 1219             int8_t u = (int8_t) p_yuv[offset + i + 0];
 1220             int8_t v = (int8_t) p_yuv[offset + i + 2];
 1221             if (fb_type == LV_FB_YUV8) {
 1222                 u += 0x80;
 1223                 v += 0x80;
 1224             }
 1225 
 1226             tmprowbuf[j + 0] = p_yuv[offset + i + 1];
 1227             tmprowbuf[j + 1] = u;
 1228             tmprowbuf[j + 2] = v;
 1229             tmprowbuf[j + 3] = p_yuv[offset + i + 3];
 1230             tmprowbuf[j + 4] = u;
 1231             tmprowbuf[j + 5] = v;
 1232 
 1233             if (!skip) {
 1234                 tmprowbuf[j + 6] = p_yuv[offset + i + 4];
 1235                 tmprowbuf[j + 7] = u;
 1236                 tmprowbuf[j + 8] = v;
 1237                 tmprowbuf[j + 9] = p_yuv[offset + i + 5];
 1238                 tmprowbuf[j +10] = u;
 1239                 tmprowbuf[j +11] = v;
 1240             }
 1241         }
 1242         jpeg_write_scanlines (&cinfo, row_ptr, 1);
 1243     }
 1244     jpeg_finish_compress (&cinfo);
 1245     jpeg_destroy_compress (&cinfo);
 1246 
 1247     gp_file_append (file, (char*)outbuf, outlen);
 1248         gp_file_set_mime_type (file, GP_MIME_JPEG);
 1249         gp_file_set_name (file, "chdk_preview.jpg");
 1250 
 1251     free (outbuf);
 1252     free (tmprowbuf);
 1253 }
 1254 
 1255 #else
 1256 static inline uint8_t clip_yuv (int v) {
 1257     if (v<0) return 0;
 1258     if (v>255) return 255;
 1259     return v;
 1260 }
 1261 
 1262 static inline uint8_t yuv_to_r (uint8_t y, int8_t v) {
 1263     return clip_yuv (((y<<12) +          v*5743 + 2048)>>12);
 1264 }
 1265 
 1266 static inline uint8_t yuv_to_g (uint8_t y, int8_t u, int8_t v) {
 1267     return clip_yuv (((y<<12) - u*1411 - v*2925 + 2048)>>12);
 1268 }
 1269 
 1270 static inline uint8_t yuv_to_b (uint8_t y, int8_t u) {
 1271     return clip_yuv (((y<<12) + u*7258          + 2048)>>12);
 1272 }
 1273 
 1274 static void yuv_live_to_ppm (unsigned char *p_yuv,
 1275                  int buf_width, int width, int height,
 1276                  int fb_type, CameraFile *file
 1277 ) {
 1278     const unsigned char  *p_row = p_yuv;
 1279     const unsigned char  *p;
 1280     unsigned int          row, x;
 1281     unsigned int          row_inc;
 1282     int           pshift, xshift, skip;
 1283     char              ppm_header[32];
 1284     uint8_t           rgb[6];
 1285 
 1286     /* Pre-Digic 6 cameras:
 1287      * 8 bit per element UYVYYY, 6 bytes used to encode 4 rgb values */
 1288     if (fb_type == LV_FB_YUV8) {
 1289         row_inc = buf_width*1.5;
 1290         pshift = 6;
 1291         xshift = 4;
 1292     /* Digic 6 cameras:
 1293      * 8 bit per element UYVY, 4 bytes used to encode 2 rgb values */
 1294     } else {
 1295         row_inc = buf_width*2;
 1296         pshift = 4;
 1297         xshift = 2;
 1298     }
 1299     /* Encode only 2 pixels from each UV pair either if it is a UYVY data
 1300      * (for Digic 6 cameras) or if the width to height ratio provided
 1301      * by camera is too large (typically width 720 for height 240), so that
 1302      * the resulting image would be stretched too much in the horizontal
 1303      * direction if all 4 Y values were used. */
 1304     skip  = (fb_type > LV_FB_YUV8) || (width/height > 2);
 1305 
 1306     sprintf (ppm_header, "P6 %d %d 255\n", (width/height > 2) ? width/2 : width, height);
 1307     gp_file_append (file, ppm_header, strlen (ppm_header));
 1308 
 1309     for (row=0; row<height; row++, p_row += row_inc) {
 1310         for (x=0, p=p_row; x<width; x+=xshift, p+=pshift) {
 1311             /* these are signed unlike the Y values */
 1312             int8_t u = (int8_t) p[0];
 1313             int8_t v = (int8_t) p[2];
 1314             /* See for example
 1315              * https://chdk.setepontos.com/index.php?topic=12692.msg130137#msg130137 */
 1316             if (fb_type > LV_FB_YUV8) {
 1317                 u -= 0x80;
 1318                 v -= 0x80;
 1319             }
 1320             rgb[0] = yuv_to_r (p[1], v);
 1321             rgb[1] = yuv_to_g (p[1], u, v);
 1322             rgb[2] = yuv_to_b (p[1], u);
 1323 
 1324             rgb[3] = yuv_to_r (p[3], v);
 1325             rgb[4] = yuv_to_g (p[3], u, v);
 1326             rgb[5] = yuv_to_b (p[3], u);
 1327             gp_file_append (file, (char*)rgb, 6);
 1328 
 1329             if (!skip) {
 1330                 rgb[0] = yuv_to_r (p[4], v);
 1331                 rgb[1] = yuv_to_g (p[4], u, v);
 1332                 rgb[2] = yuv_to_b (p[4], u);
 1333 
 1334                 rgb[3] = yuv_to_r (p[5], v);
 1335                 rgb[4] = yuv_to_g (p[5], u, v);
 1336                 rgb[5] = yuv_to_b (p[5], u);
 1337                 gp_file_append (file, (char*)rgb, 6);
 1338             }
 1339         }
 1340     }
 1341         gp_file_set_mime_type (file, GP_MIME_PPM);
 1342         gp_file_set_name (file, "chdk_preview.ppm");
 1343 }
 1344 #endif
 1345 
 1346 static int
 1347 chdk_camera_capture_preview (Camera *camera, CameraFile *file, GPContext *context)
 1348 {
 1349     unsigned char   *data = NULL;
 1350     uint32_t    size = 0;
 1351     PTPParams   *params = &camera->pl->params;
 1352     unsigned int    flags = LV_TFR_VIEWPORT;
 1353 
 1354     lv_data_header header;
 1355     lv_framebuffer_desc vpd;
 1356     lv_framebuffer_desc bmd;
 1357 
 1358     memset (&header, 0, sizeof (header));
 1359     memset (&vpd, 0, sizeof (vpd));
 1360     memset (&vpd, 0, sizeof (bmd));
 1361 
 1362     CR (camera_prepare_chdk_capture (camera, context));
 1363         C_PTP_REP_MSG (ptp_chdk_get_live_data (params, flags, &data, &size),
 1364                    _("CHDK get live data failed"));
 1365     if (ptp_chdk_parse_live_data (params, data, size, &header, &vpd, &bmd) != PTP_RC_OK) {
 1366         gp_context_error (context, _("CHDK get live data failed: incomplete data (%d bytes) returned"), size);
 1367         return GP_ERROR;
 1368     }
 1369 #ifdef HAVE_LIBJPEG
 1370     yuv_live_to_jpeg(data+vpd.data_start, vpd.buffer_width, vpd.visible_width,
 1371              vpd.visible_height, vpd.fb_type, file);
 1372 #else
 1373     yuv_live_to_ppm (data+vpd.data_start, vpd.buffer_width, vpd.visible_width,
 1374              vpd.visible_height, vpd.fb_type, file);
 1375 #endif
 1376 
 1377         free (data);
 1378         gp_file_set_mtime (file, time (NULL));
 1379         return GP_OK;
 1380 }
 1381 
 1382 int
 1383 chdk_init(Camera *camera, GPContext *context) {
 1384         camera->functions->about = chdk_camera_about;
 1385         camera->functions->exit = chdk_camera_exit;
 1386         camera->functions->capture = chdk_camera_capture;
 1387         camera->functions->summary = chdk_camera_summary;
 1388         camera->functions->get_config = chdk_camera_get_config;
 1389         camera->functions->set_config = chdk_camera_set_config;
 1390         camera->functions->capture_preview = chdk_camera_capture_preview;
 1391 /*
 1392         camera->functions->trigger_capture = camera_trigger_capture;
 1393         camera->functions->wait_for_event = camera_wait_for_event;
 1394 */
 1395 
 1396     gp_filesystem_set_funcs ( camera->fs, &chdk_fsfuncs, camera);
 1397     return GP_OK;
 1398 }