SLIPstream

Version 34 (Anthony Rowe, 10/22/2007 11:15 am)

1 2 Anthony Rowe
[[Image(slip-stream-car.png)]]
2 3 Anthony Rowe
3 12 Anthony Rowe
SLIPstream is an emerging standard in sensor networks for IP to sensor node gateway communication. The SLIPstream program allows for terminal style debugging with a transparent bi-directional packet based communication channel.  The SLIPstream server is written in C and should be easily executable on any embedded or desktop Unix based platform.  In its most basic form, the SLIPstream server can act as a terminal program that displays debugging serial messages from a gateway node.  The SLIPstream server also acts as a UDP server that allows PC programs to connect to the socket for datagram communication to a set of SLIP based functions running on the gateway node.  Unlike a simple serial to socket forwarder, the SLIP protocol allows for framing and checksumming of datagram packets going into and out of a sensor node.  Since SLIP packets have special ESC characters, this can co-exist with normal debug messages that transmit ASCII readable text.  UDP packets sent to the SLIPstream server are forwarded on to the node, and any SLIP replies from the node are passed back to the UDP client.  Below is a block diagram showing the components in the architecture:
4 4 Anthony Rowe
5 3 Anthony Rowe
[[Image(block-diagram.png)]]
6 3 Anthony Rowe
7 15 Anthony Rowe
SLIPstream uses a modified version of the SLIP (serial line IP) protocol described [http://tools.ietf.org/html/rfc1055 here].  Since we want the system to interact with normal debugging messages, we have added a <START> escape character as well as a checksum and length field.  The maximum transmission unit (MTU) is 127 bytes to match the MTU for the wireless network.  The checksum and size are 7bit values so that they can never be confused with an ESC control sequence.  To avoid synchronization errors, all control codes that appear in the SLIP data payload section are wrapped in escape sequences.  Below is a diagram of the SLIP data format which is used internally by SLIPstream and the Nano-RK slip functions:
8 5 Anthony Rowe
9 3 Anthony Rowe
[[Image(SLIP-packet.png)]]
10 6 Anthony Rowe
11 7 Anthony Rowe
There are three main components to SLIPstream.  First there is the SLIPstream server which can be found in the nano-RK/tools/SLIPstream/SLIPstream-server directory.  Second, there is the SLIP module that runs in Nano-RK on the sensor node. This provides your sensor node application with a slip_tx() and slip_rx() function. Lastly, there is a sample UDP client application which would likely be customized for your particular application that can be fond in the nano-RK/tools/SLIPstream/SLIPstream-client directory.
12 9 Anthony Rowe
13 13 Anthony Rowe
= Nano-RK APIs =
14 13 Anthony Rowe
15 34 Anthony Rowe
This section describes the Nano-RK related function calls that can be used with SLIPstream.  
16 1 Anthony Rowe
17 34 Anthony Rowe
'''STEP 1: Add the following in your nrk_cfg.h''':
18 34 Anthony Rowe
19 16 Anthony Rowe
 * #define the correct SLIP_PCP_CEILING value
20 16 Anthony Rowe
  * This must be set to the priority of the highest priority task that calls printf() or uses the serial port.  This priority is inherited by the task that calls slip_tx() so that no other serial traffic goes into the SLIP packet.  If in doubt, set this to a very high priority.  However, be careful that it is not higher than something important like the network link layer.
21 13 Anthony Rowe
 * #define NRK_UART_BUF   1
22 13 Anthony Rowe
 * #define MAX_RX_UART_BUF 128
23 13 Anthony Rowe
 * Increase NRK_MAX_RESOURCE_CNT by 1
24 13 Anthony Rowe
  * This semaphore is used to block multiple tasks from using slip_tx() at the same time.  Typically it is a good idea to keep slip_tx() and slip_rx() localized in one area.
25 13 Anthony Rowe
 * SLIP does not increase the task count in the system
26 13 Anthony Rowe
27 13 Anthony Rowe
{{{
28 13 Anthony Rowe
#!c
29 13 Anthony Rowe
// This must be greater than or equal to the highest priority task that uses
30 13 Anthony Rowe
// the serial port (i.e. print of nrk_kprintf)
31 13 Anthony Rowe
#define SLIP_PCP_CEILING                18     
32 13 Anthony Rowe
 	
33 13 Anthony Rowe
// Enable buffered and signal controlled serial RX
34 13 Anthony Rowe
#define NRK_UART_BUF                    1
35 13 Anthony Rowe
// Set buffer to MAX slip packet size.
36 13 Anthony Rowe
// This could be smaller than 128 if you are careful.
37 13 Anthony Rowe
#define MAX_RX_UART_BUF                 128
38 13 Anthony Rowe
39 13 Anthony Rowe
// Slip uses a single semaphore to control UART access
40 13 Anthony Rowe
#define NRK_MAX_RESOURCE_CNT            2
41 13 Anthony Rowe
}}}
42 1 Anthony Rowe
43 34 Anthony Rowe
'''STEP 2: Add the following in your makefile''':
44 34 Anthony Rowe
45 34 Anthony Rowe
{{{
46 34 Anthony Rowe
#!c
47 34 Anthony Rowe
SRC += $(ROOT_DIR)/src/net/slip/slip.c
48 34 Anthony Rowe
49 34 Anthony Rowe
...
50 34 Anthony Rowe
51 34 Anthony Rowe
EXTRAINCDIRS = $(ROOT_DIR)/src/net/slip
52 34 Anthony Rowe
53 34 Anthony Rowe
}}}
54 34 Anthony Rowe
55 34 Anthony Rowe
'''STEP 3: Use the following functions in your code''':
56 13 Anthony Rowe
57 24 Anthony Rowe
'''slip_init (FILE *input_stream, FILE *output_stream, uint8_t echo_flag, uint8_t delay_ms)'''
58 28 Anthony Rowe
59 24 Anthony Rowe
This function will setup SLIP on the sensor node.  The ''input_stream'' and ''output_stream'' set the file descriptors that
60 24 Anthony Rowe
should be used for input and output.  By default, these should be set to "stdin" and "stdout".  The ''echo_flag'' is currently not used, but in the future it will set if automatic echoing should be enabled.  The ''delay_ms'' parameter sets a delay that can be used between individual byte transmissions being sent by the board.  Below is a typical slip_init() call:
61 1 Anthony Rowe
62 24 Anthony Rowe
{{{
63 24 Anthony Rowe
#!c
64 24 Anthony Rowe
slip_init (stdin, stdout, 0, 0);
65 24 Anthony Rowe
}}}
66 24 Anthony Rowe
67 1 Anthony Rowe
'''int8_t slip_started ()'''
68 25 Anthony Rowe
69 24 Anthony Rowe
This function returns 1 once slip has started and 0 if slip has not yet been configured.  This can be used to synchronize tasks that are waiting for another task to call slip_init().  For example:
70 1 Anthony Rowe
71 24 Anthony Rowe
{{{
72 24 Anthony Rowe
#!c
73 24 Anthony Rowe
while (slip_started () != 1) nrk_wait_until_next_period ();
74 24 Anthony Rowe
}}}
75 24 Anthony Rowe
76 1 Anthony Rowe
'''int8_t slip_tx (uint8_t *buf, uint8_t len)'''
77 25 Anthony Rowe
78 24 Anthony Rowe
This function will transmit the buffer indicated by ''buf'' of length ''len'' using the SLIP protocol.  NRK_OK is returned upon success.  NRK_ERROR is returned if an internal error occured. 
79 13 Anthony Rowe
80 26 Anthony Rowe
{{{
81 26 Anthony Rowe
#!c
82 26 Anthony Rowe
// Remember not to declare large buffers locally
83 26 Anthony Rowe
uint8_t slip_tx_buf[MAX_SLIP_BUF];
84 26 Anthony Rowe
...
85 26 Anthony Rowe
sprintf (slip_tx_buf, "Hello %d", cnt);
86 26 Anthony Rowe
len = strlen (slip_tx_buf);
87 26 Anthony Rowe
slip_tx (slip_tx_buf, len);
88 26 Anthony Rowe
}}}
89 26 Anthony Rowe
90 1 Anthony Rowe
'''int8_t slip_rx (uint8_t *buf, uint8_t max_len)'''
91 25 Anthony Rowe
92 24 Anthony Rowe
This function will block until a slip message has been received and passes the checksum.  The application must pass a buffer ''buf'' with a max length ''max_len'' that it wishes to be filled with any incoming slip data. NRK_OK is returned upon success. NRK_ERROR can be returned if a packet is received, but the checksum fails.
93 26 Anthony Rowe
94 26 Anthony Rowe
{{{
95 26 Anthony Rowe
#!c
96 26 Anthony Rowe
int8_t v;
97 26 Anthony Rowe
// Remember not to declare large buffers inside functions. (protect your stack)
98 26 Anthony Rowe
uint8_t slip_rx_buf[MAX_SLIP_BUF];
99 26 Anthony Rowe
...
100 26 Anthony Rowe
v = slip_rx (slip_rx_buf, MAX_SLIP_BUF);
101 26 Anthony Rowe
 if (v > 0) {
102 27 Anthony Rowe
     nrk_kprintf (PSTR ("Task got data: "));
103 26 Anthony Rowe
     for (i = 0; i < v; i++)
104 26 Anthony Rowe
        printf ("%c", slip_rx_buf[i]);
105 26 Anthony Rowe
     printf ("\r\n");
106 26 Anthony Rowe
     }
107 26 Anthony Rowe
else
108 27 Anthony Rowe
     nrk_kprintf (PSTR ("Task data failed\r\n"));
109 26 Anthony Rowe
}}}
110 13 Anthony Rowe
111 13 Anthony Rowe
= UDP Client APIs =
112 10 Anthony Rowe
113 19 Anthony Rowe
The following API can be used after including "slipstream.h" in any standard C program running under Unix.  For more information see the [http://www.nanork.org/nano-RK/browser/nano-RK/tools/SLIPstream/SLIPstream-client SLIPstream-client project].  These functions are wrappers around UDP messages.  For an example of using raw UDP see the [http://www.nanork.org/nano-RK/browser/nano-RK/tools/SLIPstream/SLIPstream-client-UDP SLIPstream-client-UDP project].
114 1 Anthony Rowe
115 28 Anthony Rowe
'''Note: After opening a connection, a slipstream_send() is required before any data can be received.'''[[BR]]
116 28 Anthony Rowe
This is required because until the server receives a message from the client it has no way of knowing where to send reply packets. This packet could simply be ignored by the node.
117 1 Anthony Rowe
118 28 Anthony Rowe
'''int slipstream_open(char *address,int port, int blocking)'''
119 28 Anthony Rowe
120 28 Anthony Rowe
This function opens up a DATAGRAM socket to the given ''address'' string and UDP ''port''. Setting ''blocking'' to 1 makes future calls to slipstream_send() and slipstream_receive() block until they have received data.  Setting ''blocking'' to 0 makes both functions non-blocking.  Here is an example of opening a non-blocking connection on the localhost machine port 4000:
121 28 Anthony Rowe
122 28 Anthony Rowe
{{{
123 28 Anthony Rowe
#!c
124 28 Anthony Rowe
int v;
125 28 Anthony Rowe
126 28 Anthony Rowe
v=slipstream_open("127.0.0.1",4000,1);
127 28 Anthony Rowe
}}}
128 28 Anthony Rowe
129 1 Anthony Rowe
'''int slipstream_send(char *buf,int length)'''
130 28 Anthony Rowe
131 28 Anthony Rowe
Once a connection is opened data must first be sent to the server so that the reply address of the client is known.  This function sends a buffer ''buf'' of size ''length'' to the SLIPstream server program that then forwards the data to the sensor node.
132 32 Anthony Rowe
{{{
133 32 Anthony Rowe
#!c
134 33 Anthony Rowe
sprintf (buffer, "This is a sample slip string: Count %d\n", cnt);
135 18 Anthony Rowe
136 33 Anthony Rowe
v=slipstream_send(buffer,strlen(buffer));
137 33 Anthony Rowe
if (v == 0) printf( "Error sending\n" );
138 32 Anthony Rowe
}}}
139 32 Anthony Rowe
140 32 Anthony Rowe
141 18 Anthony Rowe
'''int slipstream_receive( char *buf)'''
142 18 Anthony Rowe
143 31 Anthony Rowe
This function takes a pointer to a buffer where it stores incoming slip messages.  The function returns the size of the message, or 0 if no data is available.  In the non-blocking mode of operation, this function will return 0 if no data is present.
144 31 Anthony Rowe
145 32 Anthony Rowe
{{{
146 32 Anthony Rowe
#!c
147 33 Anthony Rowe
v=slipstream_receive( buffer );
148 33 Anthony Rowe
if (v > 0) {
149 33 Anthony Rowe
  printf ("Got: ");
150 33 Anthony Rowe
  for (i = 0; i < v; i++)
151 33 Anthony Rowe
    printf ("%c", buffer[i]);
152 33 Anthony Rowe
  printf ("\n");
153 33 Anthony Rowe
}
154 32 Anthony Rowe
}}}
155 18 Anthony Rowe
156 10 Anthony Rowe
= Testing SLIPstream =
157 10 Anthony Rowe
158 30 Anthony Rowe
The following section shows how to run the SLIPstream sample program.  This example sends normal printf() statements to the SLIPstream terminal program while periodically sending SLIP messages.  It also echos any received SLIP messages using printf() so that you can verify the reception.  The UDP client program prints out any received SLIP messages and periodically transmits its own SLIP messages that are received and printout out by the sensor node.  Try starting the components in the order described below.
159 10 Anthony Rowe
160 10 Anthony Rowe
161 10 Anthony Rowe
'''Sensor Node SLIP sample program'''
162 10 Anthony Rowe
163 29 Anthony Rowe
To compile and download the sample SLIPstream application that runs on the FireFly node:
164 10 Anthony Rowe
165 29 Anthony Rowe
{{{
166 29 Anthony Rowe
  user:> cd nano-RK/projects/basic_SLIPstream
167 29 Anthony Rowe
  user:~/nano-RK/projects/basic_SLIPstream> make clean
168 29 Anthony Rowe
  ...
169 29 Anthony Rowe
  user:~/nano-RK/projects/basic_SLIPstream> make
170 29 Anthony Rowe
  ...
171 29 Anthony Rowe
  Size after:
172 29 Anthony Rowe
  main.elf  :
173 29 Anthony Rowe
  section     size      addr
174 29 Anthony Rowe
  .data        162   8389120
175 29 Anthony Rowe
  .text      19740         0
176 29 Anthony Rowe
  .bss        1074   8389282
177 29 Anthony Rowe
  .stab      48984         0
178 29 Anthony Rowe
  .stabstr   19310         0
179 29 Anthony Rowe
  Total      89270
180 29 Anthony Rowe
181 29 Anthony Rowe
182 29 Anthony Rowe
183 29 Anthony Rowe
  Errors: none
184 29 Anthony Rowe
  Platform: firefly2_2
185 29 Anthony Rowe
  -------- end --------
186 29 Anthony Rowe
  user:~/nano-RK/projects/basic_SLIPstream> make program
187 29 Anthony Rowe
188 29 Anthony Rowe
}}}
189 29 Anthony Rowe
190 29 Anthony Rowe
191 29 Anthony Rowe
192 9 Anthony Rowe
'''SLIPstream Server'''
193 9 Anthony Rowe
194 9 Anthony Rowe
To compile SLIPstream server do the following:
195 9 Anthony Rowe
196 9 Anthony Rowe
{{{
197 9 Anthony Rowe
 user:> cd nano-RK/tools/SLIPstream/SLIPstream-server
198 9 Anthony Rowe
 user:~/nano-RK/tools/SLIPstream/SLIPstream-server> make
199 9 Anthony Rowe
 gcc -c -o main.o main.c -I.
200 9 Anthony Rowe
 gcc -o SLIPstream main.o -I.
201 9 Anthony Rowe
 user:~/nano-RK/tools/SLIPstream/SLIPstream-server>
202 9 Anthony Rowe
}}}
203 9 Anthony Rowe
204 9 Anthony Rowe
To test the SLIPstream server type:
205 9 Anthony Rowe
206 9 Anthony Rowe
{{{
207 9 Anthony Rowe
 ./SLIPstream /dev/ttyUSB0 4000
208 9 Anthony Rowe
  opening: /dev/ttyUSB0
209 9 Anthony Rowe
}}}
210 10 Anthony Rowe
211 11 Anthony Rowe
In this case, the serial port is /dev/ttyUSB0 and the server is listening on port 4000.
212 11 Anthony Rowe
213 29 Anthony Rowe
If the programmed node is running you should see something like this printed out by the server:
214 10 Anthony Rowe
215 29 Anthony Rowe
{{{
216 29 Anthony Rowe
  Starting up...
217 29 Anthony Rowe
  Task3 PID=3
218 29 Anthony Rowe
  Task2 PID=2
219 29 Anthony Rowe
  Task2 cnt=0
220 29 Anthony Rowe
  My node's address is 0
221 29 Anthony Rowe
  Task1 PID=1
222 29 Anthony Rowe
  Task3
223 29 Anthony Rowe
  Task2 cnt=1
224 29 Anthony Rowe
  Task2 cnt=2
225 29 Anthony Rowe
  Task2 cnt=3
226 29 Anthony Rowe
  Task2 cnt=4
227 29 Anthony Rowe
  Task2 cnt=5
228 29 Anthony Rowe
  Task2 cnt=6
229 29 Anthony Rowe
  Task2 cnt=7
230 29 Anthony Rowe
  Task2 cnt=8
231 29 Anthony Rowe
  Task2 cnt=9
232 29 Anthony Rowe
  ...
233 29 Anthony Rowe
}}}
234 29 Anthony Rowe
235 10 Anthony Rowe
'''SLIPstream Client Sample'''
236 29 Anthony Rowe
To compile SLIPstream sample client do the following:
237 20 Anthony Rowe
238 29 Anthony Rowe
{{{
239 29 Anthony Rowe
 user:> cd nano-RK/tools/SLIPstream/SLIPstream-client
240 29 Anthony Rowe
 user:~/nano-RK/tools/SLIPstream/SLIPstream-client> make
241 29 Anthony Rowe
 gcc -c -o main.o main.c -I.
242 29 Anthony Rowe
 gcc -c -o slipstream.o slipstream.c -I.
243 29 Anthony Rowe
 gcc -o sample-client main.o slipstream.o -I.
244 29 Anthony Rowe
 user:~/nano-RK/tools/SLIPstream/SLIPstream-client>
245 29 Anthony Rowe
}}}
246 29 Anthony Rowe
247 29 Anthony Rowe
To test the SLIPstream server type:
248 29 Anthony Rowe
249 29 Anthony Rowe
{{{
250 29 Anthony Rowe
 ./sample-client localhost 4000
251 29 Anthony Rowe
  opening: /dev/ttyUSB0
252 29 Anthony Rowe
}}}
253 29 Anthony Rowe
254 29 Anthony Rowe
If the FireFly node connected to the gateway is running and the SLIPstream server is running you should see:
255 29 Anthony Rowe
256 29 Anthony Rowe
On the '''client''', messages sent from the FireFly node that are forwarded by the server:
257 29 Anthony Rowe
{{{
258 29 Anthony Rowe
  Got: Hello 8
259 29 Anthony Rowe
  Got: Hello 9
260 29 Anthony Rowe
  Got: Hello 10
261 29 Anthony Rowe
}}}
262 29 Anthony Rowe
263 29 Anthony Rowe
On the '''server''', you see messages sent from the client that the FireFly node echos back using printf:
264 29 Anthony Rowe
{{{
265 29 Anthony Rowe
  Task3
266 29 Anthony Rowe
  Task2 cnt=53
267 29 Anthony Rowe
  Task2 cnt=54
268 29 Anthony Rowe
  Task3 got data: This is a sample slip string: Count 6
269 29 Anthony Rowe
270 29 Anthony Rowe
  Task3
271 29 Anthony Rowe
  Task2 cnt=55
272 29 Anthony Rowe
  Task2 cnt=56
273 29 Anthony Rowe
  Task3 got data: This is a sample slip string: Count 7
274 29 Anthony Rowe
275 29 Anthony Rowe
  Task3
276 29 Anthony Rowe
  Task2 cnt=57
277 29 Anthony Rowe
  Task2 cnt=58
278 29 Anthony Rowe
  Task3 got data: This is a sample slip string: Count 8
279 29 Anthony Rowe
  ...
280 1 Anthony Rowe
}}}
281 30 Anthony Rowe
282 30 Anthony Rowe
= Another Example =
283 30 Anthony Rowe
The bmac_slipstream example project (nano-RK/projects/demo_samples/bmac_slipstream) shows how sensors can be sent 1-hop to a gateway node which in turn forwards a packet over SLIPstream to a client. 
284 30 Anthony Rowe
285 30 Anthony Rowe
The components are as follow:
286 30 Anthony Rowe
 * client
287 30 Anthony Rowe
  * Client node program to be flashed on a FireFly node sending data to the gateway
288 30 Anthony Rowe
  * make with "make NODE_ADDR=<node num>" to identify node
289 30 Anthony Rowe
 * gateway
290 30 Anthony Rowe
  * gateway code for running on the FireFly node that is connected to the gateway computer
291 30 Anthony Rowe
 * SLIPstream-client
292 30 Anthony Rowe
  * simple SLIPstream-client example that connects to the SLIPstream-server and prints out incomming data packets
293 30 Anthony Rowe
 * SLIPstream (standard server from above)
294 30 Anthony Rowe
  * SLIPstream server that forwards SLIP and UDP packets
295 30 Anthony Rowe
296 30 Anthony Rowe
When correctly operating, the SLIPstream-client should print packets from the client FireFly node with the following string:
297 30 Anthony Rowe
298 30 Anthony Rowe
"S ''mac_addr'' ''battery'' ''light'' ''temperature'' ''mic'' ''adxl_x'' ''adxl_y'' ''adxl_z''"
299 20 Anthony Rowe
300 20 Anthony Rowe
301 21 Anthony Rowe
= Important Notes =
302 20 Anthony Rowe
303 22 Anthony Rowe
 * FireFly 2 (not 2_2) boards required reduced baudrates to correctly receive data.  At full speed, the CRC will fail and slip_rx() will never return.
304 20 Anthony Rowe
 * Make sure to manage flow control going into the boards.  Your PC based UDP program can generate data much faster than the node can consume it.  Typically you should use an application level acknowledge and timeout scheme to deal with flow control.