diff --git a/README.md b/README.md index e7a80be..04af24f 100644 --- a/README.md +++ b/README.md @@ -89,17 +89,18 @@ This library depends on the blues [note-c repo][note-c] and utilizes git subtrees to include those files in the src/note-c folder. To update this repo with the latest from note-c: -```sh +```none rm -rf src/note-c -git commit -am 'remove note-c before readd' +git commit -am 'remove note-c before re-add' git subtree add --prefix=src/note-c --squash https://github.com/blues/note-c.git master ``` ## Documentation -The documentation for this library can be found [here](https://blues.github.io/note-arduino/html/index.html). +The documentation for this library can be found +[here](https://dev.blues.io/tools-and-sdks/arduino-library/). -# Examples +## Examples The [examples](examples/) directory contains examples for using this library with: diff --git a/library.properties b/library.properties index b24a757..2520f82 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Blues Wireless Notecard -version=1.3.0 +version=1.3.1 author=Blues Wireless maintainer=Blues Wireless sentence=An easy to use Notecard Library for Arduino. diff --git a/src/Notecard.cpp b/src/Notecard.cpp index a627ce0..e0cc264 100644 --- a/src/Notecard.cpp +++ b/src/Notecard.cpp @@ -38,9 +38,9 @@ #include "Notecard.h" -#include -#include -#include +#include +#include +#include TwoWire *Notecard::_i2cPort; HardwareSerial *Notecard::_notecardSerial; @@ -354,6 +354,7 @@ char Notecard::noteSerialReceive() /**************************************************************************/ bool Notecard::noteI2CReset(uint16_t DevAddress) { + (void)DevAddress; #if WIRE_HAS_END _i2cPort->end(); #endif @@ -480,14 +481,14 @@ const char *Notecard::noteI2CReceive(uint16_t DevAddress, uint8_t* pBuffer, uint if (goodbyte != Size) { #if I2C_DATA_TRACE NoteDebugf("%d != %d, received:\n", goodbyte, Size); - for (int i=0; iread(); } } diff --git a/src/Notecard.h b/src/Notecard.h index a11ce76..b5abab3 100644 --- a/src/Notecard.h +++ b/src/Notecard.h @@ -24,8 +24,8 @@ #ifndef Notecard_h #define Notecard_h -#include -#include +#include +#include #ifndef MOCK #include #include diff --git a/src/note-c/README.md b/src/note-c/README.md index 202820f..50389d8 100644 --- a/src/note-c/README.md +++ b/src/note-c/README.md @@ -25,9 +25,9 @@ For details on contributions we accept and the process for contributing, see our For additional Notecard SDKs and Libraries, see: -* [note-arduino](note-arduino) for Arduino support -* [note-python](note-python) for Python -* [note-go](note-go) for Go +* [note-arduino][note-arduino] for Arduino support +* [note-python][note-python] for Python +* [note-go][note-go] for Go ## To learn more about Blues Wireless, the Notecard and Notehub, see: @@ -45,4 +45,4 @@ Copyright (c) 2019 Blues Inc. Released under the MIT license. See [note-arduino]: https://github.com/blues/note-arduino [note-go]: https://github.com/blues/note-go [note-python]: https://github.com/blues/note-python -[code of conduct]: https://blues.github.io/opensource/code-of-conduct \ No newline at end of file +[code of conduct]: https://blues.github.io/opensource/code-of-conduct diff --git a/src/note-c/n_atof.c b/src/note-c/n_atof.c index 3eab259..e98e009 100644 --- a/src/note-c/n_atof.c +++ b/src/note-c/n_atof.c @@ -40,7 +40,7 @@ #define NULL 0 #endif -#define MAX_EXPONENT 511 /* Largest possible base 10 exponent. Any +#define MAX_EXPONENT 511 /* Largest possible base 10 exponent. Any * exponent larger than this will already * produce underflow or overflow, so there's * no need to worry about additional digits. @@ -69,7 +69,7 @@ JNUMBER JAtoN(string, endPtr) - const char *string; /* A decimal ASCII floating-point number, +const char *string; /* A decimal ASCII floating-point number, * optionally preceded by white space. * Must have form "-I.FE-X", where I is the * integer part of the mantissa, F is the @@ -81,7 +81,7 @@ JAtoN(string, endPtr) * The "E" may actually be an "e". E and X * may both be omitted (but not just one). */ - char **endPtr; /* If non-NULL, store terminating character's +char **endPtr; /* If non-NULL, store terminating character's * address here. */ { int sign, expSign = FALSE; @@ -128,8 +128,7 @@ JAtoN(string, endPtr) */ decPt = -1; - for (mantSize = 0; ; mantSize += 1) - { + for (mantSize = 0; ; mantSize += 1) { c = *p; if (c < '0' || c > '9') { if ((c != '.') || (decPt >= 0)) { @@ -146,7 +145,7 @@ JAtoN(string, endPtr) * If the mantissa has more than 18 digits, ignore the extras, since * they can't affect the value anyway. */ - + pExp = p; p -= mantSize; if (decPt < 0) { @@ -167,8 +166,7 @@ JAtoN(string, endPtr) } else { long frac1, frac2; frac1 = 0L; - for ( ; mantSize > 9; mantSize -= 1) - { + for ( ; mantSize > 9; mantSize -= 1) { c = *p; p += 1; if (c == '.') { @@ -178,8 +176,7 @@ JAtoN(string, endPtr) frac1 = 10*frac1 + (c - '0'); } frac2 = 0L; - for (; mantSize > 0; mantSize -= 1) - { + for (; mantSize > 0; mantSize -= 1) { c = *p; p += 1; if (c == '.') { @@ -224,7 +221,7 @@ JAtoN(string, endPtr) * many powers of 2 of 10. Then combine the exponent with the * fraction. */ - + if (exp < 0) { expSign = TRUE; exp = -exp; @@ -235,45 +232,46 @@ JAtoN(string, endPtr) exp = MAX_EXPONENT; } dblExp = 1.0; - int d; + int d; for (d = 0; exp != 0; exp >>= 1, d += 1) { - /* Table giving binary powers of 10. Entry */ - /* is 10^2^i. Used to convert decimal */ - /* exponents into floating-point numbers. */ - JNUMBER p10 = 0.0; - switch (d) { - case 0: - p10 = 10.0; - break; - case 1: - p10 = 100.0; - break; - case 2: - p10 = 1.0e4; - break; - case 3: - p10 = 1.0e8; - break; - case 4: - p10 = 1.0e16; - break; - case 5: - p10 = 1.0e32; - break; + /* Table giving binary powers of 10. Entry */ + /* is 10^2^i. Used to convert decimal */ + /* exponents into floating-point numbers. */ + JNUMBER p10 = 0.0; + switch (d) { + case 0: + p10 = 10.0; + break; + case 1: + p10 = 100.0; + break; + case 2: + p10 = 1.0e4; + break; + case 3: + p10 = 1.0e8; + break; + case 4: + p10 = 1.0e16; + break; + case 5: + p10 = 1.0e32; + break; #ifndef NOTE_FLOAT - case 6: - p10 = 1.0e64; - break; - case 7: - p10 = 1.0e128; - break; - case 8: - p10 = 1.0e256; - break; + case 6: + p10 = 1.0e64; + break; + case 7: + p10 = 1.0e128; + break; + case 8: + p10 = 1.0e256; + break; #endif - } - if (p10 == 0.0) - break; + } + if (p10 == 0.0) { + break; + } if (exp & 01) { dblExp *= p10; } diff --git a/src/note-c/n_b64.c b/src/note-c/n_b64.c index cd48aca..e718ce6 100644 --- a/src/note-c/n_b64.c +++ b/src/note-c/n_b64.c @@ -83,8 +83,7 @@ #include "n_lib.h" /* aaaack but it's fast and const should make it shared text page. */ -static const unsigned char pr2six[256] = -{ +static const unsigned char pr2six[256] = { /* ASCII table */ 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, @@ -135,28 +134,28 @@ int JB64Decode(char *bufplain, const char *bufcoded) bufin = (const unsigned char *) bufcoded; while (nprbytes > 4) { - *(bufout++) = - (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4); - *(bufout++) = - (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2); - *(bufout++) = - (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]); - bufin += 4; - nprbytes -= 4; + *(bufout++) = + (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4); + *(bufout++) = + (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2); + *(bufout++) = + (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]); + bufin += 4; + nprbytes -= 4; } /* Note: (nprbytes == 1) would be an error, so just ingore that case */ if (nprbytes > 1) { - *(bufout++) = - (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4); + *(bufout++) = + (unsigned char) (pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4); } if (nprbytes > 2) { - *(bufout++) = - (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2); + *(bufout++) = + (unsigned char) (pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2); } if (nprbytes > 3) { - *(bufout++) = - (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]); + *(bufout++) = + (unsigned char) (pr2six[bufin[2]] << 6 | pr2six[bufin[3]]); } *(bufout++) = '\0'; @@ -179,26 +178,22 @@ int JB64Encode(char *encoded, const char *string, int len) p = encoded; for (i = 0; i < len - 2; i += 3) { - *p++ = basis_64[(string[i] >> 2) & 0x3F]; - *p++ = basis_64[((string[i] & 0x3) << 4) | - ((int) (string[i + 1] & 0xF0) >> 4)]; - *p++ = basis_64[((string[i + 1] & 0xF) << 2) | - ((int) (string[i + 2] & 0xC0) >> 6)]; - *p++ = basis_64[string[i + 2] & 0x3F]; + *p++ = basis_64[(string[i] >> 2) & 0x3F]; + *p++ = basis_64[((string[i] & 0x3) << 4) | ((int) (string[i + 1] & 0xF0) >> 4)]; + *p++ = basis_64[((string[i + 1] & 0xF) << 2) | ((int) (string[i + 2] & 0xC0) >> 6)]; + *p++ = basis_64[string[i + 2] & 0x3F]; } if (i < len) { - *p++ = basis_64[(string[i] >> 2) & 0x3F]; - if (i == (len - 1)) { - *p++ = basis_64[((string[i] & 0x3) << 4)]; + *p++ = basis_64[(string[i] >> 2) & 0x3F]; + if (i == (len - 1)) { + *p++ = basis_64[((string[i] & 0x3) << 4)]; + *p++ = '='; + } else { + *p++ = basis_64[((string[i] & 0x3) << 4) | ((int) (string[i + 1] & 0xF0) >> 4)]; + *p++ = basis_64[((string[i + 1] & 0xF) << 2)]; + } *p++ = '='; } - else { - *p++ = basis_64[((string[i] & 0x3) << 4) | - ((int) (string[i + 1] & 0xF0) >> 4)]; - *p++ = basis_64[((string[i + 1] & 0xF) << 2)]; - } - *p++ = '='; - } *p++ = '\0'; return p - encoded; diff --git a/src/note-c/n_cjson.c b/src/note-c/n_cjson.c index b7d7987..a145da9 100644 --- a/src/note-c/n_cjson.c +++ b/src/note-c/n_cjson.c @@ -62,7 +62,7 @@ #include // For Note, disable dependencies -#undef ENABLE_LOCALES +#undef ENABLE_LOCALES #define MINIMIZE_CLIB_DEPENDENCIES 1 // Use tiny but non-robust versions of conversions #include "n_lib.h" @@ -87,12 +87,17 @@ typedef struct { } error; static error global_error = { NULL, 0 }; +// Forwards +void htoa16(uint16_t n, unsigned char *p); +static J *JNew_Item(void); + N_CJSON_PUBLIC(const char *) JGetErrorPtr(void) { return (const char*) (global_error.json + global_error.position); } -N_CJSON_PUBLIC(char *) JGetStringValue(J *item) { +N_CJSON_PUBLIC(char *) JGetStringValue(J *item) +{ if (!JIsString(item)) { return NULL; } @@ -102,7 +107,7 @@ N_CJSON_PUBLIC(char *) JGetStringValue(J *item) { /* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ #if (N_CJSON_VERSION_MAJOR != 1) || (N_CJSON_VERSION_MINOR != 7) || (N_CJSON_VERSION_PATCH != 7) - #error J.h and J.c have different versions. Make sure that both have the same. +#error J.h and J.c have different versions. Make sure that both have the same. #endif N_CJSON_PUBLIC(const char*) JVersion(void) @@ -113,20 +118,16 @@ N_CJSON_PUBLIC(const char*) JVersion(void) /* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) { - if ((string1 == NULL) || (string2 == NULL)) - { + if ((string1 == NULL) || (string2 == NULL)) { return 1; } - if (string1 == string2) - { + if (string1 == string2) { return 0; } - for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++) - { - if (*string1 == '\0') - { + for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++) { + if (*string1 == '\0') { return 0; } } @@ -139,15 +140,13 @@ static unsigned char* Jstrdup(const unsigned char* string) size_t length = 0; unsigned char *copy = NULL; - if (string == NULL) - { + if (string == NULL) { return NULL; } length = strlen((const char*)string) + sizeof(""); copy = (unsigned char*)_Malloc(length); - if (copy == NULL) - { + if (copy == NULL) { return NULL; } memcpy(copy, string, length); @@ -155,10 +154,12 @@ static unsigned char* Jstrdup(const unsigned char* string) return copy; } -N_CJSON_PUBLIC(void *) JMalloc(size_t size) { +N_CJSON_PUBLIC(void *) JMalloc(size_t size) +{ return _Malloc(size); } -N_CJSON_PUBLIC(void) JFree(void *p) { +N_CJSON_PUBLIC(void) JFree(void *p) +{ _Free(p); } @@ -166,8 +167,7 @@ N_CJSON_PUBLIC(void) JFree(void *p) { static J *JNew_Item() { J* node = (J*)_Malloc(sizeof(J)); - if (node) - { + if (node) { memset(node, '\0', sizeof(J)); } @@ -178,19 +178,15 @@ static J *JNew_Item() N_CJSON_PUBLIC(void) JDelete(J *item) { J *next = NULL; - while (item != NULL) - { + while (item != NULL) { next = item->next; - if (!(item->type & JIsReference) && (item->child != NULL)) - { + if (!(item->type & JIsReference) && (item->child != NULL)) { JDelete(item->child); } - if (!(item->type & JIsReference) && (item->valuestring != NULL)) - { + if (!(item->type & JIsReference) && (item->valuestring != NULL)) { _Free(item->valuestring); } - if (!(item->type & JStringIsConst) && (item->string != NULL)) - { + if (!(item->type & JStringIsConst) && (item->string != NULL)) { _Free(item->string); } _Free(item); @@ -209,8 +205,7 @@ static unsigned char get_decimal_point(void) #endif } -typedef struct -{ +typedef struct { const unsigned char *content; size_t length; size_t offset; @@ -234,41 +229,38 @@ static Jbool parse_number(J * const item, parse_buffer * const input_buffer) unsigned char decimal_point = get_decimal_point(); size_t i = 0; - if ((input_buffer == NULL) || (input_buffer->content == NULL)) - { + if ((input_buffer == NULL) || (input_buffer->content == NULL)) { return false; } /* copy the number into a temporary buffer and replace '.' with the decimal point * of the current locale (for strtod) * This also takes care of '\0' not necessarily being available for marking the end of the input */ - for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) - { - switch (buffer_at_offset(input_buffer)[i]) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '+': - case '-': - case 'e': - case 'E': - number_c_string[i] = buffer_at_offset(input_buffer)[i]; - break; + for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) { + switch (buffer_at_offset(input_buffer)[i]) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '+': + case '-': + case 'e': + case 'E': + number_c_string[i] = buffer_at_offset(input_buffer)[i]; + break; - case '.': - number_c_string[i] = decimal_point; - break; + case '.': + number_c_string[i] = decimal_point; + break; - default: - goto loop_end; + default: + goto loop_end; } } loop_end: @@ -280,25 +272,19 @@ static Jbool parse_number(J * const item, parse_buffer * const input_buffer) #else number = JAtoN((const char*)number_c_string, (char**)&after_end); #endif - if (number_c_string == after_end) - { + if (number_c_string == after_end) { return false; /* parse_error */ } item->valuenumber = number; /* use saturation in case of overflow */ - if (number >= INT_MAX) - { - item->valueint = INT_MAX; - } - else if (number <= INT_MIN) - { - item->valueint = INT_MIN; - } - else - { - item->valueint = (int)number; + if (number >= LONG_MAX) { + item->valueint = LONG_MAX; + } else if (number <= LONG_MIN) { + item->valueint = LONG_MIN; + } else { + item->valueint = (long int)number; } item->type = JNumber; @@ -310,24 +296,18 @@ static Jbool parse_number(J * const item, parse_buffer * const input_buffer) /* don't ask me, but the original JSetNumberValue returns an integer or JNUMBER */ N_CJSON_PUBLIC(JNUMBER) JSetNumberHelper(J *object, JNUMBER number) { - if (number >= INT_MAX) - { - object->valueint = INT_MAX; - } - else if (number <= INT_MIN) - { - object->valueint = INT_MIN; - } - else - { - object->valueint = (int)number; + if (number >= LONG_MAX) { + object->valueint = LONG_MAX; + } else if (number <= LONG_MIN) { + object->valueint = LONG_MIN; + } else { + object->valueint = (long int)number; } return object->valuenumber = number; } -typedef struct -{ +typedef struct { unsigned char *buffer; size_t length; size_t offset; @@ -342,26 +322,22 @@ static unsigned char* ensure(printbuffer * const p, size_t needed) unsigned char *newbuffer = NULL; size_t newsize = 0; - if ((p == NULL) || (p->buffer == NULL)) - { + if ((p == NULL) || (p->buffer == NULL)) { return NULL; } - if ((p->length > 0) && (p->offset >= p->length)) - { + if ((p->length > 0) && (p->offset >= p->length)) { /* make sure that offset is valid */ return NULL; } - if (needed > INT_MAX) - { + if (needed > INT_MAX) { /* sizes bigger than INT_MAX are currently not supported */ return NULL; } needed += p->offset + 1; - if (needed <= p->length) - { + if (needed <= p->length) { return p->buffer + p->offset; } @@ -370,34 +346,26 @@ static unsigned char* ensure(printbuffer * const p, size_t needed) } /* calculate new buffer size */ - if (needed > (INT_MAX / 2)) - { + if (needed > (INT_MAX / 2)) { /* overflow of int, use INT_MAX if possible */ - if (needed <= INT_MAX) - { + if (needed <= INT_MAX) { newsize = INT_MAX; - } - else - { + } else { return NULL; } - } - else - { + } else { newsize = needed * 2; } /* otherwise reallocate manually */ newbuffer = (unsigned char*)_Malloc(newsize); - if (!newbuffer) - { + if (!newbuffer) { _Free(p->buffer); p->length = 0; p->buffer = NULL; return NULL; } - if (newbuffer) - { + if (newbuffer) { memcpy(newbuffer, p->buffer, p->offset + 1); } _Free(p->buffer); @@ -412,8 +380,7 @@ static unsigned char* ensure(printbuffer * const p, size_t needed) static void update_offset(printbuffer * const buffer) { const unsigned char *buffer_pointer = NULL; - if ((buffer == NULL) || (buffer->buffer == NULL)) - { + if ((buffer == NULL) || (buffer->buffer == NULL)) { return; } buffer_pointer = buffer->buffer + buffer->offset; @@ -431,28 +398,23 @@ static Jbool print_number(const J * const item, printbuffer * const output_buffe unsigned char number_buffer[26]; /* temporary buffer to print the number into */ unsigned char decimal_point = get_decimal_point(); - if (output_buffer == NULL) - { + if (output_buffer == NULL) { return false; } /* This checks for NaN and Infinity */ - if ((d * 0) != 0) - { + if ((d * 0) != 0) { char *nbuf = (char *) number_buffer; strcpy(nbuf, "null"); length = strlen(nbuf); - } - else - { + } else { #if !MINIMIZE_CLIB_DEPENDENCIES JNUMBER test; /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ length = sprintf((char*)number_buffer, "%1.15g", d); /* Check whether the original double can be recovered */ - if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || ((JNUMBER)test != d)) - { + if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || ((JNUMBER)test != d)) { /* If not, print with 17 decimal places of precision */ length = sprintf((char*)number_buffer, "%1.17g", d); } @@ -464,24 +426,20 @@ static Jbool print_number(const J * const item, printbuffer * const output_buffe } /* conversion failed or buffer overrun occured */ - if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) - { + if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) { return false; } /* reserve appropriate space in the output */ output_pointer = ensure(output_buffer, (size_t)length + sizeof("")); - if (output_pointer == NULL) - { + if (output_pointer == NULL) { return false; } /* copy the printed number to the output and replace locale * dependent decimal point with '.' */ - for (i = 0; i < ((size_t)length); i++) - { - if (number_buffer[i] == decimal_point) - { + for (i = 0; i < ((size_t)length); i++) { + if (number_buffer[i] == decimal_point) { output_pointer[i] = '.'; continue; } @@ -496,33 +454,24 @@ static Jbool print_number(const J * const item, printbuffer * const output_buffe } /* parse 4 digit hexadecimal number */ -static unsigned parse_hex4(const unsigned char * const input) +static unsigned long parse_hex4(const unsigned char * const input) { - unsigned int h = 0; + unsigned long int h = 0; size_t i = 0; - for (i = 0; i < 4; i++) - { + for (i = 0; i < 4; i++) { /* parse digit */ - if ((input[i] >= '0') && (input[i] <= '9')) - { + if ((input[i] >= '0') && (input[i] <= '9')) { h += (unsigned int) input[i] - '0'; - } - else if ((input[i] >= 'A') && (input[i] <= 'F')) - { + } else if ((input[i] >= 'A') && (input[i] <= 'F')) { h += (unsigned int) 10 + input[i] - 'A'; - } - else if ((input[i] >= 'a') && (input[i] <= 'f')) - { + } else if ((input[i] >= 'a') && (input[i] <= 'f')) { h += (unsigned int) 10 + input[i] - 'a'; - } - else /* invalid */ - { + } else { /* invalid */ return 0; } - if (i < 3) - { + if (i < 3) { /* shift left to make place for the next nibble */ h = h << 4; } @@ -536,15 +485,14 @@ static unsigned parse_hex4(const unsigned char * const input) static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer) { long unsigned int codepoint = 0; - unsigned int first_code = 0; + unsigned long int first_code = 0; const unsigned char *first_sequence = input_pointer; unsigned char utf8_length = 0; unsigned char utf8_position = 0; unsigned char sequence_length = 0; unsigned char first_byte_mark = 0; - if ((input_end - first_sequence) < 6) - { + if ((input_end - first_sequence) < 6) { /* input ends unexpectedly */ goto fail; } @@ -553,26 +501,22 @@ static unsigned char utf16_literal_to_utf8(const unsigned char * const input_poi first_code = parse_hex4(first_sequence + 2); /* check that the code is valid */ - if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) - { + if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) { goto fail; } /* UTF16 surrogate pair */ - if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) - { + if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) { const unsigned char *second_sequence = first_sequence + 6; unsigned int second_code = 0; sequence_length = 12; /* \uXXXX\uXXXX */ - if ((input_end - second_sequence) < 6) - { + if ((input_end - second_sequence) < 6) { /* input ends unexpectedly */ goto fail; } - if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) - { + if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) { /* missing second half of the surrogate pair */ goto fail; } @@ -580,8 +524,7 @@ static unsigned char utf16_literal_to_utf8(const unsigned char * const input_poi /* get the second utf16 sequence */ second_code = parse_hex4(second_sequence + 2); /* check that the code is valid */ - if ((second_code < 0xDC00) || (second_code > 0xDFFF)) - { + if ((second_code < 0xDC00) || (second_code > 0xDFFF)) { /* invalid second half of the surrogate pair */ goto fail; } @@ -589,9 +532,7 @@ static unsigned char utf16_literal_to_utf8(const unsigned char * const input_poi /* calculate the unicode codepoint from the surrogate pair */ codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); - } - else - { + } else { sequence_length = 6; /* \uXXXX */ codepoint = first_code; } @@ -599,49 +540,36 @@ static unsigned char utf16_literal_to_utf8(const unsigned char * const input_poi /* encode as UTF-8 * takes at maximum 4 bytes to encode: * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ - if (codepoint < 0x80) - { + if (codepoint < 0x80) { /* normal ascii, encoding 0xxxxxxx */ utf8_length = 1; - } - else if (codepoint < 0x800) - { + } else if (codepoint < 0x800) { /* two bytes, encoding 110xxxxx 10xxxxxx */ utf8_length = 2; first_byte_mark = 0xC0; /* 11000000 */ - } - else if (codepoint < 0x10000) - { + } else if (codepoint < 0x10000) { /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ utf8_length = 3; first_byte_mark = 0xE0; /* 11100000 */ - } - else if (codepoint <= 0x10FFFF) - { + } else if (codepoint <= 0x10FFFF) { /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ utf8_length = 4; first_byte_mark = 0xF0; /* 11110000 */ - } - else - { + } else { /* invalid unicode codepoint */ goto fail; } /* encode as utf8 */ - for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) - { + for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) { /* 10xxxxxx */ (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF); codepoint >>= 6; } /* encode first byte */ - if (utf8_length > 1) - { + if (utf8_length > 1) { (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF); - } - else - { + } else { (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F); } @@ -662,8 +590,7 @@ static Jbool parse_string(J * const item, parse_buffer * const input_buffer) unsigned char *output = NULL; /* not a string */ - if (buffer_at_offset(input_buffer)[0] != '\"') - { + if (buffer_at_offset(input_buffer)[0] != '\"') { goto fail; } @@ -671,13 +598,10 @@ static Jbool parse_string(J * const item, parse_buffer * const input_buffer) /* calculate approximate size of the output (overestimate) */ size_t allocation_length = 0; size_t skipped_bytes = 0; - while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) - { + while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) { /* is escape sequence */ - if (input_end[0] == '\\') - { - if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) - { + if (input_end[0] == '\\') { + if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) { /* prevent buffer overflow when last input character is a backslash */ goto fail; } @@ -686,72 +610,64 @@ static Jbool parse_string(J * const item, parse_buffer * const input_buffer) } input_end++; } - if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) - { + if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) { goto fail; /* string ended unexpectedly */ } /* This is at most how much we need for the output */ allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes; - output = (unsigned char*)_Malloc(allocation_length + 1); // trailing '\0' - if (output == NULL) - { + output = (unsigned char*)_Malloc(allocation_length + 1); // trailing '\0' + if (output == NULL) { goto fail; /* allocation failure */ } } output_pointer = output; /* loop through the string literal */ - while (input_pointer < input_end) - { - if (*input_pointer != '\\') - { + while (input_pointer < input_end) { + if (*input_pointer != '\\') { *output_pointer++ = *input_pointer++; } /* escape sequence */ - else - { + else { unsigned char sequence_length = 2; - if ((input_end - input_pointer) < 1) - { + if ((input_end - input_pointer) < 1) { goto fail; } - switch (input_pointer[1]) - { - case 'b': - *output_pointer++ = '\b'; - break; - case 'f': - *output_pointer++ = '\f'; - break; - case 'n': - *output_pointer++ = '\n'; - break; - case 'r': - *output_pointer++ = '\r'; - break; - case 't': - *output_pointer++ = '\t'; - break; - case '\"': - case '\\': - case '/': - *output_pointer++ = input_pointer[1]; - break; - - /* UTF-16 literal */ - case 'u': - sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); - if (sequence_length == 0) - { - /* failed to convert UTF16-literal to UTF-8 */ - goto fail; - } - break; - - default: + switch (input_pointer[1]) { + case 'b': + *output_pointer++ = '\b'; + break; + case 'f': + *output_pointer++ = '\f'; + break; + case 'n': + *output_pointer++ = '\n'; + break; + case 'r': + *output_pointer++ = '\r'; + break; + case 't': + *output_pointer++ = '\t'; + break; + case '\"': + case '\\': + case '/': + *output_pointer++ = input_pointer[1]; + break; + + /* UTF-16 literal */ + case 'u': + sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); + if (sequence_length == 0) { + /* failed to convert UTF16-literal to UTF-8 */ goto fail; + } + break; + + default: + goto fail; } input_pointer += sequence_length; } @@ -769,13 +685,11 @@ static Jbool parse_string(J * const item, parse_buffer * const input_buffer) return true; fail: - if (output != NULL) - { + if (output != NULL) { _Free(output); } - if (input_pointer != NULL) - { + if (input_pointer != NULL) { input_buffer->offset = (size_t)(input_pointer - input_buffer->content); } @@ -786,14 +700,14 @@ static Jbool parse_string(J * const item, parse_buffer * const input_buffer) void htoa16(uint16_t n, unsigned char *p) { int i; - for (i=0; i<4; i++) - { + for (i=0; i<4; i++) { uint16_t nibble = (n >> 12) & 0xff; n = n << 4; - if (nibble >= 10) + if (nibble >= 10) { *p++ = 'A' + (nibble-10); - else + } else { *p++ = '0' + nibble; + } } *p = '\0'; } @@ -808,61 +722,53 @@ static Jbool print_string_ptr(const unsigned char * const input, printbuffer * c /* numbers of additional characters needed for escaping */ size_t escape_characters = 0; - if (output_buffer == NULL) - { + if (output_buffer == NULL) { return false; } /* empty string */ - if (input == NULL) - { - output = ensure(output_buffer, 2); // sizeof("\"\"") - if (output == NULL) - { + if (input == NULL) { + output = ensure(output_buffer, 2); // sizeof("\"\"") + if (output == NULL) { return false; } - output[0] = '"'; - output[1] = '"'; - output[2] = '\0'; + output[0] = '"'; + output[1] = '"'; + output[2] = '\0'; return true; } /* set "flag" to 1 if something needs to be escaped */ - for (input_pointer = input; *input_pointer; input_pointer++) - { - switch (*input_pointer) - { - case '\"': - case '\\': - case '\b': - case '\f': - case '\n': - case '\r': - case '\t': - /* one character escape sequence */ - escape_characters++; - break; - default: - if (*input_pointer < 32) - { - /* UTF-16 escape sequence uXXXX */ - escape_characters += 5; - } - break; + for (input_pointer = input; *input_pointer; input_pointer++) { + switch (*input_pointer) { + case '\"': + case '\\': + case '\b': + case '\f': + case '\n': + case '\r': + case '\t': + /* one character escape sequence */ + escape_characters++; + break; + default: + if (*input_pointer < 32) { + /* UTF-16 escape sequence uXXXX */ + escape_characters += 5; + } + break; } } output_length = (size_t)(input_pointer - input) + escape_characters; - output = ensure(output_buffer, output_length + 2); // sizeof("\"\"") - if (output == NULL) - { + output = ensure(output_buffer, output_length + 2); // sizeof("\"\"") + if (output == NULL) { return false; } /* no characters have to be escaped */ - if (escape_characters == 0) - { + if (escape_characters == 0) { output[0] = '\"'; memcpy(output + 1, input, output_length); output[output_length + 1] = '\"'; @@ -874,46 +780,41 @@ static Jbool print_string_ptr(const unsigned char * const input, printbuffer * c output[0] = '\"'; output_pointer = output + 1; /* copy the string */ - for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) - { - if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) - { + for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) { + if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) { /* normal character, copy */ *output_pointer = *input_pointer; - } - else - { + } else { /* character needs to be escaped */ *output_pointer++ = '\\'; - switch (*input_pointer) - { - case '\\': - *output_pointer = '\\'; - break; - case '\"': - *output_pointer = '\"'; - break; - case '\b': - *output_pointer = 'b'; - break; - case '\f': - *output_pointer = 'f'; - break; - case '\n': - *output_pointer = 'n'; - break; - case '\r': - *output_pointer = 'r'; - break; - case '\t': - *output_pointer = 't'; - break; - default: - /* escape and print as unicode codepoint */ - *output_pointer++ = 'u'; - htoa16(*input_pointer, output_pointer); - output_pointer += 4; - break; + switch (*input_pointer) { + case '\\': + *output_pointer = '\\'; + break; + case '\"': + *output_pointer = '\"'; + break; + case '\b': + *output_pointer = 'b'; + break; + case '\f': + *output_pointer = 'f'; + break; + case '\n': + *output_pointer = 'n'; + break; + case '\r': + *output_pointer = 'r'; + break; + case '\t': + *output_pointer = 't'; + break; + default: + /* escape and print as unicode codepoint */ + *output_pointer++ = 'u'; + htoa16(*input_pointer, output_pointer); + output_pointer += 4; + break; } } } @@ -940,18 +841,15 @@ static Jbool print_object(const J * const item, printbuffer * const output_buffe /* Utility to jump whitespace and cr/lf */ static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) { - if ((buffer == NULL) || (buffer->content == NULL)) - { + if ((buffer == NULL) || (buffer->content == NULL)) { return NULL; } - while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) - { - buffer->offset++; + while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) { + buffer->offset++; } - if (buffer->offset == buffer->length) - { + if (buffer->offset == buffer->length) { buffer->offset--; } @@ -961,13 +859,11 @@ static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) /* skip the UTF-8 BOM (byte order mark) if it is at the beginning of a buffer */ static parse_buffer *skip_utf8_bom(parse_buffer * const buffer) { - if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) - { + if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) { return NULL; } - if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) - { + if (can_access_at_index(buffer, 4) && (strncmp((const char*)buffer_at_offset(buffer), "\xEF\xBB\xBF", 3) == 0)) { buffer->offset += 3; } @@ -984,66 +880,54 @@ N_CJSON_PUBLIC(J *) JParseWithOpts(const char *value, const char **return_parse_ global_error.json = NULL; global_error.position = 0; - if (value == NULL) - { + if (value == NULL) { goto fail; } buffer.content = (const unsigned char*)value; - buffer.length = strlen((const char*)value) + 1; // Trailing '\0' + buffer.length = strlen((const char*)value) + 1; // Trailing '\0' buffer.offset = 0; item = JNew_Item(); - if (item == NULL) /* memory fail */ - { + if (item == NULL) { /* memory fail */ goto fail; } - if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) - { + if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))) { /* parse failure. ep is set. */ goto fail; } /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ - if (require_null_terminated) - { + if (require_null_terminated) { buffer_skip_whitespace(&buffer); - if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') - { + if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') { goto fail; } } - if (return_parse_end) - { + if (return_parse_end) { *return_parse_end = (const char*)buffer_at_offset(&buffer); } return item; fail: - if (item != NULL) - { + if (item != NULL) { JDelete(item); } - if (value != NULL) - { + if (value != NULL) { error local_error; local_error.json = (const unsigned char*)value; local_error.position = 0; - if (buffer.offset < buffer.length) - { + if (buffer.offset < buffer.length) { local_error.position = buffer.offset; - } - else if (buffer.length > 0) - { + } else if (buffer.length > 0) { local_error.position = buffer.length - 1; } - if (return_parse_end != NULL) - { + if (return_parse_end != NULL) { *return_parse_end = (const char*)local_error.json + local_error.position; } @@ -1073,22 +957,19 @@ static unsigned char *print(const J * const item, Jbool format) buffer->buffer = (unsigned char*) _Malloc(default_buffer_size); buffer->length = default_buffer_size; buffer->format = format; - if (buffer->buffer == NULL) - { + if (buffer->buffer == NULL) { goto fail; } /* print the value */ - if (!print_value(item, buffer)) - { + if (!print_value(item, buffer)) { goto fail; } update_offset(buffer); /* copy the JSON over to a new buffer */ printed = (unsigned char*) _Malloc(buffer->offset + 1); - if (printed == NULL) - { + if (printed == NULL) { goto fail; } memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1)); @@ -1100,13 +981,11 @@ static unsigned char *print(const J * const item, Jbool format) return printed; fail: - if (buffer->buffer != NULL) - { + if (buffer->buffer != NULL) { _Free(buffer->buffer); } - if (printed != NULL) - { + if (printed != NULL) { _Free(printed); } @@ -1128,14 +1007,12 @@ N_CJSON_PUBLIC(char *) JPrintBuffered(const J *item, int prebuffer, Jbool fmt) { printbuffer p = { 0, 0, 0, 0, 0, 0 }; - if (prebuffer < 0) - { + if (prebuffer < 0) { return NULL; } p.buffer = (unsigned char*)_Malloc((size_t)prebuffer); - if (!p.buffer) - { + if (!p.buffer) { return NULL; } @@ -1144,8 +1021,7 @@ N_CJSON_PUBLIC(char *) JPrintBuffered(const J *item, int prebuffer, Jbool fmt) p.noalloc = false; p.format = fmt; - if (!print_value(item, &p)) - { + if (!print_value(item, &p)) { _Free(p.buffer); return NULL; } @@ -1157,8 +1033,7 @@ N_CJSON_PUBLIC(Jbool) JPrintPreallocated(J *item, char *buf, const int len, cons { printbuffer p = { 0, 0, 0, 0, 0, 0 }; - if ((len < 0) || (buf == NULL)) - { + if ((len < 0) || (buf == NULL)) { return false; } @@ -1174,52 +1049,44 @@ N_CJSON_PUBLIC(Jbool) JPrintPreallocated(J *item, char *buf, const int len, cons /* Parser core - when encountering text, process appropriately. */ static Jbool parse_value(J * const item, parse_buffer * const input_buffer) { - if ((input_buffer == NULL) || (input_buffer->content == NULL)) - { + if ((input_buffer == NULL) || (input_buffer->content == NULL)) { return false; /* no input */ } /* parse the different types of values */ /* null */ - if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), c_null, c_null_len) == 0)) - { + if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), c_null, c_null_len) == 0)) { item->type = JNULL; input_buffer->offset += 4; return true; } /* false */ - if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), c_false, c_false_len) == 0)) - { + if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), c_false, c_false_len) == 0)) { item->type = JFalse; input_buffer->offset += 5; return true; } /* true */ - if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), c_true, c_true_len) == 0)) - { + if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), c_true, c_true_len) == 0)) { item->type = JTrue; item->valueint = 1; input_buffer->offset += 4; return true; } /* string */ - if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) - { + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) { return parse_string(item, input_buffer); } /* number */ - if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) - { + if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) { return parse_number(item, input_buffer); } /* array */ - if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) - { + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) { return parse_array(item, input_buffer); } /* object */ - if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) - { + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) { return parse_object(item, input_buffer); } @@ -1231,72 +1098,64 @@ static Jbool print_value(const J * const item, printbuffer * const output_buffer { unsigned char *output = NULL; - if ((item == NULL) || (output_buffer == NULL)) - { + if ((item == NULL) || (output_buffer == NULL)) { return false; } - switch ((item->type) & 0xFF) - { - case JNULL: - output = ensure(output_buffer, c_null_len+1); - if (output == NULL) - { - return false; - } - strcpy((char*)output, c_null); - return true; + switch ((item->type) & 0xFF) { + case JNULL: + output = ensure(output_buffer, c_null_len+1); + if (output == NULL) { + return false; + } + strcpy((char*)output, c_null); + return true; - case JFalse: - output = ensure(output_buffer, c_false_len+1); - if (output == NULL) - { - return false; - } - strcpy((char*)output, c_false); - return true; + case JFalse: + output = ensure(output_buffer, c_false_len+1); + if (output == NULL) { + return false; + } + strcpy((char*)output, c_false); + return true; - case JTrue: - output = ensure(output_buffer, c_true_len+1); - if (output == NULL) - { - return false; - } - strcpy((char*)output, c_true); - return true; + case JTrue: + output = ensure(output_buffer, c_true_len+1); + if (output == NULL) { + return false; + } + strcpy((char*)output, c_true); + return true; - case JNumber: - return print_number(item, output_buffer); + case JNumber: + return print_number(item, output_buffer); - case JRaw: - { - size_t raw_length = 0; - if (item->valuestring == NULL) - { - return false; - } + case JRaw: { + size_t raw_length = 0; + if (item->valuestring == NULL) { + return false; + } - raw_length = strlen(item->valuestring) + 1; // Trailing '\0'; - output = ensure(output_buffer, raw_length); - if (output == NULL) - { - return false; - } - memcpy(output, item->valuestring, raw_length); - return true; + raw_length = strlen(item->valuestring) + 1; // Trailing '\0'; + output = ensure(output_buffer, raw_length); + if (output == NULL) { + return false; } + memcpy(output, item->valuestring, raw_length); + return true; + } - case JString: - return print_string(item, output_buffer); + case JString: + return print_string(item, output_buffer); - case JArray: - return print_array(item, output_buffer); + case JArray: + return print_array(item, output_buffer); - case JObject: - return print_object(item, output_buffer); + case JObject: + return print_object(item, output_buffer); - default: - return false; + default: + return false; } } @@ -1306,29 +1165,25 @@ static Jbool parse_array(J * const item, parse_buffer * const input_buffer) J *head = NULL; /* head of the linked list */ J *current_item = NULL; - if (input_buffer->depth >= N_CJSON_NESTING_LIMIT) - { + if (input_buffer->depth >= N_CJSON_NESTING_LIMIT) { return false; /* to deeply nested */ } input_buffer->depth++; - if (buffer_at_offset(input_buffer)[0] != '[') - { + if (buffer_at_offset(input_buffer)[0] != '[') { /* not an array */ goto fail; } input_buffer->offset++; buffer_skip_whitespace(input_buffer); - if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) - { + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) { /* empty array */ goto success; } /* check if we skipped to the end of the buffer */ - if (cannot_access_at_index(input_buffer, 0)) - { + if (cannot_access_at_index(input_buffer, 0)) { input_buffer->offset--; goto fail; } @@ -1336,23 +1191,18 @@ static Jbool parse_array(J * const item, parse_buffer * const input_buffer) /* step back to character in front of the first element */ input_buffer->offset--; /* loop through the comma separated array elements */ - do - { + do { /* allocate next item */ J *new_item = JNew_Item(); - if (new_item == NULL) - { + if (new_item == NULL) { goto fail; /* allocation failure */ } /* attach next item to list */ - if (head == NULL) - { + if (head == NULL) { /* start the linked list */ current_item = head = new_item; - } - else - { + } else { /* add to the end and advance */ current_item->next = new_item; new_item->prev = current_item; @@ -1362,16 +1212,13 @@ static Jbool parse_array(J * const item, parse_buffer * const input_buffer) /* parse next value */ input_buffer->offset++; buffer_skip_whitespace(input_buffer); - if (!parse_value(current_item, input_buffer)) - { + if (!parse_value(current_item, input_buffer)) { goto fail; /* failed to parse value */ } buffer_skip_whitespace(input_buffer); - } - while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); - if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') - { + if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') { goto fail; /* expected end of array */ } @@ -1386,8 +1233,7 @@ static Jbool parse_array(J * const item, parse_buffer * const input_buffer) return true; fail: - if (head != NULL) - { + if (head != NULL) { JDelete(head); } @@ -1401,16 +1247,14 @@ static Jbool print_array(const J * const item, printbuffer * const output_buffer size_t length = 0; J *current_element = item->child; - if (output_buffer == NULL) - { + if (output_buffer == NULL) { return false; } /* Compose the output array. */ /* opening square bracket */ output_pointer = ensure(output_buffer, 1); - if (output_pointer == NULL) - { + if (output_pointer == NULL) { return false; } @@ -1418,24 +1262,19 @@ static Jbool print_array(const J * const item, printbuffer * const output_buffer output_buffer->offset++; output_buffer->depth++; - while (current_element != NULL) - { - if (!print_value(current_element, output_buffer)) - { + while (current_element != NULL) { + if (!print_value(current_element, output_buffer)) { return false; } update_offset(output_buffer); - if (current_element->next) - { + if (current_element->next) { length = (size_t) (output_buffer->format ? 2 : 1); output_pointer = ensure(output_buffer, length + 1); - if (output_pointer == NULL) - { + if (output_pointer == NULL) { return false; } *output_pointer++ = ','; - if(output_buffer->format) - { + if(output_buffer->format) { *output_pointer++ = ' '; } *output_pointer = '\0'; @@ -1445,8 +1284,7 @@ static Jbool print_array(const J * const item, printbuffer * const output_buffer } output_pointer = ensure(output_buffer, 2); - if (output_pointer == NULL) - { + if (output_pointer == NULL) { return false; } *output_pointer++ = ']'; @@ -1462,27 +1300,23 @@ static Jbool parse_object(J * const item, parse_buffer * const input_buffer) J *head = NULL; /* linked list head */ J *current_item = NULL; - if (input_buffer->depth >= N_CJSON_NESTING_LIMIT) - { + if (input_buffer->depth >= N_CJSON_NESTING_LIMIT) { return false; /* to deeply nested */ } input_buffer->depth++; - if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) - { + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) { goto fail; /* not an object */ } input_buffer->offset++; buffer_skip_whitespace(input_buffer); - if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) - { + if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) { goto success; /* empty object */ } /* check if we skipped to the end of the buffer */ - if (cannot_access_at_index(input_buffer, 0)) - { + if (cannot_access_at_index(input_buffer, 0)) { input_buffer->offset--; goto fail; } @@ -1490,23 +1324,18 @@ static Jbool parse_object(J * const item, parse_buffer * const input_buffer) /* step back to character in front of the first element */ input_buffer->offset--; /* loop through the comma separated array elements */ - do - { + do { /* allocate next item */ J *new_item = JNew_Item(); - if (new_item == NULL) - { + if (new_item == NULL) { goto fail; /* allocation failure */ } /* attach next item to list */ - if (head == NULL) - { + if (head == NULL) { /* start the linked list */ current_item = head = new_item; - } - else - { + } else { /* add to the end and advance */ current_item->next = new_item; new_item->prev = current_item; @@ -1516,8 +1345,7 @@ static Jbool parse_object(J * const item, parse_buffer * const input_buffer) /* parse the name of the child */ input_buffer->offset++; buffer_skip_whitespace(input_buffer); - if (!parse_string(current_item, input_buffer)) - { + if (!parse_string(current_item, input_buffer)) { goto fail; /* faile to parse name */ } buffer_skip_whitespace(input_buffer); @@ -1526,24 +1354,20 @@ static Jbool parse_object(J * const item, parse_buffer * const input_buffer) current_item->string = current_item->valuestring; current_item->valuestring = NULL; - if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) - { + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) { goto fail; /* invalid object */ } /* parse the value */ input_buffer->offset++; buffer_skip_whitespace(input_buffer); - if (!parse_value(current_item, input_buffer)) - { + if (!parse_value(current_item, input_buffer)) { goto fail; /* failed to parse value */ } buffer_skip_whitespace(input_buffer); - } - while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); + } while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); - if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) - { + if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) { goto fail; /* expected end of object */ } @@ -1557,8 +1381,7 @@ static Jbool parse_object(J * const item, parse_buffer * const input_buffer) return true; fail: - if (head != NULL) - { + if (head != NULL) { JDelete(head); } @@ -1572,67 +1395,56 @@ static Jbool print_object(const J * const item, printbuffer * const output_buffe size_t length = 0; J *current_item = item->child; - if (output_buffer == NULL) - { + if (output_buffer == NULL) { return false; } /* Compose the output: */ length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */ output_pointer = ensure(output_buffer, length + 1); - if (output_pointer == NULL) - { + if (output_pointer == NULL) { return false; } *output_pointer++ = '{'; output_buffer->depth++; - if (output_buffer->format) - { + if (output_buffer->format) { *output_pointer++ = '\n'; } output_buffer->offset += length; - while (current_item) - { - if (output_buffer->format) - { + while (current_item) { + if (output_buffer->format) { size_t i; output_pointer = ensure(output_buffer, output_buffer->depth); - if (output_pointer == NULL) - { + if (output_pointer == NULL) { return false; } - for (i = 0; i < output_buffer->depth; i++) - { + for (i = 0; i < output_buffer->depth; i++) { *output_pointer++ = '\t'; } output_buffer->offset += output_buffer->depth; } /* print key */ - if (!print_string_ptr((unsigned char*)current_item->string, output_buffer)) - { + if (!print_string_ptr((unsigned char*)current_item->string, output_buffer)) { return false; } update_offset(output_buffer); length = (size_t) (output_buffer->format ? 2 : 1); output_pointer = ensure(output_buffer, length); - if (output_pointer == NULL) - { + if (output_pointer == NULL) { return false; } *output_pointer++ = ':'; - if (output_buffer->format) - { + if (output_buffer->format) { *output_pointer++ = '\t'; } output_buffer->offset += length; /* print value */ - if (!print_value(current_item, output_buffer)) - { + if (!print_value(current_item, output_buffer)) { return false; } update_offset(output_buffer); @@ -1640,17 +1452,14 @@ static Jbool print_object(const J * const item, printbuffer * const output_buffe /* print comma if not last */ length = (size_t) ((output_buffer->format ? 1 : 0) + (current_item->next ? 1 : 0)); output_pointer = ensure(output_buffer, length + 1); - if (output_pointer == NULL) - { + if (output_pointer == NULL) { return false; } - if (current_item->next) - { + if (current_item->next) { *output_pointer++ = ','; } - if (output_buffer->format) - { + if (output_buffer->format) { *output_pointer++ = '\n'; } *output_pointer = '\0'; @@ -1660,15 +1469,12 @@ static Jbool print_object(const J * const item, printbuffer * const output_buffe } output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2); - if (output_pointer == NULL) - { + if (output_pointer == NULL) { return false; } - if (output_buffer->format) - { + if (output_buffer->format) { size_t i; - for (i = 0; i < (output_buffer->depth - 1); i++) - { + for (i = 0; i < (output_buffer->depth - 1); i++) { *output_pointer++ = '\t'; } } @@ -1685,15 +1491,13 @@ N_CJSON_PUBLIC(int) JGetArraySize(const J *array) J *child = NULL; size_t size = 0; - if (array == NULL) - { + if (array == NULL) { return 0; } child = array->child; - while(child != NULL) - { + while(child != NULL) { size++; child = child->next; } @@ -1707,14 +1511,12 @@ static J* get_array_item(const J *array, size_t index) { J *current_child = NULL; - if (array == NULL) - { + if (array == NULL) { return NULL; } current_child = array->child; - while ((current_child != NULL) && (index > 0)) - { + while ((current_child != NULL) && (index > 0)) { index--; current_child = current_child->next; } @@ -1724,8 +1526,7 @@ static J* get_array_item(const J *array, size_t index) N_CJSON_PUBLIC(J *) JGetArrayItem(const J *array, int index) { - if (index < 0) - { + if (index < 0) { return NULL; } @@ -1736,23 +1537,17 @@ static J *get_object_item(const J * const object, const char * const name, const { J *current_element = NULL; - if ((object == NULL) || (name == NULL)) - { + if ((object == NULL) || (name == NULL)) { return NULL; } current_element = object->child; - if (case_sensitive) - { - while ((current_element != NULL) && (strcmp(name, current_element->string) != 0)) - { + if (case_sensitive) { + while ((current_element != NULL) && (strcmp(name, current_element->string) != 0)) { current_element = current_element->next; } - } - else - { - while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) - { + } else { + while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) { current_element = current_element->next; } } @@ -1786,14 +1581,12 @@ static void suffix_object(J *prev, J *item) static J *create_reference(const J *item) { J *reference = NULL; - if (item == NULL) - { + if (item == NULL) { return NULL; } reference = JNew_Item(); - if (reference == NULL) - { + if (reference == NULL) { return NULL; } @@ -1808,23 +1601,18 @@ static Jbool add_item_to_array(J *array, J *item) { J *child = NULL; - if ((item == NULL) || (array == NULL)) - { + if ((item == NULL) || (array == NULL)) { return false; } child = array->child; - if (child == NULL) - { + if (child == NULL) { /* list is empty, start new one */ array->child = item; - } - else - { + } else { /* append to the end */ - while (child->next) - { + while (child->next) { child = child->next; } suffix_object(child, item); @@ -1840,7 +1628,7 @@ N_CJSON_PUBLIC(void) JAddItemToArray(J *array, J *item) } #if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) - #pragma GCC diagnostic push +#pragma GCC diagnostic push #endif #ifdef __GNUC__ #pragma GCC diagnostic ignored "-Wcast-qual" @@ -1851,7 +1639,7 @@ static void* cast_away_const(const void* string) return (void*)string; } #if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) - #pragma GCC diagnostic pop +#pragma GCC diagnostic pop #endif @@ -1860,29 +1648,23 @@ static Jbool add_item_to_object(J * const object, const char * const string, J * char *new_key = NULL; int new_type = JInvalid; - if ((object == NULL) || (string == NULL) || (item == NULL)) - { + if ((object == NULL) || (string == NULL) || (item == NULL)) { return false; } - if (constant_key) - { + if (constant_key) { new_key = (char*)cast_away_const(string); new_type = item->type | JStringIsConst; - } - else - { + } else { new_key = (char*)Jstrdup((const unsigned char*)string); - if (new_key == NULL) - { + if (new_key == NULL) { return false; } new_type = item->type & ~JStringIsConst; } - if (!(item->type & JStringIsConst) && (item->string != NULL)) - { + if (!(item->type & JStringIsConst) && (item->string != NULL)) { _Free(item->string); } @@ -1905,8 +1687,7 @@ N_CJSON_PUBLIC(void) JAddItemToObjectCS(J *object, const char *string, J *item) N_CJSON_PUBLIC(void) JAddItemReferenceToArray(J *array, J *item) { - if (array == NULL) - { + if (array == NULL) { return; } @@ -1915,8 +1696,7 @@ N_CJSON_PUBLIC(void) JAddItemReferenceToArray(J *array, J *item) N_CJSON_PUBLIC(void) JAddItemReferenceToObject(J *object, const char *string, J *item) { - if ((object == NULL) || (string == NULL)) - { + if ((object == NULL) || (string == NULL)) { return; } @@ -1926,8 +1706,7 @@ N_CJSON_PUBLIC(void) JAddItemReferenceToObject(J *object, const char *string, J N_CJSON_PUBLIC(J*) JAddNullToObject(J * const object, const char * const name) { J *null = JCreateNull(); - if (add_item_to_object(object, name, null, false)) - { + if (add_item_to_object(object, name, null, false)) { return null; } @@ -1938,8 +1717,7 @@ N_CJSON_PUBLIC(J*) JAddNullToObject(J * const object, const char * const name) N_CJSON_PUBLIC(J*) JAddTrueToObject(J * const object, const char * const name) { J *true_item = JCreateTrue(); - if (add_item_to_object(object, name, true_item, false)) - { + if (add_item_to_object(object, name, true_item, false)) { return true_item; } @@ -1950,8 +1728,7 @@ N_CJSON_PUBLIC(J*) JAddTrueToObject(J * const object, const char * const name) N_CJSON_PUBLIC(J*) JAddFalseToObject(J * const object, const char * const name) { J *false_item = JCreateFalse(); - if (add_item_to_object(object, name, false_item, false)) - { + if (add_item_to_object(object, name, false_item, false)) { return false_item; } @@ -1962,8 +1739,7 @@ N_CJSON_PUBLIC(J*) JAddFalseToObject(J * const object, const char * const name) N_CJSON_PUBLIC(J*) JAddBoolToObject(J * const object, const char * const name, const Jbool boolean) { J *bool_item = JCreateBool(boolean); - if (add_item_to_object(object, name, bool_item, false)) - { + if (add_item_to_object(object, name, bool_item, false)) { return bool_item; } @@ -1974,8 +1750,7 @@ N_CJSON_PUBLIC(J*) JAddBoolToObject(J * const object, const char * const name, c N_CJSON_PUBLIC(J*) JAddNumberToObject(J * const object, const char * const name, const JNUMBER number) { J *number_item = JCreateNumber(number); - if (add_item_to_object(object, name, number_item, false)) - { + if (add_item_to_object(object, name, number_item, false)) { return number_item; } @@ -1986,8 +1761,7 @@ N_CJSON_PUBLIC(J*) JAddNumberToObject(J * const object, const char * const name, N_CJSON_PUBLIC(J*) JAddStringToObject(J * const object, const char * const name, const char * const string) { J *string_item = JCreateString(string); - if (add_item_to_object(object, name, string_item, false)) - { + if (add_item_to_object(object, name, string_item, false)) { return string_item; } @@ -1998,8 +1772,7 @@ N_CJSON_PUBLIC(J*) JAddStringToObject(J * const object, const char * const name, N_CJSON_PUBLIC(J*) JAddRawToObject(J * const object, const char * const name, const char * const raw) { J *raw_item = JCreateRaw(raw); - if (add_item_to_object(object, name, raw_item, false)) - { + if (add_item_to_object(object, name, raw_item, false)) { return raw_item; } @@ -2010,8 +1783,7 @@ N_CJSON_PUBLIC(J*) JAddRawToObject(J * const object, const char * const name, co N_CJSON_PUBLIC(J*) JAddObjectToObject(J * const object, const char * const name) { J *object_item = JCreateObject(); - if (add_item_to_object(object, name, object_item, false)) - { + if (add_item_to_object(object, name, object_item, false)) { return object_item; } @@ -2022,8 +1794,7 @@ N_CJSON_PUBLIC(J*) JAddObjectToObject(J * const object, const char * const name) N_CJSON_PUBLIC(J*) JAddArrayToObject(J * const object, const char * const name) { J *array = JCreateArray(); - if (add_item_to_object(object, name, array, false)) - { + if (add_item_to_object(object, name, array, false)) { return array; } @@ -2033,24 +1804,20 @@ N_CJSON_PUBLIC(J*) JAddArrayToObject(J * const object, const char * const name) N_CJSON_PUBLIC(J *) JDetachItemViaPointer(J *parent, J * const item) { - if ((parent == NULL) || (item == NULL)) - { + if ((parent == NULL) || (item == NULL)) { return NULL; } - if (item->prev != NULL) - { + if (item->prev != NULL) { /* not the first element */ item->prev->next = item->next; } - if (item->next != NULL) - { + if (item->next != NULL) { /* not the last element */ item->next->prev = item->prev; } - if (item == parent->child) - { + if (item == parent->child) { /* first element */ parent->child = item->next; } @@ -2063,8 +1830,7 @@ N_CJSON_PUBLIC(J *) JDetachItemViaPointer(J *parent, J * const item) N_CJSON_PUBLIC(J *) JDetachItemFromArray(J *array, int which) { - if (which < 0) - { + if (which < 0) { return NULL; } @@ -2105,14 +1871,12 @@ N_CJSON_PUBLIC(void) JInsertItemInArray(J *array, int which, J *newitem) { J *after_inserted = NULL; - if (which < 0) - { + if (which < 0) { return; } after_inserted = get_array_item(array, (size_t)which); - if (after_inserted == NULL) - { + if (after_inserted == NULL) { add_item_to_array(array, newitem); return; } @@ -2120,41 +1884,33 @@ N_CJSON_PUBLIC(void) JInsertItemInArray(J *array, int which, J *newitem) newitem->next = after_inserted; newitem->prev = after_inserted->prev; after_inserted->prev = newitem; - if (after_inserted == array->child) - { + if (after_inserted == array->child) { array->child = newitem; - } - else - { + } else { newitem->prev->next = newitem; } } N_CJSON_PUBLIC(Jbool) JReplaceItemViaPointer(J * const parent, J * const item, J * replacement) { - if ((parent == NULL) || (replacement == NULL) || (item == NULL)) - { + if ((parent == NULL) || (replacement == NULL) || (item == NULL)) { return false; } - if (replacement == item) - { + if (replacement == item) { return true; } replacement->next = item->next; replacement->prev = item->prev; - if (replacement->next != NULL) - { + if (replacement->next != NULL) { replacement->next->prev = replacement; } - if (replacement->prev != NULL) - { + if (replacement->prev != NULL) { replacement->prev->next = replacement; } - if (parent->child == item) - { + if (parent->child == item) { parent->child = replacement; } @@ -2167,8 +1923,7 @@ N_CJSON_PUBLIC(Jbool) JReplaceItemViaPointer(J * const parent, J * const item, J N_CJSON_PUBLIC(void) JReplaceItemInArray(J *array, int which, J *newitem) { - if (which < 0) - { + if (which < 0) { return; } @@ -2177,14 +1932,12 @@ N_CJSON_PUBLIC(void) JReplaceItemInArray(J *array, int which, J *newitem) static Jbool replace_item_in_object(J *object, const char *string, J *replacement, Jbool case_sensitive) { - if ((replacement == NULL) || (string == NULL)) - { + if ((replacement == NULL) || (string == NULL)) { return false; } /* replace the name in the replacement */ - if (!(replacement->type & JStringIsConst) && (replacement->string != NULL)) - { + if (!(replacement->type & JStringIsConst) && (replacement->string != NULL)) { _Free(replacement->string); } replacement->string = (char*)Jstrdup((const unsigned char*)string); @@ -2209,8 +1962,7 @@ N_CJSON_PUBLIC(void) JReplaceItemInObjectCaseSensitive(J *object, const char *st N_CJSON_PUBLIC(J *) JCreateNull(void) { J *item = JNew_Item(); - if(item) - { + if(item) { item->type = JNULL; } @@ -2220,8 +1972,7 @@ N_CJSON_PUBLIC(J *) JCreateNull(void) N_CJSON_PUBLIC(J *) JCreateTrue(void) { J *item = JNew_Item(); - if(item) - { + if(item) { item->type = JTrue; } @@ -2231,8 +1982,7 @@ N_CJSON_PUBLIC(J *) JCreateTrue(void) N_CJSON_PUBLIC(J *) JCreateFalse(void) { J *item = JNew_Item(); - if(item) - { + if(item) { item->type = JFalse; } @@ -2242,8 +1992,7 @@ N_CJSON_PUBLIC(J *) JCreateFalse(void) N_CJSON_PUBLIC(J *) JCreateBool(Jbool b) { J *item = JNew_Item(); - if(item) - { + if(item) { item->type = b ? JTrue : JFalse; } @@ -2253,23 +2002,17 @@ N_CJSON_PUBLIC(J *) JCreateBool(Jbool b) N_CJSON_PUBLIC(J *) JCreateNumber(JNUMBER num) { J *item = JNew_Item(); - if(item) - { + if(item) { item->type = JNumber; item->valuenumber = num; /* use saturation in case of overflow */ - if (num >= INT_MAX) - { - item->valueint = INT_MAX; - } - else if (num <= INT_MIN) - { - item->valueint = INT_MIN; - } - else - { - item->valueint = (int)num; + if (num >= LONG_MAX) { + item->valueint = LONG_MAX; + } else if (num <= LONG_MIN) { + item->valueint = LONG_MIN; + } else { + item->valueint = (long int)num; } } @@ -2279,12 +2022,10 @@ N_CJSON_PUBLIC(J *) JCreateNumber(JNUMBER num) N_CJSON_PUBLIC(J *) JCreateString(const char *string) { J *item = JNew_Item(); - if(item) - { + if(item) { item->type = JString; item->valuestring = (char*)Jstrdup((const unsigned char*)string); - if(!item->valuestring) - { + if(!item->valuestring) { JDelete(item); return NULL; } @@ -2296,8 +2037,7 @@ N_CJSON_PUBLIC(J *) JCreateString(const char *string) N_CJSON_PUBLIC(J *) JCreateStringReference(const char *string) { J *item = JNew_Item(); - if (item != NULL) - { + if (item != NULL) { item->type = JString | JIsReference; item->valuestring = (char*)cast_away_const(string); } @@ -2316,7 +2056,8 @@ N_CJSON_PUBLIC(J *) JCreateObjectReference(const J *child) return item; } -N_CJSON_PUBLIC(J *) JCreateArrayReference(const J *child) { +N_CJSON_PUBLIC(J *) JCreateArrayReference(const J *child) +{ J *item = JNew_Item(); if (item != NULL) { item->type = JArray | JIsReference; @@ -2329,12 +2070,10 @@ N_CJSON_PUBLIC(J *) JCreateArrayReference(const J *child) { N_CJSON_PUBLIC(J *) JCreateRaw(const char *raw) { J *item = JNew_Item(); - if(item) - { + if(item) { item->type = JRaw; item->valuestring = (char*)Jstrdup((const unsigned char*)raw); - if(!item->valuestring) - { + if(!item->valuestring) { JDelete(item); return NULL; } @@ -2346,8 +2085,7 @@ N_CJSON_PUBLIC(J *) JCreateRaw(const char *raw) N_CJSON_PUBLIC(J *) JCreateArray(void) { J *item = JNew_Item(); - if(item) - { + if(item) { item->type=JArray; } @@ -2357,8 +2095,7 @@ N_CJSON_PUBLIC(J *) JCreateArray(void) N_CJSON_PUBLIC(J *) JCreateObject(void) { J *item = JNew_Item(); - if (item) - { + if (item) { item->type = JObject; } @@ -2366,33 +2103,27 @@ N_CJSON_PUBLIC(J *) JCreateObject(void) } /* Create Arrays: */ -N_CJSON_PUBLIC(J *) JCreateIntArray(const int *numbers, int count) +N_CJSON_PUBLIC(J *) JCreateIntArray(const long int *numbers, int count) { size_t i = 0; J *n = NULL; J *p = NULL; J *a = NULL; - if ((count < 0) || (numbers == NULL)) - { + if ((count < 0) || (numbers == NULL)) { return NULL; } a = JCreateArray(); - for(i = 0; a && (i < (size_t)count); i++) - { + for(i = 0; a && (i < (size_t)count); i++) { n = JCreateNumber(numbers[i]); - if (!n) - { + if (!n) { JDelete(a); return NULL; } - if(!i) - { + if(!i) { a->child = n; - } - else - { + } else { suffix_object(p, n); } p = n; @@ -2408,27 +2139,21 @@ N_CJSON_PUBLIC(J *) JCreateNumberArray(const JNUMBER *numbers, int count) J *p = NULL; J *a = NULL; - if ((count < 0) || (numbers == NULL)) - { + if ((count < 0) || (numbers == NULL)) { return NULL; } a = JCreateArray(); - for(i = 0;a && (i < (size_t)count); i++) - { + for(i = 0; a && (i < (size_t)count); i++) { n = JCreateNumber(numbers[i]); - if(!n) - { + if(!n) { JDelete(a); return NULL; } - if(!i) - { + if(!i) { a->child = n; - } - else - { + } else { suffix_object(p, n); } p = n; @@ -2444,27 +2169,21 @@ N_CJSON_PUBLIC(J *) JCreateStringArray(const char **strings, int count) J *p = NULL; J *a = NULL; - if ((count < 0) || (strings == NULL)) - { + if ((count < 0) || (strings == NULL)) { return NULL; } a = JCreateArray(); - for (i = 0; a && (i < (size_t)count); i++) - { + for (i = 0; a && (i < (size_t)count); i++) { n = JCreateString(strings[i]); - if(!n) - { + if(!n) { JDelete(a); return NULL; } - if(!i) - { + if(!i) { a->child = n; - } - else - { + } else { suffix_object(p,n); } p = n; @@ -2482,59 +2201,47 @@ N_CJSON_PUBLIC(J *) JDuplicate(const J *item, Jbool recurse) J *newchild = NULL; /* Bail on bad ptr */ - if (!item) - { + if (!item) { goto fail; } /* Create new item */ newitem = JNew_Item(); - if (!newitem) - { + if (!newitem) { goto fail; } /* Copy over all vars */ newitem->type = item->type & (~JIsReference); newitem->valueint = item->valueint; newitem->valuenumber = item->valuenumber; - if (item->valuestring) - { + if (item->valuestring) { newitem->valuestring = (char*)Jstrdup((unsigned char*)item->valuestring); - if (!newitem->valuestring) - { + if (!newitem->valuestring) { goto fail; } } - if (item->string) - { + if (item->string) { newitem->string = (item->type&JStringIsConst) ? item->string : (char*)Jstrdup((unsigned char*)item->string); - if (!newitem->string) - { + if (!newitem->string) { goto fail; } } /* If non-recursive, then we're done! */ - if (!recurse) - { + if (!recurse) { return newitem; } /* Walk the ->next chain for the child. */ child = item->child; - while (child != NULL) - { + while (child != NULL) { newchild = JDuplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ - if (!newchild) - { + if (!newchild) { goto fail; } - if (next != NULL) - { + if (next != NULL) { /* If newitem->child already set, then crosswire ->prev and ->next and move on */ next->next = newchild; newchild->prev = next; next = newchild; - } - else - { + } else { /* Set newitem->child and move to it */ newitem->child = newchild; next = newchild; @@ -2545,8 +2252,7 @@ N_CJSON_PUBLIC(J *) JDuplicate(const J *item, Jbool recurse) return newitem; fail: - if (newitem != NULL) - { + if (newitem != NULL) { JDelete(newitem); } @@ -2557,63 +2263,42 @@ N_CJSON_PUBLIC(void) JMinify(char *json) { unsigned char *into = (unsigned char*)json; - if (json == NULL) - { + if (json == NULL) { return; } - while (*json) - { - if (*json == ' ') - { + while (*json) { + if (*json == ' ') { json++; - } - else if (*json == '\t') - { + } else if (*json == '\t') { /* Whitespace characters. */ json++; - } - else if (*json == '\r') - { + } else if (*json == '\r') { json++; - } - else if (*json=='\n') - { + } else if (*json=='\n') { json++; - } - else if ((*json == '/') && (json[1] == '/')) - { + } else if ((*json == '/') && (json[1] == '/')) { /* double-slash comments, to end of line. */ - while (*json && (*json != '\n')) - { + while (*json && (*json != '\n')) { json++; } - } - else if ((*json == '/') && (json[1] == '*')) - { + } else if ((*json == '/') && (json[1] == '*')) { /* multiline comments. */ - while (*json && !((*json == '*') && (json[1] == '/'))) - { + while (*json && !((*json == '*') && (json[1] == '/'))) { json++; } json += 2; - } - else if (*json == '\"') - { + } else if (*json == '\"') { /* string literals, which are \" sensitive. */ *into++ = (unsigned char)*json++; - while (*json && (*json != '\"')) - { - if (*json == '\\') - { + while (*json && (*json != '\"')) { + if (*json == '\\') { *into++ = (unsigned char)*json++; } *into++ = (unsigned char)*json++; } *into++ = (unsigned char)*json++; - } - else - { + } else { /* All other characters. */ *into++ = (unsigned char)*json++; } @@ -2625,8 +2310,7 @@ N_CJSON_PUBLIC(void) JMinify(char *json) N_CJSON_PUBLIC(Jbool) JIsInvalid(const J * const item) { - if (item == NULL) - { + if (item == NULL) { return false; } @@ -2635,8 +2319,7 @@ N_CJSON_PUBLIC(Jbool) JIsInvalid(const J * const item) N_CJSON_PUBLIC(Jbool) JIsFalse(const J * const item) { - if (item == NULL) - { + if (item == NULL) { return false; } @@ -2645,8 +2328,7 @@ N_CJSON_PUBLIC(Jbool) JIsFalse(const J * const item) N_CJSON_PUBLIC(Jbool) JIsTrue(const J * const item) { - if (item == NULL) - { + if (item == NULL) { return false; } @@ -2656,8 +2338,7 @@ N_CJSON_PUBLIC(Jbool) JIsTrue(const J * const item) N_CJSON_PUBLIC(Jbool) JIsBool(const J * const item) { - if (item == NULL) - { + if (item == NULL) { return false; } @@ -2665,8 +2346,7 @@ N_CJSON_PUBLIC(Jbool) JIsBool(const J * const item) } N_CJSON_PUBLIC(Jbool) JIsNull(const J * const item) { - if (item == NULL) - { + if (item == NULL) { return false; } @@ -2675,8 +2355,7 @@ N_CJSON_PUBLIC(Jbool) JIsNull(const J * const item) N_CJSON_PUBLIC(Jbool) JIsNumber(const J * const item) { - if (item == NULL) - { + if (item == NULL) { return false; } @@ -2685,8 +2364,7 @@ N_CJSON_PUBLIC(Jbool) JIsNumber(const J * const item) N_CJSON_PUBLIC(Jbool) JIsString(const J * const item) { - if (item == NULL) - { + if (item == NULL) { return false; } @@ -2695,8 +2373,7 @@ N_CJSON_PUBLIC(Jbool) JIsString(const J * const item) N_CJSON_PUBLIC(Jbool) JIsArray(const J * const item) { - if (item == NULL) - { + if (item == NULL) { return false; } @@ -2705,8 +2382,7 @@ N_CJSON_PUBLIC(Jbool) JIsArray(const J * const item) N_CJSON_PUBLIC(Jbool) JIsObject(const J * const item) { - if (item == NULL) - { + if (item == NULL) { return false; } @@ -2715,8 +2391,7 @@ N_CJSON_PUBLIC(Jbool) JIsObject(const J * const item) N_CJSON_PUBLIC(Jbool) JIsRaw(const J * const item) { - if (item == NULL) - { + if (item == NULL) { return false; } @@ -2725,125 +2400,108 @@ N_CJSON_PUBLIC(Jbool) JIsRaw(const J * const item) N_CJSON_PUBLIC(Jbool) JCompare(const J * const a, const J * const b, const Jbool case_sensitive) { - if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || JIsInvalid(a)) - { + if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || JIsInvalid(a)) { return false; } /* check if type is valid */ - switch (a->type & 0xFF) - { - case JFalse: - case JTrue: - case JNULL: - case JNumber: - case JString: - case JRaw: - case JArray: - case JObject: - break; - - default: - return false; + switch (a->type & 0xFF) { + case JFalse: + case JTrue: + case JNULL: + case JNumber: + case JString: + case JRaw: + case JArray: + case JObject: + break; + + default: + return false; } /* identical objects are equal */ - if (a == b) - { + if (a == b) { return true; } - switch (a->type & 0xFF) - { - /* in these cases and equal type is enough */ - case JFalse: - case JTrue: - case JNULL: + switch (a->type & 0xFF) { + /* in these cases and equal type is enough */ + case JFalse: + case JTrue: + case JNULL: + return true; + + case JNumber: + if (a->valuenumber == b->valuenumber) { return true; + } + return false; - case JNumber: - if (a->valuenumber == b->valuenumber) - { - return true; - } + case JString: + case JRaw: + if ((a->valuestring == NULL) || (b->valuestring == NULL)) { return false; + } + if (strcmp(a->valuestring, b->valuestring) == 0) { + return true; + } + + return false; - case JString: - case JRaw: - if ((a->valuestring == NULL) || (b->valuestring == NULL)) - { + case JArray: { + J *a_element = a->child; + J *b_element = b->child; + + for (; (a_element != NULL) && (b_element != NULL);) { + if (!JCompare(a_element, b_element, case_sensitive)) { return false; } - if (strcmp(a->valuestring, b->valuestring) == 0) - { - return true; - } - return false; + a_element = a_element->next; + b_element = b_element->next; + } - case JArray: - { - J *a_element = a->child; - J *b_element = b->child; + /* one of the arrays is longer than the other */ + if (a_element != b_element) { + return false; + } - for (; (a_element != NULL) && (b_element != NULL);) - { - if (!JCompare(a_element, b_element, case_sensitive)) - { - return false; - } + return true; + } - a_element = a_element->next; - b_element = b_element->next; + case JObject: { + J *a_element = NULL; + J *b_element = NULL; + JArrayForEach(a_element, a) { + /* TODO This has O(n^2) runtime, which is horrible! */ + b_element = get_object_item(b, a_element->string, case_sensitive); + if (b_element == NULL) { + return false; } - /* one of the arrays is longer than the other */ - if (a_element != b_element) { + if (!JCompare(a_element, b_element, case_sensitive)) { return false; } - - return true; } - case JObject: - { - J *a_element = NULL; - J *b_element = NULL; - JArrayForEach(a_element, a) - { - /* TODO This has O(n^2) runtime, which is horrible! */ - b_element = get_object_item(b, a_element->string, case_sensitive); - if (b_element == NULL) - { - return false; - } - - if (!JCompare(a_element, b_element, case_sensitive)) - { - return false; - } + /* doing this twice, once on a and b to prevent true comparison if a subset of b + * TODO: Do this the proper way, this is just a fix for now */ + JArrayForEach(b_element, b) { + a_element = get_object_item(a, b_element->string, case_sensitive); + if (a_element == NULL) { + return false; } - /* doing this twice, once on a and b to prevent true comparison if a subset of b - * TODO: Do this the proper way, this is just a fix for now */ - JArrayForEach(b_element, b) - { - a_element = get_object_item(a, b_element->string, case_sensitive); - if (a_element == NULL) - { - return false; - } - - if (!JCompare(b_element, a_element, case_sensitive)) - { - return false; - } + if (!JCompare(b_element, a_element, case_sensitive)) { + return false; } - - return true; } - default: - return false; + return true; + } + + default: + return false; } } diff --git a/src/note-c/n_cjson.h b/src/note-c/n_cjson.h index 6682da4..b126921 100644 --- a/src/note-c/n_cjson.h +++ b/src/note-c/n_cjson.h @@ -70,8 +70,7 @@ extern "C" #define JStringIsConst 512 /* The J structure: */ -typedef struct J -{ +typedef struct J { /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ struct J *next; struct J *prev; @@ -84,17 +83,16 @@ typedef struct J /* The item's string, if type==JString and type == JRaw */ char *valuestring; /* writing to valueint is DEPRECATED, use JSetNumberValue instead */ - int valueint; + long int valueint; /* The item's number, if type==JNumber */ JNUMBER valuenumber; /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ char *string; } J; -typedef struct JHooks -{ - void *(*malloc_fn)(size_t sz); - void (*free_fn)(void *ptr); +typedef struct JHooks { + void *(*malloc_fn)(size_t sz); + void (*free_fn)(void *ptr); } JHooks; typedef int Jbool; @@ -220,7 +218,7 @@ N_CJSON_PUBLIC(J *) JCreateObjectReference(const J *child); N_CJSON_PUBLIC(J *) JCreateArrayReference(const J *child); /* These utilities create an Array of count items. */ -N_CJSON_PUBLIC(J *) JCreateIntArray(const int *numbers, int count); +N_CJSON_PUBLIC(J *) JCreateIntArray(const long int *numbers, int count); N_CJSON_PUBLIC(J *) JCreateNumberArray(const JNUMBER *numbers, int count); N_CJSON_PUBLIC(J *) JCreateStringArray(const char **strings, int count); diff --git a/src/note-c/n_cjson_helpers.c b/src/note-c/n_cjson_helpers.c index 0e73542..f1c965b 100644 --- a/src/note-c/n_cjson_helpers.c +++ b/src/note-c/n_cjson_helpers.c @@ -24,10 +24,12 @@ @returns boolean. `true` if the field is present. */ /**************************************************************************/ -bool JIsPresent(J *rsp, const char *field) { - if (rsp == NULL) - return false; - return (JGetObjectItem(rsp, field) != NULL); +bool JIsPresent(J *rsp, const char *field) +{ + if (rsp == NULL) { + return false; + } + return (JGetObjectItem(rsp, field) != NULL); } //**************************************************************************/ @@ -38,17 +40,22 @@ bool JIsPresent(J *rsp, const char *field) { @returns The string response, or an empty string, if not present. */ /**************************************************************************/ -char *JGetString(J *rsp, const char *field) { - if (rsp == NULL) - return (char *) c_nullstring; - J *item = JGetObjectItem(rsp, field); - if (item == NULL) - return (char *) c_nullstring; - if (!JIsString(item)) - return (char *) c_nullstring; - if (item->valuestring == NULL) - return (char *) c_nullstring; - return item->valuestring; +char *JGetString(J *rsp, const char *field) +{ + if (rsp == NULL) { + return (char *) c_nullstring; + } + J *item = JGetObjectItem(rsp, field); + if (item == NULL) { + return (char *) c_nullstring; + } + if (!JIsString(item)) { + return (char *) c_nullstring; + } + if (item->valuestring == NULL) { + return (char *) c_nullstring; + } + return item->valuestring; } //**************************************************************************/ @@ -59,15 +66,19 @@ char *JGetString(J *rsp, const char *field) { @returns The object found, or NULL, if not present. */ /**************************************************************************/ -J *JGetObject(J *rsp, const char *field) { - if (rsp == NULL) - return NULL; - J *item = JGetObjectItem(rsp, field); - if (item == NULL) - return NULL; - if (!JIsObject(item)) - return NULL; - return item; +J *JGetObject(J *rsp, const char *field) +{ + if (rsp == NULL) { + return NULL; + } + J *item = JGetObjectItem(rsp, field); + if (item == NULL) { + return NULL; + } + if (!JIsObject(item)) { + return NULL; + } + return item; } //**************************************************************************/ @@ -77,10 +88,12 @@ J *JGetObject(J *rsp, const char *field) { @returns The boolean value. */ /**************************************************************************/ -bool JBoolValue(J *item) { - if (item == NULL) - return false; - return ((item->type & 0xff) == JTrue); +bool JBoolValue(J *item) +{ + if (item == NULL) { + return false; + } + return ((item->type & 0xff) == JTrue); } //**************************************************************************/ @@ -90,10 +103,12 @@ bool JBoolValue(J *item) { @returns The string value, or empty string, if NULL. */ /**************************************************************************/ -char *JStringValue(J *item) { - if (item == NULL) - return ""; - return item->valuestring; +char *JStringValue(J *item) +{ + if (item == NULL) { + return ""; + } + return item->valuestring; } //**************************************************************************/ @@ -103,10 +118,12 @@ char *JStringValue(J *item) { @returns The number, or 0.0, if NULL. */ /**************************************************************************/ -JNUMBER JNumberValue(J *item) { - if (item == NULL) - return 0.0; - return item->valuenumber; +JNUMBER JNumberValue(J *item) +{ + if (item == NULL) { + return 0.0; + } + return item->valuenumber; } //**************************************************************************/ @@ -117,15 +134,19 @@ JNUMBER JNumberValue(J *item) { @returns The number found, or 0.0, if not present. */ /**************************************************************************/ -JNUMBER JGetNumber(J *rsp, const char *field) { - if (rsp == NULL) - return 0.0; - J *item = JGetObjectItem(rsp, field); - if (item == NULL) - return 0.0; - if (!JIsNumber(item)) - return 0.0; - return JNumberValue(item); +JNUMBER JGetNumber(J *rsp, const char *field) +{ + if (rsp == NULL) { + return 0.0; + } + J *item = JGetObjectItem(rsp, field); + if (item == NULL) { + return 0.0; + } + if (!JIsNumber(item)) { + return 0.0; + } + return JNumberValue(item); } //**************************************************************************/ @@ -135,10 +156,12 @@ JNUMBER JGetNumber(J *rsp, const char *field) { @returns The number, or 0, if NULL. */ /**************************************************************************/ -int JIntValue(J *item) { - if (item == NULL) - return 0; - return item->valueint; +long int JIntValue(J *item) +{ + if (item == NULL) { + return 0; + } + return item->valueint; } //**************************************************************************/ @@ -149,15 +172,19 @@ int JIntValue(J *item) { @returns The int found, or 0, if not present. */ /**************************************************************************/ -int JGetInt(J *rsp, const char *field) { - if (rsp == NULL) - return 0.0; - J *item = JGetObjectItem(rsp, field); - if (item == NULL) - return 0.0; - if (!JIsNumber(item)) - return 0.0; - return JIntValue(item); +long int JGetInt(J *rsp, const char *field) +{ + if (rsp == NULL) { + return 0; + } + J *item = JGetObjectItem(rsp, field); + if (item == NULL) { + return 0; + } + if (!JIsNumber(item)) { + return 0; + } + return JIntValue(item); } //**************************************************************************/ @@ -168,89 +195,111 @@ int JGetInt(J *rsp, const char *field) { @returns The boolean value, or false if not present. */ /**************************************************************************/ -bool JGetBool(J *rsp, const char *field) { - if (rsp == NULL) - return false; - J *item = JGetObjectItem(rsp, field); - if (item == NULL) - return false; - if (!JIsBool(item)) - return 0.0; - return JIsTrue(item); +bool JGetBool(J *rsp, const char *field) +{ + if (rsp == NULL) { + return false; + } + J *item = JGetObjectItem(rsp, field); + if (item == NULL) { + return false; + } + if (!JIsBool(item)) { + return false; + } + return JIsTrue(item); } //**************************************************************************/ /*! @brief Determine if a JSON object is valid and if a field is not present, - or null. + or null. @param rsp The JSON response object. @param field The field to return. @returns bool. False if the field is not present, or NULL. */ /**************************************************************************/ -bool JIsNullString(J *rsp, const char *field) { - if (rsp == NULL) - return false; - J *item = JGetObjectItem(rsp, field); - if (item == NULL) - return true; - if (!JIsString(item)) - return false; - if (item->valuestring == NULL) - return true; - if (item->valuestring[0] == '\0') - return true; - return false; +bool JIsNullString(J *rsp, const char *field) +{ + if (rsp == NULL) { + return false; + } + J *item = JGetObjectItem(rsp, field); + if (item == NULL) { + return true; + } + if (!JIsString(item)) { + return false; + } + if (item->valuestring == NULL) { + return true; + } + if (item->valuestring[0] == '\0') { + return true; + } + return false; } //**************************************************************************/ /*! @brief Determine if a field exists, is a string and matches a - provided value. + provided value. @param rsp The JSON response object. @param field The field to check. - @param teststr The string to test against the returned value. + @param teststr The string to test against the returned value. @returns bol. Whether the fields match exactly. */ /**************************************************************************/ -bool JIsExactString(J *rsp, const char *field, const char *teststr) { - if (rsp == NULL) - return false; - J *item = JGetObjectItem(rsp, field); - if (item == NULL) - return false; - if (!JIsString(item)) - return false; - if (item->valuestring == NULL) - return false; - if (strlen(teststr) == 0) - return false; - return (strcmp(item->valuestring, teststr) == 0); +bool JIsExactString(J *rsp, const char *field, const char *teststr) +{ + if (rsp == NULL) { + return false; + } + J *item = JGetObjectItem(rsp, field); + if (item == NULL) { + return false; + } + if (!JIsString(item)) { + return false; + } + if (item->valuestring == NULL) { + return false; + } + if (strlen(teststr) == 0) { + return false; + } + return (strcmp(item->valuestring, teststr) == 0); } //**************************************************************************/ /*! @brief Determine if a field exists, is a string and contains a provided - value. + value. @param rsp The JSON response object. @param field The field to check. - @param substr The string to test against the returned value. + @param substr The string to test against the returned value. @returns bol. Whether the provided string is found within the field. */ /**************************************************************************/ -bool JContainsString(J *rsp, const char *field, const char *substr) { - if (rsp == NULL) - return false; - J *item = JGetObjectItem(rsp, field); - if (item == NULL) - return false; - if (!JIsString(item)) - return false; - if (item->valuestring == NULL) - return false; - if (strlen(substr) == 0) - return false; - return (strstr(item->valuestring, substr) != NULL); +bool JContainsString(J *rsp, const char *field, const char *substr) +{ + if (rsp == NULL) { + return false; + } + J *item = JGetObjectItem(rsp, field); + if (item == NULL) { + return false; + } + if (!JIsString(item)) { + return false; + } + if (item->valuestring == NULL) { + return false; + } + if (strlen(substr) == 0) { + return false; + } + return (strstr(item->valuestring, substr) != NULL); } //**************************************************************************/ @@ -258,24 +307,26 @@ bool JContainsString(J *rsp, const char *field, const char *substr) { @brief Add a binary to a Note as a Base64-encoded string. @param req The JSON request object. @param fieldName The field to set. - @param binaryData The binary data to set. - @param binaryDataLen The length of the binary string. + @param binaryData The binary data to set. + @param binaryDataLen The length of the binary string. @returns bool. Whether the binary field was set. */ /**************************************************************************/ -bool JAddBinaryToObject(J *req, const char *fieldName, const void *binaryData, uint32_t binaryDataLen) { - unsigned stringDataLen = JB64EncodeLen(binaryDataLen); - char *stringData = (char *) malloc(stringDataLen); - if (stringData == NULL) - return false; - JB64Encode(stringData, binaryData, binaryDataLen); - J *stringItem = JCreateStringReference(stringData); - if (stringItem == NULL) { - free(stringData); - return false; - } - JAddItemToObject(req, fieldName, stringItem); - return true; +bool JAddBinaryToObject(J *req, const char *fieldName, const void *binaryData, uint32_t binaryDataLen) +{ + unsigned stringDataLen = JB64EncodeLen(binaryDataLen); + char *stringData = (char *) _Malloc(stringDataLen); + if (stringData == NULL) { + return false; + } + JB64Encode(stringData, binaryData, binaryDataLen); + J *stringItem = JCreateStringReference(stringData); + if (stringItem == NULL) { + _Free(stringData); + return false; + } + JAddItemToObject(req, fieldName, stringItem); + return true; } //**************************************************************************/ @@ -285,9 +336,128 @@ bool JAddBinaryToObject(J *req, const char *fieldName, const void *binaryData, u @returns The number, or and empty string, if NULL. */ /**************************************************************************/ -const char *JGetItemName(const J * item) { - if (item->string == NULL) - return ""; - return item->string; +const char *JGetItemName(const J * item) +{ + if (item->string == NULL) { + return ""; + } + return item->string; } +//**************************************************************************/ +/*! + @brief Convert an integer to text + @param an integer + @returns The number converted to text, null-terminated. + @note The buffer midt be large enough because no bounds checking is done. +*/ +/**************************************************************************/ +void JItoA(long int n, char *s) +{ + char c; + long int i, j, sign; + if ((sign = n) < 0) { + n = -n; + } + i = 0; + do { + s[i++] = n % 10 + '0'; + } while ((n /= 10) > 0); + if (sign < 0) { + s[i++] = '-'; + } + s[i] = '\0'; + for (i = 0, j = strlen(s)-1; i 9) { + break; + } + result = (10*result) + digit; + } + if (sign) { + result = -result; + } + return result; +} + +//**************************************************************************/ +/*! + @brief Convert a buffer/len to a null-terminated c-string + @param a buffer containing text with a counted length + @returns A c-string (NULL if invalid) that must be freed with JFree() +*/ +/**************************************************************************/ +char *JAllocString(uint8_t *buffer, uint32_t len) +{ + char *buf = _Malloc(len+1); + if (buf == NULL) { + return false; + } + if (len > 0) { + memcpy(buf, buffer, len); + } + buf[len] = '\0'; + return buf; +} + +//**************************************************************************/ +/*! + @brief Return the type of an item, as a string + @param item The JSON item. + @returns The type +*/ +/**************************************************************************/ +const char *JType(J *item) +{ + if (item == NULL) { + return ""; + } + switch (item->type & 0xff) { + case JTrue: + case JFalse: + return "bool"; + case JNULL: + return "null"; + case JNumber: + return "number"; + case JRaw: + case JString: + return "string"; + case JObject: + return "object"; + case JArray: + return "array"; + } + return "invalid"; +} diff --git a/src/note-c/n_ftoa.c b/src/note-c/n_ftoa.c index a4518ba..105522b 100644 --- a/src/note-c/n_ftoa.c +++ b/src/note-c/n_ftoa.c @@ -2,29 +2,29 @@ * @file n_ftoa.c * * - * stm32tpl -- STM32 C++ Template Peripheral Library + * stm32tpl -- STM32 C++ Template Peripheral Library * - * Copyright (c) 2009-2014 Anton B. Gusev aka AHTOXA + * Copyright (c) 2009-2014 Anton B. Gusev aka AHTOXA * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. * - * description : convert double to string + * description : convert double to string * */ @@ -32,133 +32,142 @@ char * JNtoA(JNUMBER f, char * buf, int original_precision) { - char * ptr = buf; - char * p = ptr; - char * p1; - char c; - long intPart; - - // For our low-SRAM devices we'd rather have this on the stack - const JNUMBER rounders[JNTOA_PRECISION + 1] = - { - 0.5, // 0 - 0.05, // 1 - 0.005, // 2 - 0.0005, // 3 - 0.00005, // 4 - 0.000005, // 5 - 0.0000005, // 6 - 0.00000005, // 7 - 0.000000005, // 8 - 0.0000000005, // 9 - 0.00000000005 // 10 - }; - - // Check specifically for uncommon but bad floating point numbers that can't be converted - uint8_t fbytes[8]; - memcpy(&fbytes, &f, sizeof(fbytes)); - bool wasFF = true; - int i; - for (i=0; i<(int)sizeof(fbytes); i++) - if (fbytes[i] != 0xff) wasFF = false; - if (wasFF) - f = 0.0; - - // check precision bounds - int precision = original_precision; - if (precision < 0 || precision > JNTOA_PRECISION) - precision = JNTOA_PRECISION; - - // sign stuff - if (f < 0) - { - f = -f; - *ptr++ = '-'; - } - - if (original_precision < 0) // negative precision == automatic precision guess - { - if (f < 1.0) precision = 6; - else if (f < 10.0) precision = 5; - else if (f < 100.0) precision = 4; - else if (f < 1000.0) precision = 3; - else if (f < 10000.0) precision = 2; - else if (f < 100000.0) precision = 1; - else precision = 0; - } - - // round value according the precision - if (precision) - f += rounders[precision]; - - // integer part... - intPart = (int) f; - f -= intPart; - - if (!intPart) - *ptr++ = '0'; - else - { - // save start pointer - p = ptr; - - // convert (reverse order) - while (intPart) - { - *p++ = '0' + intPart % 10; - intPart /= 10; - } - - // save end pos - p1 = p; - - // reverse result - while (p > ptr) - { - c = *--p; - *p = *ptr; - *ptr++ = c; - } - - // restore end pos - ptr = p1; - } - - // decimal part - if (precision) - { - - // place decimal point - *ptr++ = '.'; - - // convert - while (precision--) - { - f *= 10.0; - c = (int) f; - - // Invalid floating point numbers (specifically 0xffffff) end up at this point - // with a c == 255 after the coercion - if (c > 9) c = 0; - - *ptr++ = '0' + c; - f -= c; - } - } - - // terminating zero - *ptr = 0; - - // Remove trailing zero's if automatic precision - if (NULL != strchr(buf, '.')) { - if (original_precision < 0) { - --ptr; - while (ptr > (buf+1) && *ptr == '0') - *ptr-- = 0; - if (*ptr == '.') - *ptr = 0; - } - } - - return buf; + char * ptr = buf; + char * p = ptr; + char * p1; + char c; + long intPart; + + // For our low-SRAM devices we'd rather have this on the stack + const JNUMBER rounders[JNTOA_PRECISION + 1] = { + 0.5, // 0 + 0.05, // 1 + 0.005, // 2 + 0.0005, // 3 + 0.00005, // 4 + 0.000005, // 5 + 0.0000005, // 6 + 0.00000005, // 7 + 0.000000005, // 8 + 0.0000000005, // 9 + 0.00000000005 // 10 + }; + + // Check specifically for uncommon but bad floating point numbers that can't be converted + uint8_t fbytes[8]; + memcpy(&fbytes, &f, sizeof(fbytes)); + bool wasFF = true; + int i; + for (i=0; i<(int)sizeof(fbytes); i++) + if (fbytes[i] != 0xff) { + wasFF = false; + } + if (wasFF) { + f = 0.0; + } + + // check precision bounds + int precision = original_precision; + if (precision < 0 || precision > JNTOA_PRECISION) { + precision = JNTOA_PRECISION; + } + + // sign stuff + if (f < 0) { + f = -f; + *ptr++ = '-'; + } + + if (original_precision < 0) { // negative precision == automatic precision guess + if (f < 1.0) { + precision = 6; + } else if (f < 10.0) { + precision = 5; + } else if (f < 100.0) { + precision = 4; + } else if (f < 1000.0) { + precision = 3; + } else if (f < 10000.0) { + precision = 2; + } else if (f < 100000.0) { + precision = 1; + } else { + precision = 0; + } + } + + // round value according the precision + if (precision) { + f += rounders[precision]; + } + + // integer part... + intPart = (int) f; + f -= intPart; + + if (!intPart) { + *ptr++ = '0'; + } else { + // save start pointer + p = ptr; + + // convert (reverse order) + while (intPart) { + *p++ = '0' + intPart % 10; + intPart /= 10; + } + + // save end pos + p1 = p; + + // reverse result + while (p > ptr) { + c = *--p; + *p = *ptr; + *ptr++ = c; + } + + // restore end pos + ptr = p1; + } + + // decimal part + if (precision) { + + // place decimal point + *ptr++ = '.'; + + // convert + while (precision--) { + f *= 10.0; + c = (int) f; + + // Invalid floating point numbers (specifically 0xffffff) end up at this point + // with a c == 255 after the coercion + if (c > 9) { + c = 0; + } + + *ptr++ = '0' + c; + f -= c; + } + } + + // terminating zero + *ptr = 0; + + // Remove trailing zero's if automatic precision + if (NULL != strchr(buf, '.')) { + if (original_precision < 0) { + --ptr; + while (ptr > (buf+1) && *ptr == '0') { + *ptr-- = 0; + } + if (*ptr == '.') { + *ptr = 0; + } + } + } + + return buf; } diff --git a/src/note-c/n_helpers.c b/src/note-c/n_helpers.c index 84947e2..54bd973 100644 --- a/src/note-c/n_helpers.c +++ b/src/note-c/n_helpers.c @@ -27,9 +27,12 @@ // Time-related suppression timer and cache static uint32_t timeBaseSetAtMs = 0; static JTIME timeBaseSec = 0; +static bool timeBaseSetManually = false; +static uint32_t suppressionTimerSecs = 10; static uint32_t timeTimer = 0; static bool zoneStillUnavailable = true; -static char curZone[48] = {0}; +static bool zoneForceRefresh = false; +static char curZone[10] = {0}; static char curArea[64] = {0}; static char curCountry[8] = ""; static int curZoneOffsetMins = 0; @@ -50,121 +53,158 @@ static char scSN[128] = {0}; static char scProduct[128] = {0}; static char scService[128] = {0}; +// For date conversions +#define daysByMonth(y) ((y)&03||(y)==0?normalYearDaysByMonth:leapYearDaysByMonth) +static short leapYearDaysByMonth[] = {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}; +static short normalYearDaysByMonth[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; +static char *daynames[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; + // Forwards static bool timerExpiredSecs(uint32_t *timer, uint32_t periodSecs); +static int ytodays(int year); //**************************************************************************/ /*! - @brief Determine if the card time is "real" calendar/clock time, or if - it is simply the millisecond clock since boot. - @returns A boolean indicating whether the current time is valid. + @brief Determine if the card time is "real" calendar/clock time, or if + it is simply the millisecond clock since boot. + @returns A boolean indicating whether the current time is valid. */ /**************************************************************************/ -bool NoteTimeValid() { +bool NoteTimeValid() +{ timeTimer = 0; return NoteTimeValidST(); } //**************************************************************************/ /*! - @brief Determine if if the suppression-timer card time is valid. - @returns A boolean indicating whether the current time is valid. + @brief Determine if if the suppression-timer card time is valid. + @returns A boolean indicating whether the current time is valid. */ /**************************************************************************/ -bool NoteTimeValidST() { +bool NoteTimeValidST() +{ NoteTimeST(); return (timeBaseSec != 0); } //**************************************************************************/ /*! - @brief Get the current epoch time, unsuppressed. - @returns The current time. + @brief Get the current epoch time, unsuppressed. + @returns The current time. */ /**************************************************************************/ -JTIME NoteTime() { +JTIME NoteTime() +{ timeTimer = 0; return NoteTimeST(); } //**************************************************************************/ /*! - @brief Set the time. - @param seconds The UNIX Epoch time. + @brief Set the time. + @param seconds The UNIX Epoch time. */ /**************************************************************************/ -static void setTime(JTIME seconds) { +static void setTime(JTIME seconds) +{ timeBaseSec = seconds; timeBaseSetAtMs = _GetMs(); - _Debug("setting time\n"); } //**************************************************************************/ /*! - @brief Print a full, newline-terminated line. - @param line The c-string line to print. + @brief Set the time from a source that is NOT the Notecard + @param seconds The UNIX Epoch time, or 0 to set back to automatic Notecard time + @param offset The local time zone offset, in minutes, to adjust UTC + @param zone The optional local time zone name (3 character c-string) + @param zone The optional country + @param area The optional region */ /**************************************************************************/ -void NotePrintln(const char *line) { - NotePrint(line); - NotePrint(c_newline); +void NoteTimeSet(JTIME secondsUTC, int offset, char *zone, char *country, char *area) +{ + if (secondsUTC == 0) { + timeBaseSec = 0; + timeBaseSetAtMs = 0; + timeBaseSetManually = false; + zoneStillUnavailable = true; + zoneForceRefresh = false; + } else { + timeBaseSec = secondsUTC; + timeBaseSetAtMs = _GetMs(); + timeBaseSetManually = true; + zoneStillUnavailable = false; + curZoneOffsetMins = offset; + strlcpy(curZone, zone == NULL ? "UTC" : zone, sizeof(curZone)); + strlcpy(curArea, area == NULL ? "" : area, sizeof(curArea)); + strlcpy(curCountry, country == NULL ? "" : country, sizeof(curCountry)); + } } //**************************************************************************/ /*! - @brief Log text "raw" to either the active debug console or to the - Notecard's USB console. - @param text A debug string for output. + @brief Print a full, newline-terminated line. + @param line The c-string line to print. */ /**************************************************************************/ -bool NotePrint(const char *text) { - bool success = false; - if (NoteIsDebugOutputActive()) { - NoteDebug(text); - return true; - } - int inLog = 0; - if (inLog++ != 0) { - inLog--; - return false; - } - J *req = NoteNewRequest("card.log"); - JAddStringToObject(req, "text", text); - success = NoteRequest(req); - inLog--; - return success; +void NotePrintln(const char *line) +{ + NotePrint(line); + NotePrint(c_newline); } //**************************************************************************/ /*! - @brief Write a formatted string to the debug output. - @param format A format string for output. - @param ... One or more values to interpolate into the format string. + @brief Log text "raw" to either the active debug console or to the + Notecard's USB console. + @param text A debug string for output. */ /**************************************************************************/ -bool NotePrintf(const char *format, ...) { - char line[256]; - va_list args; - va_start(args, format); - vsnprintf(line, sizeof(line), format, args); - va_end(args); - return NotePrint(line); +bool NotePrint(const char *text) +{ + bool success = false; + if (NoteIsDebugOutputActive()) { + NoteDebug(text); + return true; + } + int inLog = 0; + if (inLog++ != 0) { + inLog--; + return false; + } + J *req = NoteNewRequest("card.log"); + JAddStringToObject(req, "text", text); + success = NoteRequest(req); + inLog--; + return success; } //**************************************************************************/ /*! - @brief Get the current epoch time as known by the module. If it isn't known - by the module, just return the time since boot as indicated by the - millisecond clock. - @returns The current time, or the time since boot. + @brief Get the current epoch time as known by the module. If it isn't known + by the module, just return the time since boot as indicated by the + millisecond clock. + @returns The current time, or the time since boot. */ /**************************************************************************/ -JTIME NoteTimeST() { +JTIME NoteTimeST() +{ + + // Handle timer tick wrap by resetting the base + uint32_t nowMs = _GetMs(); + if (timeBaseSec != 0 && nowMs < timeBaseSetAtMs) { + int64_t actualTimeMs = 0x100000000LL + (int64_t) nowMs; + int64_t elapsedTimeMs = actualTimeMs - (int64_t) timeBaseSetAtMs; + uint32_t elapsedTimeSecs = (uint32_t) (elapsedTimeMs / 1000); + timeBaseSec += elapsedTimeSecs; + timeBaseSetAtMs = nowMs; + } // If we haven't yet fetched the time, or if we still need the timezone, do so with a suppression // timer so that we don't hammer the module before it's had a chance to connect to the network to fetch time. - if (timeBaseSec == 0 || zoneStillUnavailable) { - if (timerExpiredSecs(&timeTimer, 10)) { + if (!timeBaseSetManually && (timeBaseSec == 0 || zoneStillUnavailable || zoneForceRefresh)) { + if (timerExpiredSecs(&timeTimer, suppressionTimerSecs)) { // Request time and zone info from the card J *rsp = NoteRequestResponse(NoteNewRequest("card.time")); @@ -174,8 +214,9 @@ JTIME NoteTimeST() { if (seconds != 0) { // Set the time if it hasn't yet been set - if (timeBaseSec == 0) - setTime(seconds); + if (timeBaseSec == 0) { + setTime(seconds); + } // Get the zone char *z = JGetString(rsp, "zone"); @@ -184,11 +225,13 @@ JTIME NoteTimeST() { strlcpy(zone, z, sizeof(zone)); // Only use the 3-letter abbrev char *sep = strchr(zone, ','); - if (sep == NULL) + if (sep == NULL) { zone[0] = '\0'; - else + } else { *sep = '\0'; + } zoneStillUnavailable = (memcmp(zone, "UTC", 3) == 0); + zoneForceRefresh = false; strlcpy(curZone, zone, sizeof(curZone)); curZoneOffsetMins = JGetInt(rsp, "minutes"); strlcpy(curCountry, JGetString(rsp, "country"), sizeof(curCountry)); @@ -203,7 +246,7 @@ JTIME NoteTimeST() { } // Adjust the base time by the number of seconds that have elapsed since the base. - JTIME adjustedTime = timeBaseSec + ((_GetMs() - timeBaseSetAtMs) / 1000); + JTIME adjustedTime = timeBaseSec + ((nowMs - timeBaseSetAtMs) / 1000); // Done return adjustedTime; @@ -212,47 +255,193 @@ JTIME NoteTimeST() { //**************************************************************************/ /*! - @brief Return local region info, if known. Returns true if valid. - @param retCountry (out) The country. - @param retArea (out) The area value. - @param retZone (out) The timezone value. - @param retZoneOffset (out) The timezone offset. - @returns boolean indicating if the region information is valid. + @brief Set suppression timer secs, returning the previous value + @param New suppression timer seconds + @returns Previous suppression timer seconds */ /**************************************************************************/ -bool NoteRegion(char **retCountry, char **retArea, char **retZone, int *retZoneOffset) { +uint32_t NoteSetSTSecs(uint32_t secs) +{ + uint32_t prev = suppressionTimerSecs; + suppressionTimerSecs = secs; + return prev; +} + +//**************************************************************************/ +/*! + @brief Return local region info, if known. Returns true if valid. + @param retCountry (out) The country. + @param retArea (out) The area value. + @param retZone (out) The timezone value. + @param retZoneOffset (out) The timezone offset. + @returns boolean indicating if the region information is valid. +*/ +/**************************************************************************/ +bool NoteRegion(char **retCountry, char **retArea, char **retZone, int *retZoneOffset) +{ + NoteTimeST(); if (zoneStillUnavailable) { - if (retCountry != NULL) + if (retCountry != NULL) { *retCountry = (char *) ""; - if (retArea != NULL) + } + if (retArea != NULL) { *retArea = (char *) ""; - if (retZone != NULL) - *retZone = curZone; - if (retZoneOffset != NULL) + } + if (retZone != NULL) { + *retZone = "UTC"; + } + if (retZoneOffset != NULL) { *retZoneOffset = 0; + } return false; } - if (retCountry != NULL) + if (retCountry != NULL) { *retCountry = curCountry; - if (retArea != NULL) + } + if (retArea != NULL) { *retArea = curArea; - if (retZone != NULL) + } + if (retZone != NULL) { *retZone = curZone; - if (retZoneOffset != NULL) + } + if (retZoneOffset != NULL) { *retZoneOffset = curZoneOffsetMins; + } return true;; } //**************************************************************************/ /*! - @brief See if the card location is valid. If it is OFF, it is - treated as valid. - @param errbuf (out) A buffer with any error information to return. - @param errbuflen The length of the error buffer. - @returns boolean indicating if the location information is valid. + @brief Return local region info, if known. Returns true if valid. + @param year, month, day, hour, minute, second - pointers to where to return time/date + @param retZone (in-out) if NULL, local time will be returned in UTC, else returns pointer to zone string + @returns boolean indicating if either the zone or DST have changed since last call + @note only call this if time is valid +*/ +/**************************************************************************/ +bool NoteLocalTimeST(uint16_t *retYear, uint8_t *retMonth, uint8_t *retDay, uint8_t *retHour, uint8_t *retMinute, uint8_t *retSecond, char **retWeekday, char **retZone) +{ + + // Preset + if (retYear != NULL) { + *retYear = 0; + } + if (retMonth != NULL) { + *retMonth = 0; + } + if (retDay != NULL) { + *retDay = 0; + } + if (retHour != NULL) { + *retHour = 0; + } + if (retMinute != NULL) { + *retMinute = 0; + } + if (retSecond != NULL) { + *retSecond = 0; + } + if (retWeekday != NULL) { + *retWeekday = ""; + } + if (retZone != NULL) { + *retZone = ""; + } + + // Exit if time isn't yet valid + if (!NoteTimeValidST()) { + return false; + } + + // Get the current time and region, and compute local time + char *currentZone; + int currentOffsetMins; + JTIME currentEpochTime = NoteTimeST(); + bool regionAvailable = NoteRegion(NULL, NULL, ¤tZone, ¤tOffsetMins); + + // Offset the epoch time by time zone offset + currentEpochTime += currentOffsetMins * 60; + + // Convert from unix epoch time to local date/time + int i, year, mon; + int32_t days; + uint32_t secs; + secs = (uint32_t) currentEpochTime + ((70*365L+17)*86400LU); + days = secs / 86400; + if (retWeekday != NULL) { + *retWeekday = daynames[(days + 1) % 7]; + } + for (year = days / 365; days < (i = ytodays(year) + 365L * year); ) { + --year; + } + days -= i; + if (retYear != NULL) { + *retYear = (uint16_t) year+1900; + } + short *pm = daysByMonth(year); + for (mon = 12; days < pm[--mon]; ) ; + if (retMonth != NULL) { + *retMonth = (uint8_t) mon+1; + } + if (retDay != NULL) { + *retDay = days - pm[mon] + 1; + } + secs = secs % 86400; + uint8_t currentHour = (uint8_t) (secs / 3600); + if (retHour != NULL) { + *retHour = currentHour; + } + secs %= 3600; + if (retMinute != NULL) { + *retMinute = (uint8_t) (secs/60); + } + if (retSecond != NULL) { + *retSecond = (uint8_t) (secs % 60); + } + if (retZone != NULL) { + *retZone = currentZone; + } + + // Determine whether or not we should refresh to check whether DST offset has changed, which + // is between midnight and 3am local time (if available). + static uint8_t lastHour; + static bool lastInfoIsKnown = false; + if (regionAvailable && lastInfoIsKnown) { + if ((lastHour != 1 && currentHour == 1) || (lastHour != 2 && currentHour == 2) || (lastHour != 3 && currentHour == 3)) { + zoneForceRefresh = true; + } + } + lastInfoIsKnown = true; + lastHour = currentHour; + + // Done + return regionAvailable; + +} + +// Figure out how many days at start of the year +static int ytodays(int year) +{ + int days = 0; + if (0 < year) { + days = (year - 1) / 4; + } else if (year <= -4) { + days = year / 4; + } + return days + daysByMonth(year)[0]; +} + +//**************************************************************************/ +/*! + @brief See if the card location is valid. If it is OFF, it is + treated as valid. + @param errbuf (out) A buffer with any error information to return. + @param errbuflen The length of the error buffer. + @returns boolean indicating if the location information is valid. */ /**************************************************************************/ -bool NoteLocationValid(char *errbuf, uint32_t errbuflen) { +bool NoteLocationValid(char *errbuf, uint32_t errbuflen) +{ locationTimer = 0; locationValid = false; locationLastErr[0] = '\0'; @@ -261,52 +450,59 @@ bool NoteLocationValid(char *errbuf, uint32_t errbuflen) { //**************************************************************************/ /*! - @brief See if the card location is valid, time-suppressed. If it is OFF, - it is treated as valid. - @param errbuf (out) A buffer with any error information to return. - @param errbuflen The length of the error buffer. - @returns boolean indicating if the location information is valid. + @brief See if the card location is valid, time-suppressed. If it is OFF, + it is treated as valid. + @param errbuf (out) A buffer with any error information to return. + @param errbuflen The length of the error buffer. + @returns boolean indicating if the location information is valid. */ /**************************************************************************/ -bool NoteLocationValidST(char *errbuf, uint32_t errbuflen) { +bool NoteLocationValidST(char *errbuf, uint32_t errbuflen) +{ // Preset - if (errbuf != NULL) + if (errbuf != NULL) { strlcpy(errbuf, locationLastErr, errbuflen); + } // If it was ever valid, return true if (locationValid) { locationLastErr[0] = '\0'; - if (errbuf != NULL) + if (errbuf != NULL) { *errbuf = '\0'; + } return true; } // If we haven't yet fetched the location, do so with a suppression // timer so that we don't hammer the module before it's had a chance to // connect to the gps to fetch location. - if (!timerExpiredSecs(&locationTimer, 5)) + if (!timerExpiredSecs(&locationTimer, suppressionTimerSecs)) { return false; + } // Request location from the card J *rsp = NoteRequestResponse(NoteNewRequest("card.location")); - if (rsp == NULL) + if (rsp == NULL) { return false; + } // If valid, or the location mode is OFF, we're done if (!NoteResponseError(rsp) || strcmp(JGetString(rsp, "mode"), "off") == 0) { NoteDeleteResponse(rsp); locationValid = true; locationLastErr[0] = '\0'; - if (errbuf != NULL) + if (errbuf != NULL) { *errbuf = '\0'; + } return true; } // Remember the error for next iteration strlcpy(locationLastErr, JGetString(rsp, "err"), sizeof(locationLastErr)); - if (errbuf != NULL) + if (errbuf != NULL) { strlcpy(errbuf, locationLastErr, errbuflen); + } NoteDeleteResponse(rsp); return false; @@ -314,137 +510,148 @@ bool NoteLocationValidST(char *errbuf, uint32_t errbuflen) { //**************************************************************************/ /*! - @brief Set a service environment variable default string. - @param variable The variable key. - @param buf The variable value. - @returns boolean indicating if variable was set. + @brief Set a service environment variable default string. + @param variable The variable key. + @param buf The variable value. + @returns boolean indicating if variable was set. */ /**************************************************************************/ -bool NoteSetEnvDefault(const char *variable, char *buf) { - bool success = false; +bool NoteSetEnvDefault(const char *variable, char *buf) +{ + bool success = false; J *req = NoteNewRequest("env.default"); if (req != NULL) { JAddStringToObject(req, "name", variable); - JAddStringToObject(req, "text", buf); + JAddStringToObject(req, "text", buf); success = NoteRequest(req); } - return success; + return success; } //**************************************************************************/ /*! - @brief Set a service environment variable default integer. - @param variable The variable key. - @param defaultVal The variable value. - @returns boolean indicating if variable was set. + @brief Set a service environment variable default integer. + @param variable The variable key. + @param defaultVal The variable value. + @returns boolean indicating if variable was set. */ /**************************************************************************/ -bool NoteSetEnvDefaultInt(const char *variable, int defaultVal) { +bool NoteSetEnvDefaultInt(const char *variable, long int defaultVal) +{ char buf[32]; - snprintf(buf, sizeof(buf), "%d", defaultVal); + JItoA(defaultVal, buf); return NoteSetEnvDefault(variable, buf); } //**************************************************************************/ /*! - @brief Set a service environment variable default number. - @param variable The variable key. - @param defaultVal The variable value. - @returns boolean indicating if variable was set. + @brief Set a service environment variable default number. + @param variable The variable key. + @param defaultVal The variable value. + @returns boolean indicating if variable was set. */ /**************************************************************************/ -bool NoteSetEnvDefaultNumber(const char *variable, JNUMBER defaultVal) { +bool NoteSetEnvDefaultNumber(const char *variable, JNUMBER defaultVal) +{ char buf[32]; - JNtoA(defaultVal, buf, -1); + JNtoA(defaultVal, buf, -1); return NoteSetEnvDefault(variable, buf); } //**************************************************************************/ /*! - @brief Get a service environment variable number. - @param variable The variable key. - @param defaultVal The default variable value. - @returns environment variable value. + @brief Get a service environment variable number. + @param variable The variable key. + @param defaultVal The default variable value. + @returns environment variable value. */ /**************************************************************************/ -JNUMBER NoteGetEnvNumber(const char *variable, JNUMBER defaultVal) { +JNUMBER NoteGetEnvNumber(const char *variable, JNUMBER defaultVal) +{ char buf[32], buf2[32];; - snprintf(buf2, sizeof(buf2), "%f", defaultVal); + JNtoA(defaultVal, buf2, -1); NoteGetEnv(variable, buf2, buf, sizeof(buf)); return JAtoN(buf, NULL); } //**************************************************************************/ /*! - @brief Get a service environment variable integer. - @param variable The variable key. - @param defaultVal The default variable value. - @returns environment variable value. + @brief Get a service environment variable integer. + @param variable The variable key. + @param defaultVal The default variable value. + @returns environment variable value. */ /**************************************************************************/ -int NoteGetEnvInt(const char *variable, int defaultVal) { +long int NoteGetEnvInt(const char *variable, long int defaultVal) +{ char buf[32], buf2[32];; - snprintf(buf2, sizeof(buf2), "%d", defaultVal); + JItoA(defaultVal, buf2); NoteGetEnv(variable, buf2, buf, sizeof(buf)); return atoi(buf); } //**************************************************************************/ /*! - @brief Get a service environment variable. - @param variable The variable key. - @param defaultVal The variable value. - @param buf (out) The buffer in which to place the variable value. - @param buflen The length of the output buffer. - @returns true if there is no error (JSON response with no explicit error) + @brief Get a service environment variable. + @param variable The variable key. + @param defaultVal The variable value. + @param buf (out) The buffer in which to place the variable value. + @param buflen The length of the output buffer. + @returns true if there is no error (JSON response with no explicit error) */ /**************************************************************************/ -bool NoteGetEnv(const char *variable, const char *defaultVal, char *buf, uint32_t buflen) { - bool success = false; - if (defaultVal == NULL) +bool NoteGetEnv(const char *variable, const char *defaultVal, char *buf, uint32_t buflen) +{ + bool success = false; + if (defaultVal == NULL) { buf[0] = '\0'; - else + } else { strlcpy(buf, defaultVal, buflen); + } J *req = NoteNewRequest("env.get"); if (req != NULL) { JAddStringToObject(req, "name", variable); J *rsp = NoteRequestResponse(req); if (rsp != NULL) { if (!NoteResponseError(rsp)) { - success = true; + success = true; char *val = JGetString(rsp, "text"); - if (val[0] != '\0') + if (val[0] != '\0') { strlcpy(buf, val, buflen); + } } NoteDeleteResponse(rsp); } } - return success; + return success; } //**************************************************************************/ /*! - @brief Determine if the Notecard is connected to the network. - @returns boolean. `true` if connected. + @brief Determine if the Notecard is connected to the network. + @returns boolean. `true` if connected. */ /**************************************************************************/ -bool NoteIsConnected() { +bool NoteIsConnected() +{ connectivityTimer = 0; return NoteIsConnectedST(); } //**************************************************************************/ /*! - @brief Determine if the Notecard is connected to the network. - @returns boolean. `true` if connected. + @brief Determine if the Notecard is connected to the network. + @returns boolean. `true` if connected. */ /**************************************************************************/ -bool NoteIsConnectedST() { - if (timerExpiredSecs(&connectivityTimer, 10)) { +bool NoteIsConnectedST() +{ + if (timerExpiredSecs(&connectivityTimer, suppressionTimerSecs)) { J *rsp = NoteRequestResponse(NoteNewRequest("hub.status")); if (rsp != NULL) { - if (!NoteResponseError(rsp)) + if (!NoteResponseError(rsp)) { cardConnected = JGetBool(rsp, "connected"); + } NoteDeleteResponse(rsp); } } @@ -453,13 +660,14 @@ bool NoteIsConnectedST() { //**************************************************************************/ /*! - @brief Get Full Network Status via `hub.status`. - @param statusBuf (out) a buffer to populate with the status response. - @param statusBufLen The length of the status buffer - @returns boolean. `true` if the status was retrieved. + @brief Get Full Network Status via `hub.status`. + @param statusBuf (out) a buffer to populate with the status response. + @param statusBufLen The length of the status buffer + @returns boolean. `true` if the status was retrieved. */ /**************************************************************************/ -bool NoteGetNetStatus(char *statusBuf, int statusBufLen) { +bool NoteGetNetStatus(char *statusBuf, int statusBufLen) +{ bool success = false; statusBuf[0] = '\0'; J *rsp = NoteRequestResponse(NoteNewRequest("hub.status")); @@ -475,13 +683,14 @@ bool NoteGetNetStatus(char *statusBuf, int statusBufLen) { //**************************************************************************/ /*! - @brief Make a `card.version` request - @param versionBuf (out) a buffer to populate with the version response. - @param versionBufLen The length of the version buffer - @returns boolean. `true` if the version information was retrieved. + @brief Make a `card.version` request + @param versionBuf (out) a buffer to populate with the version response. + @param versionBufLen The length of the version buffer + @returns boolean. `true` if the version information was retrieved. */ /**************************************************************************/ -bool NoteGetVersion(char *versionBuf, int versionBufLen) { +bool NoteGetVersion(char *versionBuf, int versionBufLen) +{ bool success = false; versionBuf[0] = '\0'; J *rsp = NoteRequestResponse(NoteNewRequest("card.version")); @@ -497,39 +706,48 @@ bool NoteGetVersion(char *versionBuf, int versionBufLen) { //**************************************************************************/ /*! - @brief Make a `card.location` request - @param retLat (out) The retrieved latitude value. - @param retLon (out) The retrieved longitude value. - @param time (out) The retrieved time. - @param statusBuf (out) a buffer to populate with the location response. - @param statusBufLen The length of the location buffer - @returns boolean. `true` if the location information was retrieved. + @brief Make a `card.location` request + @param retLat (out) The retrieved latitude value. + @param retLon (out) The retrieved longitude value. + @param time (out) The retrieved time. + @param statusBuf (out) a buffer to populate with the location response. + @param statusBufLen The length of the location buffer + @returns boolean. `true` if the location information was retrieved. */ /**************************************************************************/ -bool NoteGetLocation(JNUMBER *retLat, JNUMBER *retLon, JTIME *time, char *statusBuf, int statusBufLen) { +bool NoteGetLocation(JNUMBER *retLat, JNUMBER *retLon, JTIME *time, char *statusBuf, int statusBufLen) +{ bool locValid = false; - if (statusBuf != NULL) + if (statusBuf != NULL) { *statusBuf = '\0'; - if (retLat != NULL) + } + if (retLat != NULL) { *retLat = 0.0; - if (retLon != NULL) + } + if (retLon != NULL) { *retLon = 0.0; - if (time != NULL) + } + if (time != NULL) { *time = 0; + } J *rsp = NoteRequestResponse(NoteNewRequest("card.location")); if (rsp != NULL) { - if (statusBuf != NULL) + if (statusBuf != NULL) { strlcpy(statusBuf, JGetString(rsp, "err"), statusBufLen); + } if (JIsPresent(rsp, "lat") && JIsPresent(rsp, "lon")) { - if (retLat != NULL) + if (retLat != NULL) { *retLat = JGetNumber(rsp, "lat"); - if (retLon != NULL) + } + if (retLon != NULL) { *retLon = JGetNumber(rsp, "lon"); + } locValid = true; } JTIME seconds = JGetInt(rsp, "time"); - if (seconds != 0 && time != NULL) + if (seconds != 0 && time != NULL) { *time = seconds; + } NoteDeleteResponse(rsp); } return locValid; @@ -537,13 +755,14 @@ bool NoteGetLocation(JNUMBER *retLat, JNUMBER *retLon, JTIME *time, char *status //**************************************************************************/ /*! - @brief Set the card location to a static value. - @param lat The latitude value to set on the Notecard. - @param lon The longitude value to set on the Notecard. - @returns boolean. `true` if the location information was set. + @brief Set the card location to a static value. + @param lat The latitude value to set on the Notecard. + @param lon The longitude value to set on the Notecard. + @returns boolean. `true` if the location information was set. */ /**************************************************************************/ -bool NoteSetLocation(JNUMBER lat, JNUMBER lon) { +bool NoteSetLocation(JNUMBER lat, JNUMBER lon) +{ bool success = false; J *req = NoteNewRequest("card.location.mode"); if (req != NULL) { @@ -557,11 +776,12 @@ bool NoteSetLocation(JNUMBER lat, JNUMBER lon) { //**************************************************************************/ /*! - @brief Clear last known Location. - @returns boolean. `true` if the location information was cleared. + @brief Clear last known Location. + @returns boolean. `true` if the location information was cleared. */ /**************************************************************************/ -bool NoteClearLocation() { +bool NoteClearLocation() +{ bool success = false; J *req = NoteNewRequest("card.location.mode"); if (req != NULL) { @@ -573,20 +793,22 @@ bool NoteClearLocation() { //**************************************************************************/ /*! - @brief Get the current location Mode. - @param modeBuf (out) a buffer to populate with the location mode response. - @param modeBufLen The length of the mode buffer - @returns boolean. `true` if the mode information was retrieved. + @brief Get the current location Mode. + @param modeBuf (out) a buffer to populate with the location mode response. + @param modeBufLen The length of the mode buffer + @returns boolean. `true` if the mode information was retrieved. */ /**************************************************************************/ -bool NoteGetLocationMode(char *modeBuf, int modeBufLen) { +bool NoteGetLocationMode(char *modeBuf, int modeBufLen) +{ bool success = false; modeBuf[0] = '\0'; J *rsp = NoteRequestResponse(NoteNewRequest("card.location.mode")); if (rsp != NULL) { success = !NoteResponseError(rsp); - if (success) + if (success) { strlcpy(modeBuf, JGetString(rsp, "mode"), modeBufLen); + } NoteDeleteResponse(rsp); } return success; @@ -594,18 +816,20 @@ bool NoteGetLocationMode(char *modeBuf, int modeBufLen) { //**************************************************************************/ /*! - @brief Make a `card.location.mode` request. - @param mode the Notecard location mode to set. - @param seconds The value of the `seconds` field for the request. - @returns boolean. `true` if the mode was set. + @brief Make a `card.location.mode` request. + @param mode the Notecard location mode to set. + @param seconds The value of the `seconds` field for the request. + @returns boolean. `true` if the mode was set. */ /**************************************************************************/ -bool NoteSetLocationMode(const char *mode, uint32_t seconds) { +bool NoteSetLocationMode(const char *mode, uint32_t seconds) +{ bool success = false; J *req = NoteNewRequest("card.location.mode"); if (req != NULL) { - if (mode[0] == '\0') + if (mode[0] == '\0') { mode = "-"; + } JAddStringToObject(req, "mode", mode); JAddNumberToObject(req, "seconds", seconds); success = NoteRequest(req); @@ -615,47 +839,49 @@ bool NoteSetLocationMode(const char *mode, uint32_t seconds) { //**************************************************************************/ /*! - @brief Get the current service configuration information, unsuppressed. - @param productBuf (out) a buffer to populate with the ProductUID from the - response. - @param productBufLen The length of the ProductUID buffer. - @param serviceBuf (out) a buffer to populate with the host url from the - response. - @param serviceBufLen The length of the host buffer. - @param deviceBuf (out) a buffer to populate with the DeviceUID from the - response. - @param deviceBufLen The length of the DeviceUID buffer. - @param snBuf (out) a buffer to populate with the Product Serial Number - from the response. - @param snBufLen The length of the Serial Number buffer. - @returns boolean. `true` if the service configuration was obtained. + @brief Get the current service configuration information, unsuppressed. + @param productBuf (out) a buffer to populate with the ProductUID from the + response. + @param productBufLen The length of the ProductUID buffer. + @param serviceBuf (out) a buffer to populate with the host url from the + response. + @param serviceBufLen The length of the host buffer. + @param deviceBuf (out) a buffer to populate with the DeviceUID from the + response. + @param deviceBufLen The length of the DeviceUID buffer. + @param snBuf (out) a buffer to populate with the Product Serial Number + from the response. + @param snBufLen The length of the Serial Number buffer. + @returns boolean. `true` if the service configuration was obtained. */ /**************************************************************************/ -bool NoteGetServiceConfig(char *productBuf, int productBufLen, char *serviceBuf, int serviceBufLen, char *deviceBuf, int deviceBufLen, char *snBuf, int snBufLen) { +bool NoteGetServiceConfig(char *productBuf, int productBufLen, char *serviceBuf, int serviceBufLen, char *deviceBuf, int deviceBufLen, char *snBuf, int snBufLen) +{ serviceConfigTimer = 0; return NoteGetServiceConfigST(productBuf, productBufLen, serviceBuf, serviceBufLen, deviceBuf, deviceBufLen, snBuf, snBufLen); } //**************************************************************************/ /*! - @brief Get the current service configuration information, with - a supression timer. - @param productBuf (out) a buffer to populate with the ProductUID from the - response. - @param productBufLen The length of the ProductUID buffer. - @param serviceBuf (out) a buffer to populate with the host url from the - response. - @param serviceBufLen The length of the host buffer. - @param deviceBuf (out) a buffer to populate with the DeviceUID from the - response. - @param deviceBufLen The length of the DeviceUID buffer. - @param snBuf (out) a buffer to populate with the Product Serial Number - from the response. - @param snBufLen The length of the Serial Number buffer. - @returns boolean. `true` if the service configuration was obtained. + @brief Get the current service configuration information, with + a supression timer. + @param productBuf (out) a buffer to populate with the ProductUID from the + response. + @param productBufLen The length of the ProductUID buffer. + @param serviceBuf (out) a buffer to populate with the host url from the + response. + @param serviceBufLen The length of the host buffer. + @param deviceBuf (out) a buffer to populate with the DeviceUID from the + response. + @param deviceBufLen The length of the DeviceUID buffer. + @param snBuf (out) a buffer to populate with the Product Serial Number + from the response. + @param snBufLen The length of the Serial Number buffer. + @returns boolean. `true` if the service configuration was obtained. */ /**************************************************************************/ -bool NoteGetServiceConfigST(char *productBuf, int productBufLen, char *serviceBuf, int serviceBufLen, char *deviceBuf, int deviceBufLen, char *snBuf, int snBufLen) { +bool NoteGetServiceConfigST(char *productBuf, int productBufLen, char *serviceBuf, int serviceBufLen, char *deviceBuf, int deviceBufLen, char *snBuf, int snBufLen) +{ bool success = false; // Use cache except for a rare refresh @@ -676,51 +902,64 @@ bool NoteGetServiceConfigST(char *productBuf, int productBufLen, char *serviceBu } // Done - if (productBuf != NULL) + if (productBuf != NULL) { strlcpy(productBuf, scProduct, productBufLen); - if (serviceBuf != NULL) + } + if (serviceBuf != NULL) { strlcpy(serviceBuf, scService, serviceBufLen); - if (deviceBuf != NULL) + } + if (deviceBuf != NULL) { strlcpy(deviceBuf, scDevice, deviceBufLen); - if (snBuf != NULL) + } + if (snBuf != NULL) { strlcpy(snBuf, scSN, snBufLen); + } return success; } //**************************************************************************/ /*! - @brief Get Status of the Notecard, unsuppressed. - @param statusBuf (out) a buffer to populate with the Notecard status - from the response. - @param statusBufLen The length of the status buffer. - @param bootTime (out) The Notecard boot time. - @param retUSB (out) Whether the Notecard is powered over USB. - @param retSignals (out) Whether the Notecard has a network signal. - @returns boolean. `true` if the card status was obtained. + @brief Get Status of the Notecard, unsuppressed. + @param statusBuf (out) a buffer to populate with the Notecard status + from the response. + @param statusBufLen The length of the status buffer. + @param bootTime (out) The Notecard boot time. + @param retUSB (out) Whether the Notecard is powered over USB. + @param retSignals (out) Whether the Notecard has a network signal. + @returns boolean. `true` if the card status was obtained. */ /**************************************************************************/ -bool NoteGetStatus(char *statusBuf, int statusBufLen, JTIME *bootTime, bool *retUSB, bool *retSignals) { +bool NoteGetStatus(char *statusBuf, int statusBufLen, JTIME *bootTime, bool *retUSB, bool *retSignals) +{ bool success = false; - if (statusBuf != NULL) + if (statusBuf != NULL) { statusBuf[0] = '\0'; - if (bootTime != NULL) + } + if (bootTime != NULL) { *bootTime = 0; - if (retUSB != NULL) + } + if (retUSB != NULL) { *retUSB = false; - if (retSignals != NULL) + } + if (retSignals != NULL) { *retSignals = false; + } J *rsp = NoteRequestResponse(NoteNewRequest("card.status")); if (rsp != NULL) { success = !NoteResponseError(rsp); if (success) { - if (statusBuf != NULL) + if (statusBuf != NULL) { strlcpy(statusBuf, JGetString(rsp, "status"), statusBufLen); - if (bootTime != NULL) + } + if (bootTime != NULL) { *bootTime = JGetInt(rsp, "time"); - if (retUSB != NULL) + } + if (retUSB != NULL) { *retUSB = JGetBool(rsp, "usb"); - if (retSignals != NULL && JGetBool(rsp, "connected")) + } + if (retSignals != NULL && JGetBool(rsp, "connected")) { *retSignals = (JGetInt(rsp, "signals") > 0); + } } NoteDeleteResponse(rsp); } @@ -729,17 +968,18 @@ bool NoteGetStatus(char *statusBuf, int statusBufLen, JTIME *bootTime, bool *ret //**************************************************************************/ /*! - @brief Get Status of the Notecard, with a supression timer. - @param statusBuf (out) a buffer to populate with the Notecard status - from the response. - @param statusBufLen The length of the status buffer. - @param bootTime (out) The Notecard boot time. - @param retUSB (out) Whether the Notecard is powered over USB. - @param retSignals (out) Whether the Notecard has a network signal. - @returns boolean. `true` if the card status was obtained. + @brief Get Status of the Notecard, with a supression timer. + @param statusBuf (out) a buffer to populate with the Notecard status + from the response. + @param statusBufLen The length of the status buffer. + @param bootTime (out) The Notecard boot time. + @param retUSB (out) Whether the Notecard is powered over USB. + @param retSignals (out) Whether the Notecard has a network signal. + @returns boolean. `true` if the card status was obtained. */ /**************************************************************************/ -bool NoteGetStatusST(char *statusBuf, int statusBufLen, JTIME *bootTime, bool *retUSB, bool *retSignals) { +bool NoteGetStatusST(char *statusBuf, int statusBufLen, JTIME *bootTime, bool *retUSB, bool *retSignals) +{ bool success = false; static char lastStatus[128] = {0}; static JTIME lastBootTime = 0; @@ -748,7 +988,7 @@ bool NoteGetStatusST(char *statusBuf, int statusBufLen, JTIME *bootTime, bool *r static uint32_t statusTimer = 0; // Refresh if it's time to do so - if (timerExpiredSecs(&statusTimer, 10)) { + if (timerExpiredSecs(&statusTimer, suppressionTimerSecs)) { J *rsp = NoteRequestResponse(NoteNewRequest("card.status")); if (rsp != NULL) { success = !NoteResponseError(rsp); @@ -756,10 +996,11 @@ bool NoteGetStatusST(char *statusBuf, int statusBufLen, JTIME *bootTime, bool *r strlcpy(lastStatus, JGetString(rsp, "status"), sizeof(lastStatus)); lastBootTime = JGetInt(rsp, "time"); lastUSB = JGetBool(rsp, "usb"); - if (JGetBool(rsp, "connected")) + if (JGetBool(rsp, "connected")) { lastSignals = (JGetInt(rsp, "signals") > 0); - else + } else { lastSignals = false; + } } NoteDeleteResponse(rsp); } @@ -768,29 +1009,34 @@ bool NoteGetStatusST(char *statusBuf, int statusBufLen, JTIME *bootTime, bool *r } // Done - if (statusBuf != NULL) + if (statusBuf != NULL) { strlcpy(statusBuf, lastStatus, statusBufLen); - if (bootTime != NULL) + } + if (bootTime != NULL) { *bootTime = lastBootTime; - if (retUSB != NULL) + } + if (retUSB != NULL) { *retUSB = lastUSB; - if (retSignals != NULL) + } + if (retSignals != NULL) { *retSignals = lastSignals; + } return success; } //**************************************************************************/ /*! - @brief Save the current state and use `card.attn` to set a host - sleep interval. - @param stateb64 A base64 payload to keep in memory while the host sleeps. - @param seconds The duration to sleep. - @param modes A list of `card.attn` modes. - @returns boolean. `true` if request was successful. + @brief Save the current state and use `card.attn` to set a host + sleep interval. + @param stateb64 A base64 payload to keep in memory while the host sleeps. + @param seconds The duration to sleep. + @param modes A list of `card.attn` modes. + @returns boolean. `true` if request was successful. */ /**************************************************************************/ -bool NoteSleep(char *stateb64, uint32_t seconds, const char *modes) { +bool NoteSleep(char *stateb64, uint32_t seconds, const char *modes) +{ bool success = false; // Use a Command rather than a Request so that the Notecard doesn't try to send @@ -800,14 +1046,15 @@ bool NoteSleep(char *stateb64, uint32_t seconds, const char *modes) { if (req != NULL) { // Add the base64 item in a wonderful way that doesn't strdup the huge string J *stringReferenceItem = JCreateStringReference(stateb64); - if (stringReferenceItem != NULL) + if (stringReferenceItem != NULL) { JAddItemToObject(req, "payload", stringReferenceItem); - char modestr[64]; - strlcpy(modestr, "sleep", sizeof(modestr)); - if (modes != NULL) { - strlcat(modestr, ",", sizeof(modestr)); - strlcat(modestr, modes, sizeof(modestr)); - } + } + char modestr[64]; + strlcpy(modestr, "sleep", sizeof(modestr)); + if (modes != NULL) { + strlcat(modestr, ",", sizeof(modestr)); + strlcat(modestr, modes, sizeof(modestr)); + } JAddStringToObject(req, "mode", modestr); JAddNumberToObject(req, "seconds", seconds); success = NoteRequest(req); @@ -819,25 +1066,28 @@ bool NoteSleep(char *stateb64, uint32_t seconds, const char *modes) { //**************************************************************************/ /*! - @brief Wake the module by restoring state into a state buffer of a - specified length, and fail if it isn't available or isn't that - length. - @param stateLen A length of the state payload buffer to return to the host. - @param state (out) The in-memory payload to return to the host. - @returns boolean. `true` if request was successful. + @brief Wake the module by restoring state into a state buffer of a + specified length, and fail if it isn't available or isn't that + length. + @param stateLen A length of the state payload buffer to return to the host. + @param state (out) The in-memory payload to return to the host. + @returns boolean. `true` if request was successful. */ /**************************************************************************/ -bool NoteWake(int stateLen, void *state) { +bool NoteWake(int stateLen, void *state) +{ J *req = NoteNewRequest("card.attn"); - if (req == NULL) + if (req == NULL) { return false; + } // Send it a command to request the saved state JAddBoolToObject(req, "start", true); J *rsp = NoteRequestResponse(req); - if (rsp == NULL) + if (rsp == NULL) { return false; + } if (NoteResponseError(rsp)) { NoteDeleteResponse(rsp); return false; @@ -845,8 +1095,9 @@ bool NoteWake(int stateLen, void *state) { // Note the current time, if the field is present JTIME seconds = JGetInt(rsp, "time"); - if (seconds != 0) + if (seconds != 0) { setTime(seconds); + } // Exit if no payload char *payload = JGetString(rsp, "payload"); @@ -887,13 +1138,14 @@ bool NoteWake(int stateLen, void *state) { //**************************************************************************/ /*! - @brief Restore the module to factory settings. - @param deleteConfigSettings Whether to delete current configuration - settings on the Notecard during the reset. - @returns boolean. `true` if reset was successful. + @brief Restore the module to factory settings. + @param deleteConfigSettings Whether to delete current configuration + settings on the Notecard during the reset. + @returns boolean. `true` if reset was successful. */ /**************************************************************************/ -bool NoteFactoryReset(bool deleteConfigSettings) { +bool NoteFactoryReset(bool deleteConfigSettings) +{ bool success = false; // Perform the restore-to-factor-settings transaction @@ -904,16 +1156,18 @@ bool NoteFactoryReset(bool deleteConfigSettings) { } // Exit if it didn't work - if (!success) + if (!success) { return false; + } // Wait for serial to stabilize after it reboots _DelayMs(5000); _Debug("CARD RESTORED\n"); // Reset the Notecard - while (!NoteReset()) + while (!NoteReset()) { _DelayMs(5000); + } // Success return true; @@ -922,19 +1176,21 @@ bool NoteFactoryReset(bool deleteConfigSettings) { //**************************************************************************/ /*! - @brief Set the Notecard Product UID. - @param productID The ProductUID to set on the Notecard. - @returns boolean. `true` if request was successful. + @brief Set the Notecard Product UID. + @param productID The ProductUID to set on the Notecard. + @returns boolean. `true` if request was successful. */ /**************************************************************************/ -bool NoteSetProductID(const char *productID) { +bool NoteSetProductID(const char *productID) +{ bool success = false; J *req = NoteNewRequest("hub.set"); if (req != NULL) { - if (productID[0] == '\0') + if (productID[0] == '\0') { JAddStringToObject(req, "product", "-"); - else + } else { JAddStringToObject(req, "product", productID); + } success = NoteRequest(req); } // Flush cache so that service config is re-fetched @@ -944,19 +1200,21 @@ bool NoteSetProductID(const char *productID) { //**************************************************************************/ /*! - @brief Set the Notecard Serial Number. - @param sn The Serial Number to set on the Notecard. - @returns boolean. `true` if request was successful. + @brief Set the Notecard Serial Number. + @param sn The Serial Number to set on the Notecard. + @returns boolean. `true` if request was successful. */ /**************************************************************************/ -bool NoteSetSerialNumber(const char *sn) { +bool NoteSetSerialNumber(const char *sn) +{ bool success = false; J *req = NoteNewRequest("hub.set"); if (req != NULL) { - if (sn[0] == '\0') + if (sn[0] == '\0') { JAddStringToObject(req, "sn", "-"); - else + } else { JAddStringToObject(req, "sn", sn); + } success = NoteRequest(req); } // Flush cache so that service config is re-fetched @@ -966,18 +1224,19 @@ bool NoteSetSerialNumber(const char *sn) { //**************************************************************************/ /*! - @brief Set the Notecard upload mode and interval. - @param uploadMode The upload mode (for instance, `continuous`, - or `periodic`). - @param uploadMinutes The max number of minutes to wait between Notehub - uploads. - @param align Flag to specify that uploads should be grouped within the - specified period, rather than counting the number of minutes - from first modified. - @returns boolean. `true` if request was successful. + @brief Set the Notecard upload mode and interval. + @param uploadMode The upload mode (for instance, `continuous`, + or `periodic`). + @param uploadMinutes The max number of minutes to wait between Notehub + uploads. + @param align Flag to specify that uploads should be grouped within the + specified period, rather than counting the number of minutes + from first modified. + @returns boolean. `true` if request was successful. */ /**************************************************************************/ -bool NoteSetUploadMode(const char *uploadMode, int uploadMinutes, bool align) { +bool NoteSetUploadMode(const char *uploadMode, int uploadMinutes, bool align) +{ bool success = false; J *req = NoteNewRequest("hub.set"); if (req != NULL) { @@ -996,22 +1255,23 @@ bool NoteSetUploadMode(const char *uploadMode, int uploadMinutes, bool align) { //**************************************************************************/ /*! - @brief Set the Notecard upload mode, download mode and interval. - @param uploadMode The upload mode (for instance, `continuous`, - or `periodic`). - @param uploadMinutes The max number of minutes to wait between Notehub - uploads. - @param downloadMinutes The max number of minutes to wait between Notehub - downloads. - @param align Flag to specify that uploads should be grouped within the - specified period, rather than counting the number of minutes - from first modified. - @param sync Setting this flag when mode is `continuous` causes an - immediate sync when a file is modified on the service side. - @returns boolean. `true` if request was successful. + @brief Set the Notecard upload mode, download mode and interval. + @param uploadMode The upload mode (for instance, `continuous`, + or `periodic`). + @param uploadMinutes The max number of minutes to wait between Notehub + uploads. + @param downloadMinutes The max number of minutes to wait between Notehub + downloads. + @param align Flag to specify that uploads should be grouped within the + specified period, rather than counting the number of minutes + from first modified. + @param sync Setting this flag when mode is `continuous` causes an + immediate sync when a file is modified on the service side. + @returns boolean. `true` if request was successful. */ /**************************************************************************/ -bool NoteSetSyncMode(const char *uploadMode, int uploadMinutes, int downloadMinutes, bool align, bool sync) { +bool NoteSetSyncMode(const char *uploadMode, int uploadMinutes, int downloadMinutes, bool align, bool sync) +{ bool success = false; J *req = NoteNewRequest("hub.set"); if (req != NULL) { @@ -1022,8 +1282,9 @@ bool NoteSetSyncMode(const char *uploadMode, int uploadMinutes, int downloadMinu // rather than counting the number of minutes from "first modified". JAddBoolToObject(req, "align", align); } - if (downloadMinutes != 0) + if (downloadMinutes != 0) { JAddNumberToObject(req, "inbound", downloadMinutes); + } // Setting this flag when mode is "continuous" causes an immediate sync // when a file is modified on the service side via HTTP JAddBoolToObject(req, "sync", sync); @@ -1035,13 +1296,14 @@ bool NoteSetSyncMode(const char *uploadMode, int uploadMinutes, int downloadMinu //**************************************************************************/ /*! - @brief Set a template for a Notefile. - @param target The Notefile on which to set a template. - @param body The template body. - @returns boolean. `true` if request was successful. + @brief Set a template for a Notefile. + @param target The Notefile on which to set a template. + @param body The template body. + @returns boolean. `true` if request was successful. */ /**************************************************************************/ -bool NoteTemplate(const char *target, J *body) { +bool NoteTemplate(const char *target, J *body) +{ J *req = NoteNewRequest("note.template"); if (req == NULL) { JDelete(body); @@ -1054,15 +1316,16 @@ bool NoteTemplate(const char *target, J *body) { //**************************************************************************/ /*! - @brief Add a Note to a Notefile with `note.add`. - @param target The Notefile on which to set a template. - @param body The template body. - @param urgent Whether to perform an immediate sync after the Note - is added. - @returns boolean. `true` if request was successful. + @brief Add a Note to a Notefile with `note.add`. + @param target The Notefile on which to set a template. + @param body The template body. + @param urgent Whether to perform an immediate sync after the Note + is added. + @returns boolean. `true` if request was successful. */ /**************************************************************************/ -bool NoteAdd(const char *target, J *body, bool urgent) { +bool NoteAdd(const char *target, J *body, bool urgent) +{ // Initiate the request J *req = NoteNewRequest("note.add"); @@ -1077,8 +1340,9 @@ bool NoteAdd(const char *target, J *body, bool urgent) { JAddItemToObject(req, "body", body); // Initiate sync NOW if it's urgent - if (urgent) + if (urgent) { JAddBoolToObject(req, "start", true); + } // Perform the transaction return NoteRequest(req); @@ -1087,16 +1351,17 @@ bool NoteAdd(const char *target, J *body, bool urgent) { //**************************************************************************/ /*! - @brief Send a body to a route using an HTTP request. - Body is freed, regardless of success. - @param method HTTP method to use, `get`, `post` or `put`. - @param routeAlias The Notehub Route alias. - @param notefile The Notefile name. - @param body The request JSON body. - @returns boolean. `true` if request was successful. + @brief Send a body to a route using an HTTP request. + Body is freed, regardless of success. + @param method HTTP method to use, `get`, `post` or `put`. + @param routeAlias The Notehub Route alias. + @param notefile The Notefile name. + @param body The request JSON body. + @returns boolean. `true` if request was successful. */ /**************************************************************************/ -bool NoteSendToRoute(const char *method, const char *routeAlias, char *notefile, J *body) { +bool NoteSendToRoute(const char *method, const char *routeAlias, char *notefile, J *body) +{ // Create the new event J *req = NoteNewRequest("note.event"); @@ -1142,20 +1407,21 @@ bool NoteSendToRoute(const char *method, const char *routeAlias, char *notefile, //**************************************************************************/ /*! - @brief Get the voltage of the Notecard. - @param voltage (out) The Notecard voltage. - @returns boolean. `true` if request was successful. + @brief Get the voltage of the Notecard. + @param voltage (out) The Notecard voltage. + @returns boolean. `true` if request was successful. */ /**************************************************************************/ -bool NoteGetVoltage(JNUMBER *voltage) { +bool NoteGetVoltage(JNUMBER *voltage) +{ bool success = false; *voltage = 0.0; J *rsp = NoteRequestResponse(NoteNewRequest("card.voltage")); if (rsp != NULL) { if (!NoteResponseError(rsp)) { *voltage = JGetNumber(rsp, "value"); - success = true; - } + success = true; + } NoteDeleteResponse(rsp); } return success; @@ -1163,20 +1429,21 @@ bool NoteGetVoltage(JNUMBER *voltage) { //**************************************************************************/ /*! - @brief Get the temperature of the Notecard. - @param temp (out) The Notecard temperature. - @returns boolean. `true` if request was successful. + @brief Get the temperature of the Notecard. + @param temp (out) The Notecard temperature. + @returns boolean. `true` if request was successful. */ /**************************************************************************/ -bool NoteGetTemperature(JNUMBER *temp) { +bool NoteGetTemperature(JNUMBER *temp) +{ bool success = false; *temp = 0.0; J *rsp = NoteRequestResponse(NoteNewRequest("card.temp")); if (rsp != NULL) { if (!NoteResponseError(rsp)) { *temp = JGetNumber(rsp, "value"); - success = true; - } + success = true; + } NoteDeleteResponse(rsp); } return success; @@ -1184,42 +1451,51 @@ bool NoteGetTemperature(JNUMBER *temp) { //**************************************************************************/ /*! - @brief Get the Notecard contact info. - @param nameBuf (out) The contact name buffer. - @param nameBufLen The length of the contact name buffer. - @param orgBuf (out) The contact organization buffer. - @param orgBufLen The length of the contact organization buffer. - @param roleBuf (out) The contact role buffer. - @param roleBufLen The length of the contact role buffer. - @param emailBuf (out) The contact email buffer. - @param emailBufLen The length of the contact email buffer. - @returns boolean. `true` if request was successful. + @brief Get the Notecard contact info. + @param nameBuf (out) The contact name buffer. + @param nameBufLen The length of the contact name buffer. + @param orgBuf (out) The contact organization buffer. + @param orgBufLen The length of the contact organization buffer. + @param roleBuf (out) The contact role buffer. + @param roleBufLen The length of the contact role buffer. + @param emailBuf (out) The contact email buffer. + @param emailBufLen The length of the contact email buffer. + @returns boolean. `true` if request was successful. */ /**************************************************************************/ -bool NoteGetContact(char *nameBuf, int nameBufLen, char *orgBuf, int orgBufLen, char *roleBuf, int roleBufLen, char *emailBuf, int emailBufLen) { +bool NoteGetContact(char *nameBuf, int nameBufLen, char *orgBuf, int orgBufLen, char *roleBuf, int roleBufLen, char *emailBuf, int emailBufLen) +{ bool success = false; - if (nameBuf != NULL) + if (nameBuf != NULL) { *nameBuf = '\0'; - if (orgBuf != NULL) + } + if (orgBuf != NULL) { *orgBuf = '\0'; - if (roleBuf != NULL) + } + if (roleBuf != NULL) { *roleBuf = '\0'; - if (emailBuf != NULL) + } + if (emailBuf != NULL) { *emailBuf = '\0'; + } J *rsp = NoteRequestResponse(NoteNewRequest("card.contact")); if (rsp != NULL) { success = !NoteResponseError(rsp); if (success) { - if (nameBuf != NULL) + if (nameBuf != NULL) { strlcpy(nameBuf, JGetString(rsp, "name"), nameBufLen); - if (orgBuf != NULL) + } + if (orgBuf != NULL) { strlcpy(orgBuf, JGetString(rsp, "org"), orgBufLen); - if (roleBuf != NULL) + } + if (roleBuf != NULL) { strlcpy(roleBuf, JGetString(rsp, "role"), roleBufLen); - if (emailBuf != NULL) + } + if (emailBuf != NULL) { strlcpy(emailBuf, JGetString(rsp, "email"), emailBufLen); + } } NoteDeleteResponse(rsp); } @@ -1229,40 +1505,48 @@ bool NoteGetContact(char *nameBuf, int nameBufLen, char *orgBuf, int orgBufLen, //**************************************************************************/ /*! - @brief Set the Notecard contact info. - @param nameBuf (out) The contact name buffer. - @param orgBuf (out) The contact organization buffer. - @param roleBuf (out) The contact role buffer. - @param emailBuf (out) The contact email buffer. - @returns boolean. `true` if request was successful. + @brief Set the Notecard contact info. + @param nameBuf (out) The contact name buffer. + @param orgBuf (out) The contact organization buffer. + @param roleBuf (out) The contact role buffer. + @param emailBuf (out) The contact email buffer. + @returns boolean. `true` if request was successful. */ /**************************************************************************/ -bool NoteSetContact(char *nameBuf, char *orgBuf, char *roleBuf, char *emailBuf) { +bool NoteSetContact(char *nameBuf, char *orgBuf, char *roleBuf, char *emailBuf) +{ J *req = NoteNewRequest("card.contact"); - if (req == NULL) + if (req == NULL) { return false; - if (nameBuf != NULL) + } + if (nameBuf != NULL) { JAddStringToObject(req, "name", nameBuf); - if (orgBuf != NULL) + } + if (orgBuf != NULL) { JAddStringToObject(req, "org", orgBuf); - if (roleBuf != NULL) + } + if (roleBuf != NULL) { JAddStringToObject(req, "role", roleBuf); - if (emailBuf != NULL) + } + if (emailBuf != NULL) { JAddStringToObject(req, "email", emailBuf); + } return NoteRequest(req); } // A simple suppression timer based on a millisecond system clock. This clock is reset to 0 // after boot and every wake. This returns true if the specified interval has elapsed, in seconds, // and it updates the timer if it expires so that we will go another period. -static bool timerExpiredSecs(uint32_t *timer, uint32_t periodSecs) { +static bool timerExpiredSecs(uint32_t *timer, uint32_t periodSecs) +{ bool expired = false; // If the timer went backward, we've expired regardless of the interval uint32_t prev = *timer; uint32_t now = _GetMs(); - if (now < prev) + if (now < prev) { prev = 0; + } // If never initialized, it's expired if (prev == 0 || now >= prev+(periodSecs*1000)) { @@ -1276,61 +1560,64 @@ static bool timerExpiredSecs(uint32_t *timer, uint32_t periodSecs) { //**************************************************************************/ /*! - @brief Periodically show Notecard sync status, returning `true` if - something was displayed - @param pollFrequencyMs The time to wait, in milliseconds, between - polling for sync status. - @param maxLevel The Synclog level to monitor. - @returns boolean. `true` if a sync status message was displayed. + @brief Periodically show Notecard sync status, returning `true` if + something was displayed + @param pollFrequencyMs The time to wait, in milliseconds, between + polling for sync status. + @param maxLevel The Synclog level to monitor. + @returns boolean. `true` if a sync status message was displayed. */ /**************************************************************************/ -bool NoteDebugSyncStatus(int pollFrequencyMs, int maxLevel) { - - // Suppress polls so as to not overwhelm the notecard - static uint32_t lastCommStatusPollMs = 0; - if (lastCommStatusPollMs != 0 && _GetMs() < (lastCommStatusPollMs + pollFrequencyMs)) - return false; - - // Get the next queued status note - J *req = NoteNewRequest("note.get"); - if (req == NULL) - return false; - JAddStringToObject(req, "file", "_synclog.qi"); - JAddBoolToObject(req, "delete", true); - NoteSuspendTransactionDebug(); - J *rsp = NoteRequestResponse(req); - NoteResumeTransactionDebug(); - if (rsp != NULL) { - - // If an error is returned, this means that no response is pending. Note - // that it's expected that this might return either a "note does not exist" - // error if there are no pending inbound notes, or a "file does not exist" error - // if the inbound queue hasn't yet been created on the service. - if (NoteResponseError(rsp)) { - // Only stop polling quickly if we don't receive anything - lastCommStatusPollMs = _GetMs(); - NoteDeleteResponse(rsp); - return false; - } - - // Get the note's body - J *body = JGetObject(rsp, "body"); - if (body != NULL) { - if (maxLevel < 0 || JGetInt(body, "level") <= maxLevel) { - _Debug("sync: "); - _Debug(JGetString(body, "subsystem")); - _Debug(" "); - _Debug(JGetString(body, "text")); - _Debug("\n"); - } - } - - // Done with this response - NoteDeleteResponse(rsp); - return true; - } - - return false; +bool NoteDebugSyncStatus(int pollFrequencyMs, int maxLevel) +{ + + // Suppress polls so as to not overwhelm the notecard + static uint32_t lastCommStatusPollMs = 0; + if (lastCommStatusPollMs != 0 && _GetMs() < (lastCommStatusPollMs + pollFrequencyMs)) { + return false; + } + + // Get the next queued status note + J *req = NoteNewRequest("note.get"); + if (req == NULL) { + return false; + } + JAddStringToObject(req, "file", "_synclog.qi"); + JAddBoolToObject(req, "delete", true); + NoteSuspendTransactionDebug(); + J *rsp = NoteRequestResponse(req); + NoteResumeTransactionDebug(); + if (rsp != NULL) { + + // If an error is returned, this means that no response is pending. Note + // that it's expected that this might return either a "note does not exist" + // error if there are no pending inbound notes, or a "file does not exist" error + // if the inbound queue hasn't yet been created on the service. + if (NoteResponseError(rsp)) { + // Only stop polling quickly if we don't receive anything + lastCommStatusPollMs = _GetMs(); + NoteDeleteResponse(rsp); + return false; + } + + // Get the note's body + J *body = JGetObject(rsp, "body"); + if (body != NULL) { + if (maxLevel < 0 || JGetInt(body, "level") <= maxLevel) { + _Debug("sync: "); + _Debug(JGetString(body, "subsystem")); + _Debug(" "); + _Debug(JGetString(body, "text")); + _Debug("\n"); + } + } + + // Done with this response + NoteDeleteResponse(rsp); + return true; + } + + return false; } @@ -1344,21 +1631,23 @@ typedef struct objHeader_s { //**************************************************************************/ /*! - @brief Obtain the amount of free memory available on the Notecard. - @returns The number of bytes of memory available on the Notecard. + @brief Obtain the amount of free memory available on the Notecard. + @returns The number of bytes of memory available on the Notecard. */ /**************************************************************************/ -uint32_t NoteMemAvailable() { +uint32_t NoteMemAvailable() +{ // Allocate progressively smaller and smaller chunks objHeader *lastObj = NULL; - static int maxsize = 35000; - for (int i=maxsize; i>=sizeof(objHeader); i=i-sizeof(objHeader)) { - for (int j=0;;j++) { + static long int maxsize = 35000; + for (long int i=maxsize; i>=sizeof(objHeader); i=i-sizeof(objHeader)) { + for (long int j=0;; j++) { objHeader *thisObj; - thisObj = (objHeader *) malloc(i); - if (thisObj == NULL) + thisObj = (objHeader *) _Malloc(i); + if (thisObj == NULL) { break; + } thisObj->prev = lastObj; thisObj->length = i; lastObj = thisObj; @@ -1366,8 +1655,8 @@ uint32_t NoteMemAvailable() { } // Free the objects backwards - int lastLength = 0; - int lastLengthCount = 0; + long int lastLength = 0; + long int lastLengthCount = 0; uint32_t total = 0; while (lastObj != NULL) { if (lastObj->length != lastLength) { @@ -1379,9 +1668,9 @@ uint32_t NoteMemAvailable() { objHeader *thisObj = lastObj; lastObj = lastObj->prev; total += thisObj->length; - free(thisObj); + _Free(thisObj); } - return total; - + return total; + } diff --git a/src/note-c/n_hooks.c b/src/note-c/n_hooks.c index eb89266..eed98f3 100644 --- a/src/note-c/n_hooks.c +++ b/src/note-c/n_hooks.c @@ -24,10 +24,14 @@ //**************************************************************************/ /*! - @brief Show malloc operations for debugging in very low mem environments. + @brief Show malloc operations for debugging in very low mem environments. */ /**************************************************************************/ -#define NOTE_SHOW_MALLOC false +#define NOTE_SHOW_MALLOC false +#if NOTE_SHOW_MALLOC +#include +void *malloc_show(size_t len); +#endif // Which I/O port to use #define interfaceNone 0 @@ -37,121 +41,121 @@ // Externalized Hooks //**************************************************************************/ /*! - @brief Hook for the calling platform's debug interface, if any. + @brief Hook for the calling platform's debug interface, if any. */ /**************************************************************************/ debugOutputFn hookDebugOutput = NULL; //**************************************************************************/ /*! - @brief Hook for the calling platform's I2C lock function. + @brief Hook for the calling platform's I2C lock function. */ /**************************************************************************/ mutexFn hookLockI2C = NULL; //**************************************************************************/ /*! - @brief Hook for the calling platform's I2C unlock function. + @brief Hook for the calling platform's I2C unlock function. */ /**************************************************************************/ mutexFn hookUnlockI2C = NULL; //**************************************************************************/ /*! - @brief Hook for the calling platform's Notecard lock function. + @brief Hook for the calling platform's Notecard lock function. */ /**************************************************************************/ mutexFn hookLockNote = NULL; //**************************************************************************/ /*! - @brief Hook for the calling platform's Notecard lock function. + @brief Hook for the calling platform's Notecard lock function. */ /**************************************************************************/ mutexFn hookUnlockNote = NULL; //**************************************************************************/ /*! - @brief Hook for the calling platform's memory allocation function. + @brief Hook for the calling platform's memory allocation function. */ /**************************************************************************/ mallocFn hookMalloc = NULL; //**************************************************************************/ /*! - @brief Hook for the calling platform's memory free function. + @brief Hook for the calling platform's memory free function. */ /**************************************************************************/ freeFn hookFree = NULL; //**************************************************************************/ /*! - @brief Hook for the calling platform's delay function. + @brief Hook for the calling platform's delay function. */ /**************************************************************************/ delayMsFn hookDelayMs = NULL; //**************************************************************************/ /*! - @brief Hook for the calling platform's millis timing function. + @brief Hook for the calling platform's millis timing function. */ /**************************************************************************/ getMsFn hookGetMs = NULL; //**************************************************************************/ /*! - @brief Hook for the calling platform's current active interface. Value is - one of: - - interfaceNone = 0 (default) - - interfaceSerial = 1 - - interfaceI2C = 2 + @brief Hook for the calling platform's current active interface. Value is + one of: + - interfaceNone = 0 (default) + - interfaceSerial = 1 + - interfaceI2C = 2 */ /**************************************************************************/ uint32_t hookActiveInterface = interfaceNone; //**************************************************************************/ /*! - @brief Hook for the calling platform's Serial reset function. + @brief Hook for the calling platform's Serial reset function. */ /**************************************************************************/ serialResetFn hookSerialReset = NULL; //**************************************************************************/ /*! - @brief Hook for the calling platform's Serial transmit function. + @brief Hook for the calling platform's Serial transmit function. */ /**************************************************************************/ serialTransmitFn hookSerialTransmit = NULL; //**************************************************************************/ /*! - @brief Hook for the calling platform's Serial data available function. + @brief Hook for the calling platform's Serial data available function. */ /**************************************************************************/ serialAvailableFn hookSerialAvailable = NULL; //**************************************************************************/ /*! - @brief Hook for the calling platform's Serial receive function. + @brief Hook for the calling platform's Serial receive function. */ /**************************************************************************/ serialReceiveFn hookSerialReceive = NULL; //**************************************************************************/ /*! - @brief Hook for the calling platform's I2C address. + @brief Hook for the calling platform's I2C address. */ /**************************************************************************/ uint32_t i2cAddress = 0; //**************************************************************************/ /*! - @brief Hook for the calling platform's I2C maximum segment size, in bytes. + @brief Hook for the calling platform's I2C maximum segment size, in bytes. */ /**************************************************************************/ uint32_t i2cMax = 0; //**************************************************************************/ /*! - @brief Hook for the calling platform's I2C reset function. + @brief Hook for the calling platform's I2C reset function. */ /**************************************************************************/ i2cResetFn hookI2CReset = NULL; //**************************************************************************/ /*! - @brief Hook for the calling platform's transmit function. + @brief Hook for the calling platform's transmit function. */ /**************************************************************************/ i2cTransmitFn hookI2CTransmit = NULL; //**************************************************************************/ /*! - @brief Hook for the calling platform's I2C receive function. + @brief Hook for the calling platform's I2C receive function. */ /**************************************************************************/ i2cReceiveFn hookI2CReceive = NULL; @@ -164,38 +168,44 @@ static nTransactionFn notecardTransaction = NULL; //**************************************************************************/ /*! - @brief Set the default memory and timing hooks if they aren't already set - @param mallocfn The default memory allocation `malloc` - function to use. - @param freefn The default memory free - function to use. - @param delayfn The default delay function to use. - @param millisfn The default 'millis' function to use. + @brief Set the default memory and timing hooks if they aren't already set + @param mallocfn The default memory allocation `malloc` + function to use. + @param freefn The default memory free + function to use. + @param delayfn The default delay function to use. + @param millisfn The default 'millis' function to use. */ /**************************************************************************/ -void NoteSetFnDefault(mallocFn mallocfn, freeFn freefn, delayMsFn delayfn, getMsFn millisfn) { - if (hookMalloc == NULL) +void NoteSetFnDefault(mallocFn mallocfn, freeFn freefn, delayMsFn delayfn, getMsFn millisfn) +{ + if (hookMalloc == NULL) { hookMalloc = mallocfn; - if (hookFree == NULL) + } + if (hookFree == NULL) { hookFree = freefn; - if (hookDelayMs == NULL) + } + if (hookDelayMs == NULL) { hookDelayMs = delayfn; - if (hookGetMs == NULL) + } + if (hookGetMs == NULL) { hookGetMs = millisfn; + } } //**************************************************************************/ /*! - @brief Set the platform-specific memory and timing hooks. - @param mallocfn The platform-specific memory allocation `malloc` - function to use. - @param freefn The platform-specific memory free - function to use. - @param delayfn The platform-specific delay function to use. - @param millisfn The platform-specific 'millis' function to use. + @brief Set the platform-specific memory and timing hooks. + @param mallocfn The platform-specific memory allocation `malloc` + function to use. + @param freefn The platform-specific memory free + function to use. + @param delayfn The platform-specific delay function to use. + @param millisfn The platform-specific 'millis' function to use. */ /**************************************************************************/ -void NoteSetFn(mallocFn mallocfn, freeFn freefn, delayMsFn delayfn, getMsFn millisfn) { +void NoteSetFn(mallocFn mallocfn, freeFn freefn, delayMsFn delayfn, getMsFn millisfn) +{ hookMalloc = mallocfn; hookFree = freefn; hookDelayMs = delayfn; @@ -204,37 +214,40 @@ void NoteSetFn(mallocFn mallocfn, freeFn freefn, delayMsFn delayfn, getMsFn mill //**************************************************************************/ /*! - @brief Set the platform-specific debug output function. - @param fn A function pointer to call for debug output. + @brief Set the platform-specific debug output function. + @param fn A function pointer to call for debug output. */ /**************************************************************************/ -void NoteSetFnDebugOutput(debugOutputFn fn) { +void NoteSetFnDebugOutput(debugOutputFn fn) +{ hookDebugOutput = fn; } //**************************************************************************/ /*! - @brief Determine if a debug output function has been set. - @returns A boolean indicating whether a debug ouput function was - provided. + @brief Determine if a debug output function has been set. + @returns A boolean indicating whether a debug ouput function was + provided. */ /**************************************************************************/ -bool NoteIsDebugOutputActive() { +bool NoteIsDebugOutputActive() +{ return hookDebugOutput != NULL; } //**************************************************************************/ /*! - @brief Set the platform-specific mutex functions for I2C and the - Notecard. - @param lockI2Cfn The platform-specific I2C lock function to use. - @param unlockI2Cfn The platform-specific I2C unlock function to use. - @param lockNotefn The platform-specific Notecard lock function to use. - @param unlockNotefn The platform-specific Notecard unlock function - to use. + @brief Set the platform-specific mutex functions for I2C and the + Notecard. + @param lockI2Cfn The platform-specific I2C lock function to use. + @param unlockI2Cfn The platform-specific I2C unlock function to use. + @param lockNotefn The platform-specific Notecard lock function to use. + @param unlockNotefn The platform-specific Notecard unlock function + to use. */ /**************************************************************************/ -void NoteSetFnMutex(mutexFn lockI2Cfn, mutexFn unlockI2Cfn, mutexFn lockNotefn, mutexFn unlockNotefn) { +void NoteSetFnMutex(mutexFn lockI2Cfn, mutexFn unlockI2Cfn, mutexFn lockNotefn, mutexFn unlockNotefn) +{ hookLockI2C = lockI2Cfn; hookUnlockI2C = unlockI2Cfn; hookLockNote = lockNotefn; @@ -243,15 +256,16 @@ void NoteSetFnMutex(mutexFn lockI2Cfn, mutexFn unlockI2Cfn, mutexFn lockNotefn, //**************************************************************************/ /*! - @brief Set the platform-specific Serial communication functions for the - Notecard. - @param resetfn The platform-specific Serial reset function to use. - @param transmitfn The platform-specific Serial transmit function to use. - @param availfn The platform-specific Serial available function to use. - @param receivefn The platform-specific Serial receive function to use. + @brief Set the platform-specific Serial communication functions for the + Notecard. + @param resetfn The platform-specific Serial reset function to use. + @param transmitfn The platform-specific Serial transmit function to use. + @param availfn The platform-specific Serial available function to use. + @param receivefn The platform-specific Serial receive function to use. */ /**************************************************************************/ -void NoteSetFnSerial(serialResetFn resetfn, serialTransmitFn transmitfn, serialAvailableFn availfn, serialReceiveFn receivefn) { +void NoteSetFnSerial(serialResetFn resetfn, serialTransmitFn transmitfn, serialAvailableFn availfn, serialReceiveFn receivefn) +{ hookActiveInterface = interfaceSerial; hookSerialReset = resetfn; @@ -265,17 +279,18 @@ void NoteSetFnSerial(serialResetFn resetfn, serialTransmitFn transmitfn, serialA //**************************************************************************/ /*! - @brief Set the platform-specific I2C communication functions for the - Notecard. - @param i2caddress The I2C address to use for Notecard communication. - @param i2cmax The I2C maximum segment size to use for Notecard - communication. - @param resetfn The platform-specific I2C reset function to use. - @param transmitfn The platform-specific I2C transmit function to use. - @param receivefn The platform-specific I2C receive function to use. + @brief Set the platform-specific I2C communication functions for the + Notecard. + @param i2caddress The I2C address to use for Notecard communication. + @param i2cmax The I2C maximum segment size to use for Notecard + communication. + @param resetfn The platform-specific I2C reset function to use. + @param transmitfn The platform-specific I2C transmit function to use. + @param receivefn The platform-specific I2C receive function to use. */ /**************************************************************************/ -void NoteSetFnI2C(uint32_t i2caddress, uint32_t i2cmax, i2cResetFn resetfn, i2cTransmitFn transmitfn, i2cReceiveFn receivefn) { +void NoteSetFnI2C(uint32_t i2caddress, uint32_t i2cmax, i2cResetFn resetfn, i2cTransmitFn transmitfn, i2cReceiveFn receivefn) +{ i2cAddress = i2caddress; i2cMax = i2cmax; @@ -289,47 +304,45 @@ void NoteSetFnI2C(uint32_t i2caddress, uint32_t i2cmax, i2cResetFn resetfn, i2cT notecardTransaction = i2cNoteTransaction; } -// Runtime hook wrappers - //**************************************************************************/ /*! - @brief Write a to the debug stream and output a newline. - @param line A debug string for output. + @brief Set the platform-specific communications method to be disabled */ /**************************************************************************/ -void NoteDebugln(const char *line) { - NoteDebug(line); - NoteDebug(c_newline); +void NoteSetFnDisabled() +{ + + hookActiveInterface = interfaceNone; + + notecardReset = NULL; + notecardTransaction = NULL; + } +// Runtime hook wrappers + //**************************************************************************/ /*! - @brief Write to the debug stream. - @param line A debug string for output. + @brief Write a to the debug stream and output a newline. + @param line A debug string for output. */ /**************************************************************************/ -void NoteDebug(const char *line) { -#ifndef NOTE_NODEBUG - if (hookDebugOutput != NULL) - hookDebugOutput(line); -#endif +void NoteDebugln(const char *line) +{ + NoteDebug(line); + NoteDebug(c_newline); } //**************************************************************************/ /*! - @brief Write a formatted string to the debug output. - @param format A format string for output. - @param ... One or more values to interpolate into the format string. + @brief Write to the debug stream. + @param line A debug string for output. */ /**************************************************************************/ -void NoteDebugf(const char *format, ...) { +void NoteDebug(const char *line) +{ #ifndef NOTE_NODEBUG if (hookDebugOutput != NULL) { - char line[256]; - va_list args; - va_start(args, format); - vsnprintf(line, sizeof(line), format, args); - va_end(args); hookDebugOutput(line); } #endif @@ -337,55 +350,84 @@ void NoteDebugf(const char *format, ...) { //**************************************************************************/ /*! - @brief Get the current milliseconds value from the platform-specific - hook. - @returns The current milliseconds value. + @brief Get the current milliseconds value from the platform-specific + hook. + @returns The current milliseconds value. */ /**************************************************************************/ -long unsigned int NoteGetMs() { - if (hookGetMs == NULL) +long unsigned int NoteGetMs() +{ + if (hookGetMs == NULL) { return 0; + } return hookGetMs(); } //**************************************************************************/ /*! - @brief Delay milliseconds using the platform-specific hook. - @param ms the milliseconds delay value. + @brief Delay milliseconds using the platform-specific hook. + @param ms the milliseconds delay value. */ /**************************************************************************/ -void NoteDelayMs(uint32_t ms) { - if (hookDelayMs != NULL) +void NoteDelayMs(uint32_t ms) +{ + if (hookDelayMs != NULL) { hookDelayMs(ms); + } } #if NOTE_SHOW_MALLOC //**************************************************************************/ /*! - @brief If set for low-memory platforms, show a malloc call. - @param len the number of bytes of memory allocated by the last call. + @brief If set for low-memory platforms, show a malloc call. + @param len the number of bytes of memory allocated by the last call. */ /**************************************************************************/ -void *malloc_show(size_t len) { - char str[10]; - itoa(len, str, 10); +void htoa32(uint32_t n, char *p); +void htoa32(uint32_t n, char *p) +{ + int i; + for (i=0; i<8; i++) { + uint32_t nibble = (n >> 28) & 0xff; + n = n << 4; + if (nibble >= 10) { + *p++ = 'A' + (nibble-10); + } else { + *p++ = '0' + nibble; + } + } + *p = '\0'; +} +void *malloc_show(size_t len) +{ + char str[16]; + JItoA(len, str); + hookDebugOutput("malloc "); hookDebugOutput(str); - hookDebugOutput("\r\n"); - return hookMalloc(len); + void *p = hookMalloc(len); + if (p == NULL) { + hookDebugOutput("FAIL"); + } else { + htoa32((uint32_t)p, str); + hookDebugOutput(str); + } + return p; } #endif //**************************************************************************/ /*! - @brief Allocate a memory chunk using the platform-specific hook. - @param size the number of bytes to allocate. + @brief Allocate a memory chunk using the platform-specific hook. + @param size the number of bytes to allocate. */ /**************************************************************************/ -void *NoteMalloc(size_t size) { - if (hookMalloc == NULL) +void *NoteMalloc(size_t size) +{ + if (hookMalloc == NULL) { return NULL; + } #if NOTE_SHOW_MALLOC - return malloc_show(size); + return malloc_show(size); #else return hookMalloc(size); #endif @@ -393,225 +435,258 @@ void *NoteMalloc(size_t size) { //**************************************************************************/ /*! - @brief Free memory using the platform-specific hook. - @param p A pointer to the memory address to free. + @brief Free memory using the platform-specific hook. + @param p A pointer to the memory address to free. */ /**************************************************************************/ -void NoteFree(void *p) { - if (hookFree != NULL) +void NoteFree(void *p) +{ + if (hookFree != NULL) { +#if NOTE_SHOW_MALLOC + char str[16]; + htoa32((uint32_t)p, str); + hookDebugOutput("free"); + hookDebugOutput(str); +#endif hookFree(p); + } } //**************************************************************************/ /*! - @brief Lock the I2C bus using the platform-specific hook. + @brief Lock the I2C bus using the platform-specific hook. */ /**************************************************************************/ -void NoteLockI2C() { - if (hookLockI2C != NULL) +void NoteLockI2C() +{ + if (hookLockI2C != NULL) { hookLockI2C(); + } } //**************************************************************************/ /*! - @brief Unlock the I2C bus using the platform-specific hook. + @brief Unlock the I2C bus using the platform-specific hook. */ /**************************************************************************/ -void NoteUnlockI2C() { - if (hookUnlockI2C != NULL) +void NoteUnlockI2C() +{ + if (hookUnlockI2C != NULL) { hookUnlockI2C(); + } } //**************************************************************************/ /*! - @brief Lock the Notecard using the platform-specific hook. + @brief Lock the Notecard using the platform-specific hook. */ /**************************************************************************/ -void NoteLockNote() { - if (hookLockNote != NULL) +void NoteLockNote() +{ + if (hookLockNote != NULL) { hookLockNote(); + } } //**************************************************************************/ /*! - @brief Unlock the Notecard using the platform-specific hook. + @brief Unlock the Notecard using the platform-specific hook. */ /**************************************************************************/ -void NoteUnlockNote() { - if (hookUnlockNote != NULL) +void NoteUnlockNote() +{ + if (hookUnlockNote != NULL) { hookUnlockNote(); + } } //**************************************************************************/ /*! - @brief Reset the Serial bus using the platform-specific hook. - @returns A boolean indicating whether the Serial bus was reset. + @brief Reset the Serial bus using the platform-specific hook. + @returns A boolean indicating whether the Serial bus was reset. */ /**************************************************************************/ -bool NoteSerialReset() { +bool NoteSerialReset() +{ if (hookActiveInterface == interfaceSerial && hookSerialReset != NULL) { return hookSerialReset(); - } - return false; + } + return false; } //**************************************************************************/ /*! - @brief Transmit bytes over Serial using the platform-specific hook. - @param text The bytes to transmit. - @param len The length of bytes. - @param flush `true` to flush the bytes upon transmit. + @brief Transmit bytes over Serial using the platform-specific hook. + @param text The bytes to transmit. + @param len The length of bytes. + @param flush `true` to flush the bytes upon transmit. */ /**************************************************************************/ -void NoteSerialTransmit(uint8_t *text, size_t len, bool flush) { +void NoteSerialTransmit(uint8_t *text, size_t len, bool flush) +{ if (hookActiveInterface == interfaceSerial && hookSerialTransmit != NULL) { hookSerialTransmit(text, len, flush); - } + } } //**************************************************************************/ /*! - @brief Determine if Serial bus is available using the platform-specific - hook. - @returns A boolean indicating whether the Serial bus is available to read. + @brief Determine if Serial bus is available using the platform-specific + hook. + @returns A boolean indicating whether the Serial bus is available to read. */ /**************************************************************************/ -bool NoteSerialAvailable() { +bool NoteSerialAvailable() +{ if (hookActiveInterface == interfaceSerial && hookSerialAvailable != NULL) { return hookSerialAvailable(); - } + } return false; } //**************************************************************************/ /*! - @brief Obtain a character from the Serial bus using the platform-specific - hook. - @returns A character from the Serial bus. + @brief Obtain a character from the Serial bus using the platform-specific + hook. + @returns A character from the Serial bus. */ /**************************************************************************/ -char NoteSerialReceive() { +char NoteSerialReceive() +{ if (hookActiveInterface == interfaceSerial && hookSerialReceive != NULL) { return hookSerialReceive(); - } + } return 0; } //**************************************************************************/ /*! - @brief Reset the I2C bus using the platform-specific hook. - @returns A boolean indicating whether the I2C bus was reset. + @brief Reset the I2C bus using the platform-specific hook. + @returns A boolean indicating whether the I2C bus was reset. */ /**************************************************************************/ -bool NoteI2CReset(uint16_t DevAddress) { +bool NoteI2CReset(uint16_t DevAddress) +{ if (hookActiveInterface == interfaceI2C && hookI2CReset != NULL) { return hookI2CReset(DevAddress); - } - return false; + } + return false; } //**************************************************************************/ /*! - @brief Transmit bytes over I2C using the platform-specific hook. - @param DevAddress the I2C address for transmission. - @param pBuffer The bytes to transmit. - @param Size The length of bytes. - @returns A c-string from the platform-specific hook, or an error string - if the bus is not active. + @brief Transmit bytes over I2C using the platform-specific hook. + @param DevAddress the I2C address for transmission. + @param pBuffer The bytes to transmit. + @param Size The length of bytes. + @returns A c-string from the platform-specific hook, or an error string + if the bus is not active. */ /**************************************************************************/ -const char *NoteI2CTransmit(uint16_t DevAddress, uint8_t* pBuffer, uint16_t Size) { +const char *NoteI2CTransmit(uint16_t DevAddress, uint8_t* pBuffer, uint16_t Size) +{ if (hookActiveInterface == interfaceI2C && hookI2CTransmit != NULL) { return hookI2CTransmit(DevAddress, pBuffer, Size); - } + } return "i2c not active"; } //**************************************************************************/ /*! - @brief Receive bytes from I2C using the platform-specific hook. - @param DevAddress the I2C address for transmission. - @param pBuffer (out) A buffer in which to place received bytes. - @param Size The length of bytes. - @param available (out) The number of bytes left to read. - @returns A c-string from the platform-specific hook, or an error string - if the bus is not active. + @brief Receive bytes from I2C using the platform-specific hook. + @param DevAddress the I2C address for transmission. + @param pBuffer (out) A buffer in which to place received bytes. + @param Size The length of bytes. + @param available (out) The number of bytes left to read. + @returns A c-string from the platform-specific hook, or an error string + if the bus is not active. */ /**************************************************************************/ -const char *NoteI2CReceive(uint16_t DevAddress, uint8_t* pBuffer, uint16_t Size, uint32_t *available) { +const char *NoteI2CReceive(uint16_t DevAddress, uint8_t* pBuffer, uint16_t Size, uint32_t *available) +{ if (hookActiveInterface == interfaceI2C && hookI2CReceive != NULL) { return hookI2CReceive(DevAddress, pBuffer, Size, available); - } + } return "i2c not active"; } //**************************************************************************/ /*! - @brief Get the I2C address of the Notecard. - @returns The current I2C address. + @brief Get the I2C address of the Notecard. + @returns The current I2C address. */ /**************************************************************************/ -uint32_t NoteI2CAddress() { - if (i2cAddress == NOTE_I2C_ADDR_DEFAULT) +uint32_t NoteI2CAddress() +{ + if (i2cAddress == NOTE_I2C_ADDR_DEFAULT) { return 0x17; + } return i2cAddress; } //**************************************************************************/ /*! - @brief Set the I2C address for communication with the Notecard. - @param i2caddress the I2C address to use for the Notecard. + @brief Set the I2C address for communication with the Notecard. + @param i2caddress the I2C address to use for the Notecard. */ /**************************************************************************/ -void NoteSetI2CAddress(uint32_t i2caddress) { - i2cAddress = i2caddress; +void NoteSetI2CAddress(uint32_t i2caddress) +{ + i2cAddress = i2caddress; } //**************************************************************************/ /*! - @brief Determine the maximum number of bytes for each segment of - data sent to the Notecard over I2C. - @returns A 32-bit integer of the maximum number of bytes per I2C segment. + @brief Determine the maximum number of bytes for each segment of + data sent to the Notecard over I2C. + @returns A 32-bit integer of the maximum number of bytes per I2C segment. */ /**************************************************************************/ -uint32_t NoteI2CMax() { +uint32_t NoteI2CMax() +{ // Many Arduino libraries (such as ESP32) have a limit less than 32, so if the max isn't specified // we must assume the worst and segment the I2C messages into very tiny chunks. - if (i2cMax == NOTE_I2C_MAX_DEFAULT) + if (i2cMax == NOTE_I2C_MAX_DEFAULT) { return 30; + } // Note design specs - if (i2cMax > 127) + if (i2cMax > 127) { i2cMax = 127; + } return i2cMax; } //**************************************************************************/ /*! - @brief Perform a hard reset on the Notecard using the platform-specific - hook. - @returns A boolean indicating whether the Notecard has been reset. + @brief Perform a hard reset on the Notecard using the platform-specific + hook. + @returns A boolean indicating whether the Notecard has been reset. */ /**************************************************************************/ -bool NoteHardReset() { - if (notecardReset == NULL) +bool NoteHardReset() +{ + if (notecardReset == NULL) { return false; + } return notecardReset(); } //**************************************************************************/ /*! - @brief Perform a JSON request to the Notecard using the currently-set - platform hook. - @param json the JSON request. - @param jsonResponse (out) A buffer with the JSON response. - @returns NULL if successful, or an error string if the transaction failed - or the hook has not been set. + @brief Perform a JSON request to the Notecard using the currently-set + platform hook. + @param json the JSON request. + @param jsonResponse (out) A buffer with the JSON response. + @returns NULL if successful, or an error string if the transaction failed + or the hook has not been set. */ /**************************************************************************/ -const char *NoteJSONTransaction(char *json, char **jsonResponse) { - if (notecardTransaction == NULL) - return "notecard not initialized"; +const char *NoteJSONTransaction(char *json, char **jsonResponse) +{ + if (notecardTransaction == NULL || hookActiveInterface == interfaceNone) { + return "i2c or serial interface must be selected"; + } return notecardTransaction(json, jsonResponse); } diff --git a/src/note-c/n_i2c.c b/src/note-c/n_i2c.c index 8fdb43f..51c6ed4 100644 --- a/src/note-c/n_i2c.c +++ b/src/note-c/n_i2c.c @@ -13,16 +13,20 @@ #include "n_lib.h" +// Forwards +static void _DelayIO(void); + /**************************************************************************/ /*! @brief We've noticed that there's an instability in some cards' - implementations of I2C, and as a result we introduce an intentional - delay before each and every I2C I/O.The timing was computed - empirically based on a number of commercial devices. + implementations of I2C, and as a result we introduce an intentional + delay before each and every I2C I/O.The timing was computed + empirically based on a number of commercial devices. */ /**************************************************************************/ -static void _DelayIO() { - _DelayMs(6); +static void _DelayIO() +{ + _DelayMs(6); } /**************************************************************************/ @@ -30,154 +34,161 @@ static void _DelayIO() { @brief Given a JSON string, perform an I2C transaction with the Notecard. @param json A c-string containing the JSON request object. - @param jsonResponse - An out parameter c-string buffer that will contain the JSON - response from the Notercard. - @returns a c-string with an error, or `NULL` if no error ocurred. + @param jsonResponse + An out parameter c-string buffer that will contain the JSON + response from the Notercard. + @returns a c-string with an error, or `NULL` if no error ocurred. */ /**************************************************************************/ -const char *i2cNoteTransaction(char *json, char **jsonResponse) { - - // Append '\n' to the transaction - int jsonLen = strlen(json)+1; - uint8_t *transmitBuf = (uint8_t *) _Malloc(jsonLen); - if (transmitBuf == NULL) - return ERRSTR("insufficient memory",c_mem); - memcpy(transmitBuf, json, jsonLen-1); - transmitBuf[jsonLen-1] = '\n'; - - // Transmit the request in chunks, but also in segments so as not to overwhelm the notecard's interrupt buffers - const char *estr; - uint8_t *chunk = transmitBuf; - uint32_t sentInSegment = 0; - while (jsonLen > 0) { - int chunklen = (uint8_t) (jsonLen > (int)_I2CMax() ? (int)_I2CMax() : jsonLen); - _LockI2C(); - _DelayIO(); - estr = _I2CTransmit(_I2CAddress(), chunk, chunklen); - if (estr != NULL) { - _Free(transmitBuf); - _I2CReset(_I2CAddress()); - _UnlockI2C(); +const char *i2cNoteTransaction(char *json, char **jsonResponse) +{ + + // Append '\n' to the transaction + int jsonLen = strlen(json)+1; + uint8_t *transmitBuf = (uint8_t *) _Malloc(jsonLen); + if (transmitBuf == NULL) { + return ERRSTR("insufficient memory",c_mem); + } + memcpy(transmitBuf, json, jsonLen-1); + transmitBuf[jsonLen-1] = '\n'; + + // Transmit the request in chunks, but also in segments so as not to overwhelm the notecard's interrupt buffers + const char *estr; + uint8_t *chunk = transmitBuf; + uint32_t sentInSegment = 0; + while (jsonLen > 0) { + int chunklen = (uint8_t) (jsonLen > (int)_I2CMax() ? (int)_I2CMax() : jsonLen); + _LockI2C(); + _DelayIO(); + estr = _I2CTransmit(_I2CAddress(), chunk, chunklen); + if (estr != NULL) { + _Free(transmitBuf); + _I2CReset(_I2CAddress()); + _UnlockI2C(); #ifdef ERRDBG - _Debug("i2c transmit: "); - _Debug(estr); - _Debug("\n"); + _Debug("i2c transmit: "); + _Debug(estr); + _Debug("\n"); #endif - return estr; - } - _UnlockI2C(); - chunk += chunklen; - jsonLen -= chunklen; - sentInSegment += chunklen; - if (sentInSegment > CARD_REQUEST_I2C_SEGMENT_MAX_LEN) { - sentInSegment = 0; - _DelayMs(CARD_REQUEST_I2C_SEGMENT_DELAY_MS); - } - _DelayMs(CARD_REQUEST_I2C_CHUNK_DELAY_MS); - } - - // Free the transmit buffer - _Free(transmitBuf); + return estr; + } + _UnlockI2C(); + chunk += chunklen; + jsonLen -= chunklen; + sentInSegment += chunklen; + if (sentInSegment > CARD_REQUEST_I2C_SEGMENT_MAX_LEN) { + sentInSegment = 0; + _DelayMs(CARD_REQUEST_I2C_SEGMENT_DELAY_MS); + } + _DelayMs(CARD_REQUEST_I2C_CHUNK_DELAY_MS); + } + + // Free the transmit buffer + _Free(transmitBuf); // If no reply expected, we're done - if (jsonResponse == NULL) + if (jsonResponse == NULL) { return NULL; - - // Dynamically grow the buffer as we read. Note that we always put the +1 in the alloc - // so we can be assured that it can be null-terminated, which must be the case because - // our json parser requires a null-terminated string. - int growlen = ALLOC_CHUNK; - int jsonbufAllocLen = growlen; - char *jsonbuf = (char *) _Malloc(jsonbufAllocLen+1); - if (jsonbuf == NULL) { + } + + // Dynamically grow the buffer as we read. Note that we always put the +1 in the alloc + // so we can be assured that it can be null-terminated, which must be the case because + // our json parser requires a null-terminated string. + int growlen = ALLOC_CHUNK; + int jsonbufAllocLen = growlen; + char *jsonbuf = (char *) _Malloc(jsonbufAllocLen+1); + if (jsonbuf == NULL) { #ifdef ERRDBG - _Debug("transaction: jsonbuf malloc failed\n"); + _Debug("transaction: jsonbuf malloc failed\n"); #endif - return ERRSTR("insufficient memory",c_mem); - } - - // Loop, building a reply buffer out of received chunks. We'll build the reply in the same - // buffer we used to transmit, and will grow it as necessary. - bool receivedNewline = false; - int jsonbufLen = 0; - int chunklen = 0; - uint32_t startMs = _GetMs(); - while (true) { - - // Grow the buffer as necessary to read this next chunk - if (jsonbufLen + chunklen > jsonbufAllocLen) { - if (chunklen > growlen) - jsonbufAllocLen += chunklen; - else - jsonbufAllocLen += growlen; - char *jsonbufNew = (char *) _Malloc(jsonbufAllocLen+1); - if (jsonbufNew == NULL) { + return ERRSTR("insufficient memory",c_mem); + } + + // Loop, building a reply buffer out of received chunks. We'll build the reply in the same + // buffer we used to transmit, and will grow it as necessary. + bool receivedNewline = false; + int jsonbufLen = 0; + int chunklen = 0; + uint32_t startMs = _GetMs(); + while (true) { + + // Grow the buffer as necessary to read this next chunk + if (jsonbufLen + chunklen > jsonbufAllocLen) { + if (chunklen > growlen) { + jsonbufAllocLen += chunklen; + } else { + jsonbufAllocLen += growlen; + } + char *jsonbufNew = (char *) _Malloc(jsonbufAllocLen+1); + if (jsonbufNew == NULL) { #ifdef ERRDBG - _Debug("transaction: jsonbuf grow malloc failed\n"); + _Debug("transaction: jsonbuf grow malloc failed\n"); #endif - _Free(jsonbuf); - return ERRSTR("insufficient memory",c_mem); - } - memcpy(jsonbufNew, jsonbuf, jsonbufLen); - _Free(jsonbuf); - jsonbuf = jsonbufNew; - } - - // Read the chunk - uint32_t available; - _LockI2C(); - _DelayIO(); - const char *err = _I2CReceive(_I2CAddress(), (uint8_t *) &jsonbuf[jsonbufLen], chunklen, &available); - _UnlockI2C(); - if (err != NULL) { - _Free(jsonbuf); + _Free(jsonbuf); + return ERRSTR("insufficient memory",c_mem); + } + memcpy(jsonbufNew, jsonbuf, jsonbufLen); + _Free(jsonbuf); + jsonbuf = jsonbufNew; + } + + // Read the chunk + uint32_t available; + _LockI2C(); + _DelayIO(); + const char *err = _I2CReceive(_I2CAddress(), (uint8_t *) &jsonbuf[jsonbufLen], chunklen, &available); + _UnlockI2C(); + if (err != NULL) { + _Free(jsonbuf); #ifdef ERRDBG - _Debug("i2c receive error\n"); + _Debug("i2c receive error\n"); #endif - return err; - } - - // We've now received the chunk - jsonbufLen += chunklen; - - // If the last byte of the chunk is \n, chances are that we're done. However, just so - // that we pull everything pending from the module, we only exit when we've received - // a newline AND there's nothing left available from the module. - if (jsonbufLen > 0 && jsonbuf[jsonbufLen-1] == '\n') - receivedNewline = true; - - // For the next iteration, read the min of what's available and what we're permitted to read - chunklen = (int) (available > _I2CMax() ? _I2CMax() : available); - - // If there's something available on the notecard for us to receive, do it - if (chunklen > 0) - continue; - - // If there's nothing available AND we've received a newline, we're done - if (receivedNewline) - break; - - // If we've timed out and nothing's available, exit - if (_GetMs() >= startMs + (NOTECARD_TRANSACTION_TIMEOUT_SEC*1000)) { - _Free(jsonbuf); + return err; + } + + // We've now received the chunk + jsonbufLen += chunklen; + + // If the last byte of the chunk is \n, chances are that we're done. However, just so + // that we pull everything pending from the module, we only exit when we've received + // a newline AND there's nothing left available from the module. + if (jsonbufLen > 0 && jsonbuf[jsonbufLen-1] == '\n') { + receivedNewline = true; + } + + // For the next iteration, read the min of what's available and what we're permitted to read + chunklen = (int) (available > _I2CMax() ? _I2CMax() : available); + + // If there's something available on the notecard for us to receive, do it + if (chunklen > 0) { + continue; + } + + // If there's nothing available AND we've received a newline, we're done + if (receivedNewline) { + break; + } + + // If we've timed out and nothing's available, exit + if (_GetMs() >= startMs + (NOTECARD_TRANSACTION_TIMEOUT_SEC*1000)) { + _Free(jsonbuf); #ifdef ERRDBG - _Debug("reply to request didn't arrive from module in time\n"); + _Debug("reply to request didn't arrive from module in time\n"); #endif - return ERRSTR("notecard request or response was lost",c_timeout); - } + return ERRSTR("notecard request or response was lost",c_timeout); + } - // Delay, simply waiting for the Note to process the request - _DelayMs(50); + // Delay, simply waiting for the Note to process the request + _DelayMs(50); - } + } - // Null-terminate it, using the +1 space that we'd allocated in the buffer - jsonbuf[jsonbufLen] = '\0'; + // Null-terminate it, using the +1 space that we'd allocated in the buffer + jsonbuf[jsonbufLen] = '\0'; - // Return it - *jsonResponse = jsonbuf; - return NULL; + // Return it + *jsonResponse = jsonbuf; + return NULL; } //**************************************************************************/ @@ -187,65 +198,65 @@ const char *i2cNoteTransaction(char *json, char **jsonResponse) { @returns a boolean. `true` if the reset was successful, `false`, if not. */ /**************************************************************************/ -bool i2cNoteReset() { - - // Reset the I2C subsystem and exit if failure - _LockI2C(); - bool success = _I2CReset(_I2CAddress()); - _UnlockI2C(); - if (!success) - return false; - - // Synchronize by guaranteeing not only that I2C works, but that we drain the remainder of any - // pending partial reply from a previously-aborted session. This outer loop does retries on - // I2C error, and is simply here for robustness. - bool notecardReady = false; - int retries; - for (retries=0; !notecardReady && retries<3; retries++) { - -#ifdef ERRDBG - _Debug("i2c reset\n"); -#endif - - // Loop to drain all chunks of data that may be ready to transmit to us - int chunklen = 0; - while (true) { - - // Read the next chunk of available data - uint32_t available; - uint8_t buffer[128]; - chunklen = (chunklen > (int)sizeof(buffer)) ? (int)sizeof(buffer) : chunklen; - chunklen = (chunklen > (int)_I2CMax()) ? (int)_I2CMax() : chunklen; - _LockI2C(); - _DelayIO(); - const char *err = _I2CReceive(_I2CAddress(), buffer, chunklen, &available); - _UnlockI2C(); - if (err) break; - - // If nothing left, we're ready to transmit a command to receive the data - if (available == 0) { - notecardReady = true; - break; - } - - // Read everything that's left on the module - chunklen = available; - - } - - // Exit loop if success - if (notecardReady) - break; - - // Reinitialize i2c if there's no response - _LockI2C(); - _I2CReset(_I2CAddress()); - _UnlockI2C(); - _Debug(ERRSTR("notecard not responding\n", "no notecard\n")); - _DelayMs(2000); - - } - - // Done - return notecardReady; +bool i2cNoteReset() +{ + + // Reset the I2C subsystem and exit if failure + _LockI2C(); + bool success = _I2CReset(_I2CAddress()); + _UnlockI2C(); + if (!success) { + return false; + } + + // Synchronize by guaranteeing not only that I2C works, but that we drain the remainder of any + // pending partial reply from a previously-aborted session. This outer loop does retries on + // I2C error, and is simply here for robustness. + bool notecardReady = false; + int retries; + for (retries=0; !notecardReady && retries<3; retries++) { + + // Loop to drain all chunks of data that may be ready to transmit to us + int chunklen = 0; + while (true) { + + // Read the next chunk of available data + uint32_t available; + uint8_t buffer[128]; + chunklen = (chunklen > (int)sizeof(buffer)) ? (int)sizeof(buffer) : chunklen; + chunklen = (chunklen > (int)_I2CMax()) ? (int)_I2CMax() : chunklen; + _LockI2C(); + _DelayIO(); + const char *err = _I2CReceive(_I2CAddress(), buffer, chunklen, &available); + _UnlockI2C(); + if (err) { + break; + } + + // If nothing left, we're ready to transmit a command to receive the data + if (available == 0) { + notecardReady = true; + break; + } + + // Read everything that's left on the module + chunklen = available; + + } + + // Exit loop if success + if (notecardReady) { + break; + } + + // Reinitialize i2c if there's no response + _LockI2C(); + _I2CReset(_I2CAddress()); + _UnlockI2C(); + _Debug(ERRSTR("notecard not responding\n", "no notecard\n")); + + } + + // Done + return notecardReady; } diff --git a/src/note-c/n_lib.h b/src/note-c/n_lib.h index 44f4561..edc3182 100644 --- a/src/note-c/n_lib.h +++ b/src/note-c/n_lib.h @@ -96,37 +96,37 @@ bool NoteIsDebugOutputActive(void); // Constants, a global optimization to save static string memory extern const char *c_null; -#define c_null_len 4 +#define c_null_len 4 extern const char *c_false; -#define c_false_len 5 +#define c_false_len 5 extern const char *c_true; -#define c_true_len 4 +#define c_true_len 4 extern const char *c_nullstring; -#define c_nullstring_len 0 +#define c_nullstring_len 0 extern const char *c_newline; -#define c_newline_len 2 +#define c_newline_len 2 extern const char *c_mem; -#define c_mem_len 3 +#define c_mem_len 3 extern const char *c_timeout; -#define c_timeout_len 7 +#define c_timeout_len 7 extern const char *c_err; -#define c_err_len 3 +#define c_err_len 3 extern const char *c_req; -#define c_req_len 3 +#define c_req_len 3 extern const char *c_cmd; -#define c_cmd_len 3 +#define c_cmd_len 3 extern const char *c_bad; -#define c_bad_len 3 +#define c_bad_len 3 // Readability wrappers. Anything starting with _ is simply calling the wrapper diff --git a/src/note-c/n_md5.c b/src/note-c/n_md5.c index cac2b0b..a8f2c90 100644 --- a/src/note-c/n_md5.c +++ b/src/note-c/n_md5.c @@ -28,44 +28,46 @@ #include #include "n_lib.h" +// Forwards +void htoa8(unsigned char n, unsigned char *p); +static void putu32 (unsigned long data, unsigned char *addr); +static unsigned long getu32 (const unsigned char *addr); + /* Little-endian byte-swapping routines. Note that these do not depend on the size of datatypes such as unsigned long, nor do they require us to detect the endianness of the machine we are running on. It is possible they should be macros for speed, but I would be surprised if they were a performance bottleneck for MD5. */ -static unsigned long -getu32 (addr) - const unsigned char *addr; +static unsigned long getu32 (const unsigned char *addr) { - return (((((unsigned long)addr[3] << 8) | addr[2]) << 8) - | addr[1]) << 8 | addr[0]; + return (((((unsigned long)addr[3] << 8) | addr[2]) << 8) + | addr[1]) << 8 | addr[0]; } -static void -putu32 (data, addr) - unsigned long data; - unsigned char *addr; +static void putu32 (unsigned long data, unsigned char *addr) { - addr[0] = (unsigned char)data; - addr[1] = (unsigned char)(data >> 8); - addr[2] = (unsigned char)(data >> 16); - addr[3] = (unsigned char)(data >> 24); + addr[0] = (unsigned char)data; + addr[1] = (unsigned char)(data >> 8); + addr[2] = (unsigned char)(data >> 16); + addr[3] = (unsigned char)(data >> 24); } /* Convert an 8-bit number to 2 hex digits, null-terminating it */ -void htoa8(unsigned char n, unsigned char *p) { - int i; +void htoa8(unsigned char n, unsigned char *p) +{ unsigned char nibble = (n >> 4) & 0xf; - if (nibble >= 10) + if (nibble >= 10) { *p++ = 'a' + (nibble-10); - else + } else { *p++ = '0' + nibble; + } nibble = n & 0xf; - if (nibble >= 10) + if (nibble >= 10) { *p++ = 'a' + (nibble-10); - else + } else { *p++ = '0' + nibble; + } *p = '\0'; } @@ -75,62 +77,63 @@ void htoa8(unsigned char n, unsigned char *p) { */ void NoteMD5Init(NoteMD5Context *ctx) { - memset(ctx, 0, sizeof(NoteMD5Context)); + memset(ctx, 0, sizeof(NoteMD5Context)); - ctx->buf[0] = 0x67452301; - ctx->buf[1] = 0xefcdab89; - ctx->buf[2] = 0x98badcfe; - ctx->buf[3] = 0x10325476; + ctx->buf[0] = 0x67452301; + ctx->buf[1] = 0xefcdab89; + ctx->buf[2] = 0x98badcfe; + ctx->buf[3] = 0x10325476; - ctx->bits[0] = 0; - ctx->bits[1] = 0; + ctx->bits[0] = 0; + ctx->bits[1] = 0; } /* * Update context to reflect the concatenation of another buffer full * of bytes. */ -void NoteMD5Update(NoteMD5Context *ctx, unsigned char const *buf, unsigned len) +void NoteMD5Update(NoteMD5Context *ctx, unsigned char const *buf, unsigned long len) { - unsigned long t; + unsigned long t; - /* Update bitcount */ + /* Update bitcount */ - t = ctx->bits[0]; - if ((ctx->bits[0] = (t + ((unsigned long)len << 3)) & 0xffffffff) < t) - ctx->bits[1]++; /* Carry from low to high */ - ctx->bits[1] += len >> 29; + t = ctx->bits[0]; + if ((ctx->bits[0] = (t + ((unsigned long)len << 3)) & 0xffffffff) < t) { + ctx->bits[1]++; /* Carry from low to high */ + } + ctx->bits[1] += len >> 29; - t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ + t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ - /* Handle any leading odd-sized chunks */ + /* Handle any leading odd-sized chunks */ - if ( t ) { - unsigned char *p = ctx->in + t; + if ( t ) { + unsigned char *p = ctx->in + t; - t = 64-t; - if (len < t) { - memcpy(p, buf, len); - return; - } - memcpy(p, buf, t); - NoteMD5Transform(ctx->buf, ctx->in); - buf += t; - len -= t; - } + t = 64-t; + if (len < t) { + memcpy(p, buf, len); + return; + } + memcpy(p, buf, t); + NoteMD5Transform(ctx->buf, ctx->in); + buf += t; + len -= t; + } - /* Process data in 64-byte chunks */ + /* Process data in 64-byte chunks */ - while (len >= 64) { - memcpy(ctx->in, buf, 64); - NoteMD5Transform(ctx->buf, ctx->in); - buf += 64; - len -= 64; - } + while (len >= 64) { + memcpy(ctx->in, buf, 64); + NoteMD5Transform(ctx->buf, ctx->in); + buf += 64; + len -= 64; + } - /* Handle any remaining bytes of data. */ + /* Handle any remaining bytes of data. */ - memcpy(ctx->in, buf, len); + memcpy(ctx->in, buf, len); } /* @@ -139,43 +142,43 @@ void NoteMD5Update(NoteMD5Context *ctx, unsigned char const *buf, unsigned len) */ void NoteMD5Final(unsigned char *digest, NoteMD5Context *ctx) { - unsigned count; - unsigned char *p; - - /* Compute number of bytes mod 64 */ - count = (ctx->bits[0] >> 3) & 0x3F; - - /* Set the first char of padding to 0x80. This is safe since there is - always at least one byte free */ - p = ctx->in + count; - *p++ = 0x80; - - /* Bytes of padding needed to make 64 bytes */ - count = 64 - 1 - count; - - /* Pad out to 56 mod 64 */ - if (count < 8) { - /* Two lots of padding: Pad the first block to 64 bytes */ - memset(p, 0, count); - NoteMD5Transform(ctx->buf, ctx->in); - - /* Now fill the next block with 56 bytes */ - memset(ctx->in, 0, 56); - } else { - /* Pad block to 56 bytes */ - memset(p, 0, count-8); - } - - /* Append length in bits and transform */ - putu32(ctx->bits[0], ctx->in + 56); - putu32(ctx->bits[1], ctx->in + 60); - - NoteMD5Transform(ctx->buf, ctx->in); - putu32(ctx->buf[0], digest); - putu32(ctx->buf[1], digest + 4); - putu32(ctx->buf[2], digest + 8); - putu32(ctx->buf[3], digest + 12); - memset(ctx, 0, sizeof(NoteMD5Context)); /* In case it's sensitive */ + unsigned count; + unsigned char *p; + + /* Compute number of bytes mod 64 */ + count = (ctx->bits[0] >> 3) & 0x3F; + + /* Set the first char of padding to 0x80. This is safe since there is + always at least one byte free */ + p = ctx->in + count; + *p++ = 0x80; + + /* Bytes of padding needed to make 64 bytes */ + count = 64 - 1 - count; + + /* Pad out to 56 mod 64 */ + if (count < 8) { + /* Two lots of padding: Pad the first block to 64 bytes */ + memset(p, 0, count); + NoteMD5Transform(ctx->buf, ctx->in); + + /* Now fill the next block with 56 bytes */ + memset(ctx->in, 0, 56); + } else { + /* Pad block to 56 bytes */ + memset(p, 0, count-8); + } + + /* Append length in bits and transform */ + putu32(ctx->bits[0], ctx->in + 56); + putu32(ctx->bits[1], ctx->in + 60); + + NoteMD5Transform(ctx->buf, ctx->in); + putu32(ctx->buf[0], digest); + putu32(ctx->buf[1], digest + 4); + putu32(ctx->buf[2], digest + 8); + putu32(ctx->buf[3], digest + 12); + memset(ctx, 0, sizeof(NoteMD5Context)); /* In case it's sensitive */ } /* The four core functions - F1 is optimized somewhat */ @@ -188,7 +191,7 @@ void NoteMD5Final(unsigned char *digest, NoteMD5Context *ctx) /* This is the central step in the MD5 algorithm. */ #define MD5STEP(f, w, x, y, z, data, s) \ - ( w += f(x, y, z) + data, w &= 0xffffffff, w = w<>(32-s), w += x ) + ( w += f(x, y, z) + data, w &= 0xffffffff, w = w<>(32-s), w += x ) /* * The core of the MD5 algorithm, this alters an existing MD5 hash to @@ -197,95 +200,97 @@ void NoteMD5Final(unsigned char *digest, NoteMD5Context *ctx) */ void NoteMD5Transform(unsigned long buf[4], const unsigned char inraw[64]) { - register unsigned long a, b, c, d; - unsigned long in[16]; - int i; - - for (i = 0; i < 16; ++i) - in[i] = getu32 (inraw + 4 * i); - - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; - - MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7); - MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12); - MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17); - MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22); - MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7); - MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12); - MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17); - MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22); - MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7); - MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12); - MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17); - MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22); - MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7); - MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12); - MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17); - MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22); - - MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5); - MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9); - MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14); - MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20); - MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5); - MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9); - MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14); - MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20); - MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5); - MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9); - MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14); - MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20); - MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5); - MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9); - MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14); - MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20); - - MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4); - MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11); - MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16); - MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23); - MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4); - MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11); - MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16); - MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23); - MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4); - MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11); - MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16); - MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23); - MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4); - MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11); - MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16); - MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23); - - MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6); - MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10); - MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15); - MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21); - MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6); - MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10); - MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15); - MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21); - MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6); - MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10); - MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15); - MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21); - MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6); - MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10); - MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15); - MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; + register unsigned long a, b, c, d; + unsigned long in[16]; + int i; + + for (i = 0; i < 16; ++i) { + in[i] = getu32 (inraw + 4 * i); + } + + a = buf[0]; + b = buf[1]; + c = buf[2]; + d = buf[3]; + + MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7); + MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12); + MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17); + MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22); + MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7); + MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12); + MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17); + MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22); + MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7); + MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12); + MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17); + MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22); + MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7); + MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12); + MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17); + MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22); + + MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5); + MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9); + MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14); + MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20); + MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5); + MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9); + MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14); + MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20); + MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5); + MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9); + MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14); + MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20); + MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5); + MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9); + MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14); + MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20); + + MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4); + MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11); + MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16); + MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23); + MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4); + MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11); + MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16); + MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23); + MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4); + MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11); + MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16); + MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23); + MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4); + MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11); + MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16); + MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23); + + MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6); + MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10); + MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15); + MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21); + MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6); + MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10); + MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15); + MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21); + MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6); + MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10); + MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15); + MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21); + MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6); + MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10); + MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15); + MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; } // Hash data and return its binary hash into an NOTE_MD5_HASH_SIZE buffer -void NoteMD5Hash(unsigned char* data, unsigned long len, unsigned char *retHash) { +void NoteMD5Hash(unsigned char* data, unsigned long len, unsigned char *retHash) +{ NoteMD5Context context; NoteMD5Init(&context); NoteMD5Update(&context, data, len); @@ -293,20 +298,24 @@ void NoteMD5Hash(unsigned char* data, unsigned long len, unsigned char *retHash) } // Hash data and return it as a string into a buffer that is at least (16*2)+1 in length -void NoteMD5HashString(unsigned char *data, unsigned long len, char *strbuf, unsigned long buflen) { +void NoteMD5HashString(unsigned char *data, unsigned long len, char *strbuf, unsigned long buflen) +{ unsigned char hash[NOTE_MD5_HASH_SIZE]; NoteMD5Hash(data, len, hash); char hashstr[NOTE_MD5_HASH_SIZE*3] = {0}; - for (int i=0; iLICENSE + * file. + * + */ + +#include +#include +#include +#include "n_lib.h" + +// Externalized Hooks +//**************************************************************************/ +/*! + @brief Hook for the calling platform's debug interface, if any. +*/ +/**************************************************************************/ +extern debugOutputFn hookDebugOutput; + +//**************************************************************************/ +/*! + @brief Write a formatted string to the debug output. + @param format A format string for output. + @param ... One or more values to interpolate into the format string. +*/ +/**************************************************************************/ +void NoteDebugf(const char *format, ...) +{ +#ifndef NOTE_NODEBUG + if (hookDebugOutput != NULL) { + char line[256]; + va_list args; + va_start(args, format); + vsnprintf(line, sizeof(line), format, args); + va_end(args); + hookDebugOutput(line); + } +#endif +} + +//**************************************************************************/ +/*! + @brief Write a formatted string to the debug output. + @param format A format string for output. + @param ... One or more values to interpolate into the format string. + @note. Do NOT use this in a memory-constrained environment (vsnprintf is large) +*/ +/**************************************************************************/ +#ifndef NOTE_LOMEM +bool NotePrintf(const char *format, ...) +{ + char line[256]; + va_list args; + va_start(args, format); + vsnprintf(line, sizeof(line), format, args); + va_end(args); + return NotePrint(line); +} +#endif diff --git a/src/note-c/n_request.c b/src/note-c/n_request.c index 0153fc9..1ea988f 100644 --- a/src/note-c/n_request.c +++ b/src/note-c/n_request.c @@ -24,19 +24,20 @@ static bool resetRequired = true; @brief Create an error response document. @param errmsg The error message from the Notecard - @returns a `J` cJSON object with the error response. + @returns a `J` cJSON object with the error response. */ /**************************************************************************/ -static J *errDoc(const char *errmsg) { +static J *errDoc(const char *errmsg) +{ J *rspdoc = JCreateObject(); if (rspdoc != NULL) { JAddStringToObject(rspdoc, c_err, errmsg); - } - if (suppressShowTransactions == 0) { - _Debug("{\"err\":\""); - _Debug(errmsg); - _Debug("\"}\n"); - } + } + if (suppressShowTransactions == 0) { + _Debug("{\"err\":\""); + _Debug(errmsg); + _Debug("\"}\n"); + } return rspdoc; } @@ -45,8 +46,9 @@ static J *errDoc(const char *errmsg) { @brief Suppress showing transaction details. */ /**************************************************************************/ -void NoteSuspendTransactionDebug() { - suppressShowTransactions++; +void NoteSuspendTransactionDebug() +{ + suppressShowTransactions++; } /**************************************************************************/ @@ -54,41 +56,40 @@ void NoteSuspendTransactionDebug() { @brief Resume showing transaction details. */ /**************************************************************************/ -void NoteResumeTransactionDebug() { - suppressShowTransactions--; +void NoteResumeTransactionDebug() +{ + suppressShowTransactions--; } /**************************************************************************/ /*! @brief Create a new request object to populate before sending to the Notecard. - Lock for mutual exclusion, not only because access to the card must be serialized, but also because - both C++ and ArduinoJSON call malloc() which is not a thread-safe operation. - @param request - The name of the request, for example `hub.set`. - @returns a `J` cJSON object with the request name pre-populated. + @param request is The name of the request, for example `hub.set`. + @returns a `J` cJSON object with the request name pre-populated. */ /**************************************************************************/ -J *NoteNewRequest(const char *request) { +J *NoteNewRequest(const char *request) +{ J *reqdoc = JCreateObject(); - if (reqdoc != NULL) + if (reqdoc != NULL) { JAddStringToObject(reqdoc, c_req, request); + } return reqdoc; } /**************************************************************************/ /*! @brief Create a new command object to populate before sending to the Notecard. - Lock for mutual exclusion, not only because access to the card must be serialized, but also because - both C++ and ArduinoJSON call malloc() which is not a thread-safe operation. - @param request - The name of the command, for example `hub.set`. - @returns a `J` cJSON object with the request name pre-populated. + @param request is the name of the command, for example `hub.set`. + @returns a `J` cJSON object with the request name pre-populated. */ /**************************************************************************/ -J *NoteNewCommand(const char *request) { +J *NoteNewCommand(const char *request) +{ J *reqdoc = JCreateObject(); - if (reqdoc != NULL) + if (reqdoc != NULL) { JAddStringToObject(reqdoc, c_cmd, request); + } return reqdoc; } @@ -98,15 +99,17 @@ J *NoteNewCommand(const char *request) { Frees the request structure from memory after sending the request. @param req The `J` cJSON request object. - @returns a boolean. Returns `true` if successful or `false` if an error + @returns a boolean. Returns `true` if successful or `false` if an error occurs, such as an out-of-memory or if an error was returned from the transaction in the c_err field. */ /**************************************************************************/ -bool NoteRequest(J *req) { +bool NoteRequest(J *req) +{ // Exit if null request. This allows safe execution of the form NoteRequest(NoteNewRequest("xxx")) - if (req == NULL) + if (req == NULL) { return false; + } // Execute the transaction J *rsp = NoteTransaction(req); if (rsp == NULL) { @@ -126,14 +129,16 @@ bool NoteRequest(J *req) { Frees the request structure from memory after sending the request. @param req The `J` cJSON request object. - @returns a `J` cJSON object with the response, or NULL if there is + @returns a `J` cJSON object with the response, or NULL if there is insufficient memory. */ /**************************************************************************/ -J *NoteRequestResponse(J *req) { +J *NoteRequestResponse(J *req) +{ // Exit if null request. This allows safe execution of the form NoteRequestResponse(NoteNewRequest("xxx")) - if (req == NULL) + if (req == NULL) { return NULL; + } // Execute the transaction J *rsp = NoteTransaction(req); if (rsp == NULL) { @@ -151,27 +156,31 @@ J *NoteRequestResponse(J *req) { Frees the request structure from memory after sending the request. @param reqJSON A c-string containing the JSON request object. - @returns a c-string with the JSON response from the Notecard. After + @returns a c-string with the JSON response from the Notecard. After parsed by the developer, should be freed with `JFree`. */ /**************************************************************************/ -char *NoteRequestResponseJSON(char *reqJSON) { +char *NoteRequestResponseJSON(char *reqJSON) +{ // Parse the incoming JSON string J *req = JParse(reqJSON); - if (req == NULL) + if (req == NULL) { return NULL; + } // Perform the transaction and free the req J *rsp = NoteRequestResponse(req); - if (rsp == NULL) + if (rsp == NULL) { return NULL; + } // Convert response back to JSON and delete it char *json = JPrintUnformatted(rsp); NoteDeleteResponse(rsp); - if (json == NULL) + if (json == NULL) { return NULL; + } // Done return json; @@ -185,15 +194,17 @@ char *NoteRequestResponseJSON(char *reqJSON) { the request. @param req The `J` cJSON request object. - @returns a `J` cJSON object with the response, or NULL if there is + @returns a `J` cJSON object with the response, or NULL if there is insufficient memory. */ /**************************************************************************/ -J *NoteTransaction(J *req) { +J *NoteTransaction(J *req) +{ // Validate in case of memory failure of the requestor - if (req == NULL) + if (req == NULL) { return NULL; + } // Determine whether or not a response will be expected, by virtue of "cmd" being present bool noResponseExpected = (JGetString(req, "req")[0] == '\0' && JGetString(req, "cmd")[0] != '\0'); @@ -201,8 +212,9 @@ J *NoteTransaction(J *req) { // If a reset of the module is required for any reason, do it now. // We must do this before acquiring lock. if (resetRequired) { - if (!NoteReset()) + if (!NoteReset()) { return NULL; + } } // Lock @@ -215,25 +227,26 @@ J *NoteTransaction(J *req) { _UnlockNote(); return rsp; } - - if (suppressShowTransactions == 0) { - _Debugln(json); - } + + if (suppressShowTransactions == 0) { + _Debugln(json); + } // Pertform the transaction char *responseJSON; const char *errStr; - if (noResponseExpected) + if (noResponseExpected) { errStr = _Transaction(json, NULL); - else + } else { errStr = _Transaction(json, &responseJSON); + } // Free the json JFree(json); // If error, queue up a reset if (errStr != NULL) { - NoteResetRequired(); + NoteResetRequired(); J *rsp = errDoc(errStr); _UnlockNote(); return rsp; @@ -249,7 +262,7 @@ J *NoteTransaction(J *req) { J *rspdoc = JParse(responseJSON); if (rspdoc == NULL) { _Debug("invalid JSON: "); - _Debug(responseJSON); + _Debug(responseJSON); _Free(responseJSON); J *rsp = errDoc(ERRSTR("unrecognized response from card",c_bad)); _UnlockNote(); @@ -257,9 +270,13 @@ J *NoteTransaction(J *req) { } // Debug - if (suppressShowTransactions == 0) { - _Debugln(responseJSON); - } + if (suppressShowTransactions == 0) { + if (responseJSON[strlen(responseJSON)-1] == '\n') { + _Debug(responseJSON); + } else { + _Debugln(responseJSON); + } + } // Discard the buffer now that it's parsed _Free(responseJSON); @@ -269,7 +286,7 @@ J *NoteTransaction(J *req) { // Done return rspdoc; - + } /**************************************************************************/ @@ -278,7 +295,8 @@ J *NoteTransaction(J *req) { a given port. */ /**************************************************************************/ -void NoteResetRequired() { +void NoteResetRequired() +{ resetRequired = true; } @@ -289,7 +307,8 @@ void NoteResetRequired() { @returns a boolean. `true` if the reset was successful, `false`, if not. */ /**************************************************************************/ -bool NoteReset() { +bool NoteReset() +{ _LockNote(); resetRequired = !_Reset(); _UnlockNote(); @@ -303,11 +322,12 @@ bool NoteReset() { The error string. @param errtype The error type string. - @returns boolean. `true` if the string contains the error provided, `false` + @returns boolean. `true` if the string contains the error provided, `false` if not. */ /**************************************************************************/ -bool NoteErrorContains(const char *errstr, const char *errtype) { +bool NoteErrorContains(const char *errstr, const char *errtype) +{ return (strstr(errstr, errtype) != NULL); } @@ -318,17 +338,21 @@ bool NoteErrorContains(const char *errstr, const char *errtype) { The string buffer to clear of error strings. */ /**************************************************************************/ -void NoteErrorClean(char *begin) { +void NoteErrorClean(char *begin) +{ while (true) { char *end = &begin[strlen(begin)+1]; char *beginBrace = strchr(begin, '{'); - if (beginBrace == NULL) + if (beginBrace == NULL) { break; - if (beginBrace>begin && *(beginBrace-1) == ' ') + } + if (beginBrace>begin && *(beginBrace-1) == ' ') { beginBrace--; + } char *endBrace = strchr(beginBrace, '}'); - if (endBrace == NULL) + if (endBrace == NULL) { break; + } char *afterBrace = endBrace + 1; memmove(beginBrace, afterBrace, end-afterBrace); } diff --git a/src/note-c/n_serial.c b/src/note-c/n_serial.c index 63c140f..61ea3f8 100644 --- a/src/note-c/n_serial.c +++ b/src/note-c/n_serial.c @@ -18,115 +18,118 @@ @brief Given a JSON string, perform an Serial transaction with the Notecard. @param json A c-string containing the JSON request object. - @param jsonResponse - An out parameter c-string buffer that will contain the JSON - response from the Notercard. - @returns a c-string with an error, or `NULL` if no error ocurred. + @param jsonResponse + An out parameter c-string buffer that will contain the JSON + response from the Notercard. + @returns a c-string with an error, or `NULL` if no error ocurred. */ /**************************************************************************/ -const char *serialNoteTransaction(char *json, char **jsonResponse) { - - // Transmit the request in segments so as not to overwhelm the notecard's interrupt buffers - uint32_t segOff = 0; - uint32_t segLeft = strlen(json); - while (true) { - size_t segLen = segLeft; - if (segLen > CARD_REQUEST_SERIAL_SEGMENT_MAX_LEN) - segLen = CARD_REQUEST_SERIAL_SEGMENT_MAX_LEN; - segLeft -= segLen; - _SerialTransmit((uint8_t *)&json[segOff], segLen, false); - if (segLeft == 0) { - _SerialTransmit((uint8_t *)c_newline, c_newline_len, true); - break; - } - segOff += segLen; - _DelayMs(CARD_REQUEST_SERIAL_SEGMENT_DELAY_MS); - } +const char *serialNoteTransaction(char *json, char **jsonResponse) +{ + + // Transmit the request in segments so as not to overwhelm the notecard's interrupt buffers + uint32_t segOff = 0; + uint32_t segLeft = strlen(json); + while (true) { + size_t segLen = segLeft; + if (segLen > CARD_REQUEST_SERIAL_SEGMENT_MAX_LEN) { + segLen = CARD_REQUEST_SERIAL_SEGMENT_MAX_LEN; + } + segLeft -= segLen; + _SerialTransmit((uint8_t *)&json[segOff], segLen, false); + if (segLeft == 0) { + _SerialTransmit((uint8_t *)c_newline, c_newline_len, true); + break; + } + segOff += segLen; + _DelayMs(CARD_REQUEST_SERIAL_SEGMENT_DELAY_MS); + } // If no reply expected, we're done - if (jsonResponse == NULL) + if (jsonResponse == NULL) { return NULL; - - // Wait for something to become available, processing timeout errors up-front - // because the json parse operation immediately following is subject to the - // serial port timeout. We'd like more flexibility in max timeout and ultimately - // in our error handling. - uint32_t startMs; - for (startMs = _GetMs(); !_SerialAvailable(); ) { - if (_GetMs() >= startMs + (NOTECARD_TRANSACTION_TIMEOUT_SEC*1000)) { + } + + // Wait for something to become available, processing timeout errors up-front + // because the json parse operation immediately following is subject to the + // serial port timeout. We'd like more flexibility in max timeout and ultimately + // in our error handling. + uint32_t startMs; + for (startMs = _GetMs(); !_SerialAvailable(); ) { + if (_GetMs() >= startMs + (NOTECARD_TRANSACTION_TIMEOUT_SEC*1000)) { #ifdef ERRDBG - _Debug("reply to request didn't arrive from module in time\n"); + _Debug("reply to request didn't arrive from module in time\n"); #endif - return ERRSTR("transaction timeout",c_timeout); - } - _DelayMs(10); - } - - // Allocate a buffer for input, noting that we always put the +1 in the alloc so we can be assured - // that it can be null-terminated. This must be the case because json parsing requires a - // null-terminated string. - int jsonbufAllocLen = ALLOC_CHUNK; - char *jsonbuf = (char *) _Malloc(jsonbufAllocLen+1); - if (jsonbuf == NULL) { + return ERRSTR("transaction timeout",c_timeout); + } + _DelayMs(10); + } + + // Allocate a buffer for input, noting that we always put the +1 in the alloc so we can be assured + // that it can be null-terminated. This must be the case because json parsing requires a + // null-terminated string. + int jsonbufAllocLen = ALLOC_CHUNK; + char *jsonbuf = (char *) _Malloc(jsonbufAllocLen+1); + if (jsonbuf == NULL) { #ifdef ERRDBG - _Debug("transaction: jsonbuf malloc failed\n"); + _Debug("transaction: jsonbuf malloc failed\n"); #endif - return ERRSTR("insufficient memory",c_mem); - } - int jsonbufLen = 0; - char ch = 0; - startMs = _GetMs(); - while (ch != '\n') { - if (!_SerialAvailable()) { - ch = 0; - if (_GetMs() >= startMs + (NOTECARD_TRANSACTION_TIMEOUT_SEC*1000)) { + return ERRSTR("insufficient memory",c_mem); + } + int jsonbufLen = 0; + char ch = 0; + startMs = _GetMs(); + while (ch != '\n') { + if (!_SerialAvailable()) { + ch = 0; + if (_GetMs() >= startMs + (NOTECARD_TRANSACTION_TIMEOUT_SEC*1000)) { #ifdef ERRDBG - jsonbuf[jsonbufLen] = '\0'; - _Debug("received only partial reply after timeout:\n"); - _Debug(jsonbuf); - _Debug("\n"); + jsonbuf[jsonbufLen] = '\0'; + _Debug("received only partial reply after timeout:\n"); + _Debug(jsonbuf); + _Debug("\n"); #endif - _Free(jsonbuf); - return ERRSTR("transaction incomplete",c_timeout); - } - _DelayMs(1); - continue; - } - ch = _SerialReceive(); - - // Because serial I/O can be error-prone, catch common bad data early, knowing that we only accept ASCII - if (ch == 0 || (ch & 0x80) != 0) { + _Free(jsonbuf); + return ERRSTR("transaction incomplete",c_timeout); + } + _DelayMs(1); + continue; + } + ch = _SerialReceive(); + + // Because serial I/O can be error-prone, catch common bad data early, knowing that we only accept ASCII + if (ch == 0 || (ch & 0x80) != 0) { #ifdef ERRDBG - _Debug("invalid data received on serial port from notecard\n"); + _Debug("invalid data received on serial port from notecard\n"); #endif - _Free(jsonbuf); - return ERRSTR("serial communications error",c_timeout); - } - - // Append into the json buffer - jsonbuf[jsonbufLen++] = ch; - if (jsonbufLen >= jsonbufAllocLen) { - jsonbufAllocLen += ALLOC_CHUNK; - char *jsonbufNew = (char *) _Malloc(jsonbufAllocLen+1); - if (jsonbufNew == NULL) { + _Free(jsonbuf); + return ERRSTR("serial communications error",c_timeout); + } + + // Append into the json buffer + jsonbuf[jsonbufLen++] = ch; + if (jsonbufLen >= jsonbufAllocLen) { + jsonbufAllocLen += ALLOC_CHUNK; + char *jsonbufNew = (char *) _Malloc(jsonbufAllocLen+1); + if (jsonbufNew == NULL) { #ifdef ERRDBG - _Debug("transaction: jsonbuf malloc grow failed\n"); + _Debug("transaction: jsonbuf malloc grow failed\n"); #endif - _Free(jsonbuf); - return ERRSTR("insufficient memory",c_mem); - } - memcpy(jsonbufNew, jsonbuf, jsonbufLen); - _Free(jsonbuf); - jsonbuf = jsonbufNew; - } - } - - // Null-terminate it, using the +1 space that we'd allocated in the buffer - jsonbuf[jsonbufLen] = '\0'; - - // Return it - *jsonResponse = jsonbuf; - return NULL; + _Free(jsonbuf); + return ERRSTR("insufficient memory",c_mem); + } + memcpy(jsonbufNew, jsonbuf, jsonbufLen); + _Free(jsonbuf); + jsonbuf = jsonbufNew; + } + } + + // Null-terminate it, using the +1 space that we'd allocated in the buffer + jsonbuf[jsonbufLen] = '\0'; + + // Return it + *jsonResponse = jsonbuf; + return NULL; } @@ -137,55 +140,54 @@ const char *serialNoteTransaction(char *json, char **jsonResponse) { @returns a boolean. `true` if the reset was successful, `false`, if not. */ /**************************************************************************/ -bool serialNoteReset() { - - // Initialize, or re-initialize. Because we've observed Arduino serial driver flakiness, - _DelayMs(250); - if (!_SerialReset()) - return false; - - // The guaranteed behavior for robust resyncing is to send two newlines - // and wait for two echoed blank lines in return. - bool notecardReady = false; - int retries; - for (retries=0; retries<10; retries++) { - -#ifdef ERRDBG - _Debug("serial reset\n"); -#endif - - // Send a newline to the module to clean out request/response processing - _SerialTransmit((uint8_t *)c_newline, c_newline_len, true); - - // Drain all serial for 500ms - bool somethingFound = false; - bool nonControlCharFound = false; - uint32_t startMs = _GetMs(); - while (_GetMs() < startMs+500) { - while (_SerialAvailable()) { - somethingFound = true; - if (_SerialReceive() >= ' ') - nonControlCharFound = true; - } - _DelayMs(1); - } - - // If all we got back is newlines, we're ready - if (somethingFound && !nonControlCharFound) { - notecardReady = true; - break; - } +bool serialNoteReset() +{ + + // Initialize, or re-initialize. Because we've observed Arduino serial driver flakiness, + _DelayMs(250); + if (!_SerialReset()) { + return false; + } + + // The guaranteed behavior for robust resyncing is to send two newlines + // and wait for two echoed blank lines in return. + bool notecardReady = false; + int retries; + for (retries=0; retries<10; retries++) { + + // Send a newline to the module to clean out request/response processing + _SerialTransmit((uint8_t *)c_newline, c_newline_len, true); + + // Drain all serial for 500ms + bool somethingFound = false; + bool nonControlCharFound = false; + uint32_t startMs = _GetMs(); + while (_GetMs() < startMs+500) { + while (_SerialAvailable()) { + somethingFound = true; + if (_SerialReceive() >= ' ') { + nonControlCharFound = true; + } + } + _DelayMs(1); + } + + // If all we got back is newlines, we're ready + if (somethingFound && !nonControlCharFound) { + notecardReady = true; + break; + } #ifdef ERRDBG - _Debug(somethingFound ? "unrecognized data from notecard\n" : "notecard not responding\n"); + _Debug(somethingFound ? "unrecognized data from notecard\n" : "notecard not responding\n"); #else - _Debug("no notecard\n"); + _Debug("no notecard\n"); #endif - _DelayMs(500); - _SerialReset(); + _DelayMs(500); + _SerialReset(); - } + } - // Done - return notecardReady; + // Done + return notecardReady; } diff --git a/src/note-c/n_str.c b/src/note-c/n_str.c index 79f2f20..6c0bbf9 100644 --- a/src/note-c/n_str.c +++ b/src/note-c/n_str.c @@ -20,6 +20,7 @@ */ #include +#include "note.h" /* * Copy src to string dst of size siz. At most siz-1 characters @@ -35,15 +36,17 @@ __attribute__((weak)) size_t strlcpy(char *dst, const char *src, size_t siz) /* Copy as many bytes as will fit */ if (n != 0) { while (--n != 0) { - if ((*d++ = *s++) == '\0') + if ((*d++ = *s++) == '\0') { break; + } } } /* Not enough room in dst, add NUL and traverse rest of src */ if (n == 0) { - if (siz != 0) - *d = '\0'; /* NUL-terminate dst */ + if (siz != 0) { + *d = '\0'; /* NUL-terminate dst */ + } while (*s++) ; } @@ -66,13 +69,15 @@ __attribute__((weak)) size_t strlcat(char *dst, const char *src, size_t siz) size_t dlen; /* Find the end of dst and adjust bytes left but don't go past end */ - while (n-- != 0 && *d != '\0') + while (n-- != 0 && *d != '\0') { d++; + } dlen = d - dst; n = siz - dlen; - if (n == 0) + if (n == 0) { return(dlen + strlen(s)); + } while (*s != '\0') { if (n != 1) { *d++ = *s; diff --git a/src/note-c/note.h b/src/note-c/note.h index 6909f41..a84474b 100644 --- a/src/note-c/note.h +++ b/src/note-c/note.h @@ -60,12 +60,12 @@ // symbols that will save quite a bit of memory in the runtime image. #ifdef NOTE_FLOAT #define JNUMBER float -#define ERRSTR(x,y) (y) +#define ERRSTR(x,y) (y) #define NOTE_LOWMEM #else #define JNUMBER double -#define ERRSTR(x,y) (x) -#define ERRDBG +#define ERRSTR(x,y) (x) +#define ERRDBG #endif // UNIX Epoch time (also known as POSIX time) is the number of seconds that have elapsed since @@ -106,6 +106,11 @@ J *NoteRequestResponse(J *req); char *NoteRequestResponseJSON(char *reqJSON); void NoteSuspendTransactionDebug(void); void NoteResumeTransactionDebug(void); +#define SYNCSTATUS_LEVEL_MAJOR 0 +#define SYNCSTATUS_LEVEL_MINOR 1 +#define SYNCSTATUS_LEVEL_DETAILED 2 +#define SYNCSTATUS_LEVEL_ALGORITHMIC 3 +#define SYNCSTATUS_LEVEL_ALL -1 bool NoteDebugSyncStatus(int pollFrequencyMs, int maxLevel); bool NoteRequest(J *req); #define NoteResponseError(rsp) (!JIsNullString(rsp, "err")) @@ -119,9 +124,10 @@ void NoteSetFnMutex(mutexFn lockI2Cfn, mutexFn unlockI2Cfn, mutexFn lockNotefn, void NoteSetFnDefault(mallocFn mallocfn, freeFn freefn, delayMsFn delayfn, getMsFn millisfn); void NoteSetFn(mallocFn mallocfn, freeFn freefn, delayMsFn delayfn, getMsFn millisfn); void NoteSetFnSerial(serialResetFn resetfn, serialTransmitFn writefn, serialAvailableFn availfn, serialReceiveFn readfn); -#define NOTE_I2C_ADDR_DEFAULT 0 -#define NOTE_I2C_MAX_DEFAULT 0 +#define NOTE_I2C_ADDR_DEFAULT 0 +#define NOTE_I2C_MAX_DEFAULT 0 void NoteSetFnI2C(uint32_t i2caddr, uint32_t i2cmax, i2cResetFn resetfn, i2cTransmitFn transmitfn, i2cReceiveFn receivefn); +void NoteSetFnDisabled(void); void NoteSetI2CAddress(uint32_t i2caddress); // Calls to the functions set above @@ -138,7 +144,7 @@ uint32_t NoteI2CAddress(void); uint32_t NoteI2CMax(void); uint32_t NoteMemAvailable(void); bool NotePrint(const char *text); - void NotePrintln(const char *line); +void NotePrintln(const char *line); bool NotePrintf(const char *format, ...); // String helpers to help encourage the world to abandon the horribly-error-prone strn* @@ -152,23 +158,27 @@ bool JIsPresent(J *rsp, const char *field); char *JGetString(J *rsp, const char *field); JNUMBER JGetNumber(J *rsp, const char *field); J *JGetObject(J *rsp, const char *field); -int JGetInt(J *rsp, const char *field); +long int JGetInt(J *rsp, const char *field); bool JGetBool(J *rsp, const char *field); JNUMBER JNumberValue(J *item); char *JStringValue(J *item); bool JBoolValue(J *item); -int JIntValue(J *item); +long int JIntValue(J *item); bool JIsNullString(J *rsp, const char *field); bool JIsExactString(J *rsp, const char *field, const char *teststr); bool JContainsString(J *rsp, const char *field, const char *substr); bool JAddBinaryToObject(J *req, const char *fieldName, const void *binaryData, uint32_t binaryDataLen); const char *JGetItemName(const J * item); +char *JAllocString(uint8_t *buffer, uint32_t len); +const char *JType(J *item); // Helper functions for apps that wish to limit their C library dependencies #define JNTOA_PRECISION (10) #define JNTOA_MAX ((2*JNTOA_PRECISION)+1+1) char * JNtoA(JNUMBER f, char * buf, int precision); JNUMBER JAtoN(const char *string, char **endPtr); +void JItoA(long int n, char *s); +long int JAtoI(const char *s); int JB64EncodeLen(int len); int JB64Encode(char * coded_dst, const char *plain_src,int len_plain_src); int JB64DecodeLen(const char * coded_src); @@ -176,14 +186,14 @@ int JB64Decode(char * plain_dst, const char *coded_src); // MD5 Helper functions typedef struct { - unsigned long buf[4]; - unsigned long bits[2]; - unsigned char in[64]; + unsigned long buf[4]; + unsigned long bits[2]; + unsigned char in[64]; } NoteMD5Context; #define NOTE_MD5_HASH_SIZE 16 #define NOTE_MD5_HASH_STRING_SIZE (((NOTE_MD5_HASH_SIZE)*2)+1) void NoteMD5Init(NoteMD5Context *ctx); -void NoteMD5Update(NoteMD5Context *ctx, unsigned char const *buf, unsigned len); +void NoteMD5Update(NoteMD5Context *ctx, unsigned char const *buf, unsigned long len); void NoteMD5Final(unsigned char *digest, NoteMD5Context *ctx); void NoteMD5Transform(unsigned long buf[4], const unsigned char inraw[64]); void NoteMD5Hash(unsigned char* data, unsigned long len, unsigned char *retHash); @@ -191,19 +201,22 @@ void NoteMD5HashString(unsigned char *data, unsigned long len, char *strbuf, uns void NoteMD5HashToString(unsigned char *hash, char *strbuf, unsigned long buflen); // High-level helper functions that are both useful and serve to show developers how to call the API +uint32_t NoteSetSTSecs(uint32_t secs); bool NoteTimeValid(void); bool NoteTimeValidST(void); JTIME NoteTime(void); JTIME NoteTimeST(void); +void NoteTimeSet(JTIME secondsUTC, int offset, char *zone, char *country, char *area); +bool NoteLocalTimeST(uint16_t *retYear, uint8_t *retMonth, uint8_t *retDay, uint8_t *retHour, uint8_t *retMinute, uint8_t *retSecond, char **retWeekday, char **retZone); bool NoteRegion(char **retCountry, char **retArea, char **retZone, int *retZoneOffset); bool NoteLocationValid(char *errbuf, uint32_t errbuflen); bool NoteLocationValidST(char *errbuf, uint32_t errbuflen); -int NoteGetEnvInt(const char *variable, int defaultVal); +long int NoteGetEnvInt(const char *variable, long int defaultVal); JNUMBER NoteGetEnvNumber(const char *variable, JNUMBER defaultVal); bool NoteGetEnv(const char *variable, const char *defaultVal, char *buf, uint32_t buflen); bool NoteSetEnvDefault(const char *variable, char *buf); bool NoteSetEnvDefaultNumber(const char *variable, JNUMBER defaultVal); -bool NoteSetEnvDefaultInt(const char *variable, int defaultVal); +bool NoteSetEnvDefaultInt(const char *variable, long int defaultVal); bool NoteIsConnected(void); bool NoteIsConnectedST(void); bool NoteGetNetStatus(char *statusBuf, int statusBufLen); @@ -224,7 +237,6 @@ bool NoteSetSerialNumber(const char *sn); bool NoteSetProductID(const char *productID); bool NoteSetUploadMode(const char *uploadMode, int uploadMinutes, bool align); bool NoteSetSyncMode(const char *uploadMode, int uploadMinutes, int downloadMinutes, bool align, bool sync); -bool NoteTemplate(const char *target, J *body); #define NoteSend NoteAdd bool NoteAdd(const char *target, J *body, bool urgent); bool NoteSendToRoute(const char *method, const char *routeAlias, char *notefile, J *body); @@ -233,6 +245,21 @@ bool NoteGetTemperature(JNUMBER *temp); bool NoteGetContact(char *nameBuf, int nameBufLen, char *orgBuf, int orgBufLen, char *roleBuf, int roleBufLen, char *emailBuf, int emailBufLen); bool NoteSetContact(char *nameBuf, char *orgBuf, char *roleBuf, char *emailBuf); +// C macro to convert a number to a string for use below +#define _tstring(x) #x + +// Hard-wired constants used to specify field types when creating note templates +#define TINT8 11 // 1-byte signed integer +#define TINT16 12 // 2-byte signed integer +#define TINT24 13 // 3-byte signed integer +#define TINT32 14 // 4-byte signed integer +#define TINT64 18 // 8-byte signed integer (note-c support depends upon platform) +#define TFLOAT16 12.1 // 2-byte IEEE 754 floating point +#define TFLOAT32 14.1 // 4-byte IEEE 754 floating point (a.k.a. "float") +#define TFLOAT64 18.1 // 8-byte IEEE 754 floating point (a.k.a. "double") +#define TSTRING(N) _tstring(N) // UTF-8 text of N bytes maximum (fixed-length reserved buffer) +bool NoteTemplate(const char *notefileID, J *templateBody); + // End of C-callable functions #ifdef __cplusplus }