중요한 개념인 Task를 구현 합니다. 1.X에서는 상당히 애매한 상황이 벌여 졌지만 앞서 말한 TASK가 각 각 슬롯을 가짐으로 확실해 졌습니다.

TASK
이때까지 본 소스는 동시성과는 거리가 먼소스들이었습니다. 동시 실행 코드가 실행 되고 있을 동안에는 선점이 되지 않습니다. 이 메카니즘은 TinyOS 스케줄러의 자원 소모를 줄였으나 동시 실행 코드는 매우 작은 크기여야 합니다. 즉 동시 실행시 선점 되지 않기 때문에 즉각 반응 시스템엔 역효과를 내는 것입니다. 예로는 긴 코드가 실행 되어 패킷에 반응 하는 속도가 늦어 질 수 있는 것입니다.

이때까지 코드는 아주 짧은 실행 코드만을 지녀 별문제 없이 작동 했습니다. 하지만 매우 긴 시간을 요구하는 실행 코드의 경우 선점 되지 않는 문제는 많은 문제를 야기 할 수 있습니다. 그래도 2.0의 경우 매우 긴 시간을 요구하는 코드의 경우 여러부분으로 나눌것을 권장 합니다.

Task - Task는 어플리케이션에 백그라운드 프로세싱을 가능하게 합니다. 이정도로 생각 하시면 됩니다. OS에서 이야기하는 bottom halves와 deferred procedure call과 비슷 합니다.(*하드웨어 인터럽트가 먼저라 생각 하시면 됩니다.)

이제 Task를 실습 하도록 하겠습니다. cp 명령어를 사용 하여 새로운 BlinkC 백업 본을 만듭니다.(BlinkTask)

cp -R Blink BlinkTask

Timer0.fired() 이벤트를 수정하여 작업을 좀 넣도록 하겠습니다.

event void Timer0.fired()
  {
    uint32_t i;
    dbg("BlinkC", "Timer 0 fired @ %s.\n", sim_time_string());
    for(i =0; i<400001;i++){
      call Leds.led0Toggle();
    }
  }

대충 이작업은 MicaZ , Telosb 계열 모트가 20번의 패킷을 보낼 수 있는 시간의 작업을 수행 합니다. 퓨징 하시면 지연으로 인해 이상하게 동작 하는 모트를 보실 수 있습니다.

동작의 결과를 설명 드리면 Timer0에서 발생하는 연산이 Timer이벤트들의 실행을 방해 하며 결국은 Timer0의 연산이 끝나는 시점에서 동시에 발생 하게 되는것이다. 그래서 두개가 계속 나란히 켜지면 한개만 켜지는 경우는 없게 된다.

이문제를 해결 하기 위해서는 백그라운드로 저 작업을 실행 하면된다.

Task의 정의는 다음과 같다.

task void taskname(){}

Task는 인자를 가질수도 리턴값을 가질수도 없다. 그리고 Task를 실행 할때는 post를 사용한다.

post taskname();

여기서 중요한거 컴포넌트의 command,task,event는 task를 포스팅 할 수 있다. 그리고 이벤트 시그널을 위해서는 Task를 사용 하기 바란다. command에서 event를 사용하는건 루프를 발생 시킬 소지가 매우크다. 나중에 설명함(예로 인터페이스 I 제공 하는 컴포넌트 A 사용하는 B가 있을 경우 B의 이벤트에 핸들러에서 A의 command를 실행 하며 그 command에서 시그널을 날린다면 바로 루프가 발생하는 것이다.)

task를 다음과 같이 수정하여 만든다.

 task void computeTask(){
    uint32_t i;
    for(i=0;i<400001;i++){}
  }
  event void Timer0.fired()
  {
      call Leds.led0Toggle();
      post computeTask();
  }

그럼 TelosB는 아직 이상하지만 MicaZ는 작동 잘 할 것이다.

post는 Task를 큐에 FIFO 방식으로 넣는 역활을 한다. Task는 긴 수행시간을 가져서는 안된다. Task는 서로는 선점 하지 못하지만, 하드웨어 인터럽트는 Task를 선점 할수 있다. 긴시간의 수행시간을 가지는 Task의 경우 나누도록 한다. post 명령은 error_t 를 반환한다. (task가 반환 하는것이 아닌 post명령이다.) 이경우는 Task가 벌써 성공적으로 스팅 된 경우 이다.(물론 아직 실행은 안되었다.)

