arduino-json-client: 637b4194ade854c1f432fd9945f17d4e6ee71c34
1: /*
2: * Simple Arduino proxy; does what it's told
3: * via the USB connection, and reports back
4: * the values of its inputs. Allows code on
5: * the other end of the USB cable to do the
6: * computation, so the Arduino is just an IO
7: * device rather than a microcontroller.
8: *
9: * Some examples (note that the name:value
10: * pairs can appear in any order):
11: * {"mode":{"pin":1,"mode":"input"}} // Set pin 1 to be an input pin
12: * {"mode":{"mode":"output","pin":8}} // Set pin 8 to be an output pin
13: * {"write":{"pin":4,"type":"digital","value":1}} // Set digital pin 4 to HIGH
14: * {"write":{"pin":2,"type":"digital","value":0}} // Set digital pin 2 to LOW
15: * {"write":{"pin":5,"type":"analogue","value":32}} // Set analogue pin 5 to 32 (range is 0-255)
16: * {"read":{"pin":4,"type":"analogue"}} // Return the value of analogue pin 4 (0-1023)
17: */
18:
19: void setup()
20: {
21: delay(1000); // Keep this here so we don't flood the serial line
22: Serial.begin(9600); // Set up Serial library at 9600 bps
23: Serial.println("{\"status\":\"ready\"}");
24: }
25:
26: void loop()
27: {
28: // Look for some commands in JSON
29: char* input = 0;
30: input = read_json();
31:
32: // See what we received...
33: if (input==0) {
34: // Unknown input
35: }
36: else {
37: // Perform whatever actions are defined for this input
38: read_commands(input);
39: free(input);
40: }
41: }
42:
43: char read_char()
44: {
45: // Wait until some data becomes available
46: // on the USB cable (this will loop
47: // forever if you don't send it anything)
48: char data = -1;
49: while ((Serial.available() < 0) || (data < 0)) {
50: delay(1);
51: data = Serial.read();
52: }
53: return data;
54: }
55:
56: char* read_json()
57: {
58: // This will wait for some input, then
59: // read it to make sure it is an open
60: // brace "{" (discarding it if not) and
61: // reading all of the input up to a
62: // corresponding close brace "}".
63: // Nested sets of braces are allowed.
64: // Returns a pointer to whatever it's
65: // read.
66:
67: // Wait for some serial input and grab it
68: char this_value;
69: this_value = read_char();
70:
71: // See if we should continue reading
72: while (this_value != '{')
73: {
74: // Uh oh, this isn't JSON
75: // Discard it and try again...
76: this_value = read_char();
77: }
78: int nested_count = 1; // Keep track of how deeply nested our braces are
79: int pointer_size = 2; // The size of our char pointer (must be >= 2, for '{' and '}')
80: int read_so_far = 1; // How much data we've read (used to ensure our pointer is big enough)
81: char* result = (char*) malloc(sizeof(char)*pointer_size); // This pointer will be our return value
82: char* new_result; // Used during pointer reallocation
83: result[0] = this_value; // Set the first value to the '{' that we found
84:
85: // There are a few exceptions to the simple braced structure...
86: short in_quote = 0; // "strings"
87: short in_escape = 0; // \escaped characters
88:
89: while (nested_count > 0) // Loop until we've closed that first brace
90: {
91: // Wait for input then read it
92: this_value = read_char();
93:
94: // See if we've got enough room to store it
95: read_so_far++;
96: if (read_so_far > pointer_size)
97: {
98: // Try to increase the size of our JSON pointer
99: // NOTE: There are various strategies we could use here
100: // depending on what we want to conserve. Since we only
101: // build one JSON string at a time, and free it after
102: // we're done with it, we don't need to be massively
103: // conservative in our memory usage
104: char* new_result = (char*) realloc(result, (pointer_size*2));
105: if (new_result)
106: {
107: // We succeeded in allocating enough memory. Let's use it.
108: result = new_result;
109: pointer_size = pointer_size * 2;
110: }
111: else
112: {
113: // Out of memory. Abort.
114: free(result);
115: return 0;
116: }
117: }
118: // Store this character
119: result[read_so_far-1] = this_value;
120:
121: // Handle this character
122: if (in_quote) {
123: // String semantics: read in everything up to a non-escaped '"'
124: if (in_escape) {
125: // Apply escaping; ie. ignore the character, just unset in_escape
126: in_escape = 0;
127: }
128: else {
129: if (this_value == '"') {
130: in_quote = 0; // Our matching close quote
131: }
132: if (this_value == '\\') {
133: in_escape = 1; // Ignore whatever the next character is
134: }
135: }
136: }
137: else {
138: // Object semantics: Read in everything up to a non-matched '}'
139:
140: if (this_value == '{') {
141: nested_count++; // Recurse down a level
142: }
143: else {
144: if (this_value == '}') {
145: nested_count--; // Come back up a level
146: }
147: else {
148: if (this_value == '"') {
149: in_quote = 1; // Start a string
150: }
151: else {
152: // Some other character
153: }
154: }
155: }
156: }
157: }
158: return result;
159: }
160:
161: int json_length(char* json) {
162: // Give this a pointer to some JSON data and it will
163: // return the length of that JSON.
164:
165: if (json == 0) {
166: return 0; // Null pointer
167: }
168:
169: if (json[0] != '{') {
170: return 0; // Not JSON
171: }
172:
173: // Now that we know we have a JSON object, we defer
174: // the actual calculation to value_length
175: return value_length(json);
176: }
177:
178: int value_length(char* json) {
179: // This is given a fragment of JSON and returns how
180: // many characters it contains. This fragment might
181: // be an object, a number, a string , etc.
182: if (json == 0) {
183: return 0; // Null pointer
184: }
185:
186: // Switch over each possibility
187: int index = 0;
188: switch (json[index]) {
189: case '{':
190: // This is a JSON object. Find the matching '}'
191: do {
192: index++; // Read ahead
193: if (json[index] == '"') {
194: // Skip strings, as they may contain unwanted '}'
195: index = index + value_length(json+index);
196: }
197: if (json[index] == '{') {
198: // Recurse past nested objects
199: index = index + value_length(json+index);
200: }
201: } while (json[index] != '}');
202: return index + 1; // Include the '{' and '}' in the length
203: case '"':
204: // This is a string. Scan ahead to the first unescaped '"'
205: do {
206: if (json[index] == '\\') {
207: index++; // Skip escaped quotes
208: }
209: index++; // Read ahead
210: } while (json[index] != '"');
211: return index+1; // Include the quotes in the string's length
212: case '0':
213: case '1':
214: case '2':
215: case '3':
216: case '4':
217: case '5':
218: case '6':
219: case '7':
220: case '8':
221: case '9':
222: case '-':
223: // We're a number. Loop forever until we find a non-number character.
224: // Note, this is a simplistic parser that is equivalent to the regex
225: // [0123456789-][0123456789.eE]* This allows malformed numbers like
226: // 0.0.0.0e0.0e.0
227: do {
228: index++;
229: switch (json[index]) {
230: case '0':
231: case '1':
232: case '2':
233: case '3':
234: case '4':
235: case '5':
236: case '6':
237: case '7':
238: case '8':
239: case '9':
240: case '.':
241: case 'e':
242: case 'E':
243: break; // Numeric
244: default:
245: return index; // Non-numeric. Stop counting.
246: }
247: } while (1);
248: default:
249: // Unknown. Ignore it.
250: return 0;
251: }
252: }
253:
254: void read_commands(char* json) {
255: // Takes a JSON string and looks for any commands it
256: // contains. These are "key":value pairs, which are
257: // sent as arguments to the "run_command" function as
258: // they are encountered.
259: int length = json_length(json);
260: int index = 0; // Used to loop through the contents
261: int temp; // Our parsing uses lookahead, this stores how far we've gone
262:
263: // Only bother doing something if json has some contents.
264: // When this condition is false, it's essentially the
265: // escape clause of our recursion.
266: if (length > 2) { // 2 == empty, since we have '{' and '}'
267: index++; // Skip past the '{' to get at the contents
268: while (index < length) {
269: switch (json[index]) {
270: case ' ':
271: // Whitespace is insignificant
272: index++;
273: break;
274: case '{':
275: // We have an object in an object, let's recurse
276: read_commands(json+index);
277: index = index + json_length(json+index);
278: break;
279: case '"':
280: // A string. This should be part of a key:value pair
281: if (index + 2 >= length) {
282: // JSON can't end with an opening quote. Bail out.
283: break;
284: }
285:
286: // Look one character ahead, then keep going until
287: // we find our matching close quote
288: temp = index+1;
289: while ((json[temp] != '"') && (temp < length)) {
290: // We've not found our close quote, so look ahead
291: if (json[temp] == '\\') {
292: // Increment twice to skip over escaped characters
293: temp++;
294: }
295: temp++;
296: }
297: if (temp >= length-2) {
298: // We've reached the end of the JSON without finding
299: // a close quote. Bail out.
300: break;
301: }
302:
303: // Now we've read our name, find our associated value
304: temp++; // It must start after the close quote
305: while ((json[temp] == ' ') && (temp < length)) {
306: temp++; // Skip whitespace
307: }
308: if (json[temp] != ':') {
309: // We must have a colon between the name and the value
310: // Bail out if not
311: break;
312: }
313: temp++; // We don't need the colon, skip it
314: while ((json[temp] == ' ') && (temp < length)) {
315: temp++; // Skip whitespace
316: }
317:
318: // Wherever we are, we must have found our value
319: // Tell run_command what we've found
320: run_command(json+index, json+temp);
321:
322: // Now let's get our parser ready for the next value
323: index = temp + value_length(json+temp); // Skip the value
324: while ((json[index] == ' ') && (index < length)) {
325: index++; // Skip whitespace
326: }
327: if (json[index] == ',') {
328: // Skip commas between name:value pairs
329: index++;
330: }
331: break; // Done
332: default:
333: // Unknown input. Oops.
334: index++;
335: }
336: }
337: }
338: else {
339: // Our JSON is empty
340: return;
341: }
342: }
343:
344: short compare_strings(char* string1, char* string2) {
345: // Compare the first character array, which is not
346: // null-terminated and is in quotes, to the second
347: // which can be null-terminated and without quotes
348: int first_size = value_length(string1);
349: int second_size;
350: for (second_size = 0; string2[second_size] != '\0'; second_size++) {
351: // Do nothing. The loop parameters count the string for us.
352: }
353:
354: // first_size includes quotes, so we don't include them
355: // in our check
356: if (first_size - 2 != second_size) {
357: // The size is different, so the strings are different
358: return 0;
359: }
360:
361: // Now do a lexicographical comparison
362: int index;
363: for (index = 0; index < first_size - 2; index++) {
364: if (string1[index+1] != string2[index]) {
365: return 0; // Mismatch
366: }
367: }
368:
369: // If we're here then our tests couldn't find any different
370: return 1;
371: }
372:
373: float compile_digits(char* value) {
374: // Reads the JSON number in value and returns its value as
375: // a float.
376: // NOTE: This will overrun the digits by 1! Make sure that
377: // the pointer doesn't end when the digits do, or this will
378: // produce unspecified behaviour. This shouldn't be an
379: // issue if your pointer is part of some JSON object, since
380: // we can always overrun on to the '}' in the worst case.
381: float result = 0.0; // We build this up from the whole numbers
382: float fraction_result = 0.0; // We build this up from the fraction
383: int value_size = value_length(value);
384: int index;
385: short fractional = 0; // 0 = no decimal point found, 1 = found decimal point
386: for (index = 0; index < value_size; index++) {
387: result = result * 10.0; // Bump up the magnitude for each digit
388: switch (value[index]) {
389: // Each digit falls through the appropriate number of
390: // increments before breaking at 0.
391: case '9':
392: result = result + 1.0;
393: case '8':
394: result = result + 1.0;
395: case '7':
396: result = result + 1.0;
397: case '6':
398: result = result + 1.0;
399: case '5':
400: result = result + 1.0;
401: case '4':
402: result = result + 1.0;
403: case '3':
404: result = result + 1.0;
405: case '2':
406: result = result + 1.0;
407: case '1':
408: result = result + 1.0;
409: case '0':
410: break;
411: case '-':
412: result = result * -1.0;
413: break;
414: case '.':
415: fractional = 1; // Remember the decimal
416: result = result / 10.0; // Undo the magnitude bump
417: index = value_size; // Break out of the for loop
418: break;
419: case 'e':
420: case 'E':
421: // Not yet handled
422: default:
423: break;
424: }
425: }
426: if (fractional) {
427: // We found a decimal point, so we need to build up
428: // the fraction too. Easiest way is right-to-left.
429: for (index = value_size; index >= 0; index--) {
430: fraction_result = fraction_result / 10.0; // Shift everything to be < 1
431: switch (value[index]) {
432: case '9':
433: fraction_result = fraction_result + 1.0;
434: case '8':
435: fraction_result = fraction_result + 1.0;
436: case '7':
437: fraction_result = fraction_result + 1.0;
438: case '6':
439: fraction_result = fraction_result + 1.0;
440: case '5':
441: fraction_result = fraction_result + 1.0;
442: case '4':
443: fraction_result = fraction_result + 1.0;
444: case '3':
445: fraction_result = fraction_result + 1.0;
446: case '2':
447: fraction_result = fraction_result + 1.0;
448: case '1':
449: fraction_result = fraction_result + 1.0;
450: case '0':
451: break;
452: case '.':
453: fraction_result = fraction_result * 10.0; // Undo the magnitude shift
454: index = 0; // Break out of the for loop
455: break;
456: case 'e':
457: case 'E':
458: // Not yet handled
459: default:
460: break;
461: }
462: }
463: }
464: if (fractional) {
465: result = result + fraction_result;
466: }
467: return result;
468: }
469:
470: int skip_space(char* value) {
471: // Skips whitespace and commas. Returns the number of
472: // characters that were skipped.
473: if (value == 0) {
474: return 0; // Null pointer
475: }
476:
477: int offset = 0;
478: while ((value[offset] == ' ') | (value[offset] == ',')) {
479: offset++;
480: }
481: return offset;
482: }
483:
484: void run_command(char* name, char* value) {
485: // This is called for each "name":value pair found in the
486: // incoming JSON. This is where you should put your handler
487: // code.
488: // There are a few important points to note:
489: // * This function, by default, will only be called for the
490: // top-level pairs, eg. given {"a":"b", "c":{"d":"e"}} it
491: // will be called with name="a", value="b" and name="c",
492: // value={"d":"e"}. It will not be called with name="d",
493: // value="e". If you want such recursion, add it yourself
494: // by calling read_commands on your JSON objects from
495: // somewhere within this function.
496: // * The name and value pointers will be free'd automatically
497: // after the JSON parser has finished. Thus, you should not
498: // store these pointers or any derived from them. If you
499: // want some data to persist, copy its values into some
500: // memory that you manage yourself.
501: // * Likewise, do not free these pointers yourself, as that
502: // will mangle the JSON reading.
503: // * The given pointers are not C-style strings (they are
504: // not terminated). Their length is implied by their JSON
505: // encoding. The variables "name_size" and "value_size"
506: // have been set up with the respective sizes for you if
507: // you need them.
508: // * The JSON formatting is still present in the pointers'
509: // values. For example, strings still contain their quotes.
510: // Other than that, happy hacking!
511: int name_size = value_length(name);
512: int value_size = value_length(value);
513:
514: // We can't do simple string comparison since our pointers
515: // are not null-terminated. Use compare_strings instead.
516: if (compare_strings(name,"read")) {
517: run_read(value); // Read pin values
518: }
519: if (compare_strings(name,"write")) {
520: run_write(value); // Write pin values
521: }
522: if (compare_strings(name,"mode")) {
523: run_mode(value); // Set pin mode
524: }
525: if (compare_strings(name,"query")) {
526: run_query(value);
527: }
528: }
529:
530: void run_read(char* value) {
531: // Reads the value of the specified pins and sends the
532: // results back as JSON
533:
534: // We should have been given a JSON object containing
535: // "pin":x and "type":"analogue" or "type":"digital"
536: int value_size = json_length(value);
537: int index = 0; // Loop index for walking the value
538: int pin = -1; // This tells us which pin to set. -1 means unknown
539: int content_size = 0; // This keeps track of the inner contents
540: short type = 0; // 0 = unknown, 1 = digital, 2 = analogue
541: if (value_size > 2) { // We want some contents between our '{' and '}'
542: index++; // Skip the '{'
543: // Loop until we reach the '}'
544: while (index < value_size - 2) {
545: if (value[index] == ' ') {
546: continue; // Whitespace is insignificant
547: }
548: if (value[index] == '"') {
549: // We have a string. Let's see if it's what we're after
550: if (compare_strings(value+index, "pin")) {
551: //Serial.println("Found pin");
552: // This is the number of the pin to read
553: // Find the associated digits
554: index = index + value_length(value+index); // Skip over the name
555: while (value[index] == ' ') {
556: index++; // Skip whitespace
557: }
558: if (value[index] == ':') {
559: index++; // Skip the colon
560: }
561: else {
562: //Serial.println("...1...");
563: return; // No colon. Abort.
564: }
565: while (value[index] == ' ') {
566: index++; // Skip whitespace
567: }
568: // Now we should be at the pin digits
569: pin = (int) compile_digits(value+index); // Turn them into an integer
570: index = index + value_length(value+index); // Skip over the digits
571: while (value[index] == ' ') {
572: index++; // Skip whitespace
573: }
574: if (value[index] == ',') {
575: index++; // Skip over comma separators
576: }
577: while (value[index] == ' ') {
578: index++; // Skip whitespace
579: }
580: continue; // Retest the while condition
581: }
582: if (compare_strings(value+index, "type")) {
583: //Serial.println("Found type");
584: // This is the type of pin to read.
585: // Find out whether it's analogue or digital.
586: index = index + value_length(value+index);
587: index = index + skip_space(value+index); // Skip whitespace
588: if (value[index] == ':') {
589: index++; // Skip over colons
590: }
591: index = index+skip_space(value+index); // Skip whitespace
592: if (value[index] != '"') {
593: return; // We should have got a string. Bail out.
594: }
595: if (compare_strings(value+index, "digital")) {
596: // Digital read
597: type = 1;
598: }
599: if (compare_strings(value+index, "analogue")) {
600: // Analogue read
601: type = 2;
602: }
603: index = index + value_length(value+index); // Skip the value
604: index = index + skip_space(value+index); // Skip whitespace
605: if (value[index] == ',') {
606: index++; // Skip comma separators
607: }
608: index = index + skip_space(value+index); // Skip whitespace
609: continue;
610: }
611: }
612: }
613: if (pin >= 0) {
614: // Send our result over USB
615: // {"pinValue":{"type":"digital", "pin":123, "value":123}}
616: Serial.print("{\"pinValue\":{\"type\":");
617: if (type == 1) {
618: Serial.print("\"digital\"");
619: }
620: else if (type == 2) {
621: Serial.print("\"analogue\"");
622: }
623: else {
624: return; // Error, bail out
625: }
626: Serial.print(", \"pin\":");
627: Serial.print(pin);
628: Serial.print(", \"value\":");
629: if (type == 1) {
630: Serial.print(digitalRead(pin));
631: }
632: else if (type == 2) {
633: Serial.print(analogRead(pin));
634: }
635: else {
636: return; // Error, bail out
637: }
638: Serial.print("}}");
639: }
640: }
641: }
642:
643: void run_write(char* value) {
644: // Writes the specified value to the specified pin and sends
645: // back some empty JSON. The type must be given, to keep the
646: // code simple.
647:
648: // We should have been given a JSON object containing
649: // "pin":x, "value":y and "type":"digital" or "type":"analogue"
650: int value_size = json_length(value);
651: int index = 0; // Loop index for walking the value
652: int pin = -1; // This tells us which pin to set. -1 means unknown
653: int content_size = 0; // This keeps track of the inner contents
654: int pin_value = -1; // The value to write. Analogue has a range 0-255, digital is 0 (LOW) or 1 (HIGH)
655: short type = 0; // 0 = unknown, 1 = digital, 2 = analogue
656: if (value_size > 2) { // We want some contents between our '{' and '}'
657: index++; // Skip the '{'
658: // Loop until we reach the '}'
659: while (index < value_size - 2) {
660: if (value[index] == ' ') {
661: continue; // Whitespace is insignificant
662: }
663: if (value[index] == '"') {
664: // We have a string. Let's see if it's what we're after
665: if (compare_strings(value+index, "pin")) {
666: // This is the number of the pin to write
667: // Find the associated digits
668: index = index + value_length(value+index); // Skip over the name
669: while (value[index] == ' ') {
670: index++; // Skip whitespace
671: }
672: if (value[index] == ':') {
673: index++; // Skip the colon
674: }
675: else {
676: return; // No colon. Abort.
677: }
678: while (value[index] == ' ') {
679: index++; // Skip whitespace
680: }
681: // Now we should be at the pin digits
682: pin = (int) compile_digits(value+index); // Turn them into an integer
683: index = index + value_length(value+index); // Skip over the digits
684: while (value[index] == ' ') {
685: index++; // Skip whitespace
686: }
687: if (value[index] == ',') {
688: index++; // Skip over comma separators
689: }
690: while (value[index] == ' ') {
691: index++; // Skip whitespace
692: }
693: continue; // Retest the while condition
694: }
695: if (compare_strings(value+index, "type")) {
696: // This is the type of pin to write.
697: // Find out whether it's analogue or digital.
698: index = index + value_length(value+index); // Skip over "type"
699: index = index + skip_space(value+index); // Skip whitespace
700: if (value[index] == ':') {
701: index++; // Skip over colons
702: }
703: else {
704: return; // No colon. Bail out.
705: }
706: index = index + skip_space(value+index); // Skip whitespace
707: if (value[index] != '"') {
708: return; // We should have got a string. Bail out.
709: }
710: if (compare_strings(value+index, "digital")) {
711: // Digital read
712: type = 1;
713: }
714: if (compare_strings(value+index, "analogue")) {
715: // Analogue read
716: type = 2;
717: }
718: index = index + value_length(value+index); // Skip over the value string
719: index = index + skip_space(value+index); // Skip whitespace
720: if (value[index] == ',') {
721: index++; // Skip comma separators
722: }
723: index = index + skip_space(value+index); // Skip whitespace
724: continue; // Retest the while condition
725: }
726: if (compare_strings(value+index, "value")) {
727: // This is the value we should write to the pin.
728: // We can't assume the order of our input, so
729: // we just save the value without checking it
730: // until later.
731: index = index + value_length(value+index); // Skip over "value"
732: index = index + skip_space(value+index); // Skip whitespace
733: if (value[index] == ':') {
734: index++; // Skip over colons
735: }
736: else {
737: return; // No colon. Bail out.
738: }
739: index = index + skip_space(value+index); // Skip whitespace
740: pin_value = (int)(compile_digits(value+index)+0.5); // Grab the rounded value
741: index = index + value_length(value+index); // Skip over the digits
742: index = index + skip_space(value+index); // Skip whitespace
743: if (value[index] == ',') {
744: index++; // Skip commas
745: }
746: index = index + skip_space(value+index); // Skip whitespace
747: continue; // Retest the while condition
748: }
749: }
750: }
751: if (((type == 1) || (type == 2)) && (pin > 0) && (pin_value >= 0)) {
752: if (type == 1) {
753: // Digital. Our value must be 0 or 1.
754: if ((pin_value != 0) && (pin_value != 1)) {
755: return; // Bail out
756: }
757: switch (pin_value) {
758: case 0:
759: digitalWrite(pin,LOW);
760: break;
761: case 1:
762: digitalWrite(pin,HIGH);
763: break;
764: default:
765: return; // Bail out.
766: }
767: }
768: if (type == 2) {
769: // Analogue. Our value must be from 0 to 255.
770: if ((pin_value < 0) || (pin_value > 255)) {
771: return; // Bail out
772: }
773: analogWrite(pin,pin_value);
774: }
775: Serial.print("{}"); // Indicates success
776: }
777: }
778: }
779:
780: void run_mode(char* value) {
781: // Sets the mode of a pin to input or output.
782:
783: // We should have been given a JSON object containing
784: // "pin":x, "mode":"input" or "mode":"output"
785: int value_size = json_length(value);
786: int index = 0; // Loop index for walking the value
787: int pin = -1; // This tells us which pin to set. -1 means unknown
788: int content_size = 0; // This keeps track of the inner contents
789: short mode = 0; // 0 for unknown, 1 for input and 2 for output
790: if (value_size > 2) { // We want some contents between our '{' and '}'
791: index++; // Skip the '{'
792: // Loop until we reach the '}'
793: while (index < value_size - 2) {
794: if (value[index] == ' ') {
795: continue; // Whitespace is insignificant
796: }
797: if (value[index] == '"') {
798: // We have a string. Let's see if it's what we're after
799: if (compare_strings(value+index, "pin")) {
800: // This is the number of the pin to set
801: // Find the associated digits
802: index = index + value_length(value+index); // Skip over the name
803: while (value[index] == ' ') {
804: index++; // Skip whitespace
805: }
806: if (value[index] == ':') {
807: index++; // Skip the colon
808: }
809: else {
810: return; // No colon. Abort.
811: }
812: while (value[index] == ' ') {
813: index++; // Skip whitespace
814: }
815: // Now we should be at the pin digits
816: pin = (int) (compile_digits(value+index)+0.5); // Turn them into an integer
817: index = index + value_length(value+index); // Skip over the digits
818: index = index + skip_space(value+index); // Skip whitespace
819: if (value[index] == ',') {
820: index++; // Skip over comma separators
821: }
822: index = index + skip_space(value+index); // Skip whitespace
823: continue; // Retest the while condition
824: }
825: if (compare_strings(value+index, "mode")) {
826: // This is the mode to set.
827: // Find out whether it's input or output.
828: index = index + value_length(value+index); // Skip over "mode"
829: index = index + skip_space(value+index); // Skip whitespace
830: if (value[index] == ':') {
831: index++; // Skip over colons
832: }
833: else {
834: return; // No colon. Bail out.
835: }
836: index = index + skip_space(value+index); // Skip whitespace
837: if (value[index] != '"') {
838: return; // We should have got a string. Bail out.
839: }
840: if (compare_strings(value+index, "input")) {
841: // Input mode
842: mode = 1;
843: }
844: if (compare_strings(value+index, "output")) {
845: // Output mode
846: mode = 2;
847: }
848: index = index + value_length(value+index); // Skip over the value string
849: index = index + skip_space(value+index); // Skip whitespace
850: if (value[index] == ',') {
851: index++; // Skip comma separators
852: }
853: index = index + skip_space(value+index); // Skip whitespace
854: continue; // Retest the while condition
855: }
856: }
857: }
858: if (((mode == 1) || (mode == 2)) && (pin > 0)) {
859: if (mode == 1) {
860: // Input
861: pinMode(pin,INPUT);
862: }
863: if (mode == 2) {
864: // Output
865: pinMode(pin,OUTPUT);
866: }
867: Serial.print("{}"); // Indicates success
868: }
869: }
870: }
871:
872: void run_query(char* value) {
873: // We use "query" as a generic name when all we want
874: // to send is a value. We simply branch based on the
875: // contents of value (we'd use a switch, but we would
876: // have to overload comparison with compare_strings)
877: if (compare_strings(value, "status")) {
878: // This is a generic ping request. We just report
879: // that we're ready so that whatever's on the other
880: // end knows that it can send commands to us.
881: Serial.println("{\"status\":\"ready\"}");
882: }
883: }
Generated by git2html.