Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (9.34 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
// ##############
10
// ## Settings ##
11
// ##############
12

    
13
//#define comm_server_debug
14

    
15
// ###############
16
// ## Constants ##
17
// ###############
18

    
19
#define buffer_size 120
20

    
21
// Put all symbolic string constants into the program memory because else all of them would be copied into the RAM (see
22
// the avr-libc documentation, chapter "Data in Program Space").
23

    
24
// Commands 
25
const char command_ping          [] PROGMEM = "ping"       ;
26
const char command_start_test    [] PROGMEM = "start_test" ;
27
const char command_all           [] PROGMEM = "all"        ;
28
const char command_comm          [] PROGMEM = "comm"       ;
29
const char command_bom           [] PROGMEM = "bom"        ;
30
const char command_rangefinder   [] PROGMEM = "rangefinder";
31
const char command_motor         [] PROGMEM = "motor"      ;
32
const char command_encoder       [] PROGMEM = "encoder"    ;
33
const char command_help          [] PROGMEM = "help"       ;
34

    
35
// Help
36
const char help_text          [] PROGMEM =
37
        "# Available commands:" NL
38
        "#   - help" NL
39
        "#   - ping" NL
40
        "#   - start_test all" NL
41
        "#   - start_test comm" NL
42
        "#   - start_test bom all|<num> (0..15)" NL
43
        "#   - start_test rangefinder all|<num> (?..?)" NL
44
        "#   - start_test motor all|<num> (1..2)" NL
45
        "#   - start_test encoder all|<num> (1..2)" NL
46
        ;
47

    
48

    
49
// ####################
50
// ## Initialization ##
51
// ####################
52

    
53
void comm_server_init ()
54
{
55
        usb_init ();
56
}
57

    
58

    
59
// ########################
60
// ## Message processing ##
61
// ########################
62

    
63
// TODO move this to the library
64
static void serial_send_string_P (PGM_P s)
65
{
66
    char buf;
67
    while (memcpy_P (&buf, s, sizeof (char)), buf!=0)
68
    {
69
        usb_putc (buf);
70
        s++;
71
    }
72
}
73

    
74
static char *find_next_parameter (char *p)
75
{
76
        // Advance p until a blank or the terminating zero is found.
77
        while ((*p)!=' ' && (*p)!=0) p++;
78
        
79
        // Advance p until a non-blank (including the terminating zero) is found.
80
        while (*p==' ') p++;
81
        
82
        // We have found the next parameter unless p points to the terminating zero.
83
        if (*p==0)
84
                return NULL;
85
        else
86
                return p;
87
}
88

    
89
/** Check if the buffer starts with the given text, followed by a space */
90
static bool serial_match (PGM_P text, const char *buffer)
91
{
92
        uint8_t text_len=strlen_P (text);
93
        uint8_t buffer_len=strlen (buffer);
94

    
95
        // If the buffer is shorter than the text, there is no match
96
        if (buffer_len<text_len) return false;
97

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

    
101
        // Test for match
102
        if (strncmp_P ((char *)buffer, text, text_len)==0) return true;
103
        
104
        return false;
105
}
106

    
107
static bool serial_number_u8 (uint8_t *num, const char *buffer)
108
{
109
        uint8_t result=0;
110
        
111
        // Iterate over the buffer
112
        while (1)
113
        {
114
                // Look at the character
115
                char c=*buffer;
116

    
117
                if (c>='0' && c<='9')
118
                {
119
                        // It's a digit. Process it.
120
                        result*=10;
121
                        result+=(c-'0');
122
                }
123
                else if (c==' ' || c==0)
124
                {
125
                        // It's a space or a terminating zero, which means that the paramter is a valid number.
126
                        *num=result;
127
                        return true;
128
                }
129
                else
130
                {
131
                        // It's a different character, which means that the parameter is not a number.
132
                        return false;
133
                }
134
                
135
                // Move to the next byte
136
                buffer++;
137
        }
138
}
139

    
140

    
141

    
142

    
143

    
144

    
145
// ########################
146
// ## Messages (sending) ##
147
// ########################
148

    
149
void server_send_finished ()
150
{
151
        usb_puts ("finished");
152
}
153

    
154
// ##########################
155
// ## Messages (Receiving) ##
156
// ##########################
157

    
158
static void unhandled_parameters (char *buffer)
159
{
160
        usb_puts ("# Warning: unhandled parameters: [");
161
        usb_puts (buffer);
162
        usb_puts ("]" NL);
163
}
164

    
165
static void parameter_missing (void)
166
{
167
        usb_puts ("# Parameter missing" NL);
168
}
169

    
170

    
171
// ######################
172
// ## Message handlers ##
173
// ######################
174

    
175

    
176
static void handle_message_ping (char *buffer)
177
{
178
        usb_puts ("pong" NL);
179
        orbs_set (255, 127, 0, 0, 255, 0);
180
        delay_ms (400);
181
        orbs_set (0, 255, 0, 255, 127, 0);
182
}
183

    
184
static void handle_message_start_test_all (char *buffer)
185
{
186
        test_all ();
187
}
188

    
189
static void handle_message_start_test_comm (char *buffer)
190
{
191
        // TODO handle all/number
192
        test_comm ();
193
}
194

    
195
static void handle_message_start_test_component (char *buffer, void (*test_all_fn)(void), void (*test_one_fn)(uint8_t))
196
{
197
        // Find the next parameter
198
        buffer=find_next_parameter (buffer);
199

    
200
        // Initialize a buffer for the component number
201
        uint8_t num=0;
202

    
203
        if (!buffer)
204
                // No paramter found (we could also interpret that as implicit "all")
205
                parameter_missing ();
206
        else if (serial_match (command_all, buffer))
207
                // The paramter is "all". Call the all-tests function
208
                test_all_fn ();
209
        else if (serial_number_u8 (&num, buffer))
210
                // The paramter is a number. Call the one-test function 
211
                test_one_fn (num);
212
        else
213
                // Unknwon parameter
214
                unhandled_parameters (buffer);
215
}
216

    
217
static void test_bom_helper (uint8_t num)
218
{
219
        test_bom (num, true, true);
220
}
221

    
222
static void test_bom_all_helper (void)
223
{
224
        test_bom_all (true, true);
225
}
226

    
227
static void handle_message_start_test_bom (char *buffer)
228
{
229
        handle_message_start_test_component (buffer, test_bom_all_helper, test_bom_helper);
230
}
231

    
232
static void handle_message_start_test_rangefinder (char *buffer)
233
{
234
        handle_message_start_test_component (buffer, test_rangefinder_all, test_rangefinder);
235
}
236

    
237
static void handle_message_start_test_motor (char *buffer)
238
{
239
        handle_message_start_test_component (buffer, test_motor_all, test_motor);
240
}
241

    
242
static void handle_message_start_test_encoder (char *buffer)
243
{
244
        handle_message_start_test_component (buffer, test_encoder_all, test_encoder);
245
}
246

    
247
static void handle_message_start_test (char *buffer)
248
{
249
        // FIXME parameter handling
250
        // Parameters: all/rangefinder/motor/encoder all/<num>
251
        
252

    
253
        // TODO add required comm test
254
        buffer=find_next_parameter (buffer);
255
        if (!buffer)                                         parameter_missing ();
256
        else if (serial_match (command_all        , buffer)) handle_message_start_test_all         (buffer);
257
        else if (serial_match (command_comm       , buffer)) handle_message_start_test_comm        (buffer);
258
        else if (serial_match (command_bom        , buffer)) handle_message_start_test_bom         (buffer);
259
        else if (serial_match (command_rangefinder, buffer)) handle_message_start_test_rangefinder (buffer);
260
        else if (serial_match (command_motor      , buffer)) handle_message_start_test_motor       (buffer);
261
        else if (serial_match (command_encoder    , buffer)) handle_message_start_test_encoder     (buffer);
262
        else                                                 unhandled_parameters (buffer);
263
}
264

    
265
static void handle_message_help (char *buffer)
266
{
267
        serial_send_string_P (help_text);
268
}
269

    
270

    
271
// ##########################
272
// ## Messages (receiving) ##
273
// ##########################
274

    
275
/** message is 0 terminated */
276
static void handle_message (char *message)
277
{
278
#ifdef comm_server_debug
279
        // Output: "# Received a message, size <size>: [<message>]"
280
        usb_puts ("# Received a message, size ");
281
        usb_puti(size);
282
        usb_puts (": [");
283
        usb_puts ((char *)message);
284
        usb_puts ("]" NL);
285
#endif
286
        
287
        bool handled=false;
288
        if (serial_match (command_ping      , message)) { handle_message_ping       (message); handled=true; }
289
        if (serial_match (command_start_test, message)) { handle_message_start_test (message); handled=true; }
290
        if (serial_match (command_help      , message)) { handle_message_help       (message); handled=true; }
291
        // More messages go here
292
        
293
        if (!handled)
294
        {
295
                usb_puts ("# Warning: unhandled message: [");
296
                usb_puts ((char *)message);
297
                usb_puts ("]" NL);
298
        }
299
}
300

    
301

    
302
// ###############
303
// ## Debugging ##
304
// ###############
305

    
306
void byte_transmission_test (void)
307
{
308
        uint8_t c;
309
        
310
        while (1)
311
        {
312
                c=usb_getc ();
313
                usb_puts ("[");
314
                usb_puti (c);
315
                usb_puts ("] ");
316
        }
317
}
318

    
319

    
320
// ###############
321
// ## Main loop ##
322
// ###############
323

    
324
void server_main (void)
325
{
326
        char buffer[buffer_size];
327
        uint8_t c;
328
        uint8_t buffer_fill=0;
329

    
330
        //byte_transmission_test (); // Does not return
331

    
332
        usb_puts (NL);
333
        usb_puts ("# Diagnostic station server mode" NL);
334
        
335
        while (1)
336
        {
337
                // Do nothing until we receive a byte (this function will return 0 when a character has been read)
338
                // (Yes, we could use the blocking function for now, but we may need the non-blocking later)
339
                while (usb_getc_nb ((char *)&c));
340
                
341
                if (c=='\r' || c=='\n')
342
                {
343
                        // A newline character was received. This terminates the message.
344
                        
345
                        // Empty lines are ignored.
346
                        if (buffer_fill>0)
347
                        {
348
                                // Add a terminating 0 to the buffer so the string functions won't try to read outside the buffer.
349
                                buffer[buffer_fill]=0;
350
                                
351
                                // Handle the message.
352
                                handle_message (buffer);
353
                        
354
                                // Reset the buffer
355
                                buffer_fill=0;
356
                        }
357
                }
358
                else if (c==8)
359
                {
360
                        // Backspace
361
                        // Of course, the server will never send one, but it's convenient to have for debugging.
362
                        if (buffer_fill>0) --buffer_fill;
363
                }
364
                else
365
                {
366
                        // If there is enough space left in the buffer, add the character we just received. Leave one byte for a
367
                        // terminating 0. If there is not enough space in the buffer, the rest of the message is ignored.
368
                        if (buffer_fill<buffer_size-1)
369
                        {
370
                                buffer[buffer_fill]=c;
371
                                ++buffer_fill;
372
                        }
373
                }
374
        
375
        }
376
}