Project

General

Profile

Statistics
| Revision:

root / trunk / code / projects / diagnostic_station / station / comm_server.c @ 1296

History | View | Annotate | Download (10.9 KB)

1 1182 deffi
#include "comm_server.h"
2 1169 deffi
3 1171 deffi
#include <avr/pgmspace.h>
4 1198 deffi
#include <string.h>
5 1171 deffi
6 1183 deffi
#include "global.h"
7 1185 deffi
#include "tests.h"
8 1183 deffi
9 1272 deffi
#include "comm_interactive.h"
10
11 1183 deffi
// ##############
12
// ## Settings ##
13
// ##############
14
15 1198 deffi
//#define comm_server_debug
16 1183 deffi
17
// ###############
18
// ## Constants ##
19
// ###############
20
21 1171 deffi
#define buffer_size 120
22
23 1198 deffi
// Put all symbolic string constants into the program memory because else all of them would be copied into the RAM (see
24
// the avr-libc documentation, chapter "Data in Program Space").
25 1171 deffi
26 1198 deffi
// Commands
27
const char command_ping          [] PROGMEM = "ping"       ;
28
const char command_start_test    [] PROGMEM = "start_test" ;
29
const char command_all           [] PROGMEM = "all"        ;
30
const char command_comm          [] PROGMEM = "comm"       ;
31
const char command_bom           [] PROGMEM = "bom"        ;
32
const char command_rangefinder   [] PROGMEM = "rangefinder";
33
const char command_motor         [] PROGMEM = "motor"      ;
34
const char command_encoder       [] PROGMEM = "encoder"    ;
35 1271 deffi
const char command_emitter       [] PROGMEM = "emitter"    ;
36
const char command_detector      [] PROGMEM = "detector"   ;
37 1198 deffi
const char command_help          [] PROGMEM = "help"       ;
38 1272 deffi
const char command_interactive   [] PROGMEM = "interactive";
39
const char command_i             [] PROGMEM = "i"          ;
40 1198 deffi
41
// Help
42
const char help_text          [] PROGMEM =
43
        "# Available commands:" NL
44
        "#   - help" NL
45
        "#   - ping" NL
46
        "#   - start_test all" NL
47
        "#   - start_test comm" NL
48
        "#   - start_test bom all|<num> (0..15)" NL
49 1296 deffi
        "#   - start_test rangefinder all|<num> (0..4)" NL
50
        "#   - start_test motor all|<num> (0..1)" NL
51
        "#   - start_test encoder all|<num> (0..1)" NL
52 1198 deffi
        ;
