root/core/ptp.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. init_chdk_ptp
  2. init_chdk_ptp_task
  3. recv_ptp_data
  4. flush_recv_ptp_data
  5. send_ptp_data
  6. send_ptp_data_buffered
  7. script_msg_q_next
  8. script_msg_q_full
  9. script_msg_q_empty
  10. enqueue_script_msg
  11. dequeue_script_msg
  12. empty_script_msg_q
  13. ptp_script_create_msg
  14. ptp_script_write_msg
  15. ptp_script_read_msg
  16. ptp_script_write_error_msg
  17. start_ptp_script
  18. script_start_ptp
  19. handle_ptp

   1 #include "camera_info.h"
   2 #include "stddef.h"
   3 #include "stdlib.h"
   4 #include "keyboard.h"
   5 #include "ptp_chdk.h"
   6 #include "core.h"
   7 #include "task.h"
   8 #include "script.h"
   9 #include "action_stack.h"
  10 #include "live_view.h"
  11 #include "meminfo.h"
  12 #include "modules.h"
  13 #include "callfunc.h"
  14 
  15 #include "remotecap_core.h"
  16 static int buf_size=0;
  17 
  18 // process id for scripts, increments before each attempt to run script
  19 // does not handle wraparound
  20 static unsigned script_run_id; 
  21 
  22 static int handle_ptp(
  23                 int h, ptp_data *data, int opcode, int sess_id, int trans_id,
  24                 int param1, int param2, int param3, int param4, int param5);
  25 
  26 static void init_chdk_ptp()
  27 {
  28   int r;
  29  
  30   // wait until ptp_handlers_info is initialised and add CHDK PTP interface
  31   r = 0x17;
  32   while ( r==0x17 )
  33   {
  34     r = add_ptp_handler(PTP_OC_CHDK,handle_ptp,0);
  35     msleep(250);
  36   }
  37 
  38   ExitTask();
  39 }
  40 
  41 void init_chdk_ptp_task()
  42 {
  43     CreateTask("InitCHDKPTP", 0x19, 0x200, init_chdk_ptp);
  44 };
  45 
  46 /*
  47 WARNING: it appears that on some vxworks cameras,
  48 if a call to recv_ptp_data doesn't end on a word (4 byte) boundery,
  49 subsequent calls will return corrupt data
  50 the final call not ending on a word boundery is OK.
  51 see http://chdk.setepontos.com/index.php?topic=6730.msg76760#msg76760
  52 */
  53 static int recv_ptp_data(ptp_data *data, char *buf, int size)
  54   // repeated calls per transaction are ok
  55 {
  56   while ( size >= buf_size )
  57   {
  58     data->recv_data(data->handle,buf,buf_size,0,0);
  59     // XXX check for success??
  60 
  61     size -= buf_size;
  62     buf += buf_size;
  63   }
  64   if ( size != 0 )
  65   {
  66     data->recv_data(data->handle,buf,size,0,0);
  67     // XXX check for success??
  68   }
  69 
  70   return 1;
  71 }
  72 
  73 // camera will shut down if you ignore a recv data phase
  74 static void flush_recv_ptp_data(ptp_data *data,int size) {
  75   char *buf;
  76   buf = malloc((size > buf_size) ? buf_size:size);
  77   if(!buf) // buf_size should always be less then available memory
  78     return;
  79   while ( size > 0 )
  80   {
  81     if ( size >= buf_size )
  82     {
  83       recv_ptp_data(data,buf,buf_size);
  84       size -= buf_size;
  85     } else {
  86       recv_ptp_data(data,buf,size);
  87       size = 0;
  88     }
  89   }
  90   free(buf);
  91 }
  92 
  93 static int send_ptp_data(ptp_data *data, const char *buf, int size)
  94   // repeated calls per transaction are *not* ok
  95 {
  96   int tmpsize;
  97   
  98   tmpsize = size;
  99   while ( size >= buf_size )
 100   {
 101     if ( data->send_data(data->handle,buf,buf_size,tmpsize,0,0,0) )
 102     {
 103       return 0;
 104     }
 105 
 106     tmpsize = 0;
 107     size -= buf_size;
 108     buf += buf_size;
 109   }
 110   if ( size != 0 )
 111   {
 112     if ( data->send_data(data->handle,buf,size,tmpsize,0,0,0) )
 113     {
 114       return 0;
 115     }
 116   }
 117 
 118   return 1;
 119 }
 120 
 121 /*
 122 send data buffered, for regions which cannot be directly used by DMA (MMIO, some TCMs)
 123 copy_fn should behave like memcpy.
 124 A function that does word by word copy rather than LDM/STM might be more correct for MMIO, but memcpy seems to work
 125 */
 126 static int send_ptp_data_buffered(ptp_data *data, void * (*copy_fn)(void *d, const void *s, long sz), const char *src, char *buf, int size)
 127 {
 128     int tmpsize = size;
 129     int send_size;
 130     while ( size > 0 )
 131     {
 132         if(size > buf_size) {
 133             send_size = buf_size;
 134         } else {
 135             send_size = size;
 136         }
 137         // src inside buf ?
 138         if(src >= buf && src < buf + send_size) {
 139             // send whatever is in buffer without attempting to copy
 140             if(src + size < buf + buf_size) {
 141                 // all remainder is in buf
 142                 send_size = size;
 143             } else {
 144                 // send up to end of buffer
 145                 send_size = buf_size - (src - buf);
 146             }
 147         } else {
 148             // full copy size would overlap
 149             if(src < buf && src + send_size > buf) {
 150                 // copy up to start of buf
 151                 send_size = buf - src;
 152             }
 153             copy_fn(buf,src,send_size);
 154         }
 155         if ( data->send_data(data->handle,buf,send_size,tmpsize,0,0,0) )
 156         {
 157             return 0;
 158         }
 159         tmpsize = 0;
 160         size -= send_size;
 161         src += send_size;
 162     }
 163     return 1;
 164 }
 165 
 166 // TODO this could be a generic ring buffer of words
 167 #define PTP_SCRIPT_MSG_Q_LEN 16
 168 typedef struct {
 169   unsigned r; // index of current read value
 170   unsigned w; // index of next write value, if w == r, empty TODO "full" currently wastes a slot
 171   ptp_script_msg *q[PTP_SCRIPT_MSG_Q_LEN];
 172 } ptp_script_msg_q;
 173 
 174 // TODO it would be better to allocate these only when needed
 175 ptp_script_msg_q msg_q_in; // messages to pc from script
 176 ptp_script_msg_q msg_q_out; // messages to script from pc
 177 
 178 unsigned script_msg_q_next(unsigned i) {
 179   if(i == PTP_SCRIPT_MSG_Q_LEN - 1) {
 180     return 0;
 181   }
 182   return i+1;
 183 }
 184 
 185 unsigned script_msg_q_full(ptp_script_msg_q *q) {
 186   return (script_msg_q_next(q->w) == q->r);
 187 }
 188 
 189 unsigned script_msg_q_empty(ptp_script_msg_q *q) {
 190   return (q->w == q->r);
 191 }
 192 
 193 int enqueue_script_msg(ptp_script_msg_q *q,ptp_script_msg *msg) {
 194   unsigned w = script_msg_q_next(q->w);
 195   if(w == q->r) {
 196     return 0;
 197   }
 198   if(msg == NULL) {
 199     return 0;
 200   }
 201   q->q[q->w] = msg;
 202   q->w = w;
 203   return 1;
 204 }
 205 
 206 ptp_script_msg* dequeue_script_msg(ptp_script_msg_q *q) {
 207   ptp_script_msg *msg;
 208   if(script_msg_q_empty(q)) {
 209     return NULL;
 210   }
 211   msg = q->q[q->r];
 212   q->r = script_msg_q_next(q->r);
 213   return msg;
 214 }
 215 
 216 // remove all messages from queue
 217 void empty_script_msg_q(ptp_script_msg_q *q) {
 218     ptp_script_msg *msg;
 219     while((msg = dequeue_script_msg(q))) {
 220         free(msg);
 221     }
 222 }
 223 
 224 // public interface for script
 225 // create a message to be queued later
 226 ptp_script_msg* ptp_script_create_msg(unsigned type, unsigned subtype, unsigned datasize, const void *data) {
 227   ptp_script_msg *msg;
 228   msg = malloc(sizeof(ptp_script_msg) + datasize);
 229   msg->size = datasize;
 230   msg->type = type;
 231   msg->subtype = subtype;
 232   // caller may fill in data themselves
 233   // datasize may be empty (e.g. empty string)
 234   if(data && datasize) {
 235       memcpy(msg->data,data,msg->size);
 236   }
 237   return msg;
 238 }
 239 
 240 // add a message to the outgoing queue
 241 int ptp_script_write_msg(ptp_script_msg *msg) {
 242   msg->script_id = script_run_id;
 243   return enqueue_script_msg(&msg_q_out,msg);
 244 }
 245 
 246 // retrieve the next message in the incoming queue
 247 ptp_script_msg* ptp_script_read_msg(void) {
 248   ptp_script_msg *msg;
 249   while(1) {
 250     msg = dequeue_script_msg(&msg_q_in); 
 251     // no messages
 252     if(!msg) {
 253         return NULL;
 254     }
 255     // does message belong to our script
 256     if(!msg->script_id || msg->script_id == script_run_id) {
 257       return msg;
 258     } else {
 259     // no: discard and keep looking
 260       free(msg);
 261     }
 262   }
 263 }
 264 
 265 // convenience function write an error message
 266 int ptp_script_write_error_msg(unsigned errtype, const char *err) {
 267   if(script_msg_q_full(&msg_q_out)) {
 268     return 0;
 269   }
 270   ptp_script_msg *msg = ptp_script_create_msg(PTP_CHDK_S_MSGTYPE_ERR,errtype,strlen(err),err);
 271   if(!msg) {
 272     return 0;
 273   }
 274   return ptp_script_write_msg(msg);
 275 }
 276 
 277 static char*   ptp_script = 0;
 278 static int     ptp_script_state = 0;
 279 
 280 // Called from kbd process to start PTP script
 281 // Load Lua module, parse PTP script and start execution if parse ok.
 282 void start_ptp_script()
 283 {
 284     if (ptp_script)
 285     {
 286         module_set_script_lang(0);  // Force Lua script language
 287         if (libscriptapi->script_start(ptp_script,1))
 288         {
 289             camera_info.state.auto_started = 0;
 290             ptp_script_state = script_stack_start();
 291         }
 292         else
 293             ptp_script_state = -1;
 294         ptp_script = 0;
 295     }
 296 }
 297 
 298 // Setup for kbd task to start script, wait until started and return startup state
 299 static long script_start_ptp( char *script )
 300 {
 301     ptp_script = script;
 302     while (ptp_script) msleep(10);
 303     return ptp_script_state;
 304 }
 305 
 306 static int handle_ptp(
 307                int h, ptp_data *data, int opcode, int sess_id, int trans_id,
 308                int param1, int param2, int param3, int param4, int param5)
 309 {
 310   static union {
 311     char *str;
 312   } temp_data;
 313   static int temp_data_kind = 0; // 0: nothing, 1: ascii string
 314   static int temp_data_extra; // size (ascii string)
 315   PTPContainer ptp;
 316 
 317   // initialise default response
 318   memset(&ptp,0,sizeof(PTPContainer));
 319   ptp.code = PTP_RC_OK;
 320   ptp.sess_id = sess_id;
 321   ptp.trans_id = trans_id;
 322   ptp.num_param = 0;
 323   
 324   // TODO 
 325   // calling this on every PTP command is not good on cameras without CAM_FIRMWARE_MEMINFO
 326   // since it figures out free memory by repeatedly malloc'ing!
 327   // using half of available memory may be undesirable in some cases as well
 328   buf_size=(core_get_free_memory()>>1);
 329   // make sure size is an integer number of words (avoid some possible issues with multiple receive calls)
 330   buf_size &= 0xFFFFFFFC;
 331 
 332   // handle command
 333   switch ( param1 )
 334   {
 335 
 336     case PTP_CHDK_Version:
 337       ptp.num_param = 2;
 338       ptp.param1 = PTP_CHDK_VERSION_MAJOR;
 339       ptp.param2 = PTP_CHDK_VERSION_MINOR;
 340       break;
 341     case PTP_CHDK_ScriptSupport:
 342       ptp.num_param = 1;
 343       ptp.param1 = 0;
 344       ptp.param1 |= PTP_CHDK_SCRIPT_SUPPORT_LUA;
 345       break;
 346     case PTP_CHDK_ScriptStatus:
 347       ptp.num_param = 1;
 348       ptp.param1 = 0;
 349       ptp.param1 |= script_is_running()?PTP_CHDK_SCRIPT_STATUS_RUN:0;
 350       ptp.param1 |= (!script_msg_q_empty(&msg_q_out))?PTP_CHDK_SCRIPT_STATUS_MSG:0;
 351       break;
 352     case PTP_CHDK_GetMemory:
 353     {
 354       char *src=(char *)param2;
 355       int size=param3;
 356       int result=0;
 357       if ( size < 1 ) // invalid size? NULL is accepted
 358       {
 359         ptp.code = PTP_RC_GeneralError;
 360         break;
 361       }
 362 
 363       if (param4 == PTP_CHDK_GETMEM_MODE_DIRECT) {
 364         int total_size = size;
 365         // canon data->send_data fails on NULL, send first word separately
 366         // DMA from addresses occupied by TCM is suspect but seems to work on many cams
 367         // can't directly check NULL https://chdk.setepontos.com/index.php?topic=13101.0
 368         if((unsigned)param2 < 4 ) {
 369             char x[4];
 370             int send_size = 4 - param2;
 371             if(send_size > size) {
 372                 send_size = size;
 373             }
 374             memcpy(x,src,send_size);
 375 
 376             // 0 is success
 377             if(data->send_data(data->handle,x,send_size,total_size,0,0,0) != 0) {
 378                 ptp.code = PTP_RC_GeneralError;
 379                 break;
 380             }
 381             // that was all, done
 382             if(size == send_size) {
 383                 break;
 384             }
 385             size -= send_size;
 386             // total only sent on first send
 387             total_size = 0;
 388             src+=send_size;
 389         }
 390         // no need to send through send_ptp, faster with one call
 391         if(data->send_data(data->handle,src,size,total_size,0,0,0) == 0) {
 392             result = 1;
 393         }
 394       } else if(param4 == PTP_CHDK_GETMEM_MODE_BUFFER) {
 395         int chunk_size = (size > buf_size) ? buf_size:size;
 396         char *buf=malloc(chunk_size);
 397         if(buf) {
 398           result = send_ptp_data_buffered(data,memcpy,src,buf,size);
 399           free(buf);
 400         }
 401       } // else error
 402       if(!result)
 403       {
 404         ptp.code = PTP_RC_GeneralError;
 405       }
 406       break;
 407     }
 408     case PTP_CHDK_SetMemory:
 409       if ( param2 == 0 || param3 < 1 ) // null pointer or invalid size?
 410       {
 411         ptp.code = PTP_RC_GeneralError;
 412         break;
 413       }
 414 
 415       data->get_data_size(data->handle); // XXX required call before receiving
 416       if ( !recv_ptp_data(data,(char *) param2,param3) )
 417       {
 418         ptp.code = PTP_RC_GeneralError;
 419       }
 420       break;
 421 
 422     case PTP_CHDK_CallFunction:
 423       {
 424         int s = data->get_data_size(data->handle);
 425         if (s <= 0 || (s&3)) // no data or not an integer number of args
 426         {
 427           ptp.code = PTP_RC_GeneralError;
 428           break;
 429         }
 430         unsigned *buf = malloc(s);
 431 
 432         if ( buf == NULL )
 433         {
 434           ptp.code = PTP_RC_GeneralError;
 435           break;
 436         }
 437 
 438         if ( recv_ptp_data(data,(char *) buf,s) )
 439         {
 440           ptp.num_param = 1;
 441           ptp.param1 = call_func_ptr((void *)buf[0],(unsigned *)buf+1,(s-4)/4);
 442         } else {
 443           ptp.code = PTP_RC_GeneralError;
 444         }
 445 
 446         free(buf);
 447         break;
 448       }
 449 
 450     case PTP_CHDK_TempData:
 451       if ( param2 & PTP_CHDK_TD_DOWNLOAD )
 452       {
 453         const char *s = NULL;
 454         size_t l = 0;
 455 
 456         if ( temp_data_kind == 0 )
 457         {
 458           ptp.code = PTP_RC_GeneralError;
 459           break;
 460         }
 461 
 462         if ( temp_data_kind == 1 )
 463         {
 464           s = temp_data.str;
 465           l = temp_data_extra;
 466         }
 467 
 468         if ( !send_ptp_data(data,s,l) )
 469         {
 470           ptp.code = PTP_RC_GeneralError;
 471           break;
 472         }
 473         
 474       } else if ( ! (param2 & PTP_CHDK_TD_CLEAR) ) {
 475         if ( temp_data_kind == 1 )
 476         {
 477           free(temp_data.str);
 478         }
 479         temp_data_kind = 0;
 480 
 481         temp_data_extra = data->get_data_size(data->handle);
 482 
 483         temp_data.str = (char *) malloc(temp_data_extra);
 484         if ( temp_data.str == NULL )
 485         {
 486           ptp.code = PTP_RC_GeneralError;
 487           break;
 488         }
 489 
 490         if ( !recv_ptp_data(data,temp_data.str,temp_data_extra) )
 491         {
 492           ptp.code = PTP_RC_GeneralError;
 493           break;
 494         }
 495         temp_data_kind = 1;
 496       }
 497       if ( param2 & PTP_CHDK_TD_CLEAR )
 498       {
 499         if ( temp_data_kind == 1 )
 500         {
 501           free(temp_data.str);
 502         }
 503         temp_data_kind = 0;
 504       }
 505       break;
 506 
 507     case PTP_CHDK_UploadFile:
 508       {
 509         FILE *f=NULL;
 510         char *buf=NULL, *fn=NULL;
 511         unsigned data_size,fn_len,chunk_size;
 512         data_size = data->get_data_size(data->handle);
 513         while ( data_size > 0 ) {
 514             chunk_size = (data_size > buf_size) ? buf_size:data_size;
 515             // first time through
 516             // allocate buffer, parse out the file name and open file
 517             if(!buf) {
 518                 buf=malloc(chunk_size);
 519                 if(!buf) {
 520                     ptp.code = PTP_RC_GeneralError;
 521                     break;
 522                 }
 523                 recv_ptp_data(data,buf,chunk_size);
 524                 fn_len = *(unsigned *)buf;
 525                 fn = malloc(fn_len+1);
 526                 if(!fn) {
 527                     ptp.code = PTP_RC_GeneralError;
 528                     break;
 529                 }
 530                 memcpy(fn,buf+4,fn_len);
 531                 fn[fn_len] = 0;
 532                 f = fopen(fn,"wb");
 533                 free(fn);
 534                 if(!f) {
 535                     ptp.code = PTP_RC_GeneralError;
 536                     break;
 537                 }
 538                 fwrite(buf+4+fn_len,1,chunk_size - 4 - fn_len,f);
 539             } else {
 540                 recv_ptp_data(data,buf,chunk_size);
 541                 fwrite(buf,1,chunk_size,f);
 542             }
 543             data_size -= chunk_size;
 544         }
 545         if(f) {
 546             fclose(f);
 547         }
 548 
 549         free(buf);
 550         if(data_size > 0 && ptp.code != PTP_RC_OK) { 
 551             flush_recv_ptp_data(data,data_size); 
 552         } 
 553         break;
 554       }
 555       
 556     case PTP_CHDK_DownloadFile:
 557       {
 558         FILE *f;
 559         int tmp,t,s,r;
 560         char *buf, *fn;
 561 
 562         if ( temp_data_kind != 1 )
 563         {
 564           // send dummy data, otherwise error hoses connection
 565           send_ptp_data(data,"\0",1);
 566           ptp.code = PTP_RC_GeneralError;
 567           break;
 568         }
 569 
 570         fn = (char *) malloc(temp_data_extra+1);
 571         if ( fn == NULL )
 572         {
 573           // send dummy data, otherwise error hoses connection
 574           send_ptp_data(data,"\0",1);
 575           free(temp_data.str);
 576           temp_data_kind = 0;
 577           ptp.code = PTP_RC_GeneralError;
 578           break;
 579         }
 580         memcpy(fn,temp_data.str,temp_data_extra);
 581         fn[temp_data_extra] = '\0';
 582 
 583         free(temp_data.str);
 584         temp_data_kind = 0;
 585 
 586         f = fopen(fn,"rb");
 587         if ( f == NULL )
 588         {
 589           // send dummy data, otherwise error hoses connection
 590           send_ptp_data(data,"\0",1);
 591           ptp.code = PTP_RC_GeneralError;
 592           free(fn);
 593           break;
 594         }
 595         free(fn);
 596 
 597         fseek(f,0,SEEK_END);
 598         s = ftell(f);
 599         fseek(f,0,SEEK_SET);
 600 
 601         buf = (char *) malloc(buf_size);
 602         if ( buf == NULL )
 603         {
 604           // send dummy data, otherwise error hoses connection
 605           send_ptp_data(data,"\0",1);
 606           ptp.code = PTP_RC_GeneralError;
 607           break;
 608         }
 609 
 610         tmp = s;
 611         t = s;
 612         while ( (r = fread(buf,1,(t<buf_size)?t:buf_size,f)) > 0 )
 613         {
 614           t -= r;
 615           // cannot use send_ptp_data here
 616           data->send_data(data->handle,buf,r,tmp,0,0,0);
 617           tmp = 0;
 618         }
 619         fclose(f);
 620         // XXX check that we actually read/send s bytes! (t == 0)
 621 
 622         ptp.num_param = 1;
 623         ptp.param1 = s;
 624 
 625         free(buf);
 626 
 627         break;
 628       }
 629       break;
 630 
 631     case PTP_CHDK_ExecuteScript:
 632       {
 633         int s;
 634         char *buf;
 635 
 636         ptp.num_param = 2;
 637         ptp.param1 = script_run_id; // in error case, ID of most recent script
 638 
 639         s = data->get_data_size(data->handle);
 640 
 641         if ( (param2&PTP_CHDK_SL_MASK) != PTP_CHDK_SL_LUA )
 642         {
 643           flush_recv_ptp_data(data,s);
 644           ptp.code = PTP_RC_ParameterNotSupported;
 645           break;
 646         }
 647         
 648         buf = (char *) malloc(s);
 649         if ( buf == NULL )
 650         {
 651           ptp.code = PTP_RC_GeneralError;
 652           break;
 653         }
 654 
 655         recv_ptp_data(data,buf,s);
 656 
 657         // applies to both running and "interrupted" state, since interrupted means running restore
 658         if (camera_info.state.state_kbd_script_run) {
 659             // note script ID is still incremented in this case
 660             if (param2 & PTP_CHDK_SCRIPT_FL_NOKILL) {
 661                 // no message is added in this case, since the running script might also be doing 
 662                 // stuff with messages
 663                 ptp.param2 = PTP_CHDK_S_ERR_SCRIPTRUNNING;
 664                 free(buf);
 665                 break;
 666             }
 667             // kill the script
 668             script_wait_terminate();
 669         }
 670         // empty message queues if requested. 
 671         if(param2 & PTP_CHDK_SCRIPT_FL_FLUSH_CAM_MSGS) {
 672             empty_script_msg_q(&msg_q_out);
 673         }
 674         // Script either was not running or has been killed, so safe to remove from inbound queue outside of kbd task
 675         if(param2 & PTP_CHDK_SCRIPT_FL_FLUSH_HOST_MSGS) {
 676             empty_script_msg_q(&msg_q_in);
 677         }
 678 
 679         // increment script ID if script is loaded
 680         script_run_id++;
 681         ptp.param1 = script_run_id;
 682 
 683         // error details will be passed in a message
 684         if (script_start_ptp(buf) < 0) {
 685           ptp.param2 = PTP_CHDK_S_ERRTYPE_COMPILE;
 686         } else {
 687           ptp.param2 = PTP_CHDK_S_ERRTYPE_NONE;
 688         }
 689 
 690         free(buf);
 691         
 692         break;
 693       }
 694     case PTP_CHDK_ReadScriptMsg:
 695     {
 696       char *pdata="";
 697       unsigned datasize=1;
 698 
 699       ptp_script_msg *msg = dequeue_script_msg(&msg_q_out);
 700       ptp.num_param = 4;
 701       if(msg) {
 702         ptp.param1 = msg->type;
 703         ptp.param2 = msg->subtype;
 704         ptp.param3 = msg->script_id;
 705         ptp.param4 = msg->size;
 706         // empty messages must have a data phase, so use default if no data
 707         if(msg->size) {
 708             datasize = msg->size;
 709             pdata = msg->data;
 710         }
 711           } else {
 712         // return a fully formed message for easier handling
 713         ptp.param1 = PTP_CHDK_S_MSGTYPE_NONE;
 714         ptp.param2 = 0;
 715         ptp.param3 = 0;
 716         ptp.param4 = 0;
 717       }
 718 
 719       // NOTE message is lost if sending failed
 720       if ( !send_ptp_data(data,pdata,datasize) )
 721       {
 722         ptp.code = PTP_RC_GeneralError;
 723       }
 724       free(msg);
 725       break;
 726     }
 727     case PTP_CHDK_WriteScriptMsg:
 728     {
 729       int msg_size;
 730       ptp_script_msg *msg;
 731       ptp.num_param = 1;
 732       ptp.param1 = PTP_CHDK_S_MSGSTATUS_OK;
 733       if (!script_is_running()) {
 734         ptp.param1 = PTP_CHDK_S_MSGSTATUS_NOTRUN;
 735       } else if(param2 && param2 != script_run_id) {// check if target script for message is running
 736         ptp.param1 = PTP_CHDK_S_MSGSTATUS_BADID;
 737       } else if(script_msg_q_full(&msg_q_in)) {
 738         ptp.param1 = PTP_CHDK_S_MSGSTATUS_QFULL;
 739       }
 740 
 741       msg_size = data->get_data_size(data->handle);
 742 
 743       // if something was wrong, don't bother creating message, just flush
 744       if(ptp.param1 != PTP_CHDK_S_MSGSTATUS_OK) {
 745         flush_recv_ptp_data(data,msg_size);
 746         break;
 747       }
 748       msg = ptp_script_create_msg(PTP_CHDK_S_MSGTYPE_USER,PTP_CHDK_TYPE_STRING,msg_size,NULL);
 749       if ( !msg ) // malloc error or zero size
 750       {
 751         // if size is zero, things will get hosed no matter what
 752         flush_recv_ptp_data(data,msg_size);
 753         ptp.code = PTP_RC_GeneralError;
 754         break;
 755       }
 756       msg->script_id = param2;
 757       if ( !recv_ptp_data(data,msg->data,msg->size) )
 758       {
 759         ptp.code = PTP_RC_GeneralError;
 760         free(msg);
 761         break;
 762       }
 763       if( !enqueue_script_msg(&msg_q_in,msg) ) {
 764         ptp.code = PTP_RC_GeneralError;
 765         free(msg);
 766       }
 767       break;
 768     }
 769 
 770     case PTP_CHDK_GetDisplayData:
 771         {
 772             extern int live_view_get_data(ptp_data *data, int flags);
 773 
 774             ptp.num_param = 1;
 775             ptp.param1 = live_view_get_data(data,param2);
 776             if(!ptp.param1)
 777             {
 778                 ptp.code = PTP_RC_GeneralError;
 779                 // send dummy data, otherwise error hoses connection
 780                 send_ptp_data(data,"\0",1);
 781             }
 782         }
 783         break;
 784     case PTP_CHDK_RemoteCaptureIsReady:
 785         ptp.num_param = 2;
 786         remotecap_is_ready(&ptp.param1,&ptp.param2);
 787         break;
 788     case PTP_CHDK_RemoteCaptureGetData:
 789         {
 790             unsigned int rcgd_size;
 791             int rcgd_status;
 792             char *rcgd_addr;
 793             int rcgd_pos;
 794 
 795             rcgd_status = remotecap_get_data_chunk(param2, &rcgd_addr, &rcgd_size, &rcgd_pos);
 796             ptp.num_param = 3;
 797             ptp.param3 = rcgd_pos; //client needs to seek to this file position before writing the chunk (-1 = ignore)
 798             if ( (rcgd_addr==0) || (rcgd_size==0) ) {
 799                 // send dummy data, otherwise error hoses connection
 800                 send_ptp_data(data,"\0",1);
 801                 ptp.param1 = 0; //size
 802                 ptp.param2 = 0; //0 = no more chunks
 803             } else {
 804                 // send directly using send_data to avoid multiple send calls
 805                 data->send_data(data->handle,rcgd_addr,rcgd_size,rcgd_size,0,0,0);
 806                 
 807                 ptp.param1 = rcgd_size; //size
 808                 if(rcgd_status == REMOTECAP_CHUNK_STATUS_MORE) {
 809                     ptp.param2 = 1;
 810                 } else {
 811                     ptp.param2 = 0;
 812                 }
 813             }
 814             // data send complete, free hooks etc as needed, set error status if required
 815             if(!remotecap_send_complete(rcgd_status,param2)) {
 816                 ptp.code = PTP_RC_GeneralError;
 817             }
 818         }
 819         break;
 820     default:
 821       ptp.code = PTP_RC_ParameterNotSupported;
 822       break;
 823   }
 824 
 825   // send response
 826   data->send_resp( data->handle, &ptp, 0 );
 827   
 828   return 1;
 829 }

/* [<][>][^][v][top][bottom][index][help] */