source: trunk/core/action_stack.c @ 661

Revision 661, 8.4 KB checked in by reyalp, 2 years ago (diff)

Aktualisierung auf Rev. 1165 * Betrifft alle - fix sleep(0) bug.

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    // accept wait_click 0 for infinite, but use -1 internally to avoid confusion with generated waits
151    action_push(timeout?timeout:-1);
152    action_push(AS_WAIT_CLICK);
153}
154
155// Can only be called from an action stack
156void action_push(long p)
157{
158    if (active_stack == -1)
159        return;
160
161    action_stack_t* task = action_stacks[active_stack];
162    task->stack[++task->stack_ptr] = p;   
163}
164
165// Can only be called from an action stack
166long action_get_prev(int p)
167{
168    if (active_stack == -1)
169        return 0;
170
171    action_stack_t* task = action_stacks[active_stack];
172    return task->stack[task->stack_ptr-(p-1)];
173}
174
175// handle initializing and checking a timeout value on the stack
176// p is the how far up the stack the timout value is
177// returns zero if the timeout has not expired, 1 if it has
178// does not pop the delay value off the stack or clear the delay value
179int action_process_delay(int p)
180{
181    unsigned t = get_tick_count();
182    // FIXME take care if overflow occurs
183    if (action_stacks[active_stack]->delay_target_ticks == 0)
184    {
185        /* setup timer */
186        long action = action_get_prev(p);
187        /* delay of -1 signals indefinite (actually 1 day) delay*/
188        action_stacks[active_stack]->delay_target_ticks = t+((action == -1)?86400000:action);
189        return 0;
190    }
191    if (action_stacks[active_stack]->delay_target_ticks <= t)
192    {
193        return 1;
194    }
195    return 0;
196}
197
198void action_clear_delay(void)
199{
200    action_stacks[active_stack]->delay_target_ticks = 0;
201}
202
203// Defines some standard operations. Returns false if it could not process anything.
204// Can only be called from an action stack
205int action_stack_standard(long p)
206{       
207    long t;
208   
209    switch (p)
210    {
211    case AS_PRESS:
212        kbd_key_press(action_get_prev(2));
213        action_pop();
214        action_pop();
215        break;
216    case AS_RELEASE:
217        kbd_key_release(action_get_prev(2));
218        action_pop();
219        action_pop();
220        break;
221    case AS_SLEEP:
222        if(action_process_delay(2))
223        {
224            action_clear_delay();
225            action_pop();
226            action_pop();
227        }
228        break;
229    case AS_PR_WAIT_SAVE:
230        state_shooting_progress = SHOOTING_PROGRESS_NONE;
231        state_expos_recalculated = 0;
232        histogram_stop();
233
234        action_pop();
235        break;
236    case AS_WAIT_SAVE:
237        if (state_shooting_progress == SHOOTING_PROGRESS_DONE)
238            action_pop();
239        break;
240    case AS_WAIT_FLASH:
241        if (shooting_is_flash_ready())
242            action_pop();
243        break;
244    case AS_WAIT_EXPHIST:
245        if (state_expos_recalculated)
246        {
247            state_expos_under = under_exposed;
248            state_expos_over = over_exposed;
249            action_pop();
250        }
251        break;
252    case AS_PR_WAIT_EXPHIST:
253        if (shooting_in_progress() || MODE_IS_VIDEO(mode_get()))
254        {
255            state_expos_recalculated = 0;
256            histogram_restart();
257            action_pop();
258        }
259        break;
260    case AS_WAIT_CLICK:
261        if(action_process_delay(2) || (kbd_last_clicked = kbd_get_clicked_key()))
262        {
263            if (!kbd_last_clicked)
264                kbd_last_clicked=0xFFFF;
265            action_clear_delay();
266            action_pop();
267            action_pop();
268        }
269        break;
270    case AS_SHOOT:
271        // Initiate a shoot. Remember that stack program flow is reversed!
272        action_pop();
273        // XXX FIXME find out how to wait to jpeg save finished
274        action_push_delay(conf.script_shoot_delay*100);
275
276        action_push(AS_WAIT_SAVE);
277
278        action_push_release(KEY_SHOOT_HALF);
279        action_push_release(KEY_SHOOT_FULL);
280
281        action_push_press(KEY_SHOOT_FULL);
282
283        action_push(AS_WAIT_FLASH);
284        action_push(AS_WAIT_EXPHIST);
285        action_push(AS_PR_WAIT_EXPHIST);
286
287        action_push_press(KEY_SHOOT_HALF);
288
289        action_push(AS_PR_WAIT_SAVE);
290    default:
291        return 0;
292    }
293   
294    return 1;
295}
296
297static void action_stack_process(int task_id)
298{
299    action_stack_t* stack = action_stacks[task_id];
300    if (stack->stack_ptr > -1)
301    {
302        long stack_arg = action_get_prev(1);
303        if (stack->action_process)
304            stack->action_process(stack_arg);
305        else
306            action_stack_standard(stack_arg);
307    }
308    else
309    {
310        action_stack_finish(task_id);
311    }
312}
313
314void action_stack_process_all()
315{
316    int i;
317    for (i = num_stacks - 1; i >= 0; --i)
318    {
319        active_stack = i;
320        action_stack_process(i);
321    }
322   
323    active_stack = -1;
324}
Note: See TracBrowser for help on using the repository browser.