Main Page | Modules | Data Structures | File List | Data Fields | Globals | Related Pages | Examples

Idle Task


Detailed Description

By Idle Task we mean oparation between APDUs (APDU STATUS resp.). To lower power consumption ME usually stops clock between two APDUs, but because some SIMs do not allow static operation and clock must be always on, there is a way to inform ME to not stop clock.

Note:
Besides clock stopping Turbo itself goes to sleep mode.
prot_main.png

ME-SIM communication

To perform idle task operation Turbo must tell ME that clock stopping is not allowed.

To turn on the idle task operation use the:

reg_action (ACTION_IDLE_TASK);

To turn the idle task operation off use the:

unreg_action (ACTION_IDLE_TASK);

Your turbo_handler() than should handle the ACTION_IDLE_TASK action, which application receives when Turbo enters idle state - APDU STATUS was performed and ME got its answer.

Note:
Only APDU STATUS causes ACTION_IDLE_TASK - this is because other APDUs usually mean something is going on and there is very little time between. On the other hand APDU STATUS is used (usually) every 30 seconds when ME has nothing else to do - so there is reasonable time for Turbo to something else.

/*
 * Copyright (C) 2003 BLADOX, s.r.o.  All rights reserved.
 * 
 * This file is part of an example program for Turbo. This example
 * program may be used, distributed and modified without limitation.
 *
 */

#include <config.h>
#include <turbo/turbo.h>

#include <stdlib.h>

u8 idle_on;
u8 idle_pass;

/* *INDENT-OFF* */

lc_char PROGMEM lc_Idle[]={
        LC_EN("Test Idle")
        LC_END
};

lc_char PROGMEM lc_Idle_Start[]={
        LC_EN("Start")
        LC_END
};

lc_char PROGMEM lc_Idle_Stop[]={
        LC_EN("Stop")
        LC_END
};

lc_char PROGMEM lc_Idle_State[]={
        LC_EN("State")
        LC_END
};

lc_char PROGMEM lc_Pass[]={
        LC_EN("Pass: ")
        LC_END
};

/* *INDENT-ON* */

SNodeP idle_n_start;
SNodeP idle_n_stop;

void test_idle_task ()
{
  idle_pass++;
}

u8 idle_ctx (SCtx * ctx, u8 action)
{
  if (action == APP_ENTER)
  {
    if (idle_on)
      spider_append_r (ctx, &idle_n_stop);
    else
      spider_append_r (ctx, &idle_n_start);
  }
  else if (action == APP_LEAVE)
  {
    spider_clear_r (ctx);
  }

  return APP_OK;
}

u8 idle_toggle (SCtx * ctx, u8 action)
{
  if (action == APP_ENTER)
  {
    idle_pass = 0;
    if (idle_on)
    {
      idle_on = 0;
      unreg_action (ACTION_IDLE_TASK);
    }
    else
    {
      idle_on = 1;
      reg_action (ACTION_IDLE_TASK);
    }
    return APP_BACK;
  }
  return APP_OK;
}

u8 idle_state (SCtx * ctx, u8 action)
{
  if (action == APP_ENTER)
  {
    u8 *r = buf_B ();
    u8 *t;

    t = r;
    t = sprints (t, locale (lc_Pass));
    t = sprinti (t, idle_pass);
    t = sprintc (t, '\0');

    if (display_text (r, NULL) == APP_END)
      return APP_END;
    return APP_BACK;
  }
  return APP_OK;
}

SNodeP idle_n = { lc_Idle, idle_ctx };
SNodeP idle_n_start = { lc_Idle_Start, idle_toggle };
SNodeP idle_n_stop = { lc_Idle_Stop, idle_toggle };
SNodeP idle_n_state = { lc_Idle_State, idle_state };

SEdgeP idle_edges_p[] = {
  {&idle_n, &idle_n_state}
  ,
  NULL
};

void action_menu (void *data)
{
  SCtx *c = spider_init ();

  c->n = &idle_n;
  c->eP = &idle_edges_p;
  spider (c);
}

void turbo_handler (u8 action, void *data)
{
  switch (action)
  {
    case ACTION_APP_INIT:
      reg_action (ACTION_IDLE_TASK);
      idle_on = 1;
      idle_pass = 0;
      break;
    case ACTION_INSERT_MENU:
      insert_menu (locale (lc_Idle));
      break;
    case ACTION_MENU_SELECTION:
      stk_thread (action_menu, data);
      break;
    case ACTION_IDLE_TASK:
      test_idle_task ();
      break;
    default:
      break;
  }
}

The above example shows turning idle task on and off.

Attention:
Due the necessary fast response to incoming APDU there is not enough time to switch (i.e. store state, stack) from idle task to GSM handling loop. The idle task is quit instead. It means that your code can be anytime interrupted without storing its state (stack).
That means that in the idle task:
  1. you must store your state periodically
  2. it can leave to memory leaks (because you cannot guarantee free() at the end of code) - see imalloc()
  3. you must not work with SIM
  4. you must not work with memory card
  5. stk_thread() cannot be run (and hence no STK commands)
  6. irq's must not be dissabled (cli used)

To perform STK command, memory card or SIM operation based on something that happened in the idle task, register the action ACTION_STATUS and use global variable to pass the flag.

Note:
buf_B() can be used.

If your idle task code needs to malloc some memory and because free() cannot be guaranted you can use the imalloc() instead of standard malloc(). Memory allocated with imalloc() is freed automatically when the idle task is quit.

If you want to have universal code that would work also in the idle task use the is_idle() to detect if your code is running the idle task or not.

Functions


Function Documentation

void ifree void *  ptr  ) 
 

Free imalloc'ed chunk.

Parameters:
ptr 

void* imalloc u16  size  ) 
 

Same as malloc but in temporary idle task memory.

Parameters:
size 

void init_imalloc void   ) 
 

Initiate idle malloc heap. It is freed automaticaly when idle task is aborted.

u8 is_idle void   ) 
 

Informs if you are in idle task.


Copyright © 2004-2006 BLADOX
Turbo version 1.2