📄 stack.tex
字号:
detected on the network and that it may begin sending over the radio.If activity was detected over the network, it sets {\tt CM\_waiting} toanother random number and continues waiting for idleness. It is important to note that while {\tt ChannelMonC} searches for idlenessover the network, it is simultaneously searching for a preamble. If apreamble is detected, {\tt ChannelMonC} begins search for a start\_symbol.This in effect switches the network into receive mode. However,when the network finishes receiving the packet or realizes that itfalsely detected a preamble, {\tt ChannelMonC} will return to {\tt IDLE\_STATE}and resume its detection for an idle network to send the packet itaccepted to send. {\tt ChannelMonC} signals {\tt MicaHighSpeedRadioM} via the {\tt idleDetect} signalhandler that the network is idle and ready for transmission.{\tt MicaHighSpeedRadioM} then calls on {\tt SecDedEncoding} to encode the firstbyte of the {\tt TOS\_Msg}. Each byte to be encoded results in three bytesto be sent over the network. Hence, {\tt SecDedEncoding} signals{\tt MicaHighSpeedRadioM} three times for each byte called to beencoded. {\tt MicaHighSpeedRadioM} then activates {\tt SpiByteFifoC} to send thefirst byte of the preamble/start symbol (char {\tt start[12]}), sets thetime field of the {\tt TOS\_Msg} to be sent ({\tt send\_ptr$->$time}), and begins crccalculation with the first byte of the {\tt TOS\_Msg} to be sent({\tt send\_ptr[0]}). {\tt MicaHighSpeedRadioM}'s {\tt msg\_length} field is alsocalculated here. This value corresponds to the number of bytes to beencoded and sent over the network excluding the crc. This calculation proceeds as follows: taking themaximum number of unencoded bytes of a {\tt TOS\_Msg} that can be sent overthe network (36), subtracting the maximum length of the {\tt data} field(29) and the {\tt crc} (2), adding the {\tt length} field of the{\tt TOS\_Msg}, which specifies the number of bytes of the data array to be sent,results in the number of bytes to be encoded and sent over thenetwork. {\tt SpiByteFifoC} holds at most two bytes at any time; the one that iscurrently being sent, and the one that is waiting to be sent (uint8\_t{\tt nextByte}). Being in {\tt IDLE} state corresponds to inactivity in{\tt SpiByteFifoC}. When its buffer is free, its state is open, and when its buffer isin use, its state is full.{\tt SpiByteFifoC} receives a byte to send, and if it iscurrently in its {\tt IDLE} state, which in this particular case it will besince it was inactive before receiving the first byte of the startsymbol, it will accept the byte and signal to{\tt MicaHighSpeedRadioM} that data is ready. {\tt SpiByteFifoC} also initializesthe SPI hardware, initializes and sets timer2 (modifying registers{\tt TIMSK}, {\tt TCNT2}, {\tt OCR2}, {\tt TCCR2}), and sets the radio to transmit.The hardware shift register used by the SPI is now configured to shiftin a bit from the radio every 100 clock ticks (100 ticks/bit =4MHz/40kbps). After eight bits are shifted out of the {\tt SPDR} register(data register of the SPI hardware) and sent over the network,{\tt TOSH\_SIGNAL(SIG\_SPI)} in {\tt SpiByteFifoC} is called. The {\tt nextByte}field of {\tt SpiByteFifoC} is then output to {\tt SPDR} and the hardwarecontinues shifting a bit out and sending it over the network at 40kbps(1 bit every 100 clock ticks) for another group of eight bits. This isthe primary interface to the radio hardware for sending outbits. Contrary to the old stack, there is no software layer thatcommunicates directly to radio hardware when sending.To understand the following explanations on the intricacies of{\tt MicaHighSpeedRadioM}, the distinction between ``calling send on abyte'', ``sending a byte'', and ``signalling that a byte has beensent'' must be fully understood. {\tt SpiByteFifo} keeps a single bytebuffer. Calling {\tt send}() will place the byte in the buffer; the byte isnot immediately sent. {\tt SpiByteFifoC} can be in one of three states: {\tt IDLE},when it not sending a byte, {\tt OPEN}, when it is sending a byte but itsbuffer is open and can be used, and {\tt FULL}, when it is sending a byteand has a byte in its buffer. When a byte has been sent, {\tt SpiByteFifoC}signals a {\tt dataReady}() event. As there is a one byte queue, the{\tt dataReady}() event for a given byte may not be the one immediatelyfollowing the {\tt send}() request. The calling component must keep track ofthe {\tt send}() and {\tt dataReady}() counts to know which event is associatedwith a specific byte.When {\tt MicaHighSpeedRadioM} calls send on the first byte of the start symbol, itsstate changes to {\tt TRANSMITTING\_START}. At each signal of {\tt dataReady}, itcalls send on the next byte of the start symbol. After the tenth byteof the preamble/start symbol has been sent, meaning {\tt dataReady} issignaled with the tenth byte, {\tt MicaHighSpeedRadioM} calls send on the twelfthand final byte of the preamble/start symbol and changes its state to{\tt TRANSMITTING}.When {\tt dataReady} is signaled for the eleventh byte of thepreamble/start symbol, \\{\tt MicaHighSpeedRadioM} calls send on thefirst encoded byte. {\tt MicaHighSpeedRadioM} stores encoded bytes inits 4 byte array encoded\_buffer. After send is called on two of thethree encoded bytes for a single byte of the {\tt TOS\_Msg}, {\ttMicaHighSpeedRadioM} will call encode on the next byte of the {\ttTOS\_Msg} to be encoded and buffered for sending. Using the field {\tttx\_count} as an index into {\tt send\_ptr} cast into a char*, thebyte pointed to will be the next byte encoded.The field {\tt tx\_count} corresponds to the index of the next byte to beencoded and buffered for sending. Let's use the application {\tt CntToRfm}to illustrate how exactly {\tt MicaHighSpeedRadioM} behaves. The firstpacket sent by {\tt CntToRfm} appears as follows:\newpage\begin{verbatim}TOS_Msg: encoded bytes addr = 0xff 0x9b, 0x55, 0x55 0xff 0x9b, 0x55, 0x55 type = 0x4 0x52, 0xaa, 0x9a group = 0x7d 0x48, 0x95, 0x59 length = 0x4 0x9b, 0x55, 0x55 data = 0x1 0x5b, 0xaa, 0x9a 0x0 0xa4, 0xaa, 0xaa 0x0 0xa4, 0xaa, 0xaa 0x0 0xa4, 0xaa, 0xaa crc = 0xd9 0x58, 0x59, 0x69 0x2d 0x95, 0xa6, 0x59\end{verbatim}At each call to {\tt SpiByteFifo.dataReady}, {\tt send} is called onthe next encoded byte and {\tt enc\_count} is decremented. Therefore,taking the first byte of the {\tt TOS\_Msg} (0xff), the order ofoperations is as follows:\begin{itemize}\item {\tt tx\_count} is set to 1, and {\tt enc\_count} equals 3\item {\tt SpiByteFifo.dataReady()} is signaled. Call {\tt SpiByteFifo.send}(0x9b) on the first encoded byte, decrement {\tt enc\_count} to 2\item {\tt SpiByteFifo.dataReady()} is signaled. Call {\tt SpiByteFifo.send}(0x55) on the second encoded byte, decrement {\tt enc\_count} to 1. To fill up the encoded buffer, call {\tt Code.encode(next\_data)} where {\ttnext\_data} is {\tt send\_ptr[tx\_count]}. Increment {\tt tx\_count}to 2 and incrementally compute the crc ({\tt calc\_crc} = {\ttadd\_crc\_byte(next\_data, calc\_crc)}).\item {\tt Code.encodeDone()} is signaled. Add the number of encoded bytes (3) to {\tt enc\_count}, to make it 4.\item {\tt SpiByteFifo.dataReady()} is signaled. Call {\tt SpiByteFifo.send(0x55)} on the third encoded byte (the final encoded byte of the first data byte of the packet). Decrement {\tt enc\_count} to 3.\item {\tt SpiByteFifo.dataReady()} is signaled. Call {\tt SpiByteFifo.send(0x9b)} on the fourth encoded byte (the first encoded byte of the second data byte of the packet). Decrement {\tt enc\_count} to 2.\end{itemize}This cycle repeats itself for each byte of the {\tt TOS\_Msg} that issent over the radio. In the instance of the {\tt dataReady} handlerthat calls {\tt send} on the second to last byte of the encoded threebytes of the second to last byte of the {\tt TOS\_Msg} to be sent (inthis case it would be the fifth to last encoded byte before the {\ttcrc}, 0xaa, refer to {\tt CntToRfm} example above), {\tt tx\_count} isautomatically changed to 34. Therefore, independent of what {\ttmsg\_length} or the number of data bytes encoded and sent over thenetwork is, the {\tt crc} bytes will always be the last two byteencoded and called {\tt send} on.After the six bytes of the encoded {\tt crc} are called {\tt send} on,{\tt MicaHighSpeedRadioM} changes its state to {\ttSENDING\_STRENGTH\_PULSE}. The time from when {\ttMicaHighSpeedRadioM} transitions from {\tt TRANSMITTING} to {\ttSENDING\_STRENGTH\_PULSE}, to the time when it transitions from \\{\tt SENDING\_STRENGTH\_PULSE} to {\tt WAITING\_FOR\_ACK}, two bytesof 0xff are sent. As the name of the state suggests, a strength pulseis sent. However, currently in the radio stack, the strength pulse isused merely as a timing mechanism.After the strength pulse is sent, during the transition from {\ttSENDING\_STRENGTH\_PULSE} to \\{\tt WAITING\_FOR\_ACK}, {\ttSpiByteFifo.phaseShift()} is called. {\tt phaseShift} delays {\ttSpiByteFifoC}, meaning {\tt SpiByteFifoC} pauses before resumingshifting in bits from the radio.Once {\tt MicaHighSpeedRadioM} enters the {\tt WAITING\_FOR\_ACK} state, ittransitions the radio to receive mode. {\tt SpiByteFifoC} continues tosignal {\tt dataReady} to {\tt MicaHighSpeedRadioM} in 800 clock tick intervals(after 8 bits are shifted in), and the byte signalled (uint8\_t {\tt data}) corresponds to the byte heardover the radio. {\tt MicaHighSpeedRadioM} listens for four bytes, and on thelast one, if the byte is equal to 0x55, then it sets the {\tt TOS\_Msg} {\tt ack}field to 1, indicating the message sent was properly received. A{\tt packetReceived} task is then posted, which sets {\tt MicaHighSpeedRadioM} to{\tt IDLE\_STATE}, sets {\tt ChannelMonC} to {\tt IDLE\_STATE} and activates it to search for a preamble/startsymbol, and passes the sent packet to the AM layer with the {\tt ack} field and {\tt time} fieldsset.To summarize, the sender's interaction with the radio in the{\tt CntToRfm} example is as follows:\begin{verbatim} bytes sent ------------------- addr = 0xff 0x9b, 0x55, 0x55 0xff 0x9b, 0x55, 0x55 type = 0x4 0x52, 0xaa, 0x9a group = 0x7d 0x48, 0x95, 0x59 length = 0x4 0x9b, 0x55, 0x55 data = 0x1 0x5b, 0xaa, 0x9a 0x0 0xa4, 0xaa, 0xaa 0x0 0xa4, 0xaa, 0xaa 0x0 0xa4, 0xaa, 0xaa crc = 0xd9 0x58, 0x59, 0x69 0x2d 0x95, 0xa6, 0x59 strength 0xff pulse 0xff ---phase shift occurs--- ---radio now set to receiving--- byte received 0x55 byte received 0x55 byte received 0x55 data = byte received (send_ptr->ack = (data == 0x55)) DONE\end{verbatim}\section*{Receiving a Packet}{\tt ChannelMonC} initiates the reception of a packet. When the radio stackis initialized, \\{\tt ChannelMon.startSymbolSearch} is called. This methodinitializes {\tt ChannelMonC} to {\tt IDLE\_STATE} as described earlier in sectioninit/idle. Once {\tt ChannelMonC} detects a preamble, its state changes into{\tt START\_SYMBOL\_SEARCH}, where it will shift in bits in search of a startsymbol. If a start symbol was not detected after 30 bits received, itchanges its state back to {\tt IDLE\_STATE}. If a start symbol was detected,it signals {\tt MicaHigSpeedRadioM startSymDetect}.In the {\tt startSymDetect} handler, {\tt MicaHighSpeedRadioM} changes its stateto {\tt RX\_STATE}, sets the {\tt time} field of the packet received to the currenttime, trivially sets the {\tt strength} field of the packet to 0,synchronizes the receiver ({\tt RadioTiming.getTiming}() and {\tt startReadBytes}(tmp)) to the sender and activates {\tt SpiByteFifoC} tobegin shifting in bits. Synchronization details can be found insection Timing. {\tt SpiByteFifoC} is now configured to shift in bits sampled from the radioonce every 100 clock ticks, and signals {\tt dataReady} to{\tt MicaHighSpeedRadio} after 8 bits have been sampled.Now, each time {\tt dataReady} is called in {\tt MicaHighSpeedRadioM},{\tt SpiByteFifoC} will call decode on the byte received and returned by{\tt SpiByteFifoC}. {\tt SecDedEncoding} signals {\tt decodeDone} to {\tt MicaHighSpeedRadioM}after three bytes have been called to be decoded. Therefore, most ofthe logic for the receiver resides in the {\tt decodeDone} handler.Many constants are used in the {\tt decodeDone} handler and they are{\tt MSG\_DATA\_SIZE}, {\tt LENGTH\_BYTE\_NUMBER} and {\tt DATA\_LENGTH}. {\tt MSG\_DATA\_SIZE} is equal to 36,the number of bytes of a {\tt TOS\_Msg} up to and including the {\tt crc} field.{\tt LENGTH\_BYTE\_NUMBER} corresponds to the index of the {\tt length} field of{\tt TOS\_Msg} when it is cast into a (char*). {\tt DATA\_LENGTH} corresponds tothe size of the {\tt data} field of a {\tt TOS\_Msg}, which is currently set to29.The logic {\tt decodeDone} follows is nearly identical to the logic describedin the previous section for the sender of the packet. Each time a byteis decoded, it is written into the buffer {\tt TOS\_Msg} ({\tt rec\_ptr}) using theindex {\tt rec\_count}. The field {\tt msg\_length}, corresponds to the numberof decoded bytes that should be received excluding the {\tt crc}. Thecalculation for {\tt msg\_length} is the same as described in the previoussection, except that it cannot be calculated until it has received the{\tt length} field of the packet being sent (if({\tt rec\_count} ==LENGTH\_BYTE\_NUMBER)\{...\}). For the sender, {\tt msg\_length} can be calculated right away because thelength of the packet is passed as a paramter to the AM layer. Once {\tt msg\_length} bytes have been received and decoded, {\tt rec\_count} isautomatically set to 34 (if({\tt rec\_count} == {\tt msg\_length})\{...\}). This occurs because the next two bytesdecoded will be the {\tt crc}, and the index of the first byte of the {\tt crc} of {\tt rec\_ptr}, whencast as a (char*), is 34.As a note regarding CRC reception and calculation, each byte receivedexcluding the two {\tt crc} bytes is used to calculate the CRC. After the{\tt crc} has been received, it is compared with the calculated CRC. If they
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -