source: trunk/core/script.c @ 871

Revision 871, 14.4 KB checked in by fe50, 3 years ago (diff)
  • added g11-100k to the makefile (copy of the 100j version, 100j and 100k are identical)
  • NOTE: the manual loading method (ps.fi2, from Canon firmware update menu) for ALL g11 versions DOES NOT work yet !
  • common bugfix: fix sporadic crash at startup (free() was sometimes called on an invalid pointer in script.c, caused by missing initalisation)
  • 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
10//-------------------------------------------------------------------
11
12#define SCRIPT_CONSOLE_NUM_LINES    5
13#define SCRIPT_CONSOLE_LINE_LENGTH  25
14#define SCRIPT_CONSOLE_X            0
15#define SCRIPT_CONSOLE_Y            (14-SCRIPT_CONSOLE_NUM_LINES)
16
17//-------------------------------------------------------------------
18const char *state_ubasic_script=NULL; //ERR99
19char cfg_name[100] = "\0";
20char cfg_set_name[100] = "\0";
21
22static const char *ubasic_script_default =
23#if 0
24    "@title Default script\n"
25    "@param a Shoot count\n"
26    "@default a 2\n"
27    "@param b Step\n"
28    "@default b 3\n"
29
30    "sleep 1000\n"
31
32    "if a<1 then let a=2\n"
33    "if b<1 then let b=3\n"
34
35    "for s=1 to a\n"
36      "shoot\n"
37      "for n=1 to b\n"
38        "click \"right\"\n"
39      "next n\n"
40    "next s\n"
41    "shoot\n"
42
43    "for n=1 to a*b\n"
44      "click \"left\"\n"
45    "next n\n"
46
47    "end\n";
48#else
49    "@title Default Script\n"
50    "@param a Times to Repeat\n"
51    "@default a 5\n"
52    "@param b Display Delay\n"
53    "@default b 3\n"
54
55    "if a<1 then let a=1\n"
56    "if b<1 then let b=1\n"
57
58    "for n=1 to a\n"
59        "if n>1 then print \"*****\"\n"
60        "print \"This is a default script.\"\n"
61        "sleep 1000\n"
62        "print \"Scripts run when shutter\"\n"
63        "sleep 1000\n"
64        "print \"is pressed in ALT mode.\"\n"
65        "sleep 1000\n"
66        "print \"Press shutter to exit.\"\n"
67        "sleep b*1000\n"
68    "next n\n"
69
70    "end\n";
71#endif
72
73char script_title[36];
74char script_params[SCRIPT_NUM_PARAMS][28];
75int script_param_order[SCRIPT_NUM_PARAMS];
76static char script_params_update[SCRIPT_NUM_PARAMS];
77static int script_loaded_params[SCRIPT_NUM_PARAMS];
78static char script_console_buf[SCRIPT_CONSOLE_NUM_LINES][SCRIPT_CONSOLE_LINE_LENGTH+1];
79static int script_con_start_line=0; // oldest valid line in console
80static int script_con_num_lines=0; // number of valid lines
81
82//-------------------------------------------------------------------
83static void process_title(const char *title) {
84    register const char *ptr = title;
85    register int i=0;
86
87    while (ptr[0]==' ' || ptr[0]=='\t') ++ptr; // whitespaces
88    while (i<(sizeof(script_title)-1) && ptr[i] && ptr[i]!='\r' && ptr[i]!='\n') {
89        script_title[i]=ptr[i];
90        ++i;
91    }
92    script_title[i]=0;
93}
94
95//-------------------------------------------------------------------
96static int process_param(const char *param, int update) {
97    register const char *ptr = param;
98    register int n, i=0;
99
100    while (ptr[0]==' ' || ptr[0]=='\t') ++ptr; // whitespaces
101    if (ptr[0] && (ptr[0]>='a' && ptr[0]<='a'+SCRIPT_NUM_PARAMS) && (ptr[1]==' ' || ptr[1]=='\t')) {
102        n=ptr[0]-'a';
103        ptr+=2;
104        while (ptr[0]==' ' || ptr[0]=='\t') ++ptr; // whitespaces
105                script_params_update[n] = 1;
106        while (i<(sizeof(script_params[0])-1) && ptr[i] && ptr[i]!='\r' && ptr[i]!='\n') {
107                        if (update)
108                        { if (script_params[n][i]!=ptr[i]) { script_params_update[n] = 0; break; }
109                        } else script_params[n][i]=ptr[i];
110            ++i;
111        }
112                if (!update) script_params[n][i]=0;
113        n++;
114    } else n=0; // ??? else produce error message   
115    return n; // n=1 if '@param a' was processed, n=2 for 'b' ... n=26 for 'z'. n=0 if failed.
116}
117
118//-------------------------------------------------------------------
119static void process_default(const char *param, char update) {
120    register const char *ptr = param;
121    register int n;
122
123    while (ptr[0]==' ' || ptr[0]=='\t') ++ptr; // whitespaces
124    if (ptr[0] && (ptr[0]>='a' && ptr[0]<='a'+SCRIPT_NUM_PARAMS) && (ptr[1]==' ' || ptr[1]=='\t')) {
125        n=ptr[0]-'a';
126        ptr+=2;
127                if (!update || script_params_update[n])
128        {
129                        conf.ubasic_vars[n] = strtol(ptr, NULL, 0);
130            script_loaded_params[n] = conf.ubasic_vars[n];
131        }
132    } // ??? else produce error message
133}
134
135//-------------------------------------------------------------------
136static void script_scan(const char *fn, int update_vars) {
137    register const char *ptr = state_ubasic_script;
138    register int i, j=0, n;
139    char *c;
140
141    c=strrchr(fn, '/');
142    strncpy(script_title, (c)?c+1:fn, sizeof(script_title));
143    script_title[sizeof(script_title)-1]=0;
144    for (i=0; i<SCRIPT_NUM_PARAMS; ++i) {
145        script_params[i][0]=0;
146        script_param_order[i]=0;
147    }
148
149    while (ptr[0]) {
150        while (ptr[0]==' ' || ptr[0]=='\t') ++ptr; // whitespaces
151        if (ptr[0]=='@') {
152            if (strncmp("@title", ptr, 6)==0) {
153                ptr+=6;
154                process_title(ptr);
155            } else if (strncmp("@param", ptr, 6)==0) {
156                ptr+=6;
157                n=process_param(ptr, 0); // n=1 if '@param a' was processed, n=2 for 'b' ... n=26 for 'z'. n=0 if failed.
158                if (n>0 && n<=SCRIPT_NUM_PARAMS) {
159                  script_param_order[j]=n;
160                  j++;
161                }
162            } else if (update_vars && strncmp("@default", ptr, 8)==0) {
163                ptr+=8;
164                process_default(ptr, 0);
165            }
166        }
167        while (ptr[0] && ptr[0]!='\n') ++ptr; // unless end of line
168        if (ptr[0]) ++ptr;
169    }
170
171    /*for (i=0; i<SCRIPT_NUM_PARAMS; ++i) {
172        if (script_params[i][0]) break;
173    }
174    if (i==SCRIPT_NUM_PARAMS) { // there was no @param in script
175        for (i=0; i<3; ++i) {
176            strcpy(script_params[i], "Var. ? value");
177            script_params[i][5]='a'+i;
178        }
179    }*/
180}
181
182void set_params_values_name(const char *fn, int param_set)
183{
184        int shift;
185        register char *ptr = (param_set >= 0 ? cfg_set_name : cfg_name);
186        const char *name;
187       
188        if (fn == NULL || fn[0] == 0) { ptr[0] = 0; return; }
189       
190        strncpy(ptr, SCRIPT_DATA_PATH, 100); ptr[99]=0;
191        shift = strlen(SCRIPT_DATA_PATH);
192        name = strrchr(fn, '/');
193        if (name) name++; else name=fn;
194        strncpy(ptr+shift, name, 100-shift); ptr[99]=0;
195        shift = strlen(ptr); if (shift >= 100) shift=99;
196
197        if (param_set >= 0)
198                sprintf(ptr+shift-4, "_%d\0", param_set); else
199                strcpy(ptr+shift-3, "cfg\0");
200}
201
202//-------------------------------------------------------------------
203int load_params_values(const char *fn, int update_vars, int read_param_set)
204{
205        int i, fd=-1, rcnt;
206        register const char *ptr;       
207        struct stat st;
208        char *buf;
209       
210        if (fn == NULL || fn[0] == 0) return 0;
211        if (read_param_set)
212        {
213                set_params_values_name(fn, -1);
214                // find param set
215                fd = open(cfg_name, O_RDONLY, 0777);
216                if (fd >= 0)
217                {
218                        buf=umalloc(16);
219                        rcnt = read(fd, buf, 15);
220                        buf[rcnt] = 0;
221                        close(fd);
222                        conf.script_param_set = strtol(buf, NULL, 0);
223                        ufree(buf);
224                } else conf.script_param_set = 0;
225        }
226        set_params_values_name(fn, conf.script_param_set);
227        if (!update_vars) return 0;
228       
229        // open and read file
230        if (stat(cfg_set_name,&st) != 0)
231                return 0;
232        buf=umalloc(st.st_size+1);
233        if(!buf)
234                return 0;
235        fd = open(cfg_set_name, O_RDONLY, 0777);
236        if (fd < 0) {
237                ufree(buf);
238                return 0;
239        }
240        rcnt = read(fd, buf, st.st_size);
241        buf[rcnt] = 0;
242        close(fd);
243
244        for(i = 0; i < SCRIPT_NUM_PARAMS; ++i) script_params_update[i]=0;
245    ptr = buf;
246
247    while (ptr[0])
248        {
249        while (ptr[0]==' ' || ptr[0]=='\t') ++ptr; // whitespaces
250        if (ptr[0]=='@')
251                {
252            if (strncmp("@param", ptr, 6) == 0)
253                        {
254                ptr+=6;
255                                process_param(ptr, 1);
256            } else if (strncmp("@default", ptr, 8)==0) {
257                ptr+=8;
258                                process_default(ptr, 1);
259            }
260        }
261        while (ptr[0] && ptr[0]!='\n') ++ptr; // unless end of line
262        if (ptr[0]) ++ptr;
263    }
264        ufree(buf);
265        return 1;
266}
267
268//-------------------------------------------------------------------
269void save_params_values(int unconditional)
270{
271        int i, n, fd, changed=0;
272        char *buf,*p;
273        for(i = 0; i < SCRIPT_NUM_PARAMS; i++)
274        {
275                if (script_loaded_params[i] != conf.ubasic_vars[i]) changed++;
276                script_loaded_params[i] = conf.ubasic_vars[i];
277        }
278        if (!unconditional && !changed) return;
279
280        if (cfg_name[0] == 0) set_params_values_name(conf.script_file, -1);
281        fd = open(cfg_name, O_WRONLY|O_CREAT, 0777);
282        if (fd >= 0)
283        {
284                char s[20];
285                sprintf(s, " %d\n", conf.script_param_set);
286                write(fd, s, strlen(s));
287                close(fd);
288        }
289       
290        // open and read file
291        set_params_values_name(conf.script_file, conf.script_param_set);
292
293        buf=umalloc(SCRIPT_NUM_PARAMS*(28 + 20)); // max possible params * (param description + some extra for @default etc)
294        if(!buf)
295                return;
296
297        fd = open(cfg_set_name, O_WRONLY|O_CREAT, 0777);
298        if (fd < 0) {
299                ufree(buf);
300                return;
301        }
302        buf[0] = 0;
303        p=buf;
304        for(n = 0; n < SCRIPT_NUM_PARAMS; ++n)
305        {
306                if (script_params[n][0] != 0)
307                {
308                        p+=sprintf(p,"@param %c %s\n@default %c %d\n",'a'+n,script_params[n],'a'+n,conf.ubasic_vars[n]);
309                }
310        }
311        write(fd, buf, strlen(buf));
312        close(fd);
313        ufree(buf);
314}
315
316
317
318//-------------------------------------------------------------------
319void script_load(const char *fn, int saved_params) {
320    int i, update_vars;
321    FILE *fd = NULL;
322    struct stat st;
323   
324//    save_params_values(0);
325
326    if(state_ubasic_script && state_ubasic_script != ubasic_script_default)
327        free((void *)state_ubasic_script);
328
329    state_ubasic_script = ubasic_script_default;
330    update_vars = (strcmp(fn, conf.script_file) != 0) || !saved_params || (saved_params == 2);  // update if new file
331
332    if (!fn[0]) { // load internal script
333        if (!conf.script_file[0]) { // internal script was used last time
334            fd = fopen(SCRIPT_DEFAULT_FILENAME, "rb");
335            if (fd) {
336                fn = SCRIPT_DEFAULT_FILENAME;
337                update_vars = 1;
338            }
339        }
340    } else {
341        fd = fopen(fn, "rb");
342        if (!fd) {
343            conf.script_file[0]=0;
344            update_vars = 1;
345        }
346    }
347    // zero size = default script
348    if(stat(fn,&st) != 0 || st.st_size == 0) {
349        conf.script_file[0]=0;
350        update_vars = 1;
351        if(fd) {
352            fclose(fd);
353            fd=0;
354        }
355    }
356    if (fd){
357        int rcnt;
358        char *buf;
359
360        buf = malloc(st.st_size+1);
361        if(!buf) {
362            fclose(fd);
363            return;
364        }
365
366        // TODO we could process the script here to reduce size
367        // or compile for lua
368        rcnt = fread(buf, 1, st.st_size,fd);
369        if (rcnt > 0){
370            buf[rcnt] = 0;
371            state_ubasic_script = buf;
372            strcpy(conf.script_file, fn);
373        }
374        else {
375            free(buf);
376        }
377        fclose(fd);
378    }
379
380    if (update_vars) {
381        for (i=0; i<SCRIPT_NUM_PARAMS; ++i) {
382            conf.ubasic_vars[i] = 0;
383            script_loaded_params[i] = 0;
384        }
385    }
386    script_scan(conf.script_file, update_vars);
387    if (saved_params)
388        load_params_values(conf.script_file, update_vars, (saved_params!=2));   
389    gui_update_script_submenu();
390}
391
392//-------------------------------------------------------------------
393void script_console_clear() {
394    register int i;
395
396    for (i=0; i<SCRIPT_CONSOLE_NUM_LINES; ++i) {
397        script_console_buf[i][0]=0;
398    }
399    script_con_num_lines=script_con_start_line=0;
400    draw_restore();
401}
402
403//-------------------------------------------------------------------
404static inline int script_con_line_index(int i) {
405    return i%SCRIPT_CONSOLE_NUM_LINES;
406}
407
408void script_console_draw() {
409    int i,c,l;
410    for(c = 0; c < script_con_num_lines; ++c) {
411        i=script_con_line_index(script_con_start_line+c);
412        l=strlen(script_console_buf[i]);
413        draw_txt_string(SCRIPT_CONSOLE_X, SCRIPT_CONSOLE_Y+SCRIPT_CONSOLE_NUM_LINES-script_con_num_lines+c, script_console_buf[i], MAKE_COLOR(COLOR_BG, COLOR_FG));
414        for (; l<SCRIPT_CONSOLE_LINE_LENGTH; ++l)
415            draw_txt_char(SCRIPT_CONSOLE_X+l, SCRIPT_CONSOLE_Y+SCRIPT_CONSOLE_NUM_LINES-script_con_num_lines+c, ' ', MAKE_COLOR(COLOR_BG, COLOR_FG));
416    }
417}
418
419static int  print_screen_p;             // print_screen predicate: 0-off 1-on.
420static int  print_screen_d = -1;        // print_screen file descriptor.
421//static const char print_screen_file[] ="A/CHDK/SCRIPTS/PR_SCREEN.TXT";
422static const char print_screen_file_prefix[] = "A/CHDK/LOGS/LOG_";
423char print_screen_file[25];
424static const char extension_txt[] = ".TXT";
425
426void script_print_screen_init()
427{
428  print_screen_p = 0;
429  if (print_screen_d >= 0) {
430    close(print_screen_d);
431    print_screen_d = -1;
432  }
433}
434
435void script_print_screen_end()
436{
437  if (print_screen_d >= 0) {
438    close(print_screen_d);
439    print_screen_d = -1;
440    print_screen_p = 0;
441  }
442}
443
444void script_print_screen_statement(int val)
445{
446  print_screen_p = val;
447  if (val) {
448    if (print_screen_d>=0) close(print_screen_d);
449    int i=0;
450    int c=0;
451    static char file_number[5];
452    strcpy(print_screen_file, print_screen_file_prefix);
453    if (val<0) val = -val;
454    while (val > 9999) val += -10000;
455    for (i=10; i<=1000; i=i*10) { if (val<i) ++c; }
456    for (i=1; i<=c; ++i) { sprintf(file_number, "%d", 0); strcat(print_screen_file, file_number); }
457    sprintf(file_number, "%d", val);
458    strcat(print_screen_file, file_number);
459    strcat(print_screen_file, extension_txt);
460    print_screen_d = open(print_screen_file, O_WRONLY|O_CREAT|O_TRUNC, 0777);
461  }
462}
463
464//-------------------------------------------------------------------
465void script_console_start_line() {
466    if (SCRIPT_CONSOLE_NUM_LINES==script_con_num_lines) {
467        script_con_start_line=script_con_line_index(script_con_start_line+1);
468    }
469    else {
470        ++script_con_num_lines;
471    }
472     script_console_buf[script_con_line_index(script_con_start_line+script_con_num_lines-1)][0]=0;
473}
474
475void script_console_add_text(const char *str) {
476    char *cur;
477    int curlen;
478    int left;
479
480    do {
481        cur = script_console_buf[script_con_line_index(script_con_start_line+script_con_num_lines-1)];
482        curlen = strlen(cur);
483        left = SCRIPT_CONSOLE_LINE_LENGTH-curlen;
484        if(strlen(str) > left) {
485            strncpy(cur+curlen,str,left);
486            cur[SCRIPT_CONSOLE_LINE_LENGTH]=0;
487            script_console_start_line();
488            str+=left;
489        }
490        else {
491            strcat(cur,str);
492            break;
493        }
494    } while(1);
495}
496
497void script_console_add_line(const char *str) {
498    script_console_start_line();
499    script_console_add_text(str);
500    if (print_screen_p && print_screen_d>=0) {
501        char nl = '\n';
502                // TODO this should be uncached memory
503        write(print_screen_d, str, strlen(str) );
504        write(print_screen_d, &nl, 1);
505    }
506    script_console_draw();
507}
508//-------------------------------------------------------------------
509//-------------------------------------------------------------------
510//-------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.