SLIPstream

Version 32 (Anthony Rowe, 10/04/2007 04:41 pm)

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 14 Anthony Rowe
This section describes the Nano-RK related function calls that can be used with SLIPstream.  When adding SLIP to an application, '''it is important to address the following in your nrk_cfg.h''':
16 13 Anthony Rowe
17 16 Anthony Rowe
 * #define the correct SLIP_PCP_CEILING value
18 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.
19 13 Anthony Rowe
 * #define NRK_UART_BUF   1
20 13 Anthony Rowe
 * #define MAX_RX_UART_BUF 128
21 13 Anthony Rowe
 * Increase NRK_MAX_RESOURCE_CNT by 1
22 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.
23 13 Anthony Rowe
 * SLIP does not increase the task count in the system
24 13 Anthony Rowe
25 13 Anthony Rowe
{{{
26 13 Anthony Rowe
#!c
27 13 Anthony Rowe
// This must be greater than or equal to the highest priority task that uses
28 13 Anthony Rowe
// the serial port (i.e. print of nrk_kprintf)
29 13 Anthony Rowe
#define SLIP_PCP_CEILING                18     
30 13 Anthony Rowe
 	
31 13 Anthony Rowe
// Enable buffered and signal controlled serial RX
32 13 Anthony Rowe
#define NRK_UART_BUF                    1
33 13 Anthony Rowe
// Set buffer to MAX slip packet size.
34 13 Anthony Rowe
// This could be smaller than 128 if you are careful.
35 13 Anthony Rowe
#define MAX_RX_UART_BUF                 128
36 13 Anthony Rowe
37 13 Anthony Rowe
// Slip uses a single semaphore to control UART access
38 13 Anthony Rowe
#define NRK_MAX_RESOURCE_CNT            2
39 13 Anthony Rowe
}}}
40 13 Anthony Rowe
41 13 Anthony Rowe
42 24 Anthony Rowe
'''slip_init (FILE *input_stream, FILE *output_stream, uint8_t echo_flag, uint8_t delay_ms)'''
43 28 Anthony Rowe
44 24 Anthony Rowe
This function will setup SLIP on the sensor node.  The ''input_stream'' and ''output_stream'' set the file descriptors that
45 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:
46 1 Anthony Rowe
47 24 Anthony Rowe
{{{
48 24 Anthony Rowe
#!c
49 24 Anthony Rowe
slip_init (stdin, stdout, 0, 0);
50 24 Anthony Rowe
}}}
51 24 Anthony Rowe
52 1 Anthony Rowe
'''int8_t slip_started ()'''
53 25 Anthony Rowe
54 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:
55 1 Anthony Rowe
56 24 Anthony Rowe
{{{
57 24 Anthony Rowe
#!c
58 24 Anthony Rowe
while (slip_started () != 1) nrk_wait_until_next_period ();
59 24 Anthony Rowe
}}}
60 24 Anthony Rowe
61 1 Anthony Rowe
'''int8_t slip_tx (uint8_t *buf, uint8_t len)'''
62 25 Anthony Rowe
63 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. 
64 13 Anthony Rowe
65 26 Anthony Rowe
{{{
66 26 Anthony Rowe
#!c
67 26 Anthony Rowe
// Remember not to declare large buffers locally
68 26 Anthony Rowe
uint8_t slip_tx_buf[MAX_SLIP_BUF];
69 26 Anthony Rowe
...
70 26 Anthony Rowe
sprintf (slip_tx_buf, "Hello %d", cnt);
71 26 Anthony Rowe
len = strlen (slip_tx_buf);
72 26 Anthony Rowe
slip_tx (slip_tx_buf, len);
73 26 Anthony Rowe
}}}
74 26 Anthony Rowe
75 1 Anthony Rowe
'''int8_t slip_rx (uint8_t *buf, uint8_t max_len)'''
76 25 Anthony Rowe
77 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.
78 26 Anthony Rowe
79 26 Anthony Rowe
{{{
80 26 Anthony Rowe
#!c
81 26 Anthony Rowe
int8_t v;
82 26 Anthony Rowe
// Remember not to declare large buffers inside functions. (protect your stack)
83 26 Anthony Rowe
uint8_t slip_rx_buf[MAX_SLIP_BUF];
84 26 Anthony Rowe
...
85 26 Anthony Rowe
v = slip_rx (slip_rx_buf, MAX_SLIP_BUF);
86 26 Anthony Rowe
 if (v > 0) {
87 27 Anthony Rowe
     nrk_kprintf (PSTR ("Task got data: "));
88 26 Anthony Rowe
     for (i = 0; i < v; i++)
89 26 Anthony Rowe
        printf ("%c", slip_rx_buf[i]);
90 26 Anthony Rowe
     printf ("\r\n");
91 26 Anthony Rowe
     }
92 26 Anthony Rowe
else
93 27 Anthony Rowe
     nrk_kprintf (PSTR ("Task data failed\r\n"));
94 26 Anthony Rowe
}}}
95 13 Anthony Rowe
96 13 Anthony Rowe
= UDP Client APIs =
97 10 Anthony Rowe
98 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].
99 1 Anthony Rowe
100 28 Anthony Rowe
'''Note: After opening a connection, a slipstream_send() is required before any data can be received.'''[[BR]]
101 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.
102 1 Anthony Rowe
103 28 Anthony Rowe
'''int slipstream_open(char *address,int port, int blocking)'''
104 28 Anthony Rowe
105 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:
106 28 Anthony Rowe
107 28 Anthony Rowe
{{{
108 28 Anthony Rowe
#!c
109 28 Anthony Rowe
int v;
110 28 Anthony Rowe
111 28 Anthony Rowe
v=slipstream_open("127.0.0.1",4000,1);
112 28 Anthony Rowe
}}}
113 28 Anthony Rowe
114 1 Anthony Rowe
'''int slipstream_send(char *buf,int length)'''
115 28 Anthony Rowe
116 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.
117 32 Anthony Rowe
{{{
118 32 Anthony Rowe
#!c
119 32 Anthony Rowe
    sprintf (buffer, "This is a sample slip string: Count %d\n", cnt);
120 18 Anthony Rowe
121 32 Anthony Rowe
    v=slipstream_send(buffer,strlen(buffer));
122 32 Anthony Rowe
    if (v == 0) printf( "Error sending\n" );
123 32 Anthony Rowe
}}}
124 32 Anthony Rowe
125 32 Anthony Rowe
126 18 Anthony Rowe
'''int slipstream_receive( char *buf)'''
127 18 Anthony Rowe
128 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.
129 31 Anthony Rowe
130 32 Anthony Rowe
{{{
131 32 Anthony Rowe
#!c
132 32 Anthony Rowe
  v=slipstream_receive( buffer );
133 32 Anthony Rowe
    if (v > 0) {
134 32 Anthony Rowe
      printf ("Got: ");
135 32 Anthony Rowe
      for (i = 0; i < v; i++)
136 32 Anthony Rowe
        printf ("%c", buffer[i]);
137 32 Anthony Rowe
      printf ("\n");
138 32 Anthony Rowe
    }
139 32 Anthony Rowe
}}}
140 18 Anthony Rowe
141 10 Anthony Rowe
= Testing SLIPstream =
142 10 Anthony Rowe
143 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.
144 10 Anthony Rowe
145 10 Anthony Rowe
146 10 Anthony Rowe
'''Sensor Node SLIP sample program'''
147 10 Anthony Rowe
148 29 Anthony Rowe
To compile and download the sample SLIPstream application that runs on the FireFly node:
149 10 Anthony Rowe
150 29 Anthony Rowe
{{{
151 29 Anthony Rowe
  user:> cd nano-RK/projects/basic_SLIPstream
152 29 Anthony Rowe
  user:~/nano-RK/projects/basic_SLIPstream> make clean
153 29 Anthony Rowe
  ...
154 29 Anthony Rowe
  user:~/nano-RK/projects/basic_SLIPstream> make
155 29 Anthony Rowe
  ...
156 29 Anthony Rowe
  Size after:
157 29 Anthony Rowe
  main.elf  :
158 29 Anthony Rowe
  section     size      addr
159 29 Anthony Rowe
  .data        162   8389120
160 29 Anthony Rowe
  .text      19740         0
161 29 Anthony Rowe
  .bss        1074   8389282
162 29 Anthony Rowe
  .stab      48984         0
163 29 Anthony Rowe
  .stabstr   19310         0
164 29 Anthony Rowe
  Total      89270
165 29 Anthony Rowe
166 29 Anthony Rowe
167 29 Anthony Rowe
168 29 Anthony Rowe
  Errors: none
169 29 Anthony Rowe
  Platform: firefly2_2
170 29 Anthony Rowe
  -------- end --------
171 29 Anthony Rowe
  user:~/nano-RK/projects/basic_SLIPstream> make program
172 29 Anthony Rowe
173 29 Anthony Rowe
}}}
174 29 Anthony Rowe
175 29 Anthony Rowe
176 29 Anthony Rowe
177 9 Anthony Rowe
'''SLIPstream Server'''
178 9 Anthony Rowe
179 9 Anthony Rowe
To compile SLIPstream server do the following:
180 9 Anthony Rowe
181 9 Anthony Rowe
{{{
182 9 Anthony Rowe
 user:> cd nano-RK/tools/SLIPstream/SLIPstream-server
183 9 Anthony Rowe
 user:~/nano-RK/tools/SLIPstream/SLIPstream-server> make
184 9 Anthony Rowe
 gcc -c -o main.o main.c -I.
185 9 Anthony Rowe
 gcc -o SLIPstream main.o -I.
186 9 Anthony Rowe
 user:~/nano-RK/tools/SLIPstream/SLIPstream-server>
187 9 Anthony Rowe
}}}
188 9 Anthony Rowe
189 9 Anthony Rowe
To test the SLIPstream server type:
190 9 Anthony Rowe
191 9 Anthony Rowe
{{{
192 9 Anthony Rowe
 ./SLIPstream /dev/ttyUSB0 4000
193 9 Anthony Rowe
  opening: /dev/ttyUSB0
194 9 Anthony Rowe
}}}
195 10 Anthony Rowe
196 11 Anthony Rowe
In this case, the serial port is /dev/ttyUSB0 and the server is listening on port 4000.
197 11 Anthony Rowe
198 29 Anthony Rowe
If the programmed node is running you should see something like this printed out by the server:
199 10 Anthony Rowe
200 29 Anthony Rowe
{{{
201 29 Anthony Rowe
  Starting up...
202 29 Anthony Rowe
  Task3 PID=3
203 29 Anthony Rowe
  Task2 PID=2
204 29 Anthony Rowe
  Task2 cnt=0
205 29 Anthony Rowe
  My node's address is 0
206 29 Anthony Rowe
  Task1 PID=1
207 29 Anthony Rowe
  Task3
208 29 Anthony Rowe
  Task2 cnt=1
209 29 Anthony Rowe
  Task2 cnt=2
210 29 Anthony Rowe
  Task2 cnt=3
211 29 Anthony Rowe
  Task2 cnt=4
212 29 Anthony Rowe
  Task2 cnt=5
213 29 Anthony Rowe
  Task2 cnt=6
214 29 Anthony Rowe
  Task2 cnt=7
215 29 Anthony Rowe
  Task2 cnt=8
216 29 Anthony Rowe
  Task2 cnt=9
217 29 Anthony Rowe
  ...
218 29 Anthony Rowe
}}}
219 29 Anthony Rowe
220 10 Anthony Rowe
'''SLIPstream Client Sample'''
221 29 Anthony Rowe
To compile SLIPstream sample client do the following:
222 20 Anthony Rowe
223 29 Anthony Rowe
{{{
224 29 Anthony Rowe
 user:> cd nano-RK/tools/SLIPstream/SLIPstream-client
225 29 Anthony Rowe
 user:~/nano-RK/tools/SLIPstream/SLIPstream-client> make
226 29 Anthony Rowe
 gcc -c -o main.o main.c -I.
227 29 Anthony Rowe
 gcc -c -o slipstream.o slipstream.c -I.
228 29 Anthony Rowe
 gcc -o sample-client main.o slipstream.o -I.
229 29 Anthony Rowe
 user:~/nano-RK/tools/SLIPstream/SLIPstream-client>
230 29 Anthony Rowe
}}}
231 29 Anthony Rowe
232 29 Anthony Rowe
To test the SLIPstream server type:
233 29 Anthony Rowe
234 29 Anthony Rowe
{{{
235 29 Anthony Rowe
 ./sample-client localhost 4000
236 29 Anthony Rowe
  opening: /dev/ttyUSB0
237 29 Anthony Rowe
}}}
238 29 Anthony Rowe
239 29 Anthony Rowe
If the FireFly node connected to the gateway is running and the SLIPstream server is running you should see:
240 29 Anthony Rowe
241 29 Anthony Rowe
On the '''client''', messages sent from the FireFly node that are forwarded by the server:
242 29 Anthony Rowe
{{{
243 29 Anthony Rowe
  Got: Hello 8
244 29 Anthony Rowe
  Got: Hello 9
245 29 Anthony Rowe
  Got: Hello 10
246 29 Anthony Rowe
}}}
247 29 Anthony Rowe
248 29 Anthony Rowe
On the '''server''', you see messages sent from the client that the FireFly node echos back using printf:
249 29 Anthony Rowe
{{{
250 29 Anthony Rowe
  Task3
251 29 Anthony Rowe
  Task2 cnt=53
252 29 Anthony Rowe
  Task2 cnt=54
253 29 Anthony Rowe
  Task3 got data: This is a sample slip string: Count 6
254 29 Anthony Rowe
255 29 Anthony Rowe
  Task3
256 29 Anthony Rowe
  Task2 cnt=55
257 29 Anthony Rowe
  Task2 cnt=56
258 29 Anthony Rowe
  Task3 got data: This is a sample slip string: Count 7
259 29 Anthony Rowe
260 29 Anthony Rowe
  Task3
261 29 Anthony Rowe
  Task2 cnt=57
262 29 Anthony Rowe
  Task2 cnt=58
263 29 Anthony Rowe
  Task3 got data: This is a sample slip string: Count 8
264 29 Anthony Rowe
  ...
265 1 Anthony Rowe
}}}
266 30 Anthony Rowe
267 30 Anthony Rowe
= Another Example =
268 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. 
269 30 Anthony Rowe
270 30 Anthony Rowe
The components are as follow:
271 30 Anthony Rowe
 * client
272 30 Anthony Rowe
  * Client node program to be flashed on a FireFly node sending data to the gateway
273 30 Anthony Rowe
  * make with "make NODE_ADDR=<node num>" to identify node
274 30 Anthony Rowe
 * gateway
275 30 Anthony Rowe
  * gateway code for running on the FireFly node that is connected to the gateway computer
276 30 Anthony Rowe
 * SLIPstream-client
277 30 Anthony Rowe
  * simple SLIPstream-client example that connects to the SLIPstream-server and prints out incomming data packets
278 30 Anthony Rowe
 * SLIPstream (standard server from above)
279 30 Anthony Rowe
  * SLIPstream server that forwards SLIP and UDP packets
280 30 Anthony Rowe
281 30 Anthony Rowe
When correctly operating, the SLIPstream-client should print packets from the client FireFly node with the following string:
282 30 Anthony Rowe
283 30 Anthony Rowe
"S ''mac_addr'' ''battery'' ''light'' ''temperature'' ''mic'' ''adxl_x'' ''adxl_y'' ''adxl_z''"
284 20 Anthony Rowe
285 20 Anthony Rowe
286 21 Anthony Rowe
= Important Notes =
287 20 Anthony Rowe
288 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.
289 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.