53
54
55 1183 deffi
// ####################
56
// ## Initialization ##
57
// ####################
58
59 1182 deffi
void comm_server_init ()
60 1169 deffi
{
61
        usb_init ();
62
}
63
64
65 1183 deffi
// ########################
66
// ## Message processing ##
67
// ########################
68 1171 deffi
69 1198 deffi
static char *find_next_parameter (char *p)
70
{
71
        // Advance p until a blank or the terminating zero is found.
72
        while ((*p)!=' ' && (*p)!=0) p++;
73
74
        // Advance p until a non-blank (including the terminating zero) is found.
75
        while (*p==' ') p++;
76
77
        // We have found the next parameter unless p points to the terminating zero.
78
        if (*p==0)
79
                return NULL;
80
        else
81
                return p;
82
}
83
84 1182 deffi
/** Check if the buffer starts with the given text, followed by a space */
85 1198 deffi
static bool serial_match (PGM_P text, const char *buffer)
86 1182 deffi
{
87 1183 deffi
        uint8_t text_len=strlen_P (text);
88 1198 deffi
        uint8_t buffer_len=strlen (buffer);
89 1182 deffi
90
        // If the buffer is shorter than the text, there is no match
91 1198 deffi
        if (buffer_len<text_len) return false;
92 1182 deffi
93
        // If the buffer is longer than the text, it must have a space at position after the text
94 1198 deffi
        if (buffer_len>text_len && buffer[text_len]!=' ') return false;
95 1182 deffi
96 1183 deffi
        // Test for match
97
        if (strncmp_P ((char *)buffer, text, text_len)==0) return true;
98
99
        return false;
100
}
101 1182 deffi
102 1202 deffi
static bool serial_number_u8 (uint8_t *num, const char *buffer)
103
{
104
        uint8_t result=0;
105
106
        // Iterate over the buffer
107
        while (1)
108
        {
109
                // Look at the character
110
                char c=*buffer;
111 1182 deffi
112 1202 deffi
                if (c>='0' && c<='9')
113
                {
114
                        // It's a digit. Process it.
115
                        result*=10;
116
                        result+=(c-'0');
117
                }
118
                else if (c==' ' || c==0)
119
                {
120
                        // It's a space or a terminating zero, which means that the paramter is a valid number.
121
                        *num=result;
122
                        return true;
123
                }
124
                else
125
                {
126
                        // It's a different character, which means that the parameter is not a number.
127
                        return false;
128
                }
129
130
                // Move to the next byte
131
                buffer++;
132
        }
133
}
134 1182 deffi
135 1183 deffi
136 1185 deffi
137
138 1202 deffi
139
140 1183 deffi
// ########################
141
// ## Messages (sending) ##
142
// ########################
143
144
void server_send_finished ()
145
{
146
        usb_puts ("finished");
147 1182 deffi
}
148
149 1202 deffi
// ##########################
150
// ## Messages (Receiving) ##
151
// ##########################
152 1182 deffi
153 1202 deffi
static void unhandled_parameters (char *buffer)
154
{
155
        usb_puts ("# Warning: unhandled parameters: [");
156
        usb_puts (buffer);
157
        usb_puts ("]" NL);
158
}
159
160
static void parameter_missing (void)
161
{
162
        usb_puts ("# Parameter missing" NL);
163
}
164
165
166 1185 deffi
// ######################
167
// ## Message handlers ##
168
// ######################
169
170 1202 deffi
171 1198 deffi
static void handle_message_ping (char *buffer)
172 1185 deffi
{
173
        usb_puts ("pong" NL);
174
        orbs_set (255, 127, 0, 0, 255, 0);
175
        delay_ms (400);
176
        orbs_set (0, 255, 0, 255, 127, 0);
177
}
178
179 1202 deffi
static void handle_message_start_test_all (char *buffer)
180 1185 deffi
{
181 1202 deffi
        test_all ();
182
}
183
184
static void handle_message_start_test_comm (char *buffer)
185
{
186
        test_comm ();
187
}
188
189 1271 deffi
/** If the next parameter is "all", call the test all function. If it's a number, call the test one function. **/
190 1202 deffi
static void handle_message_start_test_component (char *buffer, void (*test_all_fn)(void), void (*test_one_fn)(uint8_t))
191
{
192
        // Find the next parameter
193 1198 deffi
        buffer=find_next_parameter (buffer);
194
195 1202 deffi
        // Initialize a buffer for the component number
196
        uint8_t num=0;
197
198 1198 deffi
        if (!buffer)
199 1202 deffi
                // No paramter found (we could also interpret that as implicit "all")
200
                parameter_missing ();
201 1198 deffi
        else if (serial_match (command_all, buffer))
202 1202 deffi
                // The paramter is "all". Call the all-tests function
203
                test_all_fn ();
204
        else if (serial_number_u8 (&num, buffer))
205
                // The paramter is a number. Call the one-test function
206
                test_one_fn (num);
207 1198 deffi
        else
208 1202 deffi
                // Unknwon parameter
209
                unhandled_parameters (buffer);
210 1185 deffi
}
211
212 1271 deffi
static void test_bom_both     (uint8_t num) { test_bom (num, true , true ); }
213
static void test_bom_emitter  (uint8_t num) { test_bom (num, true , false); }
214
static void test_bom_detector (uint8_t num) { test_bom (num, false, true ); }
215 1202 deffi
216 1271 deffi
static void test_bom_all_both     (void) { test_bom_all (true , true ); }
217
static void test_bom_all_emitter  (void) { test_bom_all (true , false); }
218
static void test_bom_all_detector (void) { test_bom_all (false, true ); }
219 1202 deffi
220
static void handle_message_start_test_bom (char *buffer)
221
{
222 1271 deffi
        // "start_test bom..."
223
        char *param=find_next_parameter (buffer);
224
225
        // In addition to "all" and a number, both handled by handle_message_start_test_component, we can also have
226
        // "emitter" and "detector" here. Not that we pass param rather than buffer in these cases.
227
        if (!param)
228
                // "start_test bom"
229
                // No paramter found (we could also pass that on to start_test_component)
230
                parameter_missing ();
231
        else if (serial_match (command_emitter, param))
232
                // "start_test bom emitter..."
233
                handle_message_start_test_component (param, test_bom_all_emitter, test_bom_emitter);
234
        else if (serial_match (command_detector, param))
235
                // "start_test bom detector..."
236
                handle_message_start_test_component (param, test_bom_all_detector, test_bom_detector);
237
        else
238
                // No emitter/detector given
239
                handle_message_start_test_component (buffer, test_bom_all_both, test_bom_both);
240 1202 deffi
}
241
242
static void handle_message_start_test_rangefinder (char *buffer)
243
{
244
        handle_message_start_test_component (buffer, test_rangefinder_all, test_rangefinder);
245
}
246
247
static void handle_message_start_test_motor (char *buffer)
248
{
249
        handle_message_start_test_component (buffer, test_motor_all, test_motor);
250
}
251
252
static void handle_message_start_test_encoder (char *buffer)
253
{
254
        handle_message_start_test_component (buffer, test_encoder_all, test_encoder);
255
}
256
257
static void handle_message_start_test (char *buffer)
258
{
259
        // TODO add required comm test
260
        buffer=find_next_parameter (buffer);
261
        if (!buffer)                                         parameter_missing ();
262
        else if (serial_match (command_all        , buffer)) handle_message_start_test_all         (buffer);
263
        else if (serial_match (command_comm       , buffer)) handle_message_start_test_comm        (buffer);
264
        else if (serial_match (command_bom        , buffer)) handle_message_start_test_bom         (buffer);
265
        else if (serial_match (command_rangefinder, buffer)) handle_message_start_test_rangefinder (buffer);
266
        else if (serial_match (command_motor      , buffer)) handle_message_start_test_motor       (buffer);
267
        else if (serial_match (command_encoder    , buffer)) handle_message_start_test_encoder     (buffer);
268
        else                                                 unhandled_parameters (buffer);
269
}
270
271 1198 deffi
static void handle_message_help (char *buffer)
272
{
273 1208 deffi
        usb_puts_P (help_text);
274 1198 deffi
}
275 1185 deffi
276 1198 deffi
277 1183 deffi
// ##########################
278
// ## Messages (receiving) ##
279
// ##########################
280
281 1198 deffi
/** message is 0 terminated */
282
static void handle_message (char *message)
283 1171 deffi
{
284 1183 deffi
#ifdef comm_server_debug
285 1185 deffi
        // Output: "# Received a message, size <size>: [<message>]"
286 1183 deffi
        usb_puts ("# Received a message, size ");
287 1171 deffi
        usb_puti(size);
288 1183 deffi
        usb_puts (": [");
289
        usb_puts ((char *)message);
290
        usb_puts ("]" NL);
291
#endif
292 1171 deffi
293 1185 deffi
        bool handled=false;
294 1272 deffi
        if (serial_match (command_ping       , message)) { handle_message_ping       (message); handled=true; }
295
        if (serial_match (command_start_test , message)) { handle_message_start_test (message); handled=true; }
296
        if (serial_match (command_help       , message)) { handle_message_help       (message); handled=true; }
297
        if (serial_match (command_interactive, message)) { interactive_main ()                ; handled=true; }
298
        if (serial_match (command_i          , message)) { interactive_main ()                ; handled=true; }
299 1185 deffi
        // More messages go here
300
301
        if (!handled)
302
        {
303
                usb_puts ("# Warning: unhandled message: [");
304
                usb_puts ((char *)message);
305
                usb_puts ("]" NL);
306
        }
307 1171 deffi
}
308
309
310 1185 deffi
// ###############
311
// ## Debugging ##
312
// ###############
313 1171 deffi
314 1182 deffi
void byte_transmission_test (void)
315
{
316
        uint8_t c;
317
318
        while (1)
319
        {
320
                c=usb_getc ();
321
                usb_puts ("[");
322
                usb_puti (c);
323
                usb_puts ("] ");
324
        }
325
}
326 1171 deffi
327
328 1185 deffi
// ###############
329
// ## Main loop ##
330
// ###############
331
332 1212 deffi
static void ready (void)
333 1204 deffi
{
334 1242 deffi
        usb_puts ("ready" NL);
335 1204 deffi
}
336
337 1171 deffi
void server_main (void)
338
{
339 1198 deffi
        char buffer[buffer_size];
340 1171 deffi
        uint8_t c;
341
        uint8_t buffer_fill=0;
342 1182 deffi
343 1272 deffi
        // Set the orbs to green/yellow
344
        orbs_set (0,255,0, 255,127,0);
345
346 1182 deffi
        //byte_transmission_test (); // Does not return
347
348 1185 deffi
        usb_puts (NL);
349
        usb_puts ("# Diagnostic station server mode" NL);
350 1204 deffi
351
        ready ();
352 1171 deffi
353
        while (1)
354
        {
355
                // Do nothing until we receive a byte (this function will return 0 when a character has been read)
356 1182 deffi
                // (Yes, we could use the blocking function for now, but we may need the non-blocking later)
357 1183 deffi
                while (usb_getc_nb ((char *)&c));
358 1171 deffi
359
                if (c=='\r' || c=='\n')
360
                {
361 1182 deffi
                        // A newline character was received. This terminates the message.
362 1171 deffi
363 1182 deffi
                        // Empty lines are ignored.
364
                        if (buffer_fill>0)
365
                        {
366
                                // Add a terminating 0 to the buffer so the string functions won't try to read outside the buffer.
367
                                buffer[buffer_fill]=0;
368
369
                                // Handle the message.
370 1198 deffi
                                handle_message (buffer);
371 1204 deffi
372 1182 deffi
                                // Reset the buffer
373
                                buffer_fill=0;
374
                        }
375 1204 deffi
376
                        // TODO do better, make a function get_message?
377
                        ready ();
378 1171 deffi
                }
379 1202 deffi
                else if (c==8)
380
                {
381
                        // Backspace
382
                        // Of course, the server will never send one, but it's convenient to have for debugging.
383
                        if (buffer_fill>0) --buffer_fill;
384
                }
385 1182 deffi
                else
386
                {
387
                        // If there is enough space left in the buffer, add the character we just received. Leave one byte for a
388
                        // terminating 0. If there is not enough space in the buffer, the rest of the message is ignored.
389
                        if (buffer_fill<buffer_size-1)
390
                        {
391
                                buffer[buffer_fill]=c;
392
                                ++buffer_fill;
393
                        }
394
                }
395
396 1171 deffi
        }
397
}