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;
}
}
Я удалил всю логику из кода, чтобы сосредоточиться на вызовах обмена сообщениями. Я надеюсь, что кто-то может помочь мне... спасибо.
1 ответ
TinyOS почти везде соблюдает дисциплину владения: в любой момент времени каждый "объект памяти" - кусок памяти, обычно целая переменная или отдельный элемент массива - должен принадлежать одному модулю. Команда как send
Говорят, что он передает владение своим аргументом msg от вызывающего к вызываемому.
Основная проблема вашего кода в том, что в Receive.receive
событие, которое вы используете packet
переменная двумя способами:
- как исходящий пакет, позвонив
call AMSend.send(AM_BROADCAST_ADDR, &packet, sizeof(rd_message))
- в качестве буфера для следующего входящего пакета, выполнив
return bufPtr;
результат этого кода непредсказуем (поскольку получение пакета повредит исходящий пакет). Чтобы решить вашу проблему, вы должны использовать Pool<message_t>
составная часть. Типичный псевдокод для такой программы, как ваша:
- получить (м):
- если мне не нужно обрабатывать это сообщение, верните m
- если мой список бесплатных пакетов пуст, верните m
- еще
- процесс / вперед м
- возврат записи из списка бесплатных пакетов
Это грубая реализация модуля, который использует 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 всегда нужен буфер для хранения входящих пакетов.