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
  9. send_ptp_data_buffered
  10. script_msg_q_next
  11. script_msg_q_full
  12. script_msg_q_empty
  13. enqueue_script_msg
  14. dequeue_script_msg
  15. empty_script_msg_q
  16. ptp_script_create_msg
  17. ptp_script_write_msg
  18. ptp_script_read_msg
  19. ptp_script_write_error_msg
  20. start_ptp_script
  21. script_start_ptp
  22. handle_ptp

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

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