2009년 8월 26일 수요일

MAC ack & retransmission

retransmission 기능을 사용할 때는 AMPromiscuous + Queue 조합을 사용하는데, 1hop adhoc mode의 경우는 이것이 불필요할 뿐더러 programmer-controllable하지 않은 부분이 추가되는 단점이 있음. 따라서 AMStandard component를 사용하면서 retransmission을 적용하는 것이 필요하다.

reliability를 높이기 위해 retransmission 기능을 사용하고자 할 때는 다음과 같이 설정한다.

0. 설정
  •    /opt/tinyos-1.x/tos/lib/CC2420Radio/CC2420RadioM.nc에서 bAckEnable = TRUE;로 설정
  •    /tos/system/AMPromiscuous.nc에서 crc_check = TRUE;로 설정
  •    /tos/lib/Queue/QueueSendM.nc에서 retransmit = TRUE;로 설정

1. Application에서 MacControl Component를 wiring
        configuration Test {
        }
        implementation {
           component CC2420RadioC;
           ...
           TestM.MacControl -> CC2420RadioC;
        }
           
2. StdControl.start() 에 MacControl.enableAck() 을 추가
        module TestM {

          provides {
          ...
          }
          uses {
             interface MacControl;
              ...
          }
         implementation {
            ...
            command result_t StdControl.start() {
            call MacControl.enableAck();
            }
            ...
         }

3. tos/lib/CC2420Radio/CC2420RadioM.nc
  • BackoffTimerJiffy.fired() 에서 case TIMER_ACK 의 if (!post PacketSent()) 를 주석처리. 이것 때문에 ACK이 오지 않더라도 ack timeout 시 sendDone에 SUCCESS가 return된다.
  • sendDone event callback에서 success == FAIL 인 경우 바로 msg ptr을 retransmission. 필요에 따라 retransmission counter를 두고 max_retransmission을 초과할 경우 drop
4. 멀티 홉 과 재전송 기능을 사용할 경우에 발생하는 문제 및 해결 방법
  • opt/tinyos-1.x/lib/Queue/QueuedSendM.nc 는 TinyOS의 메시지 전송 큐를 관리한다. 재전송 기능도 QueuedSendM 에서 수행된다.

event result_t SerialSendMsg.sendDone[uint8_t id](TOS_MsgPtr msg, result_t success) {
...
if (!retransmit \\ msg->ack != 0 \\ msgqueue[dequeue_next].address == TOS_UART_ADDR) {
// 재전송이 필요 없는 경우 큐의 포인터를 다음 패킷으로 이동시키고,
// 상위 컴포넌트로 메시지 전송 성공 이벤트 발생 (signal, SUCCESS)
...
} else {
...
if ((++(msgqueue[dequeue_next].xmit_count) > MAX_RETRANSMIT_COUNT)) {
// 최대 재전송횟수를 초과했을 경우 큐의 포인터를 다음 패킷으로 이동시키고,
// 상위 컴포넌트로 메시지 전송 실패 이벤트 발생 (signal, FAIL)
...
}
}
// 데이터 전송 Task 실행
post QueueServiceTask();

return SUCCESS;

}

테스트는 멀티홉 라우팅 기능을 사용하며, 라우팅 경로를 빨리 설정하기 위해 라우팅 메시지 전송 주기를 짧게 설정하였다. 그리고 모트 3개 정도에 프로그램을 올리고 테스트 한 결과 재전송이 계속 발생하지만 Base Node에 패킷이 수신되지 않는 현상이 발생하였다. 문제의 원인을 파악한 결과, 라우팅 메시지는 Broadcast 를 사용하며 Broadcast도 이 QueuedSend 의 큐를 통해 전송이 일어나고, Broadcast에 대해서도 재전송을 수행하기 때문이었다.
따라서 위 소스를 그대로 사용하여 재전송 기능을 사용할 경우, Broadcast 하는 패킷에 대한 Ack 가 없을 경우에도 계속 재전송을 하게 되어 Breadcast가 많을 경우 Queue Overflow가 발생할 수 있으며, 쓸데 없이 계속 재전송을 수행하게 된다.
(※ 수신 노드에서는 unicast 일 경우에만 ack 메시지를 전송한다)
이 문제를 해결하기 위해서 위 소스의 if 문 조건을 다음과 같이 변경하여야 한다.

if ((!retransmit) \\ (msg->ack != 0)  \\ (msgqueue[dequeue_next].address == TOS_UART_ADDR) \\ (msgqueue[dequeue_next].address == TOS_BCAST_ADDR)) {
...
}

댓글 없음:

댓글 쓰기