SLIPstream

Version 29 (Anthony Rowe, 10/04/2007 04:07 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 18 Anthony Rowe
118 18 Anthony Rowe
'''int slipstream_receive( char *buf)'''
119 18 Anthony Rowe
120 18 Anthony Rowe
121 10 Anthony Rowe
= Testing SLIPstream =
122 10 Anthony Rowe
123 23 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.
124 10 Anthony Rowe
125 10 Anthony Rowe
126 10 Anthony Rowe
'''Sensor Node SLIP sample program'''
127 10 Anthony Rowe
128 29 Anthony Rowe
To compile and download the sample SLIPstream application that runs on the FireFly node:
129 10 Anthony Rowe
130 29 Anthony Rowe
{{{
131 29 Anthony Rowe
  user:> cd nano-RK/projects/basic_SLIPstream
132 29 Anthony Rowe
  user:~/nano-RK/projects/basic_SLIPstream> make clean
133 29 Anthony Rowe
  ...
134 29 Anthony Rowe
  user:~/nano-RK/projects/basic_SLIPstream> make
135 29 Anthony Rowe
  ...
136 29 Anthony Rowe
  Size after:
137 29 Anthony Rowe
  main.elf  :
138 29 Anthony Rowe
  section     size      addr
139 29 Anthony Rowe
  .data        162   8389120
140 29 Anthony Rowe
  .text      19740         0
141 29 Anthony Rowe
  .bss        1074   8389282
142 29 Anthony Rowe
  .stab      48984         0
143 29 Anthony Rowe
  .stabstr   19310         0
144 29 Anthony Rowe
  Total      89270
145 29 Anthony Rowe
146 29 Anthony Rowe
147 29 Anthony Rowe
148 29 Anthony Rowe
  Errors: none
149 29 Anthony Rowe
  Platform: firefly2_2
150 29 Anthony Rowe
  -------- end --------
151 29 Anthony Rowe
  user:~/nano-RK/projects/basic_SLIPstream> make program
152 29 Anthony Rowe
153 29 Anthony Rowe
}}}
154 29 Anthony Rowe
155 29 Anthony Rowe
156 29 Anthony Rowe
157 9 Anthony Rowe
'''SLIPstream Server'''
158 9 Anthony Rowe
159 9 Anthony Rowe
To compile SLIPstream server do the following:
160 9 Anthony Rowe
161 9 Anthony Rowe
{{{
162 9 Anthony Rowe
 user:> cd nano-RK/tools/SLIPstream/SLIPstream-server
163 9 Anthony Rowe
 user:~/nano-RK/tools/SLIPstream/SLIPstream-server> make
164 9 Anthony Rowe
 gcc -c -o main.o main.c -I.
165 9 Anthony Rowe
 gcc -o SLIPstream main.o -I.
166 9 Anthony Rowe
 user:~/nano-RK/tools/SLIPstream/SLIPstream-server>
167 9 Anthony Rowe
}}}
168 9 Anthony Rowe
169 9 Anthony Rowe
To test the SLIPstream server type:
170 9 Anthony Rowe
171 9 Anthony Rowe
{{{
172 9 Anthony Rowe
 ./SLIPstream /dev/ttyUSB0 4000
173 9 Anthony Rowe
  opening: /dev/ttyUSB0
174 9 Anthony Rowe
}}}
175 10 Anthony Rowe
176 11 Anthony Rowe
In this case, the serial port is /dev/ttyUSB0 and the server is listening on port 4000.
177 11 Anthony Rowe
178 29 Anthony Rowe
If the programmed node is running you should see something like this printed out by the server:
179 10 Anthony Rowe
180 29 Anthony Rowe
{{{
181 29 Anthony Rowe
  Starting up...
182 29 Anthony Rowe
  Task3 PID=3
183 29 Anthony Rowe
  Task2 PID=2
184 29 Anthony Rowe
  Task2 cnt=0
185 29 Anthony Rowe
  My node's address is 0
186 29 Anthony Rowe
  Task1 PID=1
187 29 Anthony Rowe
  Task3
188 29 Anthony Rowe
  Task2 cnt=1
189 29 Anthony Rowe
  Task2 cnt=2
190 29 Anthony Rowe
  Task2 cnt=3
191 29 Anthony Rowe
  Task2 cnt=4
192 29 Anthony Rowe
  Task2 cnt=5
193 29 Anthony Rowe
  Task2 cnt=6
194 29 Anthony Rowe
  Task2 cnt=7
195 29 Anthony Rowe
  Task2 cnt=8
196 29 Anthony Rowe
  Task2 cnt=9
197 29 Anthony Rowe
  ...
198 29 Anthony Rowe
}}}
199 29 Anthony Rowe
200 10 Anthony Rowe
'''SLIPstream Client Sample'''
201 29 Anthony Rowe
To compile SLIPstream sample client do the following:
202 20 Anthony Rowe
203 29 Anthony Rowe
{{{
204 29 Anthony Rowe
 user:> cd nano-RK/tools/SLIPstream/SLIPstream-client
205 29 Anthony Rowe
 user:~/nano-RK/tools/SLIPstream/SLIPstream-client> make
206 29 Anthony Rowe
 gcc -c -o main.o main.c -I.
207 29 Anthony Rowe
 gcc -c -o slipstream.o slipstream.c -I.
208 29 Anthony Rowe
 gcc -o sample-client main.o slipstream.o -I.
209 29 Anthony Rowe
 user:~/nano-RK/tools/SLIPstream/SLIPstream-client>
210 29 Anthony Rowe
}}}
211 29 Anthony Rowe
212 29 Anthony Rowe
To test the SLIPstream server type:
213 29 Anthony Rowe
214 29 Anthony Rowe
{{{
215 29 Anthony Rowe
 ./sample-client localhost 4000
216 29 Anthony Rowe
  opening: /dev/ttyUSB0
217 29 Anthony Rowe
}}}
218 29 Anthony Rowe
219 29 Anthony Rowe
If the FireFly node connected to the gateway is running and the SLIPstream server is running you should see:
220 29 Anthony Rowe
221 29 Anthony Rowe
On the '''client''', messages sent from the FireFly node that are forwarded by the server:
222 29 Anthony Rowe
{{{
223 29 Anthony Rowe
  Got: Hello 8
224 29 Anthony Rowe
  Got: Hello 9
225 29 Anthony Rowe
  Got: Hello 10
226 29 Anthony Rowe
}}}
227 29 Anthony Rowe
228 29 Anthony Rowe
On the '''server''', you see messages sent from the client that the FireFly node echos back using printf:
229 29 Anthony Rowe
{{{
230 29 Anthony Rowe
  Task3
231 29 Anthony Rowe
  Task2 cnt=53
232 29 Anthony Rowe
  Task2 cnt=54
233 29 Anthony Rowe
  Task3 got data: This is a sample slip string: Count 6
234 29 Anthony Rowe
235 29 Anthony Rowe
  Task3
236 29 Anthony Rowe
  Task2 cnt=55
237 29 Anthony Rowe
  Task2 cnt=56
238 29 Anthony Rowe
  Task3 got data: This is a sample slip string: Count 7
239 29 Anthony Rowe
240 29 Anthony Rowe
  Task3
241 29 Anthony Rowe
  Task2 cnt=57
242 29 Anthony Rowe
  Task2 cnt=58
243 29 Anthony Rowe
  Task3 got data: This is a sample slip string: Count 8
244 29 Anthony Rowe
  ...
245 29 Anthony Rowe
}}}
246 20 Anthony Rowe
247 20 Anthony Rowe
248 21 Anthony Rowe
= Important Notes =
249 20 Anthony Rowe
250 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.
251 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.