Прием Tinyos после второго ответа не работает

У меня проблемы с кодом nesC. В моем коде я отправляю первый пакет, используя AMSend.send(AM_BROADCAST_ADDR, &packet, sizeof(rd_message)).

После этого, когда сообщение получено в функции event message_t* Receive.receive(message_t* bufPtr, void* payload, uint8_t len){, ответ генерируется и отправляется успешно, но другие узлы не могут получить ответ. В частности, я должен обработать ответ RREP, следуя основам протокола DSR. Это мой код:

implementation{


/**********************Variables used*****************************/
short phase = 0;
message_t packet;
bool locked;

event void Boot.booted(){
    dbg("Boot", "Node %hhu booted\n", TOS_NODE_ID);
    call AMControl.start(); 


}

  [cut]

event void MilliTimer.fired(){
    /*This contains the discovery message*/
    rd_message *rreq = NULL;

    if (phase == 0){
        //Route discovery phase
        rreq = (rd_message *) call Packet.getPayload(&packet, (int) NULL);


        if(call AMSend.send(AM_BROADCAST_ADDR, &packet, sizeof(rd_message)) == SUCCESS){
        //locked = TRUE;

        }
        return;
    }

}


event message_t* Receive.receive(message_t* bufPtr, void* payload, uint8_t len){
    rd_message *received_mex = NULL;  
    rd_message *reply_mex = NULL;

    int i,j;

    received_mex = (rd_message*) payload;   //cast to rd_message

      if (received_mex->type == RREQ){
          reply_mex = (rd_message*) call Packet.getPayload(&packet, (int) NULL);  //reply packet is created.
        if (received_mex->sender_id == TOS_NODE_ID){
          //The original sender received its RREQ. Stopping the forward procedure
          return bufPtr;   //FIXME: see if it's correct to return null here
        }

        //RREQ message case 1: I am not the receiver_id
        if (received_mex->receiver_id != TOS_NODE_ID){

        }
        else if (received_mex->receiver_id == TOS_NODE_ID){
          //I am the receiver of the RREQ message. I can now reply with a RREP

        }


        if (call AMSend.send(AM_BROADCAST_ADDR, &packet, sizeof(rd_message)) == SUCCESS) {
                dbg("dsr", "packet sent\n");    
                //locked = TRUE;
            }
        else{
          dbg("dsr", "failed to send reply packet.\n");

        }


      }
      else if (received_mex->type == RREP){
       //DO SOMETHING WITH CHE NEW RECEIVED MESSAGE HERE

      }

    return bufPtr;


}


  event void AMSend.sendDone(message_t* bufPtr, error_t error) {
    if (&packet == bufPtr) {
      //locked = FALSE;
    }
  }

Я удалил всю логику из кода, чтобы сосредоточиться на вызовах обмена сообщениями. Я надеюсь, что кто-то может мне помочь... спасибо.


person Raffo    schedule 01.09.2010    source источник


Ответы (1)


TinyOS почти везде следует правилу владения: в любой момент времени каждый «объект памяти» — часть памяти, обычно целая переменная или отдельный элемент массива — должен принадлежать одному модулю. Говорят, что такая команда, как send, передает право собственности на свой аргумент msg от вызывающего объекта к вызываемому.

Основная проблема вашего кода заключается в том, что в событии Receive.receive вы используете переменную packet двумя способами:

  • как исходящий пакет, вызвав call AMSend.send(AM_BROADCAST_ADDR, &packet, sizeof(rd_message))
  • в качестве буфера для следующего входящего пакета, выполнив return bufPtr;

результат этого кода непредсказуем (поскольку получение пакета испортит исходящий пакет). Чтобы решить вашу проблему, вы должны использовать компонент Pool<message_t>. Типичный псевдокод для такой программы, как ваша:

  1. получить (м):
  2. если мне не нужно обрабатывать это сообщение, верните m
  3. если мой список бесплатных пакетов пуст, вернуть m
  4. else
    1. process/forward m
    2. вернуть запись из списка свободных пакетов

Это грубая реализация модуля, который использует Pool<message_t> в качестве списка свободных пакетов для управления связью:

module Foo
{
    /* this is our free packet list */
    uses interface Pool<message_t>;
    uses interface Receive;
    uses interface AMSend;
}

implementation
{

event void MilliTimer.fired()
{
    message_t *packet;
    /* get a free packet */
    packet = Pool.get();
    if (packet)
    {
        /* code to send the packet */
    }
}

event void AMSend.sendDone(message_t *msg, error_t error)
{
    /* the send function ended, put back the packet in the free packet pool */
    /* check here if msg was taken from Pool */
    call Pool.put(msg);
}

event message_t* Receive.receive(message_t* msg, void* payload, uint8_t len)
{
    if (!haveToProcess(msg))
        return msg; // don't have to process this message
    if (Pool.empty())
        return msg; // memory exahusted;
    /* ... */
    /* code that processes the packet */
    call AMSend.send(AM_BROADCAST_ADDR, msg, sizeof(rd_message));
    /* return a free message_t* as buffer to store the next received packet */
    return Pool.get();
}

}

Если вам не нравится Pool, вы можете использовать массив message_t в качестве кольцевого буфера. Взгляните на BaseStation код для подсказки о том, как это сделать.

Для получения более подробной информации я предлагаю вам прочитать книгу по программированию TinyOS, особенно раздел 3.5.1.

Что касается вашего комментария:

return bufPtr;   //FIXME: see if it's correct to return null here

вы не можете никогда возвращать NULL в событии приема, так как TinyOS всегда нужен буфер для хранения входящих пакетов.

person Giuseppe Cardone    schedule 01.09.2010
comment
Спасибо за ответ, теперь все ясно. Конечно, я должен подробно изучить разработку TinyOS и хорошо понимать, как поступать в подобных ситуациях. Ancora grazie mille!! - person Raffo; 02.09.2010