Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (9.37 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
        test_comm ();
192
}
193

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

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

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

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

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

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

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

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

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

    
246
static void handle_message_start_test (char *buffer)
247
{
248
        // TODO add required comm test
249
        buffer=find_next_parameter (buffer);
250
        if (!buffer)                                         parameter_missing ();
251
        else if (serial_match (command_all        , buffer)) handle_message_start_test_all         (buffer);
252
        else if (serial_match (command_comm       , buffer)) handle_message_start_test_comm        (buffer);
253
        else if (serial_match (command_bom        , buffer)) handle_message_start_test_bom         (buffer);
254
        else if (serial_match (command_rangefinder, buffer)) handle_message_start_test_rangefinder (buffer);
255
        else if (serial_match (command_motor      , buffer)) handle_message_start_test_motor       (buffer);
256
        else if (serial_match (command_encoder    , buffer)) handle_message_start_test_encoder     (buffer);
257
        else                                                 unhandled_parameters (buffer);
258
}
259

    
260
static void handle_message_help (char *buffer)
261
{
262
        serial_send_string_P (help_text);
263
}
264

    
265

    
266
// ##########################
267
// ## Messages (receiving) ##
268
// ##########################
269

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

    
296

    
297
// ###############
298
// ## Debugging ##
299
// ###############
300

    
301
void byte_transmission_test (void)
302
{
303
        uint8_t c;
304
        
305
        while (1)
306
        {
307
                c=usb_getc ();
308
                usb_puts ("[");
309
                usb_puti (c);
310
                usb_puts ("] ");
311
        }
312
}
313

    
314

    
315
// ###############
316
// ## Main loop ##
317
// ###############
318

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