?? ????????? ?? ????
, .

??PDA

TINYOS 2007. 11. 16. 22:34
?? ????????? ??
, .

t3

TINYOS 2007. 11. 16. 22:31
tesr
, .
이제 수신쪽을 만들도록 하겠습니다. 과정은 송신과 비슷 합니다. 적절한 인터페이스를 찾고 선언하고 적절히 command를 부르고 event를 구현해주고, 구성파일에 컴포넌트 선언,와이어링 해주면 끝입니다.

수신 받는쪽은 패킷의 Counter를 추출하여 자기의 LED를 변화 시킬 것입니다.

먼저 timer 이벤트안의 Leds.set을 삭제 합니다.

1. 무선 수신 기능을 제공 하는 인터페이스를 찾습니다.
Recive 인터페이스를 사용 할 것입니다. Packet을 조작 할 수 있는 기능도 같이 제공 합니다.

2. uses 인터페이스에 선언 해줍니다.
 uses interface Receive;

3. 변수와 초기화 코드를 적어 줍니다.
벌써 무선모듈등을  초기 화 했기때문에 필요 없습니다.

4. 제공 인터페이스의 기능을 사용하여 코드를 작성합니다.
Receive의 경우 부를 기능은 없습니다. 단지 이벤트만 작성 합니다.

5. 이벤트를 구현합니다.

event message_t* Receive.receive(message_t* msg, void* payload, uint8_t len) {
  if (len == sizeof(BlinkToRadioMsg)) {
    BlinkToRadioMsg* btrpkt = (BlinkToRadioMsg*)payload;
    call Leds.set(btrpkt->counter);
  }
  return msg;
}

Recevie 이벤트를 구현합니다. 간단히 받은 메세지에서 길이를 점검하여 BlinkToRadioMsg와 일치 하면 msg에서 counter를 추출 하여 counter를 LED로 표현 합니다.단 return msg를 조심하시길 바랍니다. 꼭 돌려 줘야 합니다. msg는 이 이벤트를 발생시킨 모듈이 주인입니다.

좀더 정확한 동작을 원한다면 Receive 이벤트는 Task로 구현하세요( 수신버퍼에 복사하시면 되겟죠?)
그리고 태스크는 한개씩만 동작 하기때문에 변수 접근이 Task로만 이루어지면 크리티컬 세션이 필요 없습니다.

6. 구성파일에 수신 모듈을 추가 합니다.

components new AMReceiverC(AM_BLINKTORADIO);

앞에와 같이 AMReceiverC의 객체를 생성 합니다. AM_BLINKTORADIO는 AM type으로 송신과 같아야 합니다.

7. 와이어링 합니다.
  App.Receive -> AMReceiverC;

8. 프로그램을 테스트 합니다.
두개를 퓨징하여 LED를 보면 하나를끄면 멈추게 될것 입니다.

예제의 경우 apps/tutorials/BlinkToRadio에 소스가 있습니다. 참고 하세요.





, .
Sending a Message over the Radio

Blink를 다시 첨부터 구현하여 복습 하면서 NesC문법을 읽히도록 하며, 거기에 무선 메세지 송수신을 부가 하도록 하겠습니다.

먼저 디렉토리 하나 생성 합니다.

cd tinyos-2.x/apps
mkdir BlinkRadio

그담엔 BlinkToRadioC.nc를 생성 하여 작성 합니다.

#include <Timer.h>
#include "BlinkToRadio.h"

module BlinkToRadioC {
  uses interface Boot;
  uses interface Leds;
  uses interface Timer<TMilli> as Timer0;
}
implementation {
  uint16_t counter = 0;

  event void Boot.booted() {
    call Timer0.startPeriodic(TIMER_PERIOD_MILLI);
  }

  event void Timer0.fired() {
    counter++;
    call Leds.set(counter);
  }
}


