| 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 |
|
|---|
| 11 | typedef 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 |
|
|---|
| 20 | static action_stack_t** action_stacks = NULL;
|
|---|
| 21 | static int active_stack = -1;
|
|---|
| 22 | static int num_stacks = 0;
|
|---|
| 23 | static 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().
|
|---|
| 27 | int 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.
|
|---|
| 41 | long 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 |
|
|---|
| 78 | static 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
|
|---|
| 105 | void 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
|
|---|
| 114 | void 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
|
|---|
| 121 | void 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
|
|---|
| 130 | void 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 |
|
|---|
| 138 | void 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 |
|
|---|
| 148 | void 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
|
|---|
| 156 | void 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
|
|---|
| 166 | long 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
|
|---|
| 179 | int 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 |
|
|---|
| 198 | void 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
|
|---|
| 205 | int 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 |
|
|---|
| 297 | static 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 |
|
|---|
| 314 | void 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 | }
|
|---|