source: trunk/core/script.c @ 1032

Revision 1032, 18.5 KB checked in by reyalP, 2 years ago (diff)

script key handling rework from ultima in http://chdk.setepontos.com/index.php?topic=5793.msg59376#msg59376

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