source: trunk/core/script.c @ 1034

Revision 1034, 19.0 KB checked in by reyalP, 2 years ago (diff)

Thanks to ultimaA, Lua and ubasic optional at compile time, from http://chdk.setepontos.com/index.php?topic=5793.msg59376#msg59376 with minor modifications: http://chdk.setepontos.com/index.php?topic=5793.msg59606#msg59606

  • 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
457#ifdef OPT_LUA
458static int is_lua()
459{
460  int len;
461  char const* s;
462  s = conf.script_file;
463  len = strlen( s );
464  return len >= 4 && ( s[len-1] == 'a' || s[len-1] == 'A' )
465    && ( s[len-2] == 'u' || s[len-2] == 'U' )
466    && ( s[len-3] == 'l' || s[len-3] == 'L' )
467    && s[len-4] == '.';
468}
469#endif
470
471static void wait_and_end(void)
472{
473        script_console_add_line("PRESS SHUTTER TO CLOSE");
474
475        // We're not running any more, but we have scheduled stuff that
476        // needs to finish. So keep the script marked as running, but don't
477        // call any more scripting functions.
478        state_kbd_script_run = 3;       
479}
480
481static void process_script()
482{   // Note: This function is called from an action stack for AS_SCRIPT_RUN.
483   
484    long t;
485    int Lres;
486
487    if (state_kbd_script_run != 3) {
488#ifdef OPT_LUA
489        if( L ) {
490            int top;
491            if (state_lua_kbd_first_call_to_resume) {
492                state_lua_kbd_first_call_to_resume = 0;
493                top = 0;
494            } else {
495                top = lua_gettop(Lt);
496            }
497            Lres = lua_resume( Lt, top );
498
499            if (Lres != LUA_YIELD && Lres != 0) {
500                script_console_add_line( lua_tostring( Lt, -1 ) );
501                if(conf.debug_lua_restart_on_error){
502                    lua_script_reset();
503                    script_start_gui(0);
504                } else {
505                    wait_and_end();
506                }
507                return;
508            }
509
510            if (Lres != LUA_YIELD) {
511                script_console_add_line(lang_str(LANG_CONSOLE_TEXT_FINISHED));
512                action_pop();
513                script_end();
514            }   
515        } else
516#endif
517        {
518#ifdef OPT_UBASIC
519            ubasic_run();
520            if (ubasic_finished()) {
521                script_console_add_line(lang_str(LANG_CONSOLE_TEXT_FINISHED));
522                action_pop();
523                script_end();
524            }   
525#endif
526        }
527    }
528}
529
530static int script_action_stack(long p)
531{
532    // process stack operations
533    switch (p) {
534        case AS_SCRIPT_RUN:
535            if (state_kbd_script_run)
536                process_script();
537            else
538                action_pop();
539            break;
540        case AS_MOTION_DETECTOR:
541            if(md_detect_motion()==0)
542            {
543                action_pop();
544#ifdef OPT_LUA
545                if (L)
546                {
547                       // We need to recover the motion detector's
548                       // result and push
549                       // it onto the thread's stack.
550                       lua_pushnumber( Lt, md_get_result() );
551                } else
552#endif
553                {
554#ifdef OPT_UBASIC
555                    ubasic_set_md_ret(md_get_result());
556#endif
557                }
558            }
559            break;
560        default:
561            if (!action_stack_standard(p) && !state_kbd_script_run)
562            {
563                /*finished();*/
564                action_pop();
565                script_end();
566            }
567            break;
568    }
569   
570    return 1;
571}
572
573long script_stack_start()
574{
575    running_script_stack_name = action_stack_create(&script_action_stack, AS_SCRIPT_RUN);
576    return running_script_stack_name;
577}
578
579int script_is_running()
580{
581    return !action_stack_is_finished(running_script_stack_name);
582}
583
584void script_end()
585{
586    script_print_screen_end();
587#ifdef OPT_LUA
588    if( L ) {
589      lua_script_reset();
590    } else
591#endif
592    {
593#ifdef OPT_UBASIC
594      ubasic_end();
595#endif
596    }
597        md_close_motion_detector();
598        shot_histogram_set(0);
599    kbd_key_release_all();
600    state_kbd_script_run = 0;
601
602    conf_update_prevent_shutdown();
603
604    vid_bitmap_refresh();
605}
606
607long script_start_gui( int autostart )
608{
609    int i;
610
611    shot_histogram_set(0);
612    if (autostart)
613        auto_started = 1;
614    else
615        auto_started = 0;
616
617    kbd_last_clicked = 0;
618
619    /*if (!autostart)*/ kbd_key_release_all();
620
621    console_clear();
622    script_print_screen_init();
623
624    if (conf.script_param_save) {
625        save_params_values(0);
626    }
627    if( autostart )
628        script_console_add_line("***Autostart***");
629    else
630        script_console_add_line(lang_str(LANG_CONSOLE_TEXT_STARTED));
631
632#ifdef OPT_LUA
633    if( is_lua() ) {
634        if( !lua_script_start(script_source_str) ) {
635            script_print_screen_end();
636            wait_and_end();
637            return -1;
638        }
639        for (i=0; i<SCRIPT_NUM_PARAMS; ++i) {
640            if( script_params[i][0] ) {
641                char var = 'a'+i;
642                lua_pushlstring( L, &var, 1 );
643                lua_pushnumber( L, conf.ubasic_vars[i] );
644                lua_settable( L, LUA_GLOBALSINDEX );
645            }
646        }
647        state_lua_kbd_first_call_to_resume = 1;
648    } else
649#endif
650    { // ubasic
651#ifdef OPT_UBASIC
652        ubasic_init(script_source_str);
653
654        for (i=0; i<SCRIPT_NUM_PARAMS; ++i) {
655            ubasic_set_variable(i, conf.ubasic_vars[i]);
656        }
657#endif
658    }
659
660    state_kbd_script_run = 1;
661
662    conf_update_prevent_shutdown();
663
664    return script_stack_start();
665}
666
667#ifdef OPT_LUA
668long script_start_ptp( char *script , int keep_result )
669{
670  lua_script_start(script);
671  lua_keep_result = keep_result;
672  state_lua_kbd_first_call_to_resume = 1;
673  state_kbd_script_run = 1;
674  kbd_set_block(1);
675  auto_started = 0;
676  return script_stack_start();
677}
678#endif
679
680#ifndef UBASIC_TEST
681int camera_is_pressed(const char *s)
682{
683    long k = keyid_by_name(s);
684    if (k==0xFF) return get_usb_power(1);
685    if (k > 0) {
686        return (kbd_is_key_pressed(k));
687    } else {
688#ifdef OPT_LUA
689        if (is_lua()) {
690            luaL_error( L, "unknown key" );
691        } else
692#endif
693        {
694#ifdef OPT_UBASIC
695            ubasic_error = UBASIC_E_UNK_KEY;
696#endif
697        }
698    }
699    return 0;
700}
701
702int camera_is_clicked(const char *s)
703{
704    long k = keyid_by_name(s);
705    if (k==0xFF) return get_usb_power(1);
706    if (k > 0) {
707        return (kbd_last_clicked == k);
708    } else {
709#ifdef OPT_LUA
710        if (is_lua()) {
711            luaL_error( L, "unknown key" );
712        } else
713#endif
714        {
715#ifdef OPT_UBASIC
716            ubasic_error = UBASIC_E_UNK_KEY;
717#endif
718        }
719    }
720    return 0;
721}
722
723#ifdef OPT_UBASIC
724void camera_press(const char *s)
725{
726    // For Lua, luaCB_keyfunc handles this command.
727
728    long k = keyid_by_name(s);
729    if (k > 0) {
730        action_push_press(k);
731    } else {
732        ubasic_error = UBASIC_E_UNK_KEY;
733    }
734}
735
736void camera_release(const char *s)
737{
738    // For Lua, luaCB_keyfunc handles this command.
739
740    long k = keyid_by_name(s);
741    if (k > 0) {
742        action_push_release(k);
743    } else {
744        ubasic_error = UBASIC_E_UNK_KEY;
745    }
746}
747
748void camera_click(const char *s)
749{
750    // For Lua, luaCB_keyfunc handles this command.
751
752    long k = keyid_by_name(s);
753    if (k > 0) {
754        action_push_click(k);
755    } else {
756        ubasic_error = UBASIC_E_UNK_KEY;
757    }
758}
759
760void camera_shoot()
761{
762    action_push(AS_SHOOT);
763}
764
765void camera_sleep(long v)
766{
767    action_push_delay(v);
768}
769
770void camera_wait_click(int t)
771{
772    action_wait_for_click(t);
773}
774#endif
775
776#endif
Note: See TracBrowser for help on using the repository browser.