source: trunk/core/ptp.c @ 1020

Revision 1020, 10.8 KB checked in by reyalP, 2 years ago (diff)

more script code refactoring from ultima in http://chdk.setepontos.com/index.php?topic=5793.msg59228#msg59228
minor modifications from the patch - didn't include ubasic error change, include lstate.h only in luascript.c

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