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

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