root/core/action_stack.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. action_stack_is_finished
  2. action_stack_create
  3. action_stack_finish
  4. action_stack_kill
  5. action_top
  6. action_pop
  7. action_pop_func
  8. action_push
  9. action_push_func
  10. action_process_delay
  11. action_pop_delay
  12. action_stack_AS_SLEEP
  13. action_push_delay
  14. action_stack_AS_PRESS
  15. action_push_press
  16. action_stack_AS_RELEASE
  17. action_push_release
  18. action_push_click
  19. action_stack_AS_WAIT_SHOOTING_DONE
  20. action_stack_AS_WAIT_FLASH
  21. action_stack_AS_WAIT_SHOOTING_IN_PROGRESS
  22. action_push_shoot
  23. action_stack_AS_SHOOT
  24. action_stack_process
  25. action_stack_process_all

   1 #include "camera_info.h"
   2 #include "stdlib.h"
   3 #include "modes.h"
   4 #include "clock.h"
   5 #include "shooting.h"
   6 #include "console.h"
   7 #include "conf.h"
   8 #include "keyboard.h"
   9 #include "histogram.h"
  10 #include "action_stack.h"
  11 #include "script_api.h"
  12 
  13 //----------------------------------------------------------------------------------
  14 
  15 #define AS_FUNC_ENTRY   0xa32f1c9e      // Magic number to flag a function ptr on the stack
  16 
  17 //----------------------------------------------------------------------------------
  18 // action stack memory structure
  19 
  20 #define ACTION_STACK_SIZE 48
  21 #define MAX_ACTION_STACKS 5
  22 
  23 typedef struct _action_stack
  24 {
  25     long                    stack[ACTION_STACK_SIZE];   // Actions and parameters
  26     int                     stack_ptr;                  // Current position in stack
  27     AS_ID                   comp_id;                    // Unique ID
  28     unsigned long           delay_target_ticks;         // Used for sleep function
  29     struct _action_stack*   next;                       // next action stack
  30 } action_stack_t;
  31 
  32 //----------------------------------------------------------------------------------
  33 // Global variables for implementation
  34 
  35 static action_stack_t* action_stacks = NULL;            // List of active stacks
  36 static action_stack_t* active_stack = NULL;             // Currently executing stack
  37 static action_stack_t* free_stacks = NULL;              // Free list (for reuse of memory)
  38 static int num_stacks = 0;                              // Number of active stacks
  39 static AS_ID task_comp_id = 1;                          // Next stack ID (0 = unused / finished stack)
  40 
  41 //----------------------------------------------------------------------------------
  42 // Stack management functions
  43 
  44 // Returns true if the task denoted by comp_id has finished execution.
  45 // comp_id is returned by action_stack_create().
  46 int action_stack_is_finished(AS_ID comp_id)
  47 {
  48     action_stack_t *p = action_stacks;
  49     while (p)
  50     {
  51         if (p->comp_id == comp_id)
  52             return 0;
  53         p = p->next;
  54     }
  55 
  56     return 1;
  57 }
  58 
  59 // Starts a new action stack with initial stack entry p.
  60 // The action stack is alive as long as its stack has entries.
  61 // The proc_func parameter is a pointer to the initial processing function
  62 // for the stack
  63 AS_ID action_stack_create(action_func proc_func)
  64 {
  65     // Cap the maximum number of action_stacks
  66     if (num_stacks == MAX_ACTION_STACKS)
  67         return -1;
  68 
  69     // Initialize new action stack
  70     action_stack_t* stack = 0;
  71     if (free_stacks)
  72     {
  73         // Reuse previous memory block
  74         stack = free_stacks;
  75         free_stacks = free_stacks->next;
  76     }
  77     else
  78     {
  79         // Get a new block
  80         stack = (action_stack_t*)malloc(sizeof(action_stack_t));
  81     }
  82     memset(stack,0,sizeof(action_stack_t));
  83 
  84     // Insert at start of list - stacks execute in order of most recent creation
  85     stack->next = action_stacks;
  86     action_stacks = stack;
  87 
  88     // Initialize id & processing function
  89     stack->comp_id = task_comp_id;
  90     stack->stack[0] = (long)proc_func;
  91     stack->stack[1] = AS_FUNC_ENTRY;    // Can't use action_push_func as active_stack not set
  92     stack->stack_ptr = 1;
  93 
  94     ++num_stacks;
  95 
  96     // Increment task_comp_id
  97     // For this to clash with a running stack you would need to leave one running
  98     // while 4 billion more were created - highly unlikely.
  99     ++task_comp_id;
 100     // Reset just in case it wraps around to 'finished' value
 101     if (task_comp_id == 0) task_comp_id = 1;
 102 
 103     return stack->comp_id;
 104 }
 105 
 106 // Clean up and release an action stack
 107 static void action_stack_finish(action_stack_t *p)
 108 {
 109     // Check in case already finalised
 110     if (p->comp_id == 0) return;
 111 
 112     // Remove 'active_stack' from the list since it is done execuing
 113     if (p == action_stacks)
 114     {
 115         action_stacks = action_stacks->next;
 116     }
 117     else
 118     {
 119         action_stack_t* prev = action_stacks;
 120         while (prev && (prev->next != p))
 121         {
 122             prev = prev->next;
 123         }
 124         if (prev)
 125         {
 126             prev->next = prev->next->next;
 127         }
 128     }
 129 
 130     --num_stacks;
 131 
 132     // Mark as free in case this function gets called again
 133     p->comp_id = 0;
 134     p->stack_ptr = -1;
 135 
 136     // Instead of freeing memory, save it to the free list
 137     // Next time this block will be reused
 138     p->next = free_stacks;
 139     free_stacks = p;
 140 }
 141 
 142 // Find and terminate an action stack
 143 // comp_id is returned by action_stack_create().
 144 void action_stack_kill(AS_ID comp_id)
 145 {
 146     action_stack_t *p = action_stacks;
 147     while (p)
 148     {
 149         if (p->comp_id == comp_id)
 150         {
 151             action_stack_finish(p);
 152             return;
 153         }
 154         p = p->next;
 155     }
 156 }
 157 
 158 //----------------------------------------------------------------------------------
 159 // Add / remove a generic entry from the stack
 160 // Note - these assume 'active_stack' is set correctly.
 161 
 162 // Get top Nth entry off the stack (without removing it)
 163 // Can only be called from an action stack
 164 long action_top(int n)
 165 {
 166     if (active_stack)
 167         return active_stack->stack[active_stack->stack_ptr-n];
 168     return 0;
 169 }
 170 
 171 // Pop top entry off the stack
 172 // Can only be called from an action stack
 173 long action_pop()
 174 {
 175     if (active_stack)
 176         return active_stack->stack[active_stack->stack_ptr--];
 177     return 0;
 178 }
 179 
 180 // Pop top func entry off the stack
 181 // Can only be called from an action stack
 182 long action_pop_func(int nParam)
 183 {
 184     for (; nParam >= 0; nParam--)
 185         action_pop();
 186     return action_pop();    // Return function pointer / last parameter
 187 }
 188 
 189 // Push a new entry onto the stack
 190 // Can only be called from an action stack
 191 void action_push(long p)
 192 {
 193     if (active_stack)
 194         active_stack->stack[++active_stack->stack_ptr] = p;
 195 }
 196 
 197 // Push a function onto the stack
 198 void action_push_func(action_func f)
 199 {
 200     action_push((long)f);
 201     action_push(AS_FUNC_ENTRY);
 202 }
 203 
 204 //----------------------------------------------------------------------------------
 205 // Delay processing
 206 
 207 // handle initializing and checking a timeout value set by 'delay'
 208 // returns zero if the timeout has not expired, 1 if it has
 209 // does not pop the delay value off the stack or clear the delay value
 210 static int action_process_delay(long delay)
 211 {
 212     unsigned t = get_tick_count();
 213     // FIXME take care if overflow occurs
 214     if (active_stack->delay_target_ticks == 0)
 215     {
 216         /* delay of -1 signals indefinite (actually 1 day) delay*/
 217         if(delay == -1)
 218             delay = 86400000;
 219 
 220         active_stack->delay_target_ticks = t+delay;
 221         return 0;
 222     }
 223     if (active_stack->delay_target_ticks <= t)
 224     {
 225         return 1;
 226     }
 227     return 0;
 228 }
 229 
 230 //----------------------------------------------------------------------------------
 231 // Custom functions to push specific actions onto the stack
 232 
 233 // Pop a sleep from the stack
 234 // Can only be called from an action stack
 235 void action_pop_delay()
 236 {
 237     active_stack->delay_target_ticks = 0;
 238     action_pop_func(1);
 239 }
 240 
 241 // Process a sleep function from the stack
 242 static int action_stack_AS_SLEEP()
 243 {
 244     long delay = action_top(2);
 245 
 246     if (action_process_delay(delay))
 247     {
 248         action_pop_delay();
 249         return 1;
 250     }
 251 
 252     return 0;
 253 }
 254 
 255 // Push a sleep onto the stack
 256 // Can only be called from an action stack
 257 void action_push_delay(long msec)
 258 {
 259     action_push(msec);
 260     action_push_func(action_stack_AS_SLEEP);
 261 }
 262 
 263 // Process a button press action from the stack
 264 static int action_stack_AS_PRESS()
 265 {
 266     long skey = action_pop_func(1); // Key parameter returned
 267     kbd_key_press(skey);
 268     return 1;
 269 }
 270 
 271 // Push a button press action onto the stack
 272 // Can only be called from an action stack
 273 void action_push_press(long key)
 274 {
 275     // WARNING stack program flow is reversed
 276     action_push_delay(camera_info.cam_key_press_delay);
 277     action_push(key);
 278     action_push_func(action_stack_AS_PRESS);
 279 }
 280 
 281 // Process a button release action from the stack
 282 static int action_stack_AS_RELEASE()
 283 {
 284     long skey = action_pop_func(1); // Key parameter returned
 285     kbd_key_release(skey);
 286     return 1;
 287 }
 288 
 289 // Push a button release action onto the stack
 290 // Can only be called from an action stack
 291 void action_push_release(long key)
 292 {
 293     // WARNING stack program flow is reversed
 294     action_push_delay(camera_info.cam_key_release_delay);
 295     action_push(key);
 296     action_push_func(action_stack_AS_RELEASE);
 297 }
 298 
 299 // Push a button click action onto the stack (press, optional delay, release)
 300 // Can only be called from an action stack
 301 void action_push_click(long key)
 302 {
 303     // WARNING stack program flow is reversed
 304     action_push_release(key);
 305     action_push_press(key);
 306 }
 307 
 308 //----------------------------------------------------------------------------------
 309 // 'Shoot' actions
 310 
 311 // Action stack function - wait for shooting to be finished
 312 // parameters - retry flag
 313 static int action_stack_AS_WAIT_SHOOTING_DONE()
 314 {
 315     // Are we there yet?
 316     if (!shooting_in_progress())
 317     {
 318         // Remove this action from stack
 319         int retry = action_pop_func(1); // Retry parameter returned
 320 
 321         // Check if shoot succeeded or not
 322         if (camera_info.state.state_shooting_progress == SHOOTING_PROGRESS_NONE)
 323         {
 324             if (retry)
 325             {
 326                 // Shoot failed, retry once, if it fails again give up
 327                 action_push_shoot(0);
 328 
 329                 // Short delay before retrying shoot
 330                 action_push_delay(250);
 331             }
 332             else
 333             {
 334                 // Failed - already retried, or no retry requested
 335                 // Return 'shoot' status to script - 2 = shoot failed
 336                 libscriptapi->set_as_ret(2);
 337             }
 338         }
 339         else
 340         {
 341             // Return 'shoot' status to script - 0 = shoot succesful
 342             libscriptapi->set_as_ret(0);
 343 
 344             // Final script config delay (XXX FIXME find out how to wait to jpeg save finished)
 345             if (conf.script_shoot_delay > 0)
 346                 action_push_delay(conf.script_shoot_delay*100);
 347         }
 348 
 349         return 1;
 350     }
 351     return 0;
 352 }
 353 
 354 // Action stack function - wait for flash to charge
 355 static int action_stack_AS_WAIT_FLASH()
 356 {
 357     if (shooting_is_flash_ready())
 358     {
 359         action_pop_func(0);
 360         return 1;
 361     }
 362     return 0;
 363 }
 364 
 365 // Action stack function - wait for camera ready to shoot after half press, or timeout
 366 // parameters - timeout delay, retry flag
 367 static int action_stack_AS_WAIT_SHOOTING_IN_PROGRESS()
 368 {
 369     // Get parameters
 370     int timeout = action_top(2);
 371     int retry = action_top(3);
 372 
 373     if (shooting_in_progress() || camera_info.state.mode_video)
 374     {
 375         // Remove this action from the stack
 376         action_pop_func(2);
 377 
 378         // Push the rest of the shoot actions onto the stack (reversed flow)
 379 
 380         // Push 'retry if failed' parameter for exit action
 381         action_push(retry);
 382         action_push_func(action_stack_AS_WAIT_SHOOTING_DONE);
 383 
 384         // Full press shutter
 385         action_push_click(KEY_SHOOT_FULL);
 386 
 387         // Wait for flash recharged
 388         action_push_func(action_stack_AS_WAIT_FLASH);
 389 
 390         return 1;
 391     }
 392     if (get_tick_count() >= timeout)
 393     {
 394         // Remove this action from the stack
 395         action_pop_func(2);
 396 
 397         // Return 'shoot' status to script - 1 = shutter half press timed out
 398         libscriptapi->set_as_ret(1);
 399 
 400         return 1;
 401     }
 402     return 0;
 403 }
 404 
 405 // Push the core 'shoot' actions onto the stack
 406 // Note: action stack actions are processed in reverse order
 407 void action_push_shoot(int retry)
 408 {
 409     // Init shooting state
 410     camera_info.state.state_shooting_progress = SHOOTING_PROGRESS_NONE;
 411 
 412     // Wait for camera ready to shoot or timeout
 413     action_push(retry);
 414     action_push(get_tick_count() + 5000);
 415     action_push_func(action_stack_AS_WAIT_SHOOTING_IN_PROGRESS);
 416 
 417     // Half press shutter
 418     action_push_press(KEY_SHOOT_HALF);
 419 }
 420 
 421 int action_stack_AS_SHOOT()
 422 {
 423     // Remove this action from stack
 424     action_pop_func(0);
 425 
 426     // Push the shoot actions (with retry on shoot failure)
 427     action_push_shoot(1);
 428 
 429     return 1;
 430 }
 431 
 432 //----------------------------------------------------------------------------------
 433 // Stack execution
 434 
 435 // Run the topmost function on the active stack.
 436 static void action_stack_process()
 437 {
 438     int process = 1;
 439 
 440     while (process && (active_stack->stack_ptr >= 0))
 441     {
 442         // Get function address and id from stack
 443         long id = action_top(0);
 444         action_func f = (action_func)action_top(1);
 445         if (id == AS_FUNC_ENTRY)    // Safety check
 446         {
 447             process = f();
 448         }
 449         else
 450         {
 451             char buf[100];
 452             sprintf(buf,"AS Error - Not a Function. Aborting. %d %08x %08x.",active_stack->stack_ptr,id,f);
 453             script_console_add_error((long)buf);
 454             action_stack_finish(active_stack);
 455             return;
 456         }
 457     }
 458 
 459     if (active_stack->stack_ptr < 0)
 460     {
 461         action_stack_finish(active_stack);
 462     }
 463 }
 464 
 465 // Run the topmost function on each stack
 466 void action_stack_process_all()
 467 {
 468     active_stack = action_stacks;
 469 
 470     while (active_stack)
 471     {
 472         // Save the next stack in case the current one ends and 
 473         // releases it's stack during execution
 474         action_stack_t *next = active_stack->next;
 475 
 476         // Process stack functions
 477         action_stack_process();
 478 
 479         active_stack = next;
 480     }
 481 }
 482 
 483 //----------------------------------------------------------------------------------

/* [<][>][^][v][top][bottom][index][help] */