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.