source: trunk/core/ptp.c @ 1005

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

add PTP ScriptStatus? and ScriptSupport? commands, based on patch from ultimA in http://chdk.setepontos.com/index.php?topic=5793.msg57788#msg57788 with some modifications
updated CHDK ptp protocol minor to 0.2
ScriptStatus? returns a bitmask of status values. Bit 0 of param 1 is set if script is running, otherwise cleared
ScriptSupport? returns a bitmask of supported scripting interfaces. Bit 0 of param 1 is set if Lua is supported, otherwise cleared
Values of other bits or params can be added as a minor protocol change.

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    case PTP_CHDK_ScriptSupport:
120      ptp.num_param = 1;
121      ptp.param1 = PTP_CHDK_SCRIPT_SUPPORT_LUA;
122      break;
123    case PTP_CHDK_ScriptStatus:
124      ptp.num_param = 1;
125      ptp.param1 = script_is_running()?PTP_CHDK_SCRIPT_STATUS_RUN:0;
126      break;
127    case PTP_CHDK_GetMemory:
128      if ( param2 == 0 || param3 < 1 ) // null pointer or invalid size?
129      {
130        ptp.code = PTP_RC_GeneralError;
131        break;
132      }
133
134      if ( !send_ptp_data(data,(char *) param2,param3) )
135      {
136        ptp.code = PTP_RC_GeneralError;
137      }
138      break;
139     
140    case PTP_CHDK_SetMemory:
141      if ( param2 == 0 || param3 < 1 ) // null pointer or invalid size?
142      {
143        ptp.code = PTP_RC_GeneralError;
144        break;
145      }
146
147      data->get_data_size(data->handle); // XXX required call before receiving
148      if ( !recv_ptp_data(data,(char *) param2,param3) )
149      {
150        ptp.code = PTP_RC_GeneralError;
151      }
152      break;
153
154    case PTP_CHDK_CallFunction:
155      {
156        int s;
157        int *buf = (int *) malloc((10+1)*sizeof(int));
158
159        if ( buf == NULL )
160        {
161          ptp.code = PTP_RC_GeneralError;
162          break;
163        }
164
165        s = data->get_data_size(data->handle);
166        if ( !recv_ptp_data(data,(char *) buf,s) )
167        {
168          ptp.code = PTP_RC_GeneralError;
169          break;
170        }
171
172        ptp.num_param = 1;
173        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]);
174
175        free(buf);
176        break;
177      }
178
179    case PTP_CHDK_TempData:
180      if ( param2 & PTP_CHDK_TD_DOWNLOAD )
181      {
182        const char *s;
183        size_t l;
184
185        if ( temp_data_kind == 0 )
186        {
187          ptp.code = PTP_RC_GeneralError;
188          break;
189        }
190
191        if ( temp_data_kind == 1 )
192        {
193          s = temp_data.str;
194          l = temp_data_extra;
195        } else { // temp_data_kind == 2
196          s = lua_tolstring(get_lua_thread(temp_data.lua_state),1,&l);
197        }
198
199        if ( !send_ptp_data(data,s,l) )
200        {
201          ptp.code = PTP_RC_GeneralError;
202          break;
203        }
204       
205      } else if ( ! (param2 & PTP_CHDK_TD_CLEAR) ) {
206        if ( temp_data_kind == 1 )
207        {
208          free(temp_data.str);
209        } else if ( temp_data_kind == 2 )
210        {
211          lua_close(temp_data.lua_state);
212        }
213        temp_data_kind = 0;
214
215        temp_data_extra = data->get_data_size(data->handle);
216
217        temp_data.str = (char *) malloc(temp_data_extra);
218        if ( temp_data.str == NULL )
219        {
220          ptp.code = PTP_RC_GeneralError;
221          break;
222        }
223
224        if ( !recv_ptp_data(data,temp_data.str,temp_data_extra) )
225        {
226          ptp.code = PTP_RC_GeneralError;
227          break;
228        }
229        temp_data_kind = 1;
230      }
231      if ( param2 & PTP_CHDK_TD_CLEAR )
232      {
233        if ( temp_data_kind == 1 )
234        {
235          free(temp_data.str);
236        } else if ( temp_data_kind == 2 )
237        {
238          lua_close(temp_data.lua_state);
239        }
240        temp_data_kind = 0;
241      }
242      break;
243
244    case PTP_CHDK_UploadFile:
245      {
246        FILE *f;
247        int s,r,fn_len;
248        char *buf, *fn;
249
250        s = data->get_data_size(data->handle);
251
252        recv_ptp_data(data,(char *) &fn_len,4);
253        s -= 4;
254
255        fn = (char *) malloc(fn_len+1);
256        if ( fn == NULL )
257        {
258          ptp.code = PTP_RC_GeneralError;
259          break;
260        }
261        fn[fn_len] = '\0';
262
263        recv_ptp_data(data,fn,fn_len);
264        s -= fn_len;
265
266        f = fopen(fn,"wb");
267        if ( f == NULL )
268        {
269          ptp.code = PTP_RC_GeneralError;
270          free(fn);
271          break;
272        }
273        free(fn);
274
275        buf = (char *) malloc(BUF_SIZE);
276        if ( buf == NULL )
277        {
278          ptp.code = PTP_RC_GeneralError;
279          break;
280        }
281        while ( s > 0 )
282        {
283          if ( s >= BUF_SIZE )
284          {
285            recv_ptp_data(data,buf,BUF_SIZE);
286            fwrite(buf,1,BUF_SIZE,f);
287            s -= BUF_SIZE;
288          } else {
289            recv_ptp_data(data,buf,s);
290            fwrite(buf,1,s,f);
291            s = 0;
292          }
293        }
294
295        fclose(f);
296
297        free(buf);
298        break;
299      }
300     
301    case PTP_CHDK_DownloadFile:
302      {
303        FILE *f;
304        int tmp,t,s,r,fn_len;
305        char *buf, *fn;
306
307        if ( temp_data_kind != 1 )
308        {
309          ptp.code = PTP_RC_GeneralError;
310          break;
311        }
312
313        fn = (char *) malloc(temp_data_extra+1);
314        if ( fn == NULL )
315        {
316          free(temp_data.str);
317          temp_data_kind = 0;
318          ptp.code = PTP_RC_GeneralError;
319          break;
320        }
321        memcpy(fn,temp_data.str,temp_data_extra);
322        fn[temp_data_extra] = '\0';
323
324        free(temp_data.str);
325        temp_data_kind = 0;
326
327        f = fopen(fn,"rb");
328        if ( f == NULL )
329        {
330          ptp.code = PTP_RC_GeneralError;
331          free(fn);
332          break;
333        }
334        free(fn);
335
336        fseek(f,0,SEEK_END);
337        s = ftell(f);
338        fseek(f,0,SEEK_SET);
339
340        buf = (char *) malloc(BUF_SIZE);
341        if ( buf == NULL )
342        {
343          ptp.code = PTP_RC_GeneralError;
344          break;
345        }
346
347        tmp = s;
348        t = s;
349        while ( (r = fread(buf,1,(t<BUF_SIZE)?t:BUF_SIZE,f)) > 0 )
350        {
351          t -= r;
352          // cannot use send_ptp_data here
353          data->send_data(data->handle,buf,r,tmp,0,0,0);
354          tmp = 0;
355        }
356        fclose(f);
357        // XXX check that we actually read/send s bytes! (t == 0)
358
359        ptp.num_param = 1;
360        ptp.param1 = s;
361
362        free(buf);
363
364        break;
365      }
366      break;
367
368    case PTP_CHDK_ExecuteScript:
369      {
370        int s;
371        char *buf;
372
373        if ( param2 != PTP_CHDK_SL_LUA )
374        {
375          ptp.code = PTP_RC_ParameterNotSupported;
376          break;
377        }
378
379        s = data->get_data_size(data->handle);
380       
381        buf = (char *) malloc(s);
382        if ( buf == NULL )
383        {
384          ptp.code = PTP_RC_GeneralError;
385          break;
386        }
387
388        recv_ptp_data(data,buf,s);
389
390        long script_action_stack = script_start_ptp(buf, param3&PTP_CHDK_ES_RESULT);
391
392        free(buf);
393
394        if ( param3 & PTP_CHDK_ES_WAIT )
395        {
396
397          while ( script_is_running() )
398            msleep(100);
399
400          if ( param3 & PTP_CHDK_ES_RESULT )
401          {
402            lua_State *Lt;
403            temp_data.lua_state = lua_get_result();
404            Lt = get_lua_thread(temp_data.lua_state);
405            temp_data_kind = 2;
406            if ( lua_gettop(Lt) == 0 )
407            {
408              temp_data_extra = PTP_CHDK_TYPE_NOTHING;
409            } else if ( lua_isnil(Lt,1) )
410            {
411              temp_data_extra = PTP_CHDK_TYPE_NIL;
412            } else if ( lua_isboolean(Lt,1) )
413            {
414              temp_data_extra = PTP_CHDK_TYPE_BOOLEAN;
415            } else if ( lua_isnumber(Lt,1) )
416            {
417              temp_data_extra = PTP_CHDK_TYPE_INTEGER;
418            } else if ( lua_isstring(Lt,1) )
419            {
420              temp_data_extra = PTP_CHDK_TYPE_STRING;
421            } else {
422              temp_data_extra = PTP_CHDK_TYPE_NOTHING;
423            }
424            ptp.num_param = 1;
425            ptp.param1 = temp_data_extra;
426            if ( temp_data_extra != PTP_CHDK_TYPE_STRING )
427            {
428              if ( temp_data_extra == PTP_CHDK_TYPE_BOOLEAN )
429              {
430                ptp.num_param = 2;
431                ptp.param2 = lua_toboolean(Lt,1);
432              } if ( temp_data_extra == PTP_CHDK_TYPE_INTEGER )
433              {
434                ptp.num_param = 2;
435                ptp.param2 = lua_tonumber(Lt,1);
436              }
437              lua_close(Lt);
438              temp_data_kind = 0;
439            } else {
440              ptp.num_param = 2;
441              ptp.param2 = lua_objlen(Lt,1);
442            }
443          }
444        }
445
446        break;
447      }
448
449    default:
450      ptp.code = PTP_RC_ParameterNotSupported;
451      break;
452  }
453
454  // send response
455  data->send_resp( data->handle, &ptp );
456 
457  return 1;
458}
459
460#endif // CAM_CHDK_PTP
Note: See TracBrowser for help on using the repository browser.