Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (10.9 KB)

1
#include "comm_server.h"
2

    
3
#include <avr/pgmspace.h>
4
#include <string.h>
5

    
6
#include "global.h"
7
#include "tests.h"
8

    
9
#include "comm_interactive.h"
10

    
11
// ##############
12
// ## Settings ##
13
// ##############
14

    
15
//#define comm_server_debug
16

    
17
// ###############
18
// ## Constants ##
19
// ###############
20

    
21
#define buffer_size 120
22

    
23
// 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

    
26
// 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
const char command_emitter       [] PROGMEM = "emitter"    ;
36
const char command_detector      [] PROGMEM = "detector"   ;
37
const char command_help          [] PROGMEM = "help"       ;
38
const char command_interactive   [] PROGMEM = "interactive";
39
const char command_i             [] PROGMEM = "i"          ;
40

    
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
        "#   - 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
        ;
53

    
54

    
55
// ####################
56
// ## Initialization ##
57
// ####################
58

    
59
void comm_server_init ()
60
{
61
        usb_init ();
62
}
63

    
64

    
65
// ########################
66
// ## Message processing ##
67
// ########################
68

    
69
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
/** Check if the buffer starts with the given text, followed by a space */
85
static bool serial_match (PGM_P text, const char *buffer)
86
{
87
        uint8_t text_len=strlen_P (text);
88
        uint8_t buffer_len=strlen (buffer);
89

    
90
        // If the buffer is shorter than the text, there is no match
91
        if (buffer_len<text_len) return false;
92

    
93
        // If the buffer is longer than the text, it must have a space at position after the text
94
        if (buffer_len>text_len && buffer[text_len]!=' ') return false;
95

    
96
        // Test for match
97
        if (strncmp_P ((char *)buffer, text, text_len)==0) return true;
98
        
99
        return false;
100
}
101

    
102
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

    
112
                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

    
135

    
136

    
137

    
138

    
139

    
140
// ########################
141
// ## Messages (sending) ##
142
// ########################
143

    
144
void server_send_finished ()
145
{
146
        usb_puts ("finished");
147
}
148

    
149
// ##########################
150
// ## Messages (Receiving) ##
151
// ##########################
152

    
153
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
// ######################
167
// ## Message handlers ##
168
// ######################
169

    
170

    
171
static void handle_message_ping (char *buffer)
172
{
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
static void handle_message_start_test_all (char *buffer)
180
{
181
        test_all ();
182
}
183

    
184
static void handle_message_start_test_comm (char *buffer)
185
{
186
        test_comm ();
187
}
188

    
189
/** If the next parameter is "all", call the test all function. If it's a number, call the test one function. **/
190
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
        buffer=find_next_parameter (buffer);
194

    
195
        // Initialize a buffer for the component number
196
        uint8_t num=0;
197

    
198
        if (!buffer)
199
                // No paramter found (we could also interpret that as implicit "all")
200
                parameter_missing ();
201
        else if (serial_match (command_all, buffer))
202
                // 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
        else
208
                // Unknwon parameter
209
                unhandled_parameters (buffer);
210
}
211

    
212
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

    
216
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

    
220
static void handle_message_start_test_bom (char *buffer)
221
{
222
        // "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
}
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
static void handle_message_help (char *buffer)
272
{
273
        usb_puts_P (help_text);
274
}
275

    
276

    
277
// ##########################
278
// ## Messages (receiving) ##
279
// ##########################
280

    
281
/** message is 0 terminated */
282
static void handle_message (char *message)
283
{
284
#ifdef comm_server_debug
285
        // Output: "# Received a message, size <size>: [<message>]"
286
        usb_puts ("# Received a message, size ");
287
        usb_puti(size);
288
        usb_puts (": [");
289
        usb_puts ((char *)message);
290
        usb_puts ("]" NL);
291
#endif
292
        
293
        bool handled=false;
294
        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
        // 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
}
308

    
309

    
310
// ###############
311
// ## Debugging ##
312
// ###############
313

    
314
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

    
327

    
328
// ###############
329
// ## Main loop ##
330
// ###############
331

    
332
static void ready (void)
333
{
334
        usb_puts ("ready" NL);
335
}
336

    
337
void server_main (void)
338
{
339
        char buffer[buffer_size];
340
        uint8_t c;
341
        uint8_t buffer_fill=0;
342

    
343
        // Set the orbs to green/yellow
344
        orbs_set (0,255,0, 255,127,0);
345

    
346
        //byte_transmission_test (); // Does not return
347

    
348
        usb_puts (NL);
349
        usb_puts ("# Diagnostic station server mode" NL);
350

    
351
        ready ();
352
        
353
        while (1)
354
        {
355
                // Do nothing until we receive a byte (this function will return 0 when a character has been read)
356
                // (Yes, we could use the blocking function for now, but we may need the non-blocking later)
357
                while (usb_getc_nb ((char *)&c));
358
                
359
                if (c=='\r' || c=='\n')
360
                {
361
                        // A newline character was received. This terminates the message.
362
                        
363
                        // 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
                                handle_message (buffer);
371
                                
372
                                // Reset the buffer
373
                                buffer_fill=0;
374
                        }
375
                        
376
                        // TODO do better, make a function get_message?
377
                        ready ();
378
                }
379
                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
                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
        }
397
}