source: trunk/core/ptp.c @ 1000

Revision 1000, 10.6 KB checked in by reyalp, 2 years ago (diff)

more preparation for making script optional - split scriptable actions out of kbd.c from ultimA in http://chdk.setepontos.com/index.php?topic=5793.msg57539#msg57539

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