이 부분의 내용은 그렇게 어려운게 없습니다.NesC의 문법은 C와 거의 비슷 합니다. 알아두실건 <>의 include 의 경우 기본 TOS 디렉토리인 tos이하에서 찾는다는 내용입니다. " " 의 경우 현재 디렉토리에서 파일을 검색 합니다.
* Makefile에서 -I 옵션을 사용하여 디렉토리를 추가 하실수 도 있습니다.

TIMER_PERIOD_MILLI 가 정의 되어 있는 헤더파일도 작성 합니다.

#ifndef BLINKTORADIO_H
#define BLINKTORADIO_H

enum {
  TIMER_PERIOD_MILLI = 250
};

#endif

물론 헤더 파일의 경우 C 파일 처럼 작성 가능 합니다. 구조체 등은 헤더파일에 작성 하시면 됩니다.

BlinkRadioC의 경우 기능을 담당 하고 있습니다. 그럼 구성 파일도 있어야 겠죠? BlinkRadioAppC.nc 파일도 작성 합니다.

#include <Timer.h>
#include "BlinkToRadio.h"

configuration BlinkToRadioAppC {
}
implementation {
  components MainC;
  components LedsC;
  components BlinkToRadioC as App;
  components new TimerMilliC() as Timer0;

  App.Boot -> MainC;
  App.Leds -> LedsC;
  App.Timer0 -> Timer0;
}

이제 Blink와 완전히 똑같이 동작 할 겁니다.

마지막으로 Makefile을 작성 합니다.
COMPONENT=BlinkToRadioAppC
include $(MAKERULES)

COMPONET=BlinkToRadioAppC는 top-configuration 파일을 지칭 하여 컴파일을 시작 하게 만듭니다.

그럼 작성 하고 테스트 해보세요.

Define a Message Structure

이제 본격적으로 무선 통신을 시작 하겠습니다. 앞서 전송 보낼 프로토콜을 정의 하기위해 구조체를 사용 합니다. message_t 에 바로 접근 하는것 보다는 여러가지 편한 점을 제공 하기 때문에 구조체를 사용하며 카피 하는 방식으로 사용 하도록 하겠습니다.
typedef nx_struct BlinkToRadioMsg {
  nx_uint16_t nodeid;
  nx_uint16_t counter;
} BlinkToRadioMsg;

우선 nx_ 가 생소 할겁니다. 이건 CPU 에따라 빅에디언 또는 리틀 에디언 방식을 취하기때문에 서로 다른 플랫폼 끼리 통신할 경우 똑같은 방식을 제공하기 위해 사용 합니다. 그리니 nx를 꼭 적어 주시길 바랍니다.

Sending Message
이제 메세지를 선언했으니 송신해 보도록 하겠습니다.
이제 정해진 시간에 따라 LED가 깜빡이게 되어 있으니 카운터값 즉 Value를 송신 하겠습니다.

1. message_t와 무선 통신 기능 제공해주는 인터페이스를 찾습니다.
여기서는 AMSender를 사용 하도록 하며, AMSenderC컴포넌트를 사용 하도록 하겠습니다. 하지만 무선 모듈을 초기화 하기위해서는 ActiveMessageC.SplitControl 인터페이스를 사용 해야 합니다.

AMSenderC는 추상 계층입니다. 이전 버전에는 추상 계층을 사용 하지 않고 무선 모듈에 다중 와이어를 해서 사용 하여 한쪽이 사용할때 인식을 못하는 문제가 있었습니다.

2. 사용할 무선 통신 인터페이스를 BlinkToRadioC.nc 컴포넌트에 uses 란에 선언합니다.
module BlinkToRadioC {
  ...
  uses interface Packet;
  uses interface AMPacket;
  uses interface AMSend;
  uses interface SplitControl as AMControl;
}

SplitControl은 as를 사용하여 재명명 하였습니다. 똑같은 이름을 가진 인터페이스를 제공 하는 모듈이 있을 수 있기때문에 구분할때 사용 할 수 있습니다. SplitControl은 ActiveMessageC를 컨트롤 하기 위해 필요합니다.

3. 변수와 초기화 작업을 추가 합니다.
우선 송신할 메세지 버퍼와 무선 통신을 제어할 변수 두개를 추가 합니다.

