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_init
  4. recv_ptp_data_chunk
  5. recv_ptp_data_finish
  6. recv_ptp_data
  7. flush_recv_ptp_data
  8. send_ptp_data_buf_init
  9. send_ptp_data_buf_free
  10. send_ptp_data
  11. send_ptp_data_buffered
  12. script_msg_q_next
  13. script_msg_q_full
  14. script_msg_q_empty
  15. enqueue_script_msg
  16. dequeue_script_msg
  17. empty_script_msg_q
  18. ptp_script_create_msg
  19. ptp_script_write_msg
  20. ptp_script_read_msg
  21. ptp_script_write_error_msg
  22. start_ptp_script
  23. script_start_ptp
  24. handle_ptp

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

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