3. UnetStack basics
UnetStack is an agent-based network stack . Each agent is similar to a layer in a traditional network stack, but has more flexibility to use the scarce resources (bandwidth, energy, etc) in the Unet more efficiently. In order to develop Unet applications, we need to understand some basic concepts in UnetStack.
3.1. The command shell
The simplest way to interact with UnetStack is via the command shell (or simply shell ). The shell may be accessed on the console, a TCP/IP port or via the web interface. In Chapter 2 , we have already seen how to set up a 2-node network and access the command shell for each of the nodes using a web browser. For the rest of this section, we assume that you have shells open on nodes A and B.
On node A, we can ask for a list of agents running:
> ps
statemanager: org.arl.unet.state.StateManager - IDLE
remote: org.arl.unet.remote.RemoteControl - IDLE
rdp: org.arl.unet.net.RouteDiscoveryProtocol - IDLE
ranging: org.arl.unet.localization.Ranging - IDLE
uwlink: org.arl.unet.link.ReliableLink - IDLE
node: org.arl.unet.nodeinfo.NodeInfo - IDLE
websh: org.arl.fjage.shell.ShellAgent - RUNNING
simulator: org.arl.unet.sim.SimulationAgent - IDLE
phy: org.arl.unet.sim.HalfDuplexModem - IDLE
bbmon: org.arl.unet.bb.BasebandSignalMonitor - IDLE
arp: org.arl.unet.addr.AddressResolution - IDLE
transport: org.arl.unet.transport.SWTransport - IDLE
router: org.arl.unet.net.Router - IDLE
mac: org.arl.unet.mac.CSMA - IDLE
We can further ask for more details of a specific agent:
> phy
« Half-duplex modem »
Generic half duplex modem simulator.
[org.arl.unet.DatagramParam]
MTU ⤇ 56
RTU ⤇ 56
[org.arl.unet.bb.BasebandParam]
basebandRate = 12000.0
carrierFrequency = 12000.0
maxPreambleID ⤇ 4
maxSignalLength = 65536
signalPowerLevel = -42.0
[org.arl.unet.phy.PhysicalParam]
busy ⤇ false
maxPowerLevel = 0.0
minPowerLevel = -96.0
propagationSpeed ⤇ 1534.4574
refPowerLevel = 185.0
rxEnable = true
rxSensitivity = -200.0
time ⤇ 3074996380
timestampedTxDelay = 1.0
[org.arl.unet.sim.HalfDuplexModemParam]
basebandRxDuration = 1.0
clockOffset = 2932.3245
We asked for details of the agent
phy
, and we got a list of parameters supported by the agent. We can get or set individual parameters of the agent:
> phy.MTU
56
> phy.rxEnable
true
> phy.rxEnable = false
false
> phy.rxEnable
false
> phy.rxEnable = true
true
To find out more about a specific parameter, we can ask for help on the parameter:
> help phy.MTU
phy.MTU - maximum transmission unit (MTU) in bytes
> help phy.rxEnable
phy.rxEnable - true if reception enabled
We can also ask for help on an agent:
> help phy
phy - access to physical service
Examples:
phy // access physical parameters
phy[CONTROL] // access control channel parameters
phy[DATA] // access data channel parameters
phy << msg // send request msg to physical agent
phy.rxEnable = false // disable reception of frames
Commands:
- pclr - clear PHY queues
- plvl - get/set TX power level for all PHY channel types
Parameters:
The following parameters are available on all modems. Additional modem
dependent parameters are also available. For information on these
parameters type "help modem".
- phy.MTU - maximum transmission unit (MTU) in bytes
- phy.RTU - recommended data transfer size in bytes
- phy.rxEnable - true if reception enabled
- phy.propagationSpeed - propagation speed in m/s
- phy.timestampedTxDelay - delay before TX of timestamped frames
- phy.time - physical layer time (us)
- phy.busy - true if modem is TX/RX a frame, false if idle
- phy.refPowerLevel - reference power level in dB re uPa @ 1m
- phy.maxPowerLevel - maximum supported power level (relative to reference)
- phy.minPowerLevel - minimum supported power level (relative to reference)
Channel Parameters:
The following parameters are available on all modems. Additional modem
dependent parameters are also available. For information on these
parameters type "help modem".
- phy[].MTU - maximum transmission unit (MTU) in bytes
- phy[].RTU - recommended data transfer size in bytes
- phy[].dataRate - effective frame data rate (bps)
- phy[].frameDuration - frame duration (seconds)
- phy[].powerLevel - powel level used for transmission (relative to reference)
- phy[].errorDetection - number of bytes for error detection
- phy[].frameLength - frame length (bytes)
- phy[].maxFrameLength - maximum settable frame length (bytes)
- phy[].fec - forward error correction code
- phy[].fecList - list of available forward error correction codes
From this help, we see that
phy
agent also supports channel parameters (also known as
indexed
parameters). It supports two logical channels, CONTROL (1) and DATA (2). The CONTROL channel is meant for low-rate robust data transmission, whereas the DATA channel is typically configured for higher rate data transmission. Channel parameters work in the same way as normal parameters, but with an index:
> phy[CONTROL]
« PHY »
[org.arl.unet.DatagramParam]
MTU ⤇ 16
RTU ⤇ 16
[org.arl.unet.phy.PhysicalChannelParam]
dataRate = 202.10527
errorDetection ⤇ 1
fec ⤇ 0
fecList ⤇ null
frameDuration ⤇ 0.95
frameLength = 24
janus = false
llr ⤇ false
maxFrameLength = 128
powerLevel = -42.0
> phy[DATA]
« PHY »
[org.arl.unet.DatagramParam]
MTU ⤇ 56
RTU ⤇ 56
[org.arl.unet.phy.PhysicalChannelParam]
dataRate = 731.4286
errorDetection ⤇ 1
fec ⤇ 0
fecList ⤇ null
frameDuration ⤇ 0.7
frameLength = 64
janus = false
llr ⤇ false
maxFrameLength = 512
powerLevel = -42.0
> phy[CONTROL].MTU
16
> phy[CONTROL].frameLength = 32
32
> phy[CONTROL].frameLength
32
> phy[CONTROL].MTU
24
> phy[CONTROL].frameLength = 24
24
The actual parameters you see may differ if you are working with a modem, depending on the specific capabilities of the modem. Use
help
to find out more about any listed parameter on your modem, or refer to the modem’s documentation for further information.
|
Most agents also support some commands. For example, the
phy
agent supports the
plvl
command:
> help plvl
plvl - get/set TX power level for all PHY channel types
Examples:
plvl // get all power levels
plvl -10 // set all power to -10 dB
plvl(-10) // alternative syntax
plvl = -10 // alternative syntax
> plvl
phy[1].powerLevel = -42.0
phy[2].powerLevel = -42.0
phy[3].powerLevel = -42.0
phy.signalPowerLevel = -42.0
> plvl -20
OK
> plvl
phy[1].powerLevel = -20.0
phy[2].powerLevel = -20.0
phy[3].powerLevel = -20.0
phy.signalPowerLevel = -20.0
The
plvl
command simply displays or sets the
powerLevel
parameter of all channels. The same can be manually accomplished by setting or getting individual parameters, if desired:
> phy[1].powerLevel
-20
> phy[1].powerLevel = -10
-10
> phy[1].powerLevel
-10
> plvl
phy[1].powerLevel = -10.0
phy[2].powerLevel = -20.0
phy[3].powerLevel = -20.0
phy.signalPowerLevel = -20.0
While
plvl
seems like a command to just set/get a
powerLevel
parameter, it does that for several channels in one go. This can save you a lot of time and typing — to achieve the same thing manually, you’d be typing 4 commands!
|
3.2. Interacting with agents using messages
While you can access a lot of functionality via parameters and commands, to fully harness the power of UnetStack, we require an understanding of the underlying messaging system between the agents. All agents support messages that expose their functionality. In fact, all parameters and commands are implemented by exchanging messages between the shell agent and other agents. In this section, we’ll take a brief look at how messaging between agents works.
All parameters and commands are implemented by exchanging messages between the shell agent and other agents. When you get/set a parameter, all the shell is doing is sending a
ParameterReq
message to the appropriate agent, and showing you the
ParameterRsp
message that the agent responds with.
|
Typically, we would want to send a
request
to an agent and get a
response
message back. This can be accomplished with the
request
call (or the equivalent alias
<<
) on the agent:
> phy << new TxFrameReq(data: [1,2,3])
AGREE
phy >> TxFrameNtf:INFORM[type:CONTROL txTime:2913909740]
Here we made a request to the
phy
agent to transmit some data. The agent responded with an
AGREE
response, shortly followed by a
TxFrameNtf
notification from
phy
telling us that the transmission was successful.
A frame is simply a datagram at the physical layer, also sometimes called a "packet". We prefer the term "frame" when working at the physical layer, but the distinction between frames and datagrams is unimportant at this point in time. We will come back to this later, in Chapter 15 . |
We can also use the return value in a condition, but we need to remember that the return value from the
request
is a message:
> x = phy << new TxFrameReq();
phy >> TxFrameNtf:INFORM[type:CONTROL txTime:3381446740]
> x
AGREE
> x.class
class org.arl.fjage.Message
> x.performative
AGREE
> if (x.performative == Performative.AGREE) print 'OK'
OK
The semicolon ";" at the end of the first statement prevents the return value from being printed on the shell. |
Unsolicited notification messages can be received by subscribing to the topic of interest. For example, on node B, we can subscribe to physical layer events on node B:
> subscribe phy
Now, if we broadcast a frame from node A using
phy << new TxFrameReq()
, we will see the relevant reception events on node B:
phy >> RxFrameStartNtf:INFORM[type:CONTROL rxTime:1765508396]
phy >> RxFrameNtf:INFORM[type:CONTROL from:232 rxTime:1765508396]
The first event
RxFrameStartNtf
is triggered as soon as the frame is detected at node B. The second event
RxFrameNtf
is triggered when the frame is fully received, demodulated and successfully decoded at the receiver.
If all of this seems somewhat confusing to you, don’t worry about it. Most of the basic functionality of the stack can be accessed without having to deal with messages directly. As we need functionality that requires an understanding of messaging, we’ll gradually introduce them in later chapters.
3.3. Shell scripting
The default UnetStack shell accepts any Groovy code, and so is very flexible:
> 1+2
3
> 5.times { print it }
0
1
2
3
4
You can also define closures (if you’re not familiar with closures, you can think of them as functions for now):
> tx2 = {
- 2.times {
- phy << new TxFrameReq()
- }
- };
and call them later:
> tx2
phy >> TxFrameNtf:INFORM[type:CONTROL txTime:3911898740]
phy >> TxFrameNtf:INFORM[type:CONTROL txTime:3912307740]
You can write Groovy scripts and store them in the
scripts
folder with an extension
.groovy
. You can then invoke them from the shell by simply typing the name of the script (without the extension).
|
This only scratches the surface of what the command shell is capable of. However, it should provide you a basic understanding of how the shell works, and illustrate its power. To understand more, we suggest that you explore the online
help
. As you further understand the UnetStack and fjåge API, you’ll develop expertise on using the shell.
<<< [Getting started] | [Unet basics] >>> |