tinyosnesc

Tinyos reception after second reply doesn't work


I'm in trouble with my nesC code. In my code I send a first packet using AMSend.send(AM_BROADCAST_ADDR, &packet, sizeof(rd_message)).

After that, when a message is received in function event message_t* Receive.receive(message_t* bufPtr, void* payload, uint8_t len){ a reply is generated and sent successfully, but the other nodes are not able to receive the reply. In particular I have to process a RREP reply, following the basics of DSR protocol. This is my code:

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;
    }
  }

I removed all the logic from the code to focus on the message exchange calls. I hope that someone can help me... thanks.


Solution

  • TinyOS follows almost everywhere a ownership discipline: at any point in time, every "memory object" - a piece of memory, typically a whole variable or a single array element - should be owned by a single module. A command like send is said to pass ownership of its msg argument from caller to callee.

    The main problem of your code is that in the Receive.receive event you are using the packet variable in two ways:

    the result of this code is unpredictable (since receiving a packet will corrupt the outgoing packet). To solve your problem, you should use a Pool<message_t> component. The typical pseudocode for a program like yours is like:

    1. receive (m):
    2. if I don't need to process this message, return m
    3. if my free packet list is empty, return m
    4. else
      1. process/forward m
      2. return entry from free packet list

    This is a rough implementation of a module that uses Pool<message_t> as list of free packets to manage communication:

    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();
    }
    
    }
    

    If you don't like Pool, you can use a message_t array as circular buffer. Take a look at the BaseStation code for a hint on how to do so.

    For more details, I suggest you to read the TinyOS programming book, especially section 3.5.1.

    As for your comment:

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

    you can never return NULL in a receive event, since TinyOS needs always a buffer to store incoming packets.