TelosB의 경우 아직 Task 가 많은 시간을 소모 하기 때문에 정상 작동 하지 않는 것이다. 다음과 같이 수정한다.

외적으로 static 변수를 사용하는건 생략 한다. 대략 컴포넌트안의 변수는 모두 Private이기때문에 static를 사용하는건 의미가 없다.
, .

이제 부터 공부의 속력을 내기 위해 요약 해석 할 예정입니다.

속도가 넘 안나네요.

Interfaces,Commands,and Events

Lesson1의 경험으로 인터페이스를 사용하는 컴포넌트는 인터페이스의 command를 실행 할 수 있으며, 역으로 이벤트는 받아서 처리 해야 한다는걸 알 수 있게 되었습니다. 그럼 BlinkC가 사용 하는 인터페이스를 분석 하도록 하겠습니다. BlinkC가 사용 하는 인터페이스는 Timer,Leds,Boot가 있습니다.

tos/interfaces/Boot.nc:
interface Boot {
  event void booted();
}

tos/interfaces/Leds.nc:
interface Leds {

  /**
   * Turn LED n on, off, or toggle its present state.
   */
  async command void led0On();
  async command void led0Off();
  async command void led0Toggle();

  async command void led1On();
  async command void led1Off();
  async command void led1Toggle();

  async command void led2On();
  async command void led2Off();
  async command void led2Toggle();

  /**
   * Get/Set the current LED settings as a bitmask. Each bit corresponds to
   * whether an LED is on; bit 0 is LED 0, bit 1 is LED 1, etc.
   */
  async command uint8_t get();
  async command void set(uint8_t val);
 
}

tos/interfaces/Timer.nc:
interface Timer
{
  // basic interface
  command void startPeriodic( uint32_t dt );
  command void startOneShot( uint32_t dt );
  command void stop();
  event void fired();

  // extended interface omitted (all commands)
}

Looking over the interfaces for Boot, Leds, and Timer, we can see that since BlinkC uses those interfaces it must implement handlers for the Boot.booted() event, and the Timer.fired() event. The Leds interface signature does not include any events, so BlinkC need not implement any in order to call the Leds commands. Here, again, is BlinkC's implementation of Boot.booted():


apps/Blink/BlinkC.nc:
  event void Boot.booted()
  {
    call Timer0.startPeriodic( 250 );
    call Timer1.startPeriodic( 500 );
    call Timer2.startPeriodic( 1000 );
  }

그럼 여기서 BlinkC가 꼭 구현해야 하는 이벤트는 어떤것이 있을까요? 위에서 보면 알 수 있으시겠지만.
여기서 구현해야 하는 Event는 Boot.booted() Timer.fired() 이벤트가 있습니다.그럼 BlinkC가 구현 하고 있는 Boot.booted() 이벤트를 보도록 하죠.

apps/Blink/BlinkC.nc:
  event void Boot.booted()
  {
    call Timer0.startPeriodic( 250 );
    call Timer1.startPeriodic( 500 );
    call Timer2.startPeriodic( 1000 );
  }

BlinkC는 세개의 타이머 객체를 사용하고 있으며, booted() 이벤트는 세개를 시작 시키는 역활을 하고 있습니다. startPeriodic 은 타이머를 시작 시키며, ()안의 숫자는 MillicSecond를 의미합니다.(<TMilli> 객체 생성시 결정) ()안의 숫자와 객체 생성시 정해진 단위로 타이머는 발생됩니다.

call이란 키워드는 command를 실행 할때 쓰며, 역으로 이벤트 전달시에는 signal을 사용합니다. 일단 BlinkC에는 없으니 넘어가도록 하겠습니다.

 event void Timer0.fired()
  {
    dbg("BlinkC", "Timer 0 fired @ %s.\n", sim_time_string());
    call Leds.led0Toggle();
  }
 
  event void Timer1.fired()
  {
    dbg("BlinkC", "Timer 1 fired @ %s \n", sim_time_string());
    call Leds.led1Toggle();
  }
 
  event void Timer2.fired()
  {
    dbg("BlinkC", "Timer 2 fired @ %s.\n", sim_time_string());
    call Leds.led2Toggle();
  }

앞에서 언급 한것 처럼 이벤트의 처리는 사용자에서 하도록 되어있으므로 위와 같이 BlinkC에서 Timer.fired() 이벤트를 처리 해야 합니다. 그리고 함수의 선언은 interface.function 식으로 구분을 확실히 해야 합니다.

, .