第二次回复后的Tinyos接收不起作用

时间:2010-09-01 12:25:57

标签: tinyos nesc

我的nesC代码遇到了麻烦。在我的代码中,我使用AMSend.send(AM_BROADCAST_ADDR, &packet, sizeof(rd_message))发送第一个数据包。

之后,当在功能event message_t* Receive.receive(message_t* bufPtr, void* payload, uint8_t len){中收到消息时,会生成并成功发送回复,但其他节点无法接收回复。特别是我必须按照DSR协议的基础处理RREP回复。 这是我的代码:

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

我从代码中删除了所有逻辑,专注于消息交换调用。我希望有人可以帮助我......谢谢。

1 个答案:

答案 0 :(得分:4)

TinyOS几乎随处可见所有权纪律:在任何时间点,每一个 “内存对象” - 一块内存,通常是整个变量或单个数组元素 - 应该由单个模块拥有。像send这样的命令被称为将其msg参数的所有权从调用者传递给被调用者。

您的代码的主要问题是在Receive.receive事件中,您使用packet变量有两种方式:

  • 通过呼叫call AMSend.send(AM_BROADCAST_ADDR, &packet, sizeof(rd_message))
  • 作为传出数据包
  • 通过执行return bufPtr;
  • 作为下一个传入数据包的缓冲区

此代码的结果是不可预测的(因为接收数据包会破坏传出数据包)。要解决您的问题,您应该使用Pool<message_t>组件。像你这样的程序的典型伪代码如下:

  1. 收到(m):
  2. 如果我不需要处理此消息,请返回m
  3. 如果我的免费数据包列表为空,请返回m
  4. 否则
    1. process / forward m
    2. 从免费包列表中返回条目
  5. 这是一个模块的粗略实现,它使用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 programming book,尤其是第3.5.1节。

    至于你的评论:

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

    你可以从不在接收事件中返回NULL,因为TinyOS总是需要一个缓冲区来存储传入的数据包。