source: trunk/core/ptp.c @ 1022

Revision 1022, 10.4 KB checked in by reyalP, 2 years ago (diff)

merge chdkde rev 465 - generic switch_mode_usb, smart buffer size for PTP. Thanks CHDKLover

Line 
1#include "camera.h"
2#ifdef CAM_CHDK_PTP
3#include "platform.h"
4#include "stdlib.h"
5#include "ptp.h"
6#include "action_stack.h"
7#include "lua.h"
8#include "kbd.h"
9
10#include "core.h"
11 
12static int buf_size=0;
13
14#include "script.h"
15
16static lua_State *get_lua_thread(lua_State *L)
17{
18  lua_State *Lt;
19
20  lua_getfield(L,LUA_REGISTRYINDEX,"Lt");
21  Lt = lua_tothread(L,-1);
22  lua_pop(L,1);
23
24  return Lt;
25}
26
27static int handle_ptp(
28                int h, ptp_data *data, int opcode, int sess_id, int trans_id,
29                int param1, int param2, int param3, int param4, int param5);
30
31void init_chdk_ptp()
32{
33  int r;
34 
35  // wait until ptp_handlers_info is initialised and add CHDK PTP interface
36  r = 0x17;
37  while ( r==0x17 )
38  {
39    r = add_ptp_handler(PTP_OC_CHDK,handle_ptp,0);
40    msleep(250);
41  }
42
43  ExitTask();
44}
45
46static int recv_ptp_data(ptp_data *data, char *buf, int size)
47  // repeated calls per transaction are ok
48{
49  while ( size >= buf_size )
50  {
51    data->recv_data(data->handle,buf,buf_size,0,0);
52    // XXX check for success??
53
54    size -= buf_size;
55    buf += buf_size;
56  }
57  if ( size != 0 )
58  {
59    data->recv_data(data->handle,buf,size,0,0);
60    // XXX check for success??
61  }
62
63  return 1;
64}
65
66static int send_ptp_data(ptp_data *data, const char *buf, int size)
67  // repeated calls per transaction are *not* ok
68{
69  int tmpsize;
70 
71  tmpsize = size;
72  while ( size >= buf_size )
73  {
74    if ( data->send_data(data->handle,buf,buf_size,tmpsize,0,0,0) )
75    {
76      return 0;
77    }
78
79    tmpsize = 0;
80    size -= buf_size;
81    buf += buf_size;
82  }
83  if ( size != 0 )
84  {
85    if ( data->send_data(data->handle,buf,size,tmpsize,0,0,0) )
86    {
87      return 0;
88    }
89  }
90
91  return 1;
92}
93
94static int handle_ptp(
95               int h, ptp_data *data, int opcode, int sess_id, int trans_id,
96               int param1, int param2, int param3, int param4, int param5)
97{
98  static union {
99    char *str;
100    lua_State *lua_state;
101  } temp_data;
102  static int temp_data_kind = 0; // 0: nothing, 1: ascii string, 2: lua object
103  static int temp_data_extra; // size (ascii string) or type (lua object)
104  PTPContainer ptp;
105
106  // initialise default response
107  memset(&ptp,0,sizeof(PTPContainer));
108  ptp.code = PTP_RC_OK;
109  ptp.sess_id = sess_id;
110  ptp.trans_id = trans_id;
111  ptp.num_param = 0;
112 
113  buf_size=core_get_free_memory()>>1;
114
115  // handle command
116  switch ( param1 )
117  {
118
119    case PTP_CHDK_Version:
120      ptp.num_param = 2;
121      ptp.param1 = PTP_CHDK_VERSION_MAJOR;
122      ptp.param2 = PTP_CHDK_VERSION_MINOR;
123      break;
124    case PTP_CHDK_ScriptSupport:
125      ptp.num_param = 1;
126      ptp.param1 = PTP_CHDK_SCRIPT_SUPPORT_LUA;
127      break;
128    case PTP_CHDK_ScriptStatus:
129      ptp.num_param = 1;
130      ptp.param1 = script_is_running()?PTP_CHDK_SCRIPT_STATUS_RUN:0;
131      break;
132    case PTP_CHDK_GetMemory:
133      if ( param2 == 0 || param3 < 1 ) // null pointer or invalid size?
134      {
135        ptp.code = PTP_RC_GeneralError;
136        break;
137      }
138
139      if ( !send_ptp_data(data,(char *) param2,param3) )
140      {
141        ptp.code = PTP_RC_GeneralError;
142      }
143      break;
144     
145    case PTP_CHDK_SetMemory:
146      if ( param2 == 0 || param3 < 1 ) // null pointer or invalid size?
147      {
148        ptp.code = PTP_RC_GeneralError;
149        break;
150      }
151
152      data->get_data_size(data->handle); // XXX required call before receiving
153      if ( !recv_ptp_data(data,(char *) param2,param3) )
154      {
155        ptp.code = PTP_RC_GeneralError;
156      }
157      break;
158
159    case PTP_CHDK_CallFunction:
160      {
161        int s;
162        int *buf = (int *) malloc((10+1)*sizeof(int));
163
164        if ( buf == NULL )
165        {
166          ptp.code = PTP_RC_GeneralError;
167          break;
168        }
169
170        s = data->get_data_size(data->handle);
171        if ( !recv_ptp_data(data,(char *) buf,s) )
172        {
173          ptp.code = PTP_RC_GeneralError;
174          break;
175        }
176
177        ptp.num_param = 1;
178        ptp.param1 = ((int (*)(int,int,int,int,int,int,int,int,int,int)) buf[0])(buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7],buf[8],buf[9],buf[10]);
179
180        free(buf);
181        break;
182      }
183
184    case PTP_CHDK_TempData:
185      if ( param2 & PTP_CHDK_TD_DOWNLOAD )
186      {
187        const char *s;
188        size_t l;
189
190        if ( temp_data_kind == 0 )
191        {
192          ptp.code = PTP_RC_GeneralError;
193          break;
194        }
195
196        if ( temp_data_kind == 1 )
197        {
198          s = temp_data.str;
199          l = temp_data_extra;
200        } else { // temp_data_kind == 2
201          s = lua_tolstring(get_lua_thread(temp_data.lua_state),1,&l);
202        }
203
204        if ( !send_ptp_data(data,s,l) )
205        {
206          ptp.code = PTP_RC_GeneralError;
207          break;
208        }
209       
210      } else if ( ! (param2 & PTP_CHDK_TD_CLEAR) ) {
211        if ( temp_data_kind == 1 )
212        {
213          free(temp_data.str);
214        } else if ( temp_data_kind == 2 )
215        {
216          lua_close(temp_data.lua_state);
217        }
218        temp_data_kind = 0;
219
220        temp_data_extra = data->get_data_size(data->handle);
221
222        temp_data.str = (char *) malloc(temp_data_extra);
223        if ( temp_data.str == NULL )
224        {
225          ptp.code = PTP_RC_GeneralError;
226          break;
227        }
228
229        if ( !recv_ptp_data(data,temp_data.str,temp_data_extra) )
230        {
231          ptp.code = PTP_RC_GeneralError;
232          break;
233        }
234        temp_data_kind = 1;
235      }
236      if ( param2 & PTP_CHDK_TD_CLEAR )
237      {
238        if ( temp_data_kind == 1 )
239        {
240          free(temp_data.str);
241        } else if ( temp_data_kind == 2 )
242        {
243          lua_close(temp_data.lua_state);
244        }
245        temp_data_kind = 0;
246      }
247      break;
248
249    case PTP_CHDK_UploadFile:
250      {
251        FILE *f;
252        int s,r,fn_len;
253        char *buf, *fn;
254
255        s = data->get_data_size(data->handle);
256
257        recv_ptp_data(data,(char *) &fn_len,4);
258        s -= 4;
259
260        fn = (char *) malloc(fn_len+1);
261        if ( fn == NULL )
262        {
263          ptp.code = PTP_RC_GeneralError;
264          break;
265        }
266        fn[fn_len] = '\0';
267
268        recv_ptp_data(data,fn,fn_len);
269        s -= fn_len;
270
271        f = fopen(fn,"wb");
272        if ( f == NULL )
273        {
274          ptp.code = PTP_RC_GeneralError;
275          free(fn);
276          break;
277        }
278        free(fn);
279
280        buf = (char *) malloc(buf_size);
281        if ( buf == NULL )
282        {
283          ptp.code = PTP_RC_GeneralError;
284          break;
285        }
286        while ( s > 0 )
287        {
288          if ( s >= buf_size )
289          {
290            recv_ptp_data(data,buf,buf_size);
291            fwrite(buf,1,buf_size,f);
292            s -= buf_size;
293          } else {
294            recv_ptp_data(data,buf,s);
295            fwrite(buf,1,s,f);
296            s = 0;
297          }
298        }
299
300        fclose(f);
301
302        free(buf);
303        break;
304      }
305     
306    case PTP_CHDK_DownloadFile:
307      {
308        FILE *f;
309        int tmp,t,s,r,fn_len;
310        char *buf, *fn;
311
312        if ( temp_data_kind != 1 )
313        {
314          ptp.code = PTP_RC_GeneralError;
315          break;
316        }
317
318        fn = (char *) malloc(temp_data_extra+1);
319        if ( fn == NULL )
320        {
321          free(temp_data.str);
322          temp_data_kind = 0;
323          ptp.code = PTP_RC_GeneralError;
324          break;
325        }
326        memcpy(fn,temp_data.str,temp_data_extra);
327        fn[temp_data_extra] = '\0';
328
329        free(temp_data.str);
330        temp_data_kind = 0;
331
332        f = fopen(fn,"rb");
333        if ( f == NULL )
334        {
335          ptp.code = PTP_RC_GeneralError;
336          free(fn);
337          break;
338        }
339        free(fn);
340
341        fseek(f,0,SEEK_END);
342        s = ftell(f);
343        fseek(f,0,SEEK_SET);
344
345        buf = (char *) malloc(buf_size);
346        if ( buf == NULL )
347        {
348          ptp.code = PTP_RC_GeneralError;
349          break;
350        }
351
352        tmp = s;
353        t = s;
354        while ( (r = fread(buf,1,(t<buf_size)?t:buf_size,f)) > 0 )
355        {
356          t -= r;
357          // cannot use send_ptp_data here
358          data->send_data(data->handle,buf,r,tmp,0,0,0);
359          tmp = 0;
360        }
361        fclose(f);
362        // XXX check that we actually read/send s bytes! (t == 0)
363
364        ptp.num_param = 1;
365        ptp.param1 = s;
366
367        free(buf);
368
369        break;
370      }
371      break;
372
373    case PTP_CHDK_ExecuteScript:
374      {
375        int s;
376        char *buf;
377
378        if ( param2 != PTP_CHDK_SL_LUA )
379        {
380          ptp.code = PTP_RC_ParameterNotSupported;
381          break;
382        }
383
384        s = data->get_data_size(data->handle);
385       
386        buf = (char *) malloc(s);
387        if ( buf == NULL )
388        {
389          ptp.code = PTP_RC_GeneralError;
390          break;
391        }
392
393        recv_ptp_data(data,buf,s);
394
395        long script_action_stack = script_start_ptp(buf, param3&PTP_CHDK_ES_RESULT);
396
397        free(buf);
398
399        if ( param3 & PTP_CHDK_ES_WAIT )
400        {
401
402          while ( script_is_running() )
403            msleep(100);
404
405          if ( param3 & PTP_CHDK_ES_RESULT )
406          {
407            lua_State *Lt;
408            temp_data.lua_state = lua_consume_result();
409            Lt = get_lua_thread(temp_data.lua_state);
410            temp_data_kind = 2;
411            if ( lua_gettop(Lt) == 0 )
412            {
413              temp_data_extra = PTP_CHDK_TYPE_NOTHING;
414            } else if ( lua_isnil(Lt,1) )
415            {
416              temp_data_extra = PTP_CHDK_TYPE_NIL;
417            } else if ( lua_isboolean(Lt,1) )
418            {
419              temp_data_extra = PTP_CHDK_TYPE_BOOLEAN;
420            } else if ( lua_isnumber(Lt,1) )
421            {
422              temp_data_extra = PTP_CHDK_TYPE_INTEGER;
423            } else if ( lua_isstring(Lt,1) )
424            {
425              temp_data_extra = PTP_CHDK_TYPE_STRING;
426            } else {
427              temp_data_extra = PTP_CHDK_TYPE_NOTHING;
428            }
429            ptp.num_param = 1;
430            ptp.param1 = temp_data_extra;
431            if ( temp_data_extra != PTP_CHDK_TYPE_STRING )
432            {
433              if ( temp_data_extra == PTP_CHDK_TYPE_BOOLEAN )
434              {
435                ptp.num_param = 2;
436                ptp.param2 = lua_toboolean(Lt,1);
437              } if ( temp_data_extra == PTP_CHDK_TYPE_INTEGER )
438              {
439                ptp.num_param = 2;
440                ptp.param2 = lua_tonumber(Lt,1);
441              }
442              lua_close(Lt);
443              temp_data_kind = 0;
444            } else {
445              ptp.num_param = 2;
446              ptp.param2 = lua_objlen(Lt,1);
447            }
448          }
449        }
450
451        break;
452      }
453
454    default:
455      ptp.code = PTP_RC_ParameterNotSupported;
456      break;
457  }
458
459  // send response
460  data->send_resp( data->handle, &ptp );
461 
462  return 1;
463}
464
465#endif // CAM_CHDK_PTP
Note: See TracBrowser for help on using the repository browser.