Project

General

Profile

Statistics
| Revision:

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

History | View | Annotate | Download (9.15 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
static char *find_next_parameter (char *p)
64
{
65
        // Advance p until a blank or the terminating zero is found.
66
        while ((*p)!=' ' && (*p)!=0) p++;
67
        
68
        // Advance p until a non-blank (including the terminating zero) is found.
69
        while (*p==' ') p++;
70
        
71
        // We have found the next parameter unless p points to the terminating zero.
72
        if (*p==0)
73
                return NULL;
74
        else
75
                return p;
76
}
77

    
78
/** Check if the buffer starts with the given text, followed by a space */
79
static bool serial_match (PGM_P text, const char *buffer)
80
{
81
        uint8_t text_len=strlen_P (text);
82
        uint8_t buffer_len=strlen (buffer);
83

    
84
        // If the buffer is shorter than the text, there is no match
85
        if (buffer_len<text_len) return false;
86

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

    
90
        // Test for match
91
        if (strncmp_P ((char *)buffer, text, text_len)==0) return true;
92
        
93
        return false;
94
}
95

    
96
static bool serial_number_u8 (uint8_t *num, const char *buffer)
97
{
98
        uint8_t result=0;
99
        
100
        // Iterate over the buffer
101
        while (1)
102
        {
103
                // Look at the character
104
                char c=*buffer;
105

    
106
                if (c>='0' && c<='9')
107
                {
108
                        // It's a digit. Process it.
109
                        result*=10;
110
                        result+=(c-'0');
111
                }
112
                else if (c==' ' || c==0)
113
                {
114
                        // It's a space or a terminating zero, which means that the paramter is a valid number.
115
                        *num=result;
116
                        return true;
117
                }
118
                else
119
                {
120
                        // It's a different character, which means that the parameter is not a number.
121
                        return false;
122
                }
123
                
124
                // Move to the next byte
125
                buffer++;
126
        }
127
}
128

    
129

    
130

    
131

    
132

    
133

    
134
// ########################
135
// ## Messages (sending) ##
136
// ########################
137

    
138
void server_send_finished ()
139
{
140
        usb_puts ("finished");
141
}
142

    
143
// ##########################
144
// ## Messages (Receiving) ##
145
// ##########################
146

    
147
static void unhandled_parameters (char *buffer)
148
{
149
        usb_puts ("# Warning: unhandled parameters: [");
150
        usb_puts (buffer);
151
        usb_puts ("]" NL);
152
}
153

    
154
static void parameter_missing (void)
155
{
156
        usb_puts ("# Parameter missing" NL);
157
}
158

    
159

    
160
// ######################
161
// ## Message handlers ##
162
// ######################
163

    
164

    
165
static void handle_message_ping (char *buffer)
166
{
167
        usb_puts ("pong" NL);
168
        orbs_set (255, 127, 0, 0, 255, 0);
169
        delay_ms (400);
170
        orbs_set (0, 255, 0, 255, 127, 0);
171
}
172

    
173
static void handle_message_start_test_all (char *buffer)
174
{
175
        test_all ();
176
}
177

    
178
static void handle_message_start_test_comm (char *buffer)
179
{
180
        test_comm ();
181
}
182

    
183
static void handle_message_start_test_component (char *buffer, void (*test_all_fn)(void), void (*test_one_fn)(uint8_t))
184
{
185
        // Find the next parameter
186
        buffer=find_next_parameter (buffer);
187

    
188
        // Initialize a buffer for the component number
189
        uint8_t num=0;
190

    
191
        if (!buffer)
192
                // No paramter found (we could also interpret that as implicit "all")
193
                parameter_missing ();
194
        else if (serial_match (command_all, buffer))
195
                // The paramter is "all". Call the all-tests function
196
                test_all_fn ();
197
        else if (serial_number_u8 (&num, buffer))
198
                // The paramter is a number. Call the one-test function 
199
                test_one_fn (num);
200
        else
201
                // Unknwon parameter
202
                unhandled_parameters (buffer);
203
}
204

    
205
static void test_bom_helper (uint8_t num)
206
{
207
        test_bom (num, true, true);
208
}
209

    
210
static void test_bom_all_helper (void)
211
{
212
        test_bom_all (true, true);
213
}
214

    
215
static void handle_message_start_test_bom (char *buffer)
216
{
217
        handle_message_start_test_component (buffer, test_bom_all_helper, test_bom_helper);
218
}
219

    
220
static void handle_message_start_test_rangefinder (char *buffer)
221
{
222
        handle_message_start_test_component (buffer, test_rangefinder_all, test_rangefinder);
223
}
224

    
225
static void handle_message_start_test_motor (char *buffer)
226
{
227
        handle_message_start_test_component (buffer, test_motor_all, test_motor);
228
}
229

    
230
static void handle_message_start_test_encoder (char *buffer)
231
{
232
        handle_message_start_test_component (buffer, test_encoder_all, test_encoder);
233
}
234

    
235
static void handle_message_start_test (char *buffer)
236
{
237
        // TODO add required comm test
238
        buffer=find_next_parameter (buffer);
239
        if (!buffer)                                         parameter_missing ();
240
        else if (serial_match (command_all        , buffer)) handle_message_start_test_all         (buffer);
241
        else if (serial_match (command_comm       , buffer)) handle_message_start_test_comm        (buffer);
242
        else if (serial_match (command_bom        , buffer)) handle_message_start_test_bom         (buffer);
243
        else if (serial_match (command_rangefinder, buffer)) handle_message_start_test_rangefinder (buffer);
244
        else if (serial_match (command_motor      , buffer)) handle_message_start_test_motor       (buffer);
245
        else if (serial_match (command_encoder    , buffer)) handle_message_start_test_encoder     (buffer);
246
        else                                                 unhandled_parameters (buffer);
247
}
248

    
249
static void handle_message_help (char *buffer)
250
{
251
        usb_puts_P (help_text);
252
}
253

    
254

    
255
// ##########################
256
// ## Messages (receiving) ##
257
// ##########################
258

    
259
/** message is 0 terminated */
260
static void handle_message (char *message)
261
{
262
#ifdef comm_server_debug
263
        // Output: "# Received a message, size <size>: [<message>]"
264
        usb_puts ("# Received a message, size ");
265
        usb_puti(size);
266
        usb_puts (": [");
267
        usb_puts ((char *)message);
268
        usb_puts ("]" NL);
269
#endif
270
        
271
        bool handled=false;
272
        if (serial_match (command_ping      , message)) { handle_message_ping       (message); handled=true; }
273
        if (serial_match (command_start_test, message)) { handle_message_start_test (message); handled=true; }
274
        if (serial_match (command_help      , message)) { handle_message_help       (message); handled=true; }
275
        // More messages go here
276
        
277
        if (!handled)
278
        {
279
                usb_puts ("# Warning: unhandled message: [");
280
                usb_puts ((char *)message);
281
                usb_puts ("]" NL);
282
        }
283
}
284

    
285

    
286
// ###############
287
// ## Debugging ##
288
// ###############
289

    
290
void byte_transmission_test (void)
291
{
292
        uint8_t c;
293
        
294
        while (1)
295
        {
296
                c=usb_getc ();
297
                usb_puts ("[");
298
                usb_puti (c);
299
                usb_puts ("] ");
300
        }
301
}
302

    
303

    
304
// ###############
305
// ## Main loop ##
306
// ###############
307

    
308
static void ready ()
309
{
310
        usb_puts ("# Ready" NL);
311
}
312

    
313
void server_main (void)
314
{
315
        char buffer[buffer_size];
316
        uint8_t c;
317
        uint8_t buffer_fill=0;
318

    
319
        //byte_transmission_test (); // Does not return
320

    
321
        usb_puts (NL);
322
        usb_puts ("# Diagnostic station server mode" NL);
323

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