bool busy=FALSE;
message_t pkt;

무선 모듈을 초기화 합니다. 여기서 유의 할점은 타이머 이벤트마다 무선모듈을 사용 하기 때문에 무선 모듈이 초기화가 완료 될때 타이머를 시작 하도록 합니다.
event void Boot.booted() {
    call AMControl.start();
  }
무선 모듈을 초기화
event void AMControl.startDone(error_t err) {
    if (err == SUCCESS) {
      call Timer0.startPeriodic(TIMER_PERIOD_MILLI);
    }
    else {
      call AMControl.start();
    }
  }

  event void AMControl.stopDone(error_t err) {
  }

위와같이 startDone 이벤트 이후 타이머를 시작 하며, error_t 의 경우 성공 일 겨우 SUCCESS를 반환 합니다.

4. 이제 추가한 인터페이스 기능 즉 무선통신 기능을 추가 합니다.

event void Timer0.fired() {
  ...
  if (!busy) {
    BlinkToRadioMsg* btrpkt = (BlinkToRadioMsg*)(call Packet.getPayload(&pkt, NULL));
    btrpkt->nodeid = TOS_NODE_ID;
    btrpkt->counter = counter;
    if (call AMSend.send(AM_BROADCAST_ADDR, &pkt, sizeof(BlinkToRadioMsg)) == SUCCESS) {
      busy = TRUE;
    }
  }
}

타이머가 발생 할때 마다.  getPayload를 사용하여 데이타부분을 가져와 구조체로 바꾸어 데이타를 버퍼에 채우는 코드입니다. 그리고 send이벤트를 사용하여 브로드 캐스트로 메세지를 송신 하고 있습니다. busy=true;코드를 눈여겨 보셔야 합니다. send 명령을 사용 하는 순간 pkt는 무선 컴포넌트의 것이 됩니다. 그러니 끝나기 전에 다시 접근 하지 마시길 바랍니다.

5. 사용한 인터페이스의 이벤트를 구현 합니다.
Packet.AMPacket,AMSend 인터페이스를 보면 AMSend.sendDone 이벤트하나 뿐입니다.

event void AMSend.sendDone(message_t* msg, error_t error) {
    if (&pkt == msg) {
      busy = FALSE;
    }
  }

sendDone 이벤트는 send 컨맨드를 사용한 컴포넌트에게 송신시 사용한 메세지의 포인터와 함께 반환 됩니다. 그래서 sendDone이벤트에서 버퍼 사용을 해제 합니다.

* &pkt == msg 의 경우 다른 컴포넌트가 AMSend를 쓸경우 같이 이벤트를 받습니다. 그래서 구분을 해줘야 합니다.

6. 이제 구성 파일을 수정 합니다. 사용하는 인터페이스의 컴포넌트를 선언하며 적절하게 와이어링 작업을 합니다.

implementation {
  ...
  components ActiveMessageC;
  components new AMSenderC(AM_BLINKTORADIO);
  ...
}

여기서 ActiveMessagC의 경우 하드웨어 플랫폼에 따라 하나 만 존재 하면 되지만 AMSenderC의 경우 무선 모듈을 통해 송신 하는 모듈의 경우 다중으로 사용 할 수 있습니다. new은 AMSenderC의 객체를 하나 생성 하는 작업입니다. AM_BNLIKTORADIO는 AM_TYPE을 구분 합니다. 즉 AMSenderC를 사용하는 컴포넌트를 구분 할수 있습니다. 헤더 파일에 AM_BLINKTORADIO를 정의 해주도록 합니다.


enum {
  AM_BLINKTORADIO = 6,
  TIMER_PERIOD_MILLI = 250
};

7. 사용하는 모듈을 와이어링 합니다.
implementation {
  ...
  App.Packet -> AMSenderC;
  App.AMPacket -> AMSenderC;
  App.AMSend -> AMSenderC;
  App.AMControl -> ActiveMessageC;
}

보내는 쪽은 끝입니다.





, .