source: trunk/core/script.c @ 1020

Revision 1020, 17.0 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

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