I'm pretty sure the following is a problem under heavy receive loads on the
serial link. This is especially true for high baud rates that have
interarrival character times that are quite small.
In SerialP, rx_state_machine, the following code gets executed at the end of
a packet being received.
In particular *ReceiveBytePacket.endPacket(SUCCESS) is signaled and then a
jump to nosync is done*
*where ReceiveBytePacket.endPacket(FAIL) is signalled.*
*
*
*Signalling endPacket twice from the same event is wrong. It doesn't hurt
anything as long as the load*
*is light and the state of the other slot is unlocked.*
*
*
*Under heavy loads and just the right circumstances this can cause an in use
receive slot to become*
*unlocked causing a packet loss. The unlocked slot will get used for a new
incoming packet. The packet*
*contained in the slot's msg buffer will be lost and the msg buffer reused
for the new incoming packet.*
void rx_state_machine(bool isDelimeter, uint8_t data){
switch (rxState) {
.....
case RXSTATE_INFO:
if (rxByteCnt < SERIAL_MTU){
if (isDelimeter) { /* handle end of frame */
if (rxByteCnt >= 2) {
if (rx_current_crc() == rxCRC) {
signal ReceiveBytePacket.endPacket(SUCCESS);
ack_queue_push(rxSeqno);
goto nosync;
} else
goto nosync;
}
else
goto nosync;
} else { /* handle new bytes to save */
if (rxByteCnt >= 2){
tmp = rx_buffer_pop();
signal ReceiveBytePacket.byteReceived(tmp);
rxCRC = crcByte(rxCRC, tmp);
}
rx_buffer_push(data);
rxByteCnt++;
}
}
/* no valid message.. */
else
goto nosync;
break;
default:
goto nosync;
}
return;
nosync:
/* reset all counters, etc */
rxInit();
call SerialFrameComm.resetReceive();
signal ReceiveBytePacket.endPacket(FAIL);
if (offPending) {
rxState = RXSTATE_INACTIVE;
testOff();
return;
}
/* if this was a flag, start in proto state.. */
if (isDelimeter)
rxState = RXSTATE_PROTO;
}
Consider the case where there is heavy incoming load and the
SerialDispatcher already has a packet in the
other slot. But it hasn't been delivered yet because the task level hasn't
had a chance to run yet.
The current packet's last byte has come in and we signal the
endPacket(SUCCESS). The Dispatcher finishes
things off and switches over to the other receive slot.
But then we signal endPacket(FAIL) which causes the Dispatcher to assume
that something happened with
the current slot and that it should unlock. This is forced and the current
slot (the other slot) then is forced
unlocked and it will get used if another incoming packet starts up. The
pending packet inside the buffer
is lost.
I have reworked code in my tree that fixes this. However, I've been
cleaning the code up too to make it
easier to follow. So it has other changes in it as well.
--
Eric B. Decker
Senior (over 50 :-) Researcher
_______________________________________________
Tinyos-help mailing list
[email protected]
https://www.millennium.berkeley.edu/cgi-bin/mailman/listinfo/tinyos-help