source: trunk/core/script.c @ 1051

Revision 1051, 19.2 KB checked in by msl, 2 years ago (diff)

Fix camera crash because syntax error in ptpcam

+ lua(r) syntax error will be shown direct in ptpcam.

+ fix in ptpcam chdkde changeset 560: http://my-trac.assembla.com/chdkde/changeset/560

  • Property svn:eol-style set to native
Line 
1#include "stdlib.h"
2#include "keyboard.h"
3#include "platform.h"
4#include "core.h"
5#include "gui.h"
6#include "gui_draw.h"
7#include "conf.h"
8#include "script.h"
9#include "console.h"
10#include "action_stack.h"
11#include "motion_detector.h"
12#include "shot_histogram.h"
13#include "lang.h"
14#include "gui_lang.h"
15#include "kbd.h"
16
17#ifdef OPT_LUA
18#include "lauxlib.h"
19#endif
20
21//-------------------------------------------------------------------
22
23const char *script_source_str=NULL; //ERR99
24char cfg_name[100] = "\0";
25char cfg_set_name[100] = "\0";
26
27static const char *ubasic_script_default =
28#if 0
29    "@title Default script\n"
30    "@param a Shoot count\n"
31    "@default a 2\n"
32    "@param b Step\n"
33    "@default b 3\n"
34
35    "sleep 1000\n"
36
37    "if a<1 then let a=2\n"
38    "if b<1 then let b=3\n"
39
40    "for s=1 to a\n"
41      "shoot\n"
42      "for n=1 to b\n"
43        "click \"right\"\n"
44      "next n\n"
45    "next s\n"
46    "shoot\n"
47
48    "for n=1 to a*b\n"
49      "click \"left\"\n"
50    "next n\n"
51
52    "end\n";
53#else
54    "@title Default Script\n"
55    "@param a Times to Repeat\n"
56    "@default a 5\n"
57    "@param b Display Delay\n"
58    "@default b 3\n"
59
60    "if a<1 then let a=1\n"
61    "if b<1 then let b=1\n"
62
63    "for n=1 to a\n"
64        "if n>1 then print \"*****\"\n"
65        "print \"This is a default script.\"\n"
66        "sleep 1000\n"
67        "print \"Scripts run when shutter\"\n"
68        "sleep 1000\n"
69        "print \"is pressed in ALT mode.\"\n"
70        "sleep 1000\n"
71        "print \"Press shutter to exit.\"\n"
72        "sleep b*1000\n"
73    "next n\n"
74
75    "end\n";
76#endif
77
78char script_title[36];
79char script_params[SCRIPT_NUM_PARAMS][28];
80int script_param_order[SCRIPT_NUM_PARAMS];
81static char script_params_update[SCRIPT_NUM_PARAMS];
82static int script_loaded_params[SCRIPT_NUM_PARAMS];
83static long running_script_stack_name = -1;
84
85#ifdef OPT_LUA
86static int state_lua_kbd_first_call_to_resume;  // AUJ
87#endif
88
89//-------------------------------------------------------------------
90static void process_title(const char *title) {
91    register const char *ptr = title;
92    register int i=0;
93
94    while (ptr[0]==' ' || ptr[0]=='\t') ++ptr; // whitespaces
95    while (i<(sizeof(script_title)-1) && ptr[i] && ptr[i]!='\r' && ptr[i]!='\n') {
96        script_title[i]=ptr[i];
97        ++i;
98    }
99    script_title[i]=0;
100}
101
102//-------------------------------------------------------------------
103static int process_param(const char *param, int update) {
104    register const char *ptr = param;
105    register int n, i=0;
106
107    while (ptr[0]==' ' || ptr[0]=='\t') ++ptr; // whitespaces
108    if (ptr[0] && (ptr[0]>='a' && ptr[0]<='a'+SCRIPT_NUM_PARAMS) && (ptr[1]==' ' || ptr[1]=='\t')) {
109        n=ptr[0]-'a';
110        ptr+=2;
111        while (ptr[0]==' ' || ptr[0]=='\t') ++ptr; // whitespaces
112                script_params_update[n] = 1;
113        while (i<(sizeof(script_params[0])-1) && ptr[i] && ptr[i]!='\r' && ptr[i]!='\n') {
114                        if (update)
115                        { if (script_params[n][i]!=ptr[i]) { script_params_update[n] = 0; break; }
116                        } else script_params[n][i]=ptr[i];
117            ++i;
118        }
119                if (!update) script_params[n][i]=0;
120        n++;
121    } else n=0; // ??? else produce error message   
122    return n; // n=1 if '@param a' was processed, n=2 for 'b' ... n=26 for 'z'. n=0 if failed.
123}
124
125//-------------------------------------------------------------------
126static void process_default(const char *param, char update) {
127    register const char *ptr = param;
128    register int n;
129
130    while (ptr[0]==' ' || ptr[0]=='\t') ++ptr; // whitespaces
131    if (ptr[0] && (ptr[0]>='a' && ptr[0]<='a'+SCRIPT_NUM_PARAMS) && (ptr[1]==' ' || ptr[1]=='\t')) {
132        n=ptr[0]-'a';
133        ptr+=2;
134                if (!update || script_params_update[n])
135        {
136                        conf.ubasic_vars[n] = strtol(ptr, NULL, 0);
137            script_loaded_params[n] = conf.ubasic_vars[n];
138        }
139    } // ??? else produce error message
140}
141
142//-------------------------------------------------------------------
143static void script_scan(const char *fn, int update_vars) {
144    register const char *ptr = script_source_str;
145    register int i, j=0, n;
146    char *c;
147
148    c=strrchr(fn, '/');
149    strncpy(script_title, (c)?c+1:fn, sizeof(script_title));
150    script_title[sizeof(script_title)-1]=0;
151    for (i=0; i<SCRIPT_NUM_PARAMS; ++i) {
152        script_params[i][0]=0;
153        script_param_order[i]=0;
154    }
155
156    while (ptr[0]) {
157        while (ptr[0]==' ' || ptr[0]=='\t') ++ptr; // whitespaces
158        if (ptr[0]=='@') {
159            if (strncmp("@title", ptr, 6)==0) {
160                ptr+=6;
161                process_title(ptr);
162            } else if (strncmp("@param", ptr, 6)==0) {
163                ptr+=6;
164                n=process_param(ptr, 0); // n=1 if '@param a' was processed, n=2 for 'b' ... n=26 for 'z'. n=0 if failed.
165                if (n>0 && n<=SCRIPT_NUM_PARAMS) {
166                  script_param_order[j]=n;
167                  j++;
168                }
169            } else if (update_vars && strncmp("@default", ptr, 8)==0) {
170                ptr+=8;
171                process_default(ptr, 0);
172            }
173        }
174        while (ptr[0] && ptr[0]!='\n') ++ptr; // unless end of line
175        if (ptr[0]) ++ptr;
176    }
177
178    /*for (i=0; i<SCRIPT_NUM_PARAMS; ++i) {
179        if (script_params[i][0]) break;
180    }
181    if (i==SCRIPT_NUM_PARAMS) { // there was no @param in script
182        for (i=0; i<3; ++i) {
183            strcpy(script_params[i], "Var. ? value");
184            script_params[i][5]='a'+i;
185        }
186    }*/
187}
188
189void set_params_values_name(const char *fn, int param_set)
190{
191        int shift;
192        register char *ptr = (param_set >= 0 ? cfg_set_name : cfg_name);
193        const char *name;
194       
195        if (fn == NULL || fn[0] == 0) { ptr[0] = 0; return; }
196       
197        strncpy(ptr, SCRIPT_DATA_PATH, 100); ptr[99]=0;
198        shift = strlen(SCRIPT_DATA_PATH);
199        name = strrchr(fn, '/');
200        if (name) name++; else name=fn;
201        strncpy(ptr+shift, name, 100-shift); ptr[99]=0;
202        shift = strlen(ptr); if (shift >= 100) shift=99;
203
204        if (param_set >= 0)
205                sprintf(ptr+shift-4, "_%d\0", param_set); else
206                strcpy(ptr+shift-3, "cfg\0");
207}
208
209//-------------------------------------------------------------------
210int load_params_values(const char *fn, int update_vars, int read_param_set)
211{
212        int i, fd=-1, rcnt;
213        register const char *ptr;       
214        struct stat st;
215        char *buf;
216       
217        if (fn == NULL || fn[0] == 0) return 0;
218        if (read_param_set)
219        {
220                set_params_values_name(fn, -1);
221                // find param set
222                fd = open(cfg_name, O_RDONLY, 0777);
223                if (fd >= 0)
224                {
225                        buf=umalloc(16);
226                        rcnt = read(fd, buf, 15);
227                        buf[rcnt] = 0;
228                        close(fd);
229                        conf.script_param_set = strtol(buf, NULL, 0);
230                        ufree(buf);
231                } else conf.script_param_set = 0;
232        }
233        set_params_values_name(fn, conf.script_param_set);
234        if (!update_vars) return 0;
235       
236        // open and read file
237        if (stat(cfg_set_name,&st) != 0)
238                return 0;
239        buf=umalloc(st.st_size+1);
240        if(!buf)
241                return 0;
242        fd = open(cfg_set_name, O_RDONLY, 0777);
243        if (fd < 0) {
244                ufree(buf);
245                return 0;
246        }
247        rcnt = read(fd, buf, st.st_size);
248        buf[rcnt] = 0;
249        close(fd);
250
251        for(i = 0; i < SCRIPT_NUM_PARAMS; ++i) script_params_update[i]=0;
252    ptr = buf;
253
254    while (ptr[0])
255        {
256        while (ptr[0]==' ' || ptr[0]=='\t') ++ptr; // whitespaces
257        if (ptr[0]=='@')
258                {
259            if (strncmp("@param", ptr, 6) == 0)
260                        {
261                ptr+=6;
262                                process_param(ptr, 1);
263            } else if (strncmp("@default", ptr, 8)==0) {
264                ptr+=8;
265                                process_default(ptr, 1);
266            }
267        }
268        while (ptr[0] && ptr[0]!='\n') ++ptr; // unless end of line
269        if (ptr[0]) ++ptr;
270    }
271        ufree(buf);
272        return 1;
273}
274
275//-------------------------------------------------------------------
276void save_params_values(int unconditional)
277{
278        int i, n, fd, changed=0;
279        char *buf,*p;
280        for(i = 0; i < SCRIPT_NUM_PARAMS; i++)
281        {
282                if (script_loaded_params[i] != conf.ubasic_vars[i]) changed++;
283                script_loaded_params[i] = conf.ubasic_vars[i];
284        }
285        if (!unconditional && !changed) return;
286
287        if (cfg_name[0] == 0) set_params_values_name(conf.script_file, -1);
288        fd = open(cfg_name, O_WRONLY|O_CREAT, 0777);
289        if (fd >= 0)
290        {
291                char s[20];
292                sprintf(s, " %d\n", conf.script_param_set);
293                write(fd, s, strlen(s));
294                close(fd);
295        }
296       
297        // open and read file
298        set_params_values_name(conf.script_file, conf.script_param_set);
299
300        buf=umalloc(SCRIPT_NUM_PARAMS*(28 + 20)); // max possible params * (param description + some extra for @default etc)
301        if(!buf)
302                return;
303
304        fd = open(cfg_set_name, O_WRONLY|O_CREAT, 0777);
305        if (fd < 0) {
306                ufree(buf);
307                return;
308        }
309        buf[0] = 0;
310        p=buf;
311        for(n = 0; n < SCRIPT_NUM_PARAMS; ++n)
312        {
313                if (script_params[n][0] != 0)
314                {
315                        p+=sprintf(p,"@param %c %s\n@default %c %d\n",'a'+n,script_params[n],'a'+n,conf.ubasic_vars[n]);
316                }
317        }
318        write(fd, buf, strlen(buf));
319        close(fd);
320        ufree(buf);
321}
322
323
324
325//-------------------------------------------------------------------
326void script_load(const char *fn, int saved_params) {
327    int i, update_vars;
328    FILE *fd = NULL;
329    struct stat st;
330   
331//    save_params_values(0);
332
333    if(script_source_str && script_source_str != ubasic_script_default)
334        free((void *)script_source_str);
335
336    script_source_str = ubasic_script_default;
337    update_vars = (strcmp(fn, conf.script_file) != 0) || !saved_params || (saved_params == 2);  // update if new file
338
339    if (!fn[0]) { // load internal script
340        if (!conf.script_file[0]) { // internal script was used last time
341            fd = fopen(SCRIPT_DEFAULT_FILENAME, "rb");
342            if (fd) {
343                fn = SCRIPT_DEFAULT_FILENAME;
344                update_vars = 1;
345            }
346        }
347    } else {
348        fd = fopen(fn, "rb");
349        if (!fd) {
350            conf.script_file[0]=0;
351            update_vars = 1;
352        }
353    }
354    // zero size = default script
355    if(stat(fn,&st) != 0 || st.st_size == 0) {
356        conf.script_file[0]=0;
357        update_vars = 1;
358        if(fd) {
359            fclose(fd);
360            fd=0;
361        }
362    }
363    if (fd){
364        int rcnt;
365        char *buf;
366
367        buf = malloc(st.st_size+1);
368        if(!buf) {
369            fclose(fd);
370            return;
371        }
372
373        // TODO we could process the script here to reduce size
374        // or compile for lua
375        rcnt = fread(buf, 1, st.st_size,fd);
376        if (rcnt > 0){
377            buf[rcnt] = 0;
378            script_source_str = buf;
379            strcpy(conf.script_file, fn);
380        }
381        else {
382            free(buf);
383        }
384        fclose(fd);
385    }
386
387    if (update_vars) {
388        for (i=0; i<SCRIPT_NUM_PARAMS; ++i) {
389            conf.ubasic_vars[i] = 0;
390            script_loaded_params[i] = 0;
391        }
392    }
393    script_scan(conf.script_file, update_vars);
394    if (saved_params)
395        load_params_values(conf.script_file, update_vars, (saved_params!=2));   
396    gui_update_script_submenu();
397}
398
399//-------------------------------------------------------------------
400static int  print_screen_p;             // print_screen predicate: 0-off 1-on.
401static int  print_screen_d = -1;        // print_screen file descriptor.
402//static const char print_screen_file[] ="A/CHDK/SCRIPTS/PR_SCREEN.TXT";
403static const char print_screen_file_prefix[] = "A/CHDK/LOGS/LOG_";
404char print_screen_file[25];
405static const char extension_txt[] = ".TXT";
406
407void script_print_screen_init()
408{
409  print_screen_p = 0;
410  if (print_screen_d >= 0) {
411    close(print_screen_d);
412    print_screen_d = -1;
413  }
414}
415
416void script_print_screen_end()
417{
418  if (print_screen_d >= 0) {
419    close(print_screen_d);
420    print_screen_d = -1;
421    print_screen_p = 0;
422  }
423}
424
425void script_print_screen_statement(int val)
426{
427  print_screen_p = val;
428  if (val) {
429    if (print_screen_d>=0) close(print_screen_d);
430    int i=0;
431    int c=0;
432    static char file_number[5];
433    strcpy(print_screen_file, print_screen_file_prefix);
434    if (val<0) val = -val;
435    while (val > 9999) val += -10000;
436    for (i=10; i<=1000; i=i*10) { if (val<i) ++c; }
437    for (i=1; i<=c; ++i) { sprintf(file_number, "%d", 0); strcat(print_screen_file, file_number); }
438    sprintf(file_number, "%d", val);
439    strcat(print_screen_file, file_number);
440    strcat(print_screen_file, extension_txt);
441    print_screen_d = open(print_screen_file, O_WRONLY|O_CREAT|O_TRUNC, 0777);
442  }
443}
444
445void script_console_add_line(const char *str)
446{
447    console_add_line(str);
448
449    if (print_screen_p && (print_screen_d >= 0)) {
450        char nl = '\n';
451                // TODO this should be uncached memory
452        write(print_screen_d, str, strlen(str) );
453        write(print_screen_d, &nl, 1);
454    }
455}
456
457static int is_lua()
458{
459  int len;
460  char const* s;
461  s = conf.script_file;
462  len = strlen( s );
463  return len >= 4 && ( s[len-1] == 'a' || s[len-1] == 'A' )
464    && ( s[len-2] == 'u' || s[len-2] == 'U' )
465    && ( s[len-3] == 'l' || s[len-3] == 'L' )
466    && s[len-4] == '.';
467}
468
469static void wait_and_end(void)
470{
471        script_console_add_line("PRESS SHUTTER TO CLOSE");
472
473        // We're not running any more, but we have scheduled stuff that
474        // needs to finish. So keep the script marked as running, but don't
475        // call any more scripting functions.
476        state_kbd_script_run = 3;       
477}
478
479static void process_script()
480{   // Note: This function is called from an action stack for AS_SCRIPT_RUN.
481   
482    long t;
483    int Lres;
484
485    if (state_kbd_script_run != 3) {
486#ifdef OPT_LUA
487        if( L ) {
488            int top;
489            if (state_lua_kbd_first_call_to_resume) {
490                state_lua_kbd_first_call_to_resume = 0;
491                top = 0;
492            } else {
493                top = lua_gettop(Lt);
494            }
495            Lres = lua_resume( Lt, top );
496
497            if (Lres != LUA_YIELD && Lres != 0) {
498                script_console_add_line( lua_tostring( Lt, -1 ) );
499                if(conf.debug_lua_restart_on_error){
500                    lua_script_reset();
501                    script_start_gui(0);
502                } else {
503                    wait_and_end();
504                }
505                return;
506            }
507
508            if (Lres != LUA_YIELD) {
509                script_console_add_line(lang_str(LANG_CONSOLE_TEXT_FINISHED));
510                action_pop();
511                script_end();
512            }   
513        } else
514#endif
515        {
516#ifdef OPT_UBASIC
517            ubasic_run();
518            if (ubasic_finished()) {
519                script_console_add_line(lang_str(LANG_CONSOLE_TEXT_FINISHED));
520                action_pop();
521                script_end();
522            }   
523#endif
524        }
525    }
526}
527
528static int script_action_stack(long p)
529{
530    // process stack operations
531    switch (p) {
532        case AS_SCRIPT_RUN:
533            if (state_kbd_script_run)
534                process_script();
535            else
536                action_pop();
537            break;
538        case AS_MOTION_DETECTOR:
539            if(md_detect_motion()==0)
540            {
541                action_pop();
542#ifdef OPT_LUA
543                if (L)
544                {
545                       // We need to recover the motion detector's
546                       // result and push
547                       // it onto the thread's stack.
548                       lua_pushnumber( Lt, md_get_result() );
549                } else
550#endif
551                {
552#ifdef OPT_UBASIC
553                    ubasic_set_md_ret(md_get_result());
554#endif
555                }
556            }
557            break;
558        default:
559            if (!action_stack_standard(p) && !state_kbd_script_run)
560            {
561                /*finished();*/
562                action_pop();
563                script_end();
564            }
565            break;
566    }
567   
568    return 1;
569}
570
571long script_stack_start()
572{
573    running_script_stack_name = action_stack_create(&script_action_stack, AS_SCRIPT_RUN);
574    return running_script_stack_name;
575}
576
577int script_is_running()
578{
579    return !action_stack_is_finished(running_script_stack_name);
580}
581
582void script_end()
583{
584    script_print_screen_end();
585#ifdef OPT_LUA
586    if( L ) {
587      lua_script_reset();
588    } else
589#endif
590    {
591#ifdef OPT_UBASIC
592      ubasic_end();
593#endif
594    }
595        md_close_motion_detector();
596        shot_histogram_set(0);
597    kbd_key_release_all();
598    state_kbd_script_run = 0;
599
600    conf_update_prevent_shutdown();
601
602    vid_bitmap_refresh();
603}
604
605long script_start_gui( int autostart )
606{
607    int i;
608
609    shot_histogram_set(0);
610    if (autostart)
611        auto_started = 1;
612    else
613        auto_started = 0;
614
615    kbd_last_clicked = 0;
616
617    /*if (!autostart)*/ kbd_key_release_all();
618
619    console_clear();
620    script_print_screen_init();
621
622    if (conf.script_param_save) {
623        save_params_values(0);
624    }
625    if( autostart )
626        script_console_add_line("***Autostart***");
627    else
628        script_console_add_line(lang_str(LANG_CONSOLE_TEXT_STARTED));
629
630    if( is_lua() ) {
631#ifdef OPT_LUA
632        if( !lua_script_start(script_source_str) ) {
633            script_print_screen_end();
634            wait_and_end();
635            return -1;
636        }
637        for (i=0; i<SCRIPT_NUM_PARAMS; ++i) {
638            if( script_params[i][0] ) {
639                char var = 'a'+i;
640                lua_pushlstring( L, &var, 1 );
641                lua_pushnumber( L, conf.ubasic_vars[i] );
642                lua_settable( L, LUA_GLOBALSINDEX );
643            }
644        }
645        state_lua_kbd_first_call_to_resume = 1;
646#else
647        char msg[64];
648        sprintf(msg,lang_str(LANG_CONSOLE_SCRIPT_DISABLED_IN_BUILD),"Lua");
649        console_add_line(msg);
650        return -1;
651#endif
652    } else
653    { // ubasic
654#ifdef OPT_UBASIC
655        ubasic_init(script_source_str);
656
657        for (i=0; i<SCRIPT_NUM_PARAMS; ++i) {
658            ubasic_set_variable(i, conf.ubasic_vars[i]);
659        }
660#else
661        char msg[64];
662        sprintf(msg,lang_str(LANG_CONSOLE_SCRIPT_DISABLED_IN_BUILD),"UBASIC");
663        console_add_line(msg);
664        return -1;
665#endif
666    }
667
668    state_kbd_script_run = 1;
669
670    conf_update_prevent_shutdown();
671
672    return script_stack_start();
673}
674
675#ifdef OPT_LUA
676long script_start_ptp( char *script , int keep_result )
677{
678  if (!lua_script_start(script)) return -1;
679  lua_keep_result = keep_result;
680  state_lua_kbd_first_call_to_resume = 1;
681  state_kbd_script_run = 1;
682  kbd_set_block(1);
683  auto_started = 0;
684  return script_stack_start();
685}
686#endif
687
688int script_key_is_pressed(int k)
689{
690    if (k==0xFF)
691        return get_usb_power(1);
692    if (k > 0)
693        return kbd_is_key_pressed(k);
694    return 0;
695}
696
697int script_key_is_clicked(int k)
698{
699    if (k==0xFF)
700        return get_usb_power(1);
701    if (k > 0)
702        return (kbd_last_clicked == k);
703    return 0;
704}
705
706static const struct Keynames {
707    int keyid;
708    char *keyname;
709} keynames[] = {
710    { KEY_UP,           "up"         },
711    { KEY_DOWN,         "down"       },
712    { KEY_LEFT,         "left"       },
713    { KEY_RIGHT,        "right"      },
714    { KEY_SET,          "set"        },
715    { KEY_SHOOT_HALF,   "shoot_half" },
716    { KEY_SHOOT_FULL,   "shoot_full" },
717    { KEY_ZOOM_IN,      "zoom_in"    },
718    { KEY_ZOOM_OUT,     "zoom_out"   },
719    { KEY_MENU,         "menu"       },
720    { KEY_DISPLAY,      "display"    },
721    { KEY_PRINT,        "print"      },
722    { KEY_ERASE,        "erase"      },
723    { KEY_ISO,          "iso"        },
724    { KEY_FLASH,        "flash"      },
725    { KEY_MF,           "mf"         },
726    { KEY_MACRO,        "macro"      },
727    { KEY_VIDEO,        "video"      },
728    { KEY_TIMER,        "timer"      },
729    { KEY_EXPO_CORR,    "expo_corr"  },
730    { KEY_MICROPHONE,   "fe"         },
731    { KEY_ZOOM_ASSIST,  "zoom_assist"},
732    { KEY_AE_LOCK,      "ae_lock"    },
733    { KEY_METERING,     "metering_mode"},
734    { 0xFF,             "remote"     },
735    { 0xFFFF,           "no_key"     },
736};
737
738int script_keyid_by_name (const char *n)
739{
740    int i;
741    for (i=0;i<sizeof(keynames)/sizeof(keynames[0]);i++)
742    if (strcmp(keynames[i].keyname,n) == 0)
743        return keynames[i].keyid;
744    return 0;
745}
746
Note: See TracBrowser for help on using the repository browser.