Hostmote and the Serial Interface
From CSL Wiki
Contents |
[edit]
Files examined
EmStar / PC side code
- emstar/mote/hostmote/hostmote_main.c: host<-->mote driver: only speaks the host-mote protocol, and exports host-mote packets. Other MoteD modules must be run on top of hostmoted that impose semantics such as MoteNIC, SensorNIC, Config, etc. Entry point for all hostmote functions found in this directory. Usage (taken from this file):
- moted [-h] -s <serial-port> [-r <mote-index>] [-m <motetype>] [-b <baudrate>] [-c <config_file>] [-t <check_interval (seconds)>]
- Supported baudrates are 57600 (mica2) 19200 (all others)
- Supported MOTE types are: mica, mica128, mica2, mica2dot
- Defaults for parameters are -mmica -b19200 -r0
- Config file is usually /etc/node.info, mote-index is defined in this file
- If a config file is specified it it not necessary to specify -s, -r or -g flags
- example: moted -s /dev/ttyS0 -r 1 will create /dev/mote/1/*
- emstar/mote/nic/motenic_main.c: a driver that creates a link interface using an underlying mote device
- emstar/mote/libmote/mote_user.c: a library containing functions used to communicate with the mote (initialize / shutdown the interface, send / receive packets etc.), functions called from motenic_main.c
Tiny-OS / mote side code
- tos-contrib/hostmote/tos/system/HostMotePacketM.nc: contains the mote side implementation of the protocol to communicate over the serial interface (lowest level code)
- tos-contrib/hostmote/tos/system/HostMoteM.nc: calls functions in HostMostPacketM.nc. Maintains the higher level code to transmit / receive packets over the serial interface. Demultiplexes packets to the clients Conf, Data and Dbg.
- tos-contrib/transceiver/apps/Transceiver/TransceiverM.nc: acts as an intermediary between the ConfM and DataM modules and the radio. Contains a lot of radio specific code that should probably be removed into a seperate file.
[edit]
Protocol on Serial Interface
- Serial interface is full-duplex, so it is possible to transmit and receive simultaneously
- Communication protocol is only reliable from the PC to the mote, not from the mote to the PC (in other words, ACK and NACK packets are only ever sent from the mote to the PC, not the other way around). The serial interface is fairly reliable (typically, around 1 in 10,000 packets are lost due to CRC errors on this interface). The extra complexity on the mote side was considered too great to justify the small improvement in performance.
[edit]
General Mote-side
- Static priority configured for the three clients (Data, Conf and Debug, from highest to lowest priority). Highest priority always sends first, then medium priority, then lowest priority
- Will only accept one pending transmission from each client at a time
- Clients do not buffer packets either, due to the very constrained memory footprint on the mote. They accept only one packet at a time, and immediately forward to hostmote (subsequent packets are not accepted until the sendDone signal is received from the serial interface, and hostmote can begin transmitting another packet). The only exception is Dbg, although the multiple packet buffering capabilities of this client are optional.
[edit]
Mote-side Send
- Receives request from client for packet transmit
- Performs sanity checking on packet, ensures there is no pending transmission
- Fills in the packet type, subtype and length
- Sets the queue status to SEND_PENDING
- Posts a task to send the packet
In the send packet task (trySend):
- Make sure the UART is not already in use
- If an ACK is pending: send it to the PC, then return
- Send the highest priority packet which is pending
In the task that handles notification that a send has been completed (sendDone):
- Mark the UART as no longer is use
- Post another trySend task
- If we sent an ACK: if it succeeded: clear the ack_status flag, otherwise: mark as SEND_PENDING
- If we sent a data frame: if it succeeded: call the client callback, otherwise: mark the flag as SEND_PENDING
[edit]
Notes
- Should check packet is not a runt, as well as checking it is not oversized. Both these checks should be in the same place, not with one in HostMotePacketM.nc, and the other in HostModeM.nc
- In the start of the trySend task, the value of uart_inuse is checked. If it is found to be non-zero (ie. in the incorrect state), the trySend task is exited, without any error logging or recovery attempts. This sounds like a serious error if it ever occurs, since the UART is marked as in-use at the time when we try and send a packet (a situation that should not occur). However, if it does ever occur, it could cause serious problems, since it doesn't look like the trySend task is reposted, which could result in the system locking up.
- The static priority system per clientis very inflexible, and could be error prone
it is inflexible yes, that's why we need a dynamic system
[edit]
Mote-side Receive
- Perform sanity checking
- Check if packet ID = last packet ID: if so, send ACK, but don't forward packet to client
- Check if it is a reset packet: if so, perform reset operation, send ACK
- If it is a data packet: call the appropriate client's callback function
- On success: send an ACK to the sender
- On failure: send a NACK to the sender
[edit]
Notes
- Should check for CRC failure before doing any other sanity checking (other than the NULL pointer test). Ensures that CRC errors are correctly diagnosed, rather than looking like length errors. However, in the code as it stands, the length is first checked, and then the CRC status is checked. If the CRC check fails, the length field does not necessarily contain any meaningful data, meaning the prior check is useless. (see line 140-150 hostMoteM.nc)
- Should check for runt as well as overlong packets (see line 140 hostMoteM.nc)
[edit]
General PC-side
- Something that makes the hostmote code more difficult to follow than should be necessary are as much to do with the style of the code than the substance. For example, although the operations to transmit packets over the serial interface are almost identical on both sides, the implementations are very different (in terms of how functionality is broken up between subroutines, in the way functions are named, in the order in which operations are performed). Granted, many differences are necessitated by the fact that implementation must be different on the PC versus the mote, simply because of the fact that the hardware and programming language are so different on the two platforms. However, simple things like doing similar splitting of functionality and matching names not only makes the code easier to read, but also makes it easier to check for symmetry (to make sure all checks performed on one side are performed on the other, to ensure both sides of the protocol are compatible)
- As noted by Ben, there is no prioritization of packets on the PC side (unlike on the mote side) of the interface. The only exception is I believe that ACK packets get priority over all other packets on transmit. However, the system could benefit from having at least two levels of priority, for example, for the transmission of reset packets (and / or any other special packets).
The reason there is prioritization on the mote side is that this is the side that is the most resource constrained, without large queues, with multiple occuring interrupts etc etc etc. The reset point is valid and the newer uncommitted version bypasses the queue completely on the hard_reset. The queue itself needs rewriting and rethinking though. Specifically, it should usue the emstar queue macros. And probably one slot per client should be enough.
[edit]
PC-side Transmit
From mote_serial_send in hostmote_serial.c:
- Perform sanity checking
- Set framing bytes and length
- If there is already an ACK pending: enqueue the packet for future transmission and return
- Fill in more header fields and calculate the CRC
- Send the packet (if in the correct state)
- Start the ACK timeout timer
- Store the packet
On ACK timeout in ack_timeout_handler:
- Perform sanity checking
- Log the error
- Resend the packet
- Restart the timer
On receive NACK in handle_nack_pkt:
- Perform sanity checking
- Log the error
- Resend the packet
- Restart the ACK timer
On receive ACK in handle_ack_pkt:
- If we are waiting for an ACK and the sequence number matches:
- Stop the timer
- Destroy the stored packet
- Increment the sequence number
- If there is a stored packet: transmit it, else unblock the device to handle more packets
- Else:
- Log the error, send the packet again (if any), allow the device to handle more packets
[edit]
Notes
- Should check that packets are not over long, as well as checking for runts
It does check for length already. hostmote_serial.c
same issue as above: both checks should be performed in the same place in the code
- Not very robust on send: if the mote is not in the correct state, it silently does not send the packet, but still sets the ACK timeout etc.
An example would be useful. If it is in STATE_SD and it retransmits, it will set the ack timeout because the mote will send and ACK and a SD
See hostmote_serial.c line 453 (what is mote_prog_state?)
- Should log an error if there is no stored packet while we are waiting for an ACK
It should but this is definately an invalid state. Plus I think if there is no stored packet, the code will exit when trying to send anyway
[edit]
PC-side Receive
From mote_serial_handler in hostmote_serial.c:
- Read the data from the serial port, checking for framing errors
- Perform sanity checking
- Check the CRC
- Handle ACK, NACK and conf packets locally
- Forward the received packet to a client
[edit]
Notes
- It looks like ACK and NACK packets are also processed through the pd_receive code, which doesn't look necessary
