source: trunk/core/action_stack.c @ 1170

Revision 1170, 8.0 KB checked in by reyalP, 2 years ago (diff)

fix bug in shoot command if script shoot delay set to zero, introduced in r1166

  • Property svn:eol-style set to native
Line 
1#include "console.h"
2#include "stdlib.h"
3#include "platform.h"
4#include "camera.h"
5#include "conf.h"
6#include "kbd.h"
7#include "keyboard.h"
8#include "histogram.h"
9#include "action_stack.h"
10
11typedef struct _action_stack
12{
13    int (*action_process)(long p);
14    long stack[ACTION_STACK_SIZE];
15    int stack_ptr;
16    long comp_id;
17    unsigned long delay_target_ticks;
18} action_stack_t;
19
20static action_stack_t** action_stacks = NULL;
21static int active_stack = -1;
22static int num_stacks = 0;
23static long task_comp_id = 1;
24
25// Returns true if the task denoted by comp_id has finished execution.
26// comp_id is returned by action_stack_create().
27int action_stack_is_finished(long comp_id)
28{
29    int i;
30    for (i = 0; i < num_stacks; ++i)
31    {
32        if (action_stacks[i]->comp_id == comp_id)
33            return 0;
34    }
35   
36    return 1;
37}
38
39// Starts a new action stack with initial stack entry p.
40// The action stack is alive as long as its stack has entries.
41long action_stack_create(action_process proc_func, long p)
42{
43    // Cap the maximum number of action_stacks
44    if (num_stacks == MAX_ACTION_STACKS)
45        return -1;
46       
47    // Initialize new action stack
48    action_stack_t** tmp = (action_stack_t**)malloc(sizeof(action_stack_t*) * (num_stacks + 1));
49    memcpy(tmp, action_stacks, sizeof(action_stack_t*) * num_stacks);
50
51    tmp[num_stacks] = (action_stack_t*)malloc(sizeof(action_stack_t));
52   
53    action_stack_t* stack = tmp[num_stacks];
54    stack->action_process = proc_func;
55    stack->stack_ptr = 0;
56    stack->comp_id = task_comp_id;
57    stack->delay_target_ticks = 0;
58    stack->stack[0] = p;   
59
60    action_stack_t** old = action_stacks;
61    action_stacks = tmp;
62    ++num_stacks;
63   
64    if (old != NULL)
65        free(old);
66       
67    // Increment task_comp_id, handle wraparound,
68    // and do not take values already in use
69    do
70    {
71        ++task_comp_id;
72        if (task_comp_id < 0)
73            task_comp_id = 0;
74    } while( !action_stack_is_finished(task_comp_id) );
75    return stack->comp_id;
76}
77
78static void action_stack_finish(int task_id)
79{
80    action_stack_t** tmp = NULL;
81    if (num_stacks > 1)
82        tmp = (action_stack_t**)malloc(sizeof(action_stack_t*) * (num_stacks - 1));
83   
84    int src_index, dst_index;
85    for (src_index = 0, dst_index = 0; src_index < num_stacks; ++src_index)
86    {
87        if (src_index != task_id)
88        {
89            tmp[dst_index] = action_stacks[src_index];
90            ++dst_index;
91        }
92        else
93        {
94            free(action_stacks[src_index]);
95        }
96    }
97       
98    action_stack_t** old = action_stacks;
99    --num_stacks;
100    action_stacks = tmp;
101    free(old);
102}
103
104// Can only be called from an action stack
105void action_pop()
106{
107    if (active_stack == -1)
108        return;
109   
110    --(action_stacks[active_stack]->stack_ptr);
111}
112
113// Can only be called from an action stack
114void action_push_delay(long msec)
115{
116    action_push(msec);
117    action_push(AS_SLEEP);
118}
119
120// Can only be called from an action stack
121void action_push_press(long key)
122{
123    // WARNING stack program flow is reversed
124    action_push_delay(CAM_KEY_PRESS_DELAY);
125    action_push(key);
126    action_push(AS_PRESS);
127}
128
129// Can only be called from an action stack
130void action_push_release(long key)
131{
132    // WARNING stack program flow is reversed
133    action_push_delay(CAM_KEY_RELEASE_DELAY);
134    action_push(key);
135    action_push(AS_RELEASE);
136}
137
138void action_push_click(long key)
139{
140// WARNING stack program flow is reversed
141    action_push_release(key);
142#if defined(CAM_KEY_CLICK_DELAY) // camera need delay for click
143    action_push_delay(CAM_KEY_CLICK_DELAY);
144#endif
145    action_push_press(key);
146}
147
148void action_wait_for_click(int timeout)
149{
150    action_push(timeout);
151    action_push(AS_WAIT_CLICK);
152}
153
154// Can only be called from an action stack
155void action_push(long p)
156{
157    if (active_stack == -1)
158        return;
159
160    action_stack_t* task = action_stacks[active_stack];
161    task->stack[++task->stack_ptr] = p;   
162}
163
164// Can only be called from an action stack
165long action_get_prev(int p)
166{
167    if (active_stack == -1)
168        return 0;
169
170    action_stack_t* task = action_stacks[active_stack];
171    return task->stack[task->stack_ptr-(p-1)];
172}
173
174// handle initializing and checking a timeout value on the stack
175// p is the how far up the stack the timout value is
176// returns zero if the timeout has not expired, 1 if it has
177// does not pop the delay value off the stack or clear the delay value
178int action_process_delay(int p)
179{
180    int t = get_tick_count();
181    // FIXME take care if overflow occurs
182    if (action_stacks[active_stack]->delay_target_ticks == 0)
183    {
184        /* setup timer */
185        long action = action_get_prev(p);
186        action_stacks[active_stack]->delay_target_ticks = t+((action)?action:86400000);
187        return 0;
188    }
189    if (action_stacks[active_stack]->delay_target_ticks <= t)
190    {
191        return 1;
192    }
193    return 0;
194}
195
196void action_clear_delay(void)
197{
198    action_stacks[active_stack]->delay_target_ticks = 0;
199}
200
201// Defines some standard operations. Returns false if it could not process anything.
202// Can only be called from an action stack
203int action_stack_standard(long p)
204{       
205    long t;
206   
207    switch (p)
208    {
209    case AS_PRESS:
210        kbd_key_press(action_get_prev(2));
211        action_pop();
212        action_pop();
213        break;
214    case AS_RELEASE:
215        kbd_key_release(action_get_prev(2));
216        action_pop();
217        action_pop();
218        break;
219    case AS_SLEEP:
220        if(action_process_delay(2))
221        {
222            action_clear_delay();
223            action_pop();
224            action_pop();
225        }
226        break;
227    case AS_PR_WAIT_SAVE:
228        state_shooting_progress = SHOOTING_PROGRESS_NONE;
229        state_expos_recalculated = 0;
230        histogram_stop();
231
232        action_pop();
233        break;
234    case AS_WAIT_SAVE:
235        if (state_shooting_progress == SHOOTING_PROGRESS_DONE)
236            action_pop();
237        break;
238    case AS_WAIT_FLASH:
239        if (shooting_is_flash_ready())
240            action_pop();
241        break;
242    case AS_WAIT_EXPHIST:
243        if (state_expos_recalculated)
244        {
245            state_expos_under = under_exposed;
246            state_expos_over = over_exposed;
247            action_pop();
248        }
249        break;
250    case AS_PR_WAIT_EXPHIST:
251        if (shooting_in_progress() || MODE_IS_VIDEO(mode_get()))
252        {
253            state_expos_recalculated = 0;
254            histogram_restart();
255            action_pop();
256        }
257        break;
258    case AS_WAIT_CLICK:
259        if(action_process_delay(2) || (kbd_last_clicked = kbd_get_clicked_key()))
260        {
261            if (!kbd_last_clicked)
262                kbd_last_clicked=0xFFFF;
263            action_clear_delay();
264            action_pop();
265            action_pop();
266        }
267        break;
268    case AS_SHOOT:
269        // Initiate a shoot. Remember that stack program flow is reversed!
270        action_pop();
271        // XXX FIXME find out how to wait to jpeg save finished
272        // note, must not wait 0, means forever
273        action_push_delay((conf.script_shoot_delay)?conf.script_shoot_delay*100:1);
274
275        action_push(AS_WAIT_SAVE);
276
277        action_push_release(KEY_SHOOT_HALF);
278        action_push_release(KEY_SHOOT_FULL);
279
280        action_push_press(KEY_SHOOT_FULL);
281
282        action_push(AS_WAIT_FLASH);
283        action_push(AS_WAIT_EXPHIST);
284        action_push(AS_PR_WAIT_EXPHIST);
285
286        action_push_press(KEY_SHOOT_HALF);
287
288        action_push(AS_PR_WAIT_SAVE);
289    default:
290        return 0;
291    }
292   
293    return 1;
294}
295
296static void action_stack_process(int task_id)
297{
298    action_stack_t* stack = action_stacks[task_id];
299    if (stack->stack_ptr > -1)
300    {
301        long stack_arg = action_get_prev(1);
302        if (stack->action_process)
303            stack->action_process(stack_arg);
304        else
305            action_stack_standard(stack_arg);
306    }
307    else
308    {
309        action_stack_finish(task_id);
310    }
311}
312
313void action_stack_process_all()
314{
315    int i;
316    for (i = num_stacks - 1; i >= 0; --i)
317    {
318        active_stack = i;
319        action_stack_process(i);
320    }
321   
322    active_stack = -1;
323}
Note: See TracBrowser for help on using the repository browser.