diff --git a/README.md b/README.md index f2128d0..26e6c01 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,9 @@ with: - [Sensor tutorial](examples/Example6_SensorTutorial/Example6_SensorTutorial.ino) - [Power control](examples/Example7_PowerControl/Example7_PowerControl.ino) -Before running an example, you will need to set the Product Identifier, either in code or on your connected Notecard. Steps on how to do this can be found at [https://dev.blues.io/tools-and-sdks/samples/product-uid](https://dev.blues.io/tools-and-sdks/samples/product-uid). +Before running an example, you will need to set the Product Identifier, either +in code or on your connected Notecard. Steps on how to do this can be found at +[https://dev.blues.io/tools-and-sdks/samples/product-uid](https://dev.blues.io/tools-and-sdks/samples/product-uid). ## Contributing @@ -256,6 +258,36 @@ in the `tests` array in the `main` function. The entry will occupy it's own line at the end of the array, and syntax should be as follows, `{test_name, "test_name"},`. +## Generating a Release + +### Update Files + +When generating a release of the `note-arduino` library, you will need to update +the version in two places. + +- `NoteDefines.h` + + The `note-arduino` library provides preprocessor defines to allow for + programmatic access to the version number. The following preprocessor + defines should be updated with the version you wish to publish: + + - `NOTE_ARDUINO_VERSION_MAJOR` + - `NOTE_ARDUINO_VERSION_MINOR` + - `NOTE_ARDUINO_VERSION_PATCH` + +- `library.properties` + + Update the `version` key to reflect the version you wish to publish. The + version string should follow the form "\.\.\" (e.g. + `1.6.4`). This value will be used by the Arduino Library Manager. + +### GitHub Release + +Publishing a release on GitHub will trigger the Arduino Library Manager. The +Arduino Library Manager will then look to the `library.properties` file, and +generate a release based on the `version` value it finds there. It should be +noted, the version on GitHub is not evaluated by the Arduino Library Manager. + ## More Information For additional Notecard SDKs and Libraries, see: diff --git a/library.properties b/library.properties index cecc3de..454790d 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Blues Wireless Notecard -version=1.6.3 +version=1.6.4 author=Blues maintainer=Blues sentence=An easy to use Notecard Library for Arduino. diff --git a/src/NoteDefines.h b/src/NoteDefines.h index 20c5176..060f333 100644 --- a/src/NoteDefines.h +++ b/src/NoteDefines.h @@ -4,7 +4,7 @@ // Define the version of the `note-arduino` library #define NOTE_ARDUINO_VERSION_MAJOR 1 #define NOTE_ARDUINO_VERSION_MINOR 6 -#define NOTE_ARDUINO_VERSION_PATCH 3 +#define NOTE_ARDUINO_VERSION_PATCH 4 #define NOTE_ARDUINO_VERSION NOTE_C_STRINGIZE(NOTE_ARDUINO_VERSION_MAJOR) "." NOTE_C_STRINGIZE(NOTE_ARDUINO_VERSION_MINOR) "." NOTE_C_STRINGIZE(NOTE_ARDUINO_VERSION_PATCH) diff --git a/src/note-c/.gitignore b/src/note-c/.gitignore index 9552ba0..d6056bf 100644 --- a/src/note-c/.gitignore +++ b/src/note-c/.gitignore @@ -8,3 +8,6 @@ __pycache__/ *.code-workspace *.orig settings.json + +# Development Artifacts +cppcheck_output.txt diff --git a/src/note-c/CMakeLists.txt b/src/note-c/CMakeLists.txt index 449cbdb..eccdc7f 100644 --- a/src/note-c/CMakeLists.txt +++ b/src/note-c/CMakeLists.txt @@ -1,4 +1,5 @@ -cmake_minimum_required(VERSION 3.13) +cmake_minimum_required(VERSION 3.20) +cmake_policy(SET CMP0095 NEW) if ("${CMAKE_BINARY_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}") message(FATAL_ERROR "In-source builds are not allowed. @@ -14,13 +15,14 @@ if(NOT EXISTS ${PROJECT_BINARY_DIR}/.gitignore) file(WRITE ${PROJECT_BINARY_DIR}/.gitignore "*") endif() -option(NOTE_C_BUILD_TESTS "Build tests." OFF) +option(NOTE_C_BUILD_DOCS "Build docs." OFF) +option(NOTE_C_BUILD_TESTS "Build tests." ON) option(NOTE_C_COVERAGE "Compile for test NOTE_C_COVERAGE reporting." OFF) +option(NOTE_C_LOW_MEM "Build the library tailored for low memory usage." OFF) option(NOTE_C_MEM_CHECK "Run tests with Valgrind." OFF) -option(NOTE_C_BUILD_DOCS "Build docs." OFF) option(NOTE_C_NO_LIBC "Build the library without linking against libc, generating errors for any undefined symbols." OFF) -option(NOTE_C_LOW_MEM "Build the library tailored for low memory usage." OFF) -option(NOTE_C_TEST_SINGLE_PRECISION "Use single precision for JSON floating point numbers." OFF) +option(NOTE_C_SHOW_MALLOC "Build the library with flags required to log memory usage." OFF) +option(NOTE_C_SINGLE_PRECISION "Use single precision for JSON floating point numbers." OFF) set(NOTE_C_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}) add_library(note_c SHARED) @@ -52,11 +54,28 @@ target_compile_options( -Werror -Og -ggdb + PUBLIC + -m32 + -mfpmath=sse + -msse2 ) target_include_directories( note_c PUBLIC ${NOTE_C_SRC_DIR} ) +target_link_directories( + note_c + PUBLIC + /lib32 + /usr/lib32 + /usr/lib/gcc/x86_64-linux-gnu/12/32 +) +target_link_options( + note_c + PUBLIC + -m32 + -Wl,-melf_i386 +) if(NOTE_C_LOW_MEM) target_compile_definitions( @@ -85,11 +104,19 @@ if(NOTE_C_NO_LIBC) ) endif() -if(NOTE_C_TEST_SINGLE_PRECISION) +if(NOTE_C_SHOW_MALLOC) + target_compile_definitions( + note_c + PUBLIC + NOTE_C_SHOW_MALLOC + ) +endif() + +if(NOTE_C_SINGLE_PRECISION) target_compile_definitions( note_c PUBLIC - NOTE_C_TEST_SINGLE_PRECISION + NOTE_C_SINGLE_PRECISION ) endif() diff --git a/src/note-c/CONTRIBUTING.md b/src/note-c/CONTRIBUTING.md index 39410cb..0d32823 100644 --- a/src/note-c/CONTRIBUTING.md +++ b/src/note-c/CONTRIBUTING.md @@ -3,8 +3,6 @@ We love pull requests from everyone. By participating in this project, you agree to abide by the Blues Inc [code of conduct]. -[code of conduct]: https://blues.github.io/opensource/code-of-conduct - Here are some ways *you* can contribute: * by using alpha, beta, and prerelease versions @@ -33,6 +31,12 @@ clean up inconsistent whitespace ) [gist]: https://gist.github.com/ +## Library Development + +Review our [contribution guidelines](./CONTRIBUTING.md) and [developer +documentation](./test/README.md) for setting up your environment and +configuring your toolchain. + ## Cleaning up issues * Issues that have no response from the submitter will be closed after 30 days. @@ -59,6 +63,7 @@ clean up inconsistent whitespace ) https://help.github.com/articles/creating-and-deleting-branches-within-your-repository/ [pr]: https://help.github.com/articles/creating-a-pull-request-from-a-fork/ -Inspired by +Inspired by: https://github.com/thoughtbot/factory_bot/blob/master/CONTRIBUTING.md +[code of conduct]: https://blues.github.io/opensource/code-of-conduct diff --git a/src/note-c/Dockerfile b/src/note-c/Dockerfile index 0368b33..334df54 100644 --- a/src/note-c/Dockerfile +++ b/src/note-c/Dockerfile @@ -21,6 +21,9 @@ ARG USER # Local Argument(s) +# Local Environment Variable(s) +ENV LC_ALL="C.UTF-8" + # Create Non-Root User RUN ["dash", "-c", "\ addgroup \ @@ -38,6 +41,11 @@ RUN ["dash", "-c", "\ \"${USER}\" \ "] +# Add 32-bit binaries to the index. +RUN ["dash", "-c", "\ + dpkg --add-architecture i386 \ +"] + # Install whatever dependencies we can via apt-get. RUN ["dash", "-c", "\ apt-get update --quiet \ @@ -46,14 +54,18 @@ RUN ["dash", "-c", "\ ca-certificates \ curl \ g++ \ + g++-multilib \ gcc \ + gcc-multilib \ gdb \ git \ lcov \ + libc6-dbg:i386 \ make \ nano \ python3-pip \ python3-sphinx \ + cppcheck \ valgrind \ && pip install --break-system-packages \ breathe \ @@ -83,13 +95,3 @@ RUN ["dash", "-c", "\ && tar xf cmake-3.25.1-linux-x86_64.tar.gz --strip-components=1 -C /usr \ && rm cmake-3.25.1-linux-x86_64.tar.gz \ "] - -# Download and install Catch2 v3.2.1. -RUN ["dash", "-c", "\ - curl -LO https://github.com/catchorg/Catch2/archive/refs/tags/v3.2.1.tar.gz \ - && tar xf v3.2.1.tar.gz \ - && cd Catch2-3.2.1 \ - && cmake -DCATCH_INSTALL_DOCS=0 -B build/ \ - && cmake --build build/ --target install \ - && rm -rf Catch2-3.2.1 v3.2.1.tar.gz \ -"] diff --git a/src/note-c/README.md b/src/note-c/README.md index a6e8f3b..3a29089 100644 --- a/src/note-c/README.md +++ b/src/note-c/README.md @@ -1,4 +1,4 @@ -[![Coverage Status](https://coveralls.io/repos/github/blues/note-c/badge.svg?branch=master)](https://coveralls.io/github/blues/note-c?branch=master) +[![Coverage Status][coverage badge]][coverage details] # note-c @@ -12,22 +12,116 @@ Notes to [Notehub.io][notehub]. This library is used by the [note-arduino library][note-arduino], which includes it as a git subtree. -## Documentation +## API Documentation -The documentation for this library can be found [here](https://blues.github.io/note-c/index.html). +The API documentation for this library can be found [here][note-c API docs]. -## CMake +## Logging Control -The CMake build system is primarily here for testing note-c on a development -machine. You can use it to generate a static or shared note-c library, but -embedded users will typically just compile all the .c source files into their -firmware image. For more on testing, see test/README.md. +`note-c` provides a comprehensive and flexible logging functionality. -### Options +To activate logging, you must provide a callback for logging via +`hookDebugOutput()`. The callback takes the following form: -- BUILD_TESTS: Build the tests. See the tests directory. Default: ON. -- BUILD_SHARED_LIBS: Build the note-c library as shared instead of static. This -reduces the total size of the compiled tests. Default: ON. +```c +typedef size_t (*debugOutputFn) (const char *text); +``` + +The callback is responsible for taking a character array (C-style string) and +returning the number of bytes processed (written out) as confirmation. The +exact implementation will be up to the user who provided the function pointer, +but its presence will active logging in the library. + +### Library Logging + +#### Log Levels + +`note-c` provides for four (4) levels of logging. Here they are listed from +most severe to most verbose: + +0. `NOTE_C_LOG_LEVEL_ERROR` +1. `NOTE_C_LOG_LEVEL_WARN` +2. `NOTE_C_LOG_LEVEL_INFO` +3. `NOTE_C_LOG_LEVEL_DEBUG` + +By default, `note-c` logs at `NOTE_C_LOG_LEVEL_INFO`. + +#### Default Logging Behavior + +To modify the default behavior, you may specify the desired log level at compile +time, as follows: + +```sh +-DNOTE_C_LOG_LEVEL=0 +``` + +_**NOTE:** In the example above, you will notice we used zero (`0`), instead of +`NOTE_C_LOG_LEVEL_ERROR`. This is because the warning constants are internal to +the library, and not available in the context of the command line._ + +Here, we have decided to show only the most severe (i.e. `[ERROR]`) logs. +Alternatively, you may set the level to any of the values listed above. + +#### Dynamic Logging Behavior + +In the previous section, we discussed setting the base (or default) logging +behavior for the library. However, you may also set the log level dynamically, +during runtime, by using the `NoteSetLogLevel()` API. + +```c +NoteSetLogLevel(NOTE_C_LOG_LEVEL_WARN); +``` + +### Notecard Sync Logging (`[SYNC]`) + +Tangential to the standard logging behavior, `note-c` also provides a helper +function to invoke/extract synchronization logs from the Notecard. + +- `NoteDebugSyncStatus()` + +Instead of toggling features inside the library, this helper functions sends a +request to the Notecard to inquire about its synchronization status and logs +those details. + +The function is designed to be called in a loop and throttled by a parameter. +See [the documentation page][NoteDebugSyncStatus] for more information. + +## Versioning + +The `note-c` versioning scheme is a variant of [Semantic +Versioning](https://semver.org/). + +Below is a high-level overview of the major/minor/patch versions: + +- Major Version: Signals incompatible API changes. +- Minor Version: Signals added functionality in a backward compatible manner. +- Patch Version: Signals backward compatible bug fixes. + +Beyond the SemVer foundation, Blues has imposed additional requirements for a +version to be considered valid: + +- Major/minor/patch versions SHALL NOT be zero. +- For anything other than major version, version numbers MUST NOT contain +EITHER leading zeroes OR trailing zeroes (e.g. version `1.10.2` is invalid). + +> Example version progression: +> +> `1.8.1`, `1.9.1`, `1.9.2`, `1.11.1`, `1.11.2`, `1.11.3`, `1.12.1`, `2.1.1` + +These additional constraints have been observed to help disambiguate versions +and reduce support burden. + +### Version Artifacts + +The version can be referenced/tested programmatically via the following +preprocessor defined integers found in `note.h`: + +- `NOTE_C_VERSION_MAJOR` +- `NOTE_C_VERSION_MINOR` +- `NOTE_C_VERSION_PATCH` + +The version may also be logged via the preprocessor defined string literal, +`NOTE_C_VERSION`. ## Contributing @@ -57,8 +151,12 @@ Copyright (c) 2019 Blues Inc. Released under the MIT license. See [LICENSE](LICENSE) for details. [blues]: https://blues.com +[code of conduct]: https://blues.github.io/opensource/code-of-conduct +[coverage badge]: https://coveralls.io/repos/github/blues/note-c/badge.svg?branch=master +[coverage details]: https://coveralls.io/github/blues/note-c?branch=master +[NoteDebugSyncStatus]: https://blues.github.io/note-c/api_reference.html#c.NoteDebugSyncStatus [notehub]: https://notehub.io [note-arduino]: https://github.com/blues/note-arduino +[note-c API docs]: https://blues.github.io/note-c/index.html [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 diff --git a/src/note-c/n_atof.c b/src/note-c/n_atof.c index d465dec..4809d8c 100644 --- a/src/note-c/n_atof.c +++ b/src/note-c/n_atof.c @@ -256,7 +256,7 @@ char **endPtr; /* If non-NULL, store terminating character's case 5: p10 = 1.0e32; break; -#ifndef NOTE_C_LOW_MEM +#ifndef NOTE_C_SINGLE_PRECISION case 6: p10 = 1.0e64; break; diff --git a/src/note-c/n_cjson.c b/src/note-c/n_cjson.c index 365742b..d743205 100644 --- a/src/note-c/n_cjson.c +++ b/src/note-c/n_cjson.c @@ -79,12 +79,6 @@ #define PRINT_TAB_CHARS 4 -#ifdef NOTE_C_TEST -#include "test_static.h" -#else -#define NOTE_C_STATIC static -#endif - typedef struct { const unsigned char *json; size_t position; @@ -92,7 +86,7 @@ typedef struct { static error global_error = { NULL, 0 }; // Forwards -static J *JNew_Item(void); +NOTE_C_STATIC J *_jNew_Item(void); N_CJSON_PUBLIC(const char *) JGetErrorPtr(void) { @@ -118,7 +112,7 @@ N_CJSON_PUBLIC(const char*) JVersion(void) return NOTE_C_STRINGIZE(N_CJSON_VERSION_MAJOR) "." NOTE_C_STRINGIZE(N_CJSON_VERSION_MINOR) "." NOTE_C_STRINGIZE(N_CJSON_VERSION_PATCH); } -NOTE_C_STATIC char Jtolower(char c) +NOTE_C_STATIC char _j_tolower(char c) { if (c < 'A' || c > 'Z') { return c; @@ -130,7 +124,7 @@ NOTE_C_STATIC char Jtolower(char c) } /* 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) +NOTE_C_STATIC int _case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) { if ((string1 == NULL) || (string2 == NULL)) { return 1; @@ -140,16 +134,16 @@ static int case_insensitive_strcmp(const unsigned char *string1, const unsigned return 0; } - for(; Jtolower(*string1) == Jtolower(*string2); (void)string1++, string2++) { + for(; _j_tolower(*string1) == _j_tolower(*string2); (void)string1++, string2++) { if (*string1 == '\0') { return 0; } } - return Jtolower(*string1) - Jtolower(*string2); + return _j_tolower(*string1) - _j_tolower(*string2); } -static unsigned char* Jstrdup(const unsigned char* string) +NOTE_C_STATIC unsigned char* _j_strdup(const unsigned char* string) { size_t length = 0; unsigned char *copy = NULL; @@ -197,7 +191,7 @@ N_CJSON_PUBLIC(void) JFree(void *p) } /* Internal constructor. */ -static J *JNew_Item(void) +NOTE_C_STATIC J *_jNew_Item(void) { J* node = (J*)_Malloc(sizeof(J)); if (node) { @@ -232,7 +226,7 @@ N_CJSON_PUBLIC(void) JDelete(J *item) } /* get the decimal point character of the current locale */ -static unsigned char get_decimal_point(void) +NOTE_C_STATIC unsigned char _get_decimal_point(void) { #ifdef ENABLE_LOCALES struct lconv *lconv = localeconv(); @@ -258,12 +252,12 @@ typedef struct { #define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) /* Parse the input text to generate a number, and populate the result into item. */ -static Jbool parse_number(J * const item, parse_buffer * const input_buffer) +NOTE_C_STATIC Jbool _parse_number(J * const item, parse_buffer * const input_buffer) { JNUMBER number = 0; unsigned char *after_end = NULL; unsigned char number_c_string[64]; - unsigned char decimal_point = get_decimal_point(); + unsigned char decimal_point = _get_decimal_point(); size_t i = 0; if ((input_buffer == NULL) || (input_buffer->content == NULL)) { @@ -354,7 +348,7 @@ typedef struct { } printbuffer; /* realloc printbuffer if necessary to have at least "needed" bytes more */ -static unsigned char* ensure(printbuffer * const p, size_t needed) +NOTE_C_STATIC unsigned char* _ensure(printbuffer * const p, size_t needed) { unsigned char *newbuffer = NULL; size_t newsize = 0; @@ -414,7 +408,7 @@ static unsigned char* ensure(printbuffer * const p, size_t needed) } /* calculate the new length of the string in a printbuffer and update the offset */ -static void update_offset(printbuffer * const buffer) +NOTE_C_STATIC void _update_offset(printbuffer * const buffer) { const unsigned char *buffer_pointer = NULL; if ((buffer == NULL) || (buffer->buffer == NULL)) { @@ -426,7 +420,7 @@ static void update_offset(printbuffer * const buffer) } /* Render the number nicely from the given item into a string. */ -static Jbool print_number(const J * const item, printbuffer * const output_buffer) +NOTE_C_STATIC Jbool _print_number(const J * const item, printbuffer * const output_buffer) { if (item == NULL) { return false; @@ -438,7 +432,7 @@ static Jbool print_number(const J * const item, printbuffer * const output_buffe int length = 0; size_t i = 0; unsigned char number_buffer[JNTOA_MAX]; /* temporary buffer to print the number into */ - unsigned char decimal_point = get_decimal_point(); + unsigned char decimal_point = _get_decimal_point(); if (output_buffer == NULL) { return false; @@ -467,7 +461,7 @@ static Jbool print_number(const J * const item, printbuffer * const output_buffe } /* reserve appropriate space in the output */ - output_pointer = ensure(output_buffer, (size_t)length + sizeof("")); + output_pointer = _ensure(output_buffer, (size_t)length + sizeof("")); if (output_pointer == NULL) { return false; } @@ -490,7 +484,7 @@ static Jbool print_number(const J * const item, printbuffer * const output_buffe } /* parse 4 digit hexadecimal number */ -static unsigned long parse_hex4(const unsigned char * const input) +NOTE_C_STATIC unsigned long _parse_hex4(const unsigned char * const input) { unsigned long int h = 0; size_t i = 0; @@ -518,7 +512,7 @@ static unsigned long parse_hex4(const unsigned char * const input) /* converts a UTF-16 literal to UTF-8 * A literal can be one or two sequences of the form \uXXXX */ -static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer) +NOTE_C_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 long int first_code = 0; @@ -534,7 +528,7 @@ static unsigned char utf16_literal_to_utf8(const unsigned char * const input_poi } /* get the first utf16 sequence */ - first_code = parse_hex4(first_sequence + 2); + first_code = _parse_hex4(first_sequence + 2); /* check that the code is valid */ if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) { @@ -558,7 +552,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); + second_code = _parse_hex4(second_sequence + 2); /* check that the code is valid */ if ((second_code < 0xDC00) || (second_code > 0xDFFF)) { /* invalid second half of the surrogate pair */ @@ -618,14 +612,23 @@ static unsigned char utf16_literal_to_utf8(const unsigned char * const input_poi } /* Parse the input text into an unescaped cinput, and populate item. */ -static Jbool parse_string(J * const item, parse_buffer * const input_buffer) +NOTE_C_STATIC Jbool _parse_string(J * const item, parse_buffer * const input_buffer) { + // This is a static function that is only called internally, and we are + // guaranteed that item is not NULL. `cppcheck` is not able to infer this + // from the code, because we are using a macro, NOTE_C_STATIC, to remove + // the static keyword in the public header during testing. + + // cppcheck-suppress ctunullpointer + // cppcheck-suppress nullPointerRedundantCheck const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; + // cppcheck-suppress nullPointerRedundantCheck const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; unsigned char *output_pointer = NULL; unsigned char *output = NULL; /* not a string */ + // cppcheck-suppress nullPointerRedundantCheck if (buffer_at_offset(input_buffer)[0] != '\"') { goto fail; } @@ -695,7 +698,7 @@ static Jbool parse_string(J * const item, parse_buffer * const input_buffer) /* UTF-16 literal */ case 'u': - sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); + 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; @@ -733,7 +736,7 @@ static Jbool parse_string(J * const item, parse_buffer * const input_buffer) } /* Convert a 16-bit number to 4 hex digits, null-terminating it */ -void n_htoa16(uint16_t n, unsigned char *p) +void _n_htoa16(uint16_t n, unsigned char *p) { int i; for (i=0; i<4; i++) { @@ -749,7 +752,7 @@ void n_htoa16(uint16_t n, unsigned char *p) } /* Render the cstring provided to an escaped version that can be printed. */ -static Jbool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer) +NOTE_C_STATIC Jbool _print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer) { const unsigned char *input_pointer = NULL; unsigned char *output = NULL; @@ -764,7 +767,7 @@ static Jbool print_string_ptr(const unsigned char * const input, printbuffer * c /* empty string */ if (input == NULL) { - output = ensure(output_buffer, 2); // sizeof("\"\"") + output = _ensure(output_buffer, 2); // sizeof("\"\"") if (output == NULL) { return false; } @@ -798,7 +801,7 @@ static Jbool print_string_ptr(const unsigned char * const input, printbuffer * c } output_length = (size_t)(input_pointer - input) + escape_characters; - output = ensure(output_buffer, output_length + 2); // sizeof("\"\"") + output = _ensure(output_buffer, output_length + 2); // sizeof("\"\"") if (output == NULL) { return false; } @@ -848,7 +851,7 @@ static Jbool print_string_ptr(const unsigned char * const input, printbuffer * c default: /* escape and print as unicode codepoint */ *output_pointer++ = 'u'; - n_htoa16(*input_pointer, output_pointer); + _n_htoa16(*input_pointer, output_pointer); output_pointer += 4; break; } @@ -860,22 +863,22 @@ static Jbool print_string_ptr(const unsigned char * const input, printbuffer * c return true; } -/* Invoke print_string_ptr (which is useful) on an item. */ -static Jbool print_string(const J * const item, printbuffer * const p) +/* Invoke _print_string_ptr (which is useful) on an item. */ +NOTE_C_STATIC Jbool _print_string(const J * const item, printbuffer * const p) { - return print_string_ptr((unsigned char*)item->valuestring, p); + return _print_string_ptr((unsigned char*)item->valuestring, p); } /* Predeclare these prototypes. */ -static Jbool parse_value(J * const item, parse_buffer * const input_buffer); -static Jbool print_value(const J * const item, printbuffer * const output_buffer); -static Jbool parse_array(J * const item, parse_buffer * const input_buffer); -static Jbool print_array(const J * const item, printbuffer * const output_buffer); -static Jbool parse_object(J * const item, parse_buffer * const input_buffer); -static Jbool print_object(const J * const item, printbuffer * const output_buffer); +NOTE_C_STATIC Jbool _parse_value(J * const item, parse_buffer * const input_buffer); +NOTE_C_STATIC Jbool _print_value(const J * const item, printbuffer * const output_buffer); +NOTE_C_STATIC Jbool _parse_array(J * const item, parse_buffer * const input_buffer); +NOTE_C_STATIC Jbool _print_array(const J * const item, printbuffer * const output_buffer); +NOTE_C_STATIC Jbool _parse_object(J * const item, parse_buffer * const input_buffer); +NOTE_C_STATIC Jbool _print_object(const J * const item, printbuffer * const output_buffer); /* Utility to jump whitespace and cr/lf */ -static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) +NOTE_C_STATIC parse_buffer *_buffer_skip_whitespace(parse_buffer * const buffer) { if ((buffer == NULL) || (buffer->content == NULL)) { return NULL; @@ -893,7 +896,7 @@ 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) +NOTE_C_STATIC parse_buffer *_skip_utf8_bom(parse_buffer * const buffer) { if ((buffer == NULL) || (buffer->content == NULL) || (buffer->offset != 0)) { return NULL; @@ -924,19 +927,19 @@ N_CJSON_PUBLIC(J *) JParseWithOpts(const char *value, const char **return_parse_ buffer.length = strlen((const char*)value) + 1; // Trailing '\0' buffer.offset = 0; - item = JNew_Item(); + item = _jNew_Item(); 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) { - buffer_skip_whitespace(&buffer); + _buffer_skip_whitespace(&buffer); if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') { goto fail; } @@ -988,7 +991,7 @@ N_CJSON_PUBLIC(J *) JParse(const char *value) #define cjson_min(a, b) ((a < b) ? a : b) -static unsigned char *print(const J * const item, Jbool format, Jbool omitempty) +NOTE_C_STATIC unsigned char *_print(const J * const item, Jbool format, Jbool omitempty) { static const size_t default_buffer_size = 128; printbuffer buffer[1]; @@ -1006,10 +1009,10 @@ static unsigned char *print(const J * const item, Jbool format, Jbool omitempty) } /* print the value */ - if (!print_value(item, buffer)) { + if (!_print_value(item, buffer)) { goto fail; } - update_offset(buffer); + _update_offset(buffer); /* copy the JSON over to a new buffer */ printed = (unsigned char*) _Malloc(buffer->offset + 1); @@ -1042,7 +1045,7 @@ N_CJSON_PUBLIC(char *) JPrint(const J *item) if (item == NULL) { return NULL; } - return (char*)print(item, true, false); + return (char*)_print(item, true, false); } /*! @@ -1061,7 +1064,7 @@ N_CJSON_PUBLIC(char *) JPrintUnformatted(const J *item) if (item == NULL) { return NULL; } - return (char*)print(item, false, false); + return (char*)_print(item, false, false); } N_CJSON_PUBLIC(char *) JPrintUnformattedOmitEmpty(const J *item) @@ -1069,7 +1072,7 @@ N_CJSON_PUBLIC(char *) JPrintUnformattedOmitEmpty(const J *item) if (item == NULL) { return NULL; } - return (char*)print(item, false, true); + return (char*)_print(item, false, true); } N_CJSON_PUBLIC(char *) JPrintBuffered(const J *item, int prebuffer, Jbool fmt) @@ -1094,7 +1097,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; } @@ -1102,7 +1105,7 @@ N_CJSON_PUBLIC(char *) JPrintBuffered(const J *item, int prebuffer, Jbool fmt) return (char*)p.buffer; } -static Jbool printPreallocated(J *item, char *buf, const int len, const Jbool fmt, const Jbool omit) +NOTE_C_STATIC Jbool _printPreallocated(J *item, char *buf, const int len, const Jbool fmt, const Jbool omit) { printbuffer p = { 0, 0, 0, 0, 0, 0, 0 }; @@ -1120,21 +1123,21 @@ static Jbool printPreallocated(J *item, char *buf, const int len, const Jbool fm p.format = fmt; p.omitempty = omit; - return print_value(item, &p); + return _print_value(item, &p); } N_CJSON_PUBLIC(Jbool) JPrintPreallocatedOmitEmpty(J *item, char *buf, const int len, const Jbool fmt) { - return printPreallocated(item, buf, len, fmt, true); + return _printPreallocated(item, buf, len, fmt, true); } N_CJSON_PUBLIC(Jbool) JPrintPreallocated(J *item, char *buf, const int len, const Jbool fmt) { - return printPreallocated(item, buf, len, fmt, false); + return _printPreallocated(item, buf, len, fmt, false); } /* Parser core - when encountering text, process appropriately. */ -static Jbool parse_value(J * const item, parse_buffer * const input_buffer) +NOTE_C_STATIC Jbool _parse_value(J * const item, parse_buffer * const input_buffer) { if (item == NULL) { return false; @@ -1165,26 +1168,26 @@ static Jbool parse_value(J * const item, parse_buffer * const input_buffer) } /* string */ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) { - return parse_string(item, input_buffer); + 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')))) { - return parse_number(item, input_buffer); + return _parse_number(item, input_buffer); } /* array */ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) { - return parse_array(item, input_buffer); + return _parse_array(item, input_buffer); } /* object */ if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) { - return parse_object(item, input_buffer); + return _parse_object(item, input_buffer); } return false; } /* Render a value to text. */ -static Jbool print_value(const J * const item, printbuffer * const output_buffer) +NOTE_C_STATIC Jbool _print_value(const J * const item, printbuffer * const output_buffer) { unsigned char *output = NULL; @@ -1194,7 +1197,7 @@ static Jbool print_value(const J * const item, printbuffer * const output_buffer switch ((item->type) & 0xFF) { case JNULL: - output = ensure(output_buffer, c_null_len+1); + output = _ensure(output_buffer, c_null_len+1); if (output == NULL) { return false; } @@ -1202,7 +1205,7 @@ static Jbool print_value(const J * const item, printbuffer * const output_buffer return true; case JFalse: - output = ensure(output_buffer, c_false_len+1); + output = _ensure(output_buffer, c_false_len+1); if (output == NULL) { return false; } @@ -1210,7 +1213,7 @@ static Jbool print_value(const J * const item, printbuffer * const output_buffer return true; case JTrue: - output = ensure(output_buffer, c_true_len+1); + output = _ensure(output_buffer, c_true_len+1); if (output == NULL) { return false; } @@ -1218,7 +1221,7 @@ static Jbool print_value(const J * const item, printbuffer * const output_buffer return true; case JNumber: - return print_number(item, output_buffer); + return _print_number(item, output_buffer); case JRaw: { size_t raw_length = 0; @@ -1227,7 +1230,7 @@ static Jbool print_value(const J * const item, printbuffer * const output_buffer } raw_length = strlen(item->valuestring) + 1; // Trailing '\0'; - output = ensure(output_buffer, raw_length); + output = _ensure(output_buffer, raw_length); if (output == NULL) { return false; } @@ -1236,13 +1239,13 @@ static Jbool print_value(const J * const item, printbuffer * const output_buffer } case JString: - return print_string(item, output_buffer); + return _print_string(item, output_buffer); case JArray: - return print_array(item, output_buffer); + return _print_array(item, output_buffer); case JObject: - return print_object(item, output_buffer); + return _print_object(item, output_buffer); default: return false; @@ -1250,23 +1253,34 @@ static Jbool print_value(const J * const item, printbuffer * const output_buffer } /* Build an array from input text. */ -static Jbool parse_array(J * const item, parse_buffer * const input_buffer) +NOTE_C_STATIC Jbool _parse_array(J * const item, parse_buffer * const input_buffer) { + // This is a static function that is only called internally, and we are + // guaranteed that item is not NULL. `cppcheck` is not able to infer this + // from the code, because we are using a macro, NOTE_C_STATIC, to remove + // the static keyword in the public header during testing. + J *head = NULL; /* head of the linked list */ J *current_item = NULL; + // cppcheck-suppress nullPointerRedundantCheck if (input_buffer->depth >= N_CJSON_NESTING_LIMIT) { return false; /* to deeply nested */ } + // cppcheck-suppress nullPointerRedundantCheck input_buffer->depth++; + // cppcheck-suppress nullPointerRedundantCheck if (buffer_at_offset(input_buffer)[0] != '[') { /* not an array */ goto fail; } + // _buffer_skip_whitespace() will verify the input_buffer is not NULL at + // the new offset. + // cppcheck-suppress nullPointerRedundantCheck input_buffer->offset++; - buffer_skip_whitespace(input_buffer); + _buffer_skip_whitespace(input_buffer); if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) { /* empty array */ goto success; @@ -1274,16 +1288,20 @@ static Jbool parse_array(J * const item, parse_buffer * const input_buffer) /* check if we skipped to the end of the buffer */ if (cannot_access_at_index(input_buffer, 0)) { + // _buffer_skip_whitespace() has moved us one beyond the end, therefore + // we need to move back one, and we know we can access it. + // cppcheck-suppress nullPointerRedundantCheck input_buffer->offset--; goto fail; } /* step back to character in front of the first element */ input_buffer->offset--; + /* loop through the comma separated array elements */ do { /* allocate next item */ - J *new_item = JNew_Item(); + J *new_item = _jNew_Item(); if (new_item == NULL) { goto fail; /* allocation failure */ } @@ -1301,11 +1319,11 @@ 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)) { + _buffer_skip_whitespace(input_buffer); + if (!_parse_value(current_item, input_buffer)) { goto fail; /* failed to parse value */ } - buffer_skip_whitespace(input_buffer); + _buffer_skip_whitespace(input_buffer); } 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] != ']') { @@ -1331,7 +1349,7 @@ static Jbool parse_array(J * const item, parse_buffer * const input_buffer) } /* Render an array to text */ -static Jbool print_array(const J * const item, printbuffer * const output_buffer) +NOTE_C_STATIC Jbool _print_array(const J * const item, printbuffer * const output_buffer) { unsigned char *output_pointer = NULL; size_t length = 0; @@ -1343,7 +1361,7 @@ static Jbool print_array(const J * const item, printbuffer * const output_buffer /* Compose the output array. */ /* opening square bracket */ - output_pointer = ensure(output_buffer, 1); + output_pointer = _ensure(output_buffer, 1); if (output_pointer == NULL) { return false; } @@ -1353,13 +1371,13 @@ static Jbool print_array(const J * const item, printbuffer * const output_buffer output_buffer->depth++; while (current_element != NULL) { - if (!print_value(current_element, output_buffer)) { + if (!_print_value(current_element, output_buffer)) { return false; } - update_offset(output_buffer); + _update_offset(output_buffer); if (current_element->next) { length = (size_t) (output_buffer->format ? 2 : 1); - output_pointer = ensure(output_buffer, length + 1); + output_pointer = _ensure(output_buffer, length + 1); if (output_pointer == NULL) { return false; } @@ -1373,7 +1391,7 @@ static Jbool print_array(const J * const item, printbuffer * const output_buffer current_element = current_element->next; } - output_pointer = ensure(output_buffer, 2); + output_pointer = _ensure(output_buffer, 2); if (output_pointer == NULL) { return false; } @@ -1385,38 +1403,53 @@ static Jbool print_array(const J * const item, printbuffer * const output_buffer } /* Build an object from the text. */ -static Jbool parse_object(J * const item, parse_buffer * const input_buffer) +NOTE_C_STATIC Jbool _parse_object(J * const item, parse_buffer * const input_buffer) { + // This is a static function that is only called internally, and we are + // guaranteed that item is not NULL. `cppcheck` is not able to infer this + // from the code, because we are using a macro, NOTE_C_STATIC, to remove + // the static keyword in the public header during testing. + J *head = NULL; /* linked list head */ J *current_item = NULL; + // cppcheck-suppress nullPointerRedundantCheck if (input_buffer->depth >= N_CJSON_NESTING_LIMIT) { return false; /* to deeply nested */ } + // cppcheck-suppress nullPointerRedundantCheck input_buffer->depth++; if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) { goto fail; /* not an object */ } + // _buffer_skip_whitespace() will verify the input_buffer is not NULL at + // the new offset. + // cppcheck-suppress nullPointerRedundantCheck input_buffer->offset++; - buffer_skip_whitespace(input_buffer); + _buffer_skip_whitespace(input_buffer); 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)) { + // _buffer_skip_whitespace() has moved us one beyond the end, therefore + // we need to move back one, and we know we can access it. + // cppcheck-suppress nullPointerRedundantCheck input_buffer->offset--; goto fail; } /* step back to character in front of the first element */ + // cppcheck-suppress nullPointerRedundantCheck input_buffer->offset--; + /* loop through the comma separated array elements */ do { /* allocate next item */ - J *new_item = JNew_Item(); + J *new_item = _jNew_Item(); if (new_item == NULL) { goto fail; /* allocation failure */ } @@ -1433,12 +1466,15 @@ static Jbool parse_object(J * const item, parse_buffer * const input_buffer) } /* parse the name of the child */ + // _buffer_skip_whitespace() will verify the input_buffer is not NULL at + // the new offset. + // cppcheck-suppress nullPointerRedundantCheck input_buffer->offset++; - buffer_skip_whitespace(input_buffer); - if (!parse_string(current_item, input_buffer)) { + _buffer_skip_whitespace(input_buffer); + if (!_parse_string(current_item, input_buffer)) { goto fail; /* faile to parse name */ } - buffer_skip_whitespace(input_buffer); + _buffer_skip_whitespace(input_buffer); /* swap valuestring and string, because we parsed the name */ current_item->string = current_item->valuestring; @@ -1450,11 +1486,11 @@ static Jbool parse_object(J * const item, parse_buffer * const input_buffer) /* parse the value */ input_buffer->offset++; - buffer_skip_whitespace(input_buffer); - if (!parse_value(current_item, input_buffer)) { + _buffer_skip_whitespace(input_buffer); + if (!_parse_value(current_item, input_buffer)) { goto fail; /* failed to parse value */ } - buffer_skip_whitespace(input_buffer); + _buffer_skip_whitespace(input_buffer); } 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] != '}')) { @@ -1479,7 +1515,7 @@ static Jbool parse_object(J * const item, parse_buffer * const input_buffer) } /* See if there is another non-omitted item looking forward */ -static bool last_non_omitted_object(J * item, printbuffer * const output_buffer) +NOTE_C_STATIC bool _last_non_omitted_object(J * item, printbuffer * const output_buffer) { if (!output_buffer->omitempty) { return (item->next == 0); @@ -1495,7 +1531,7 @@ static bool last_non_omitted_object(J * item, printbuffer * const output_buffer) } /* Render an object to text. */ -static Jbool print_object(const J * const item, printbuffer * const output_buffer) +NOTE_C_STATIC Jbool _print_object(const J * const item, printbuffer * const output_buffer) { unsigned char *output_pointer = NULL; size_t length = 0; @@ -1507,7 +1543,7 @@ static Jbool print_object(const J * const item, printbuffer * const output_buffe /* Compose the output: */ length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */ - output_pointer = ensure(output_buffer, length + 1); + output_pointer = _ensure(output_buffer, length + 1); if (output_pointer == NULL) { return false; } @@ -1527,7 +1563,7 @@ static Jbool print_object(const J * const item, printbuffer * const output_buffe #else int needed = output_buffer->depth * PRINT_TAB_CHARS; #endif - output_pointer = ensure(output_buffer, needed); + output_pointer = _ensure(output_buffer, needed); if (output_pointer == NULL) { return false; } @@ -1555,13 +1591,13 @@ static Jbool print_object(const J * const item, printbuffer * const output_buffe if (!omit) { /* 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); + _update_offset(output_buffer); length = (size_t) (output_buffer->format ? 2 : 1); - output_pointer = ensure(output_buffer, length); + output_pointer = _ensure(output_buffer, length); if (output_pointer == NULL) { return false; } @@ -1576,15 +1612,15 @@ static Jbool print_object(const J * const item, printbuffer * const output_buffe 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); + _update_offset(output_buffer); /* print comma if not last */ - bool more_fields_coming = !last_non_omitted_object(current_item, output_buffer); + bool more_fields_coming = !_last_non_omitted_object(current_item, output_buffer); length = (size_t) ((output_buffer->format ? 1 : 0) + (more_fields_coming ? 1 : 0)); - output_pointer = ensure(output_buffer, length + 1); + output_pointer = _ensure(output_buffer, length + 1); if (output_pointer == NULL) { return false; } @@ -1608,7 +1644,7 @@ static Jbool print_object(const J * const item, printbuffer * const output_buffe int needed = output_buffer->format ? ((output_buffer->depth - 1) * PRINT_TAB_CHARS) : 0; #endif needed += 2; // }\0 - output_pointer = ensure(output_buffer, needed); + output_pointer = _ensure(output_buffer, needed); if (output_pointer == NULL) { return false; } @@ -1653,7 +1689,7 @@ N_CJSON_PUBLIC(int) JGetArraySize(const J *array) return (int)size; } -static J* get_array_item(const J *array, size_t index) +NOTE_C_STATIC J* _get_array_item(const J *array, size_t index) { J *current_child = NULL; @@ -1679,10 +1715,10 @@ N_CJSON_PUBLIC(J *) JGetArrayItem(const J *array, int index) return NULL; } - return get_array_item(array, (size_t)index); + return _get_array_item(array, (size_t)index); } -static J *get_object_item(const J * const object, const char * const name, const Jbool case_sensitive) +NOTE_C_STATIC J *_get_object_item(const J * const object, const char * const name, const Jbool case_sensitive) { J *current_element = NULL; @@ -1696,7 +1732,7 @@ static J *get_object_item(const J * const object, const char * const name, const current_element = current_element->next; } } else { - while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) { + while ((current_element != NULL) && (_case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) { current_element = current_element->next; } } @@ -1709,7 +1745,7 @@ N_CJSON_PUBLIC(J *) JGetObjectItem(const J * const object, const char * const st if (object == NULL) { return NULL; } - return get_object_item(object, string, false); + return _get_object_item(object, string, false); } N_CJSON_PUBLIC(J *) JGetObjectItemCaseSensitive(const J * const object, const char * const string) @@ -1717,7 +1753,7 @@ N_CJSON_PUBLIC(J *) JGetObjectItemCaseSensitive(const J * const object, const ch if (object == NULL) { return NULL; } - return get_object_item(object, string, true); + return _get_object_item(object, string, true); } N_CJSON_PUBLIC(Jbool) JHasObjectItem(const J *object, const char *string) @@ -1729,21 +1765,21 @@ N_CJSON_PUBLIC(Jbool) JHasObjectItem(const J *object, const char *string) } /* Utility for array list handling. */ -static void suffix_object(J *prev, J *item) +NOTE_C_STATIC void _suffix_object(J *prev, J *item) { prev->next = item; item->prev = prev; } /* Utility for handling references. */ -static J *create_reference(const J *item) +NOTE_C_STATIC J *_create_reference(const J *item) { J *reference = NULL; if (item == NULL) { return NULL; } - reference = JNew_Item(); + reference = _jNew_Item(); if (reference == NULL) { return NULL; } @@ -1755,7 +1791,7 @@ static J *create_reference(const J *item) return reference; } -static Jbool add_item_to_array(J *array, J *item) +NOTE_C_STATIC Jbool _add_item_to_array(J *array, J *item) { J *child = NULL; @@ -1773,7 +1809,7 @@ static Jbool add_item_to_array(J *array, J *item) while (child->next) { child = child->next; } - suffix_object(child, item); + _suffix_object(child, item); } return true; @@ -1785,7 +1821,7 @@ N_CJSON_PUBLIC(void) JAddItemToArray(J *array, J *item) if (array == NULL || item == NULL) { return; } - add_item_to_array(array, item); + _add_item_to_array(array, item); } #if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) @@ -1795,7 +1831,7 @@ N_CJSON_PUBLIC(void) JAddItemToArray(J *array, J *item) #pragma GCC diagnostic ignored "-Wcast-qual" #endif /* helper function to cast away const */ -static void* cast_away_const(const void* string) +NOTE_C_STATIC void* _cast_away_const(const void* string) { return (void*)string; } @@ -1804,7 +1840,7 @@ static void* cast_away_const(const void* string) #endif -static Jbool add_item_to_object(J * const object, const char * const string, J * const item, const Jbool constant_key) +NOTE_C_STATIC Jbool _add_item_to_object(J * const object, const char * const string, J * const item, const Jbool constant_key) { char *new_key = NULL; int new_type = JInvalid; @@ -1814,10 +1850,10 @@ static Jbool add_item_to_object(J * const object, const char * const string, J * } if (constant_key) { - new_key = (char*)cast_away_const(string); + new_key = (char*)_cast_away_const(string); new_type = item->type | JStringIsConst; } else { - new_key = (char*)Jstrdup((const unsigned char*)string); + new_key = (char*)_j_strdup((const unsigned char*)string); if (new_key == NULL) { return false; } @@ -1832,7 +1868,7 @@ static Jbool add_item_to_object(J * const object, const char * const string, J * item->string = new_key; item->type = new_type; - return add_item_to_array(object, item); + return _add_item_to_array(object, item); } N_CJSON_PUBLIC(void) JAddItemToObject(J *object, const char *string, J *item) @@ -1840,7 +1876,7 @@ N_CJSON_PUBLIC(void) JAddItemToObject(J *object, const char *string, J *item) if (object == NULL || string == NULL || item == NULL) { return; } - add_item_to_object(object, string, item, false); + _add_item_to_object(object, string, item, false); } /* Add an item to an object with constant string as key */ @@ -1849,7 +1885,7 @@ N_CJSON_PUBLIC(void) JAddItemToObjectCS(J *object, const char *string, J *item) if (object == NULL || string == NULL || item == NULL) { return; } - add_item_to_object(object, string, item, true); + _add_item_to_object(object, string, item, true); } N_CJSON_PUBLIC(void) JAddItemReferenceToArray(J *array, J *item) @@ -1857,7 +1893,7 @@ N_CJSON_PUBLIC(void) JAddItemReferenceToArray(J *array, J *item) if (array == NULL || item == NULL) { return; } - add_item_to_array(array, create_reference(item)); + _add_item_to_array(array, _create_reference(item)); } N_CJSON_PUBLIC(void) JAddItemReferenceToObject(J *object, const char *string, J *item) @@ -1865,7 +1901,7 @@ N_CJSON_PUBLIC(void) JAddItemReferenceToObject(J *object, const char *string, J if (object == NULL || string == NULL || item == NULL) { return; } - add_item_to_object(object, string, create_reference(item), false); + _add_item_to_object(object, string, _create_reference(item), false); } N_CJSON_PUBLIC(J*) JAddTrueToObject(J * const object, const char * const name) @@ -1875,7 +1911,7 @@ 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; } @@ -1890,7 +1926,7 @@ 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; } @@ -1914,7 +1950,7 @@ N_CJSON_PUBLIC(J*) JAddBoolToObject(J * const object, const char * const name, c } 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; } @@ -1938,7 +1974,7 @@ N_CJSON_PUBLIC(J*) JAddNumberToObject(J * const object, const char * const name, } 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; } @@ -1953,7 +1989,7 @@ N_CJSON_PUBLIC(J*) JAddIntToObject(J * const object, const char * const name, co } J *integer_item = JCreateInteger(integer); - if (add_item_to_object(object, name, integer_item, false)) { + if (_add_item_to_object(object, name, integer_item, false)) { return integer_item; } @@ -1977,7 +2013,7 @@ N_CJSON_PUBLIC(J*) JAddStringToObject(J * const object, const char * const name, } 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; } @@ -1992,7 +2028,7 @@ N_CJSON_PUBLIC(J*) JAddRawToObject(J * const object, const char * const name, co } 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; } @@ -2015,7 +2051,7 @@ 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; } @@ -2038,7 +2074,7 @@ 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; } @@ -2081,7 +2117,7 @@ N_CJSON_PUBLIC(J *) JDetachItemFromArray(J *array, int which) return NULL; } - return JDetachItemViaPointer(array, get_array_item(array, (size_t)which)); + return JDetachItemViaPointer(array, _get_array_item(array, (size_t)which)); } N_CJSON_PUBLIC(void) JDeleteItemFromArray(J *array, int which) @@ -2143,9 +2179,9 @@ N_CJSON_PUBLIC(void) JInsertItemInArray(J *array, int which, J *newitem) return; } - after_inserted = get_array_item(array, (size_t)which); + after_inserted = _get_array_item(array, (size_t)which); if (after_inserted == NULL) { - add_item_to_array(array, newitem); + _add_item_to_array(array, newitem); return; } @@ -2199,10 +2235,10 @@ N_CJSON_PUBLIC(void) JReplaceItemInArray(J *array, int which, J *newitem) return; } - JReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); + JReplaceItemViaPointer(array, _get_array_item(array, (size_t)which), newitem); } -static Jbool replace_item_in_object(J *object, const char *string, J *replacement, Jbool case_sensitive) +NOTE_C_STATIC Jbool _replace_item_in_object(J *object, const char *string, J *replacement, Jbool case_sensitive) { if (object == NULL || replacement == NULL || string == NULL) { return false; @@ -2212,10 +2248,10 @@ static Jbool replace_item_in_object(J *object, const char *string, J *replacemen if (!(replacement->type & JStringIsConst) && (replacement->string != NULL)) { _Free(replacement->string); } - replacement->string = (char*)Jstrdup((const unsigned char*)string); + replacement->string = (char*)_j_strdup((const unsigned char*)string); replacement->type &= ~JStringIsConst; - JReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); + JReplaceItemViaPointer(object, _get_object_item(object, string, case_sensitive), replacement); return true; } @@ -2225,7 +2261,7 @@ N_CJSON_PUBLIC(void) JReplaceItemInObject(J *object, const char *string, J *newi if (object == NULL || newitem == NULL) { return; } - replace_item_in_object(object, string, newitem, false); + _replace_item_in_object(object, string, newitem, false); } N_CJSON_PUBLIC(void) JReplaceItemInObjectCaseSensitive(J *object, const char *string, J *newitem) @@ -2233,12 +2269,12 @@ N_CJSON_PUBLIC(void) JReplaceItemInObjectCaseSensitive(J *object, const char *st if (object == NULL || newitem == NULL) { return; } - replace_item_in_object(object, string, newitem, true); + _replace_item_in_object(object, string, newitem, true); } N_CJSON_PUBLIC(J *) JCreateTrue(void) { - J *item = JNew_Item(); + J *item = _jNew_Item(); if(item) { item->type = JTrue; } @@ -2247,7 +2283,7 @@ N_CJSON_PUBLIC(J *) JCreateTrue(void) N_CJSON_PUBLIC(J *) JCreateFalse(void) { - J *item = JNew_Item(); + J *item = _jNew_Item(); if(item) { item->type = JFalse; } @@ -2256,7 +2292,7 @@ N_CJSON_PUBLIC(J *) JCreateFalse(void) N_CJSON_PUBLIC(J *) JCreateBool(Jbool b) { - J *item = JNew_Item(); + J *item = _jNew_Item(); if(item) { item->type = b ? JTrue : JFalse; } @@ -2265,7 +2301,7 @@ N_CJSON_PUBLIC(J *) JCreateBool(Jbool b) N_CJSON_PUBLIC(J *) JCreateNumber(JNUMBER num) { - J *item = JNew_Item(); + J *item = _jNew_Item(); if(item) { item->type = JNumber; item->valuenumber = num; @@ -2284,7 +2320,7 @@ N_CJSON_PUBLIC(J *) JCreateNumber(JNUMBER num) N_CJSON_PUBLIC(J *) JCreateInteger(JINTEGER integer) { - J *item = JNew_Item(); + J *item = _jNew_Item(); if(item) { item->type = JNumber; item->valuenumber = (JNUMBER)integer; @@ -2295,10 +2331,10 @@ N_CJSON_PUBLIC(J *) JCreateInteger(JINTEGER integer) N_CJSON_PUBLIC(J *) JCreateString(const char *string) { - J *item = JNew_Item(); + J *item = _jNew_Item(); if(item) { item->type = JString; - item->valuestring = (char*)Jstrdup((const unsigned char*)string); + item->valuestring = (char*)_j_strdup((const unsigned char*)string); if(!item->valuestring) { JDelete(item); return NULL; @@ -2309,20 +2345,20 @@ N_CJSON_PUBLIC(J *) JCreateString(const char *string) N_CJSON_PUBLIC(J *) JCreateStringValue(const char *string) { - J *item = JNew_Item(); + J *item = _jNew_Item(); if (item != NULL) { item->type = JString; - item->valuestring = (char*)cast_away_const(string); + item->valuestring = (char*)_cast_away_const(string); } return item; } N_CJSON_PUBLIC(J *) JCreateStringReference(const char *string) { - J *item = JNew_Item(); + J *item = _jNew_Item(); if (item != NULL) { item->type = JString | JIsReference; - item->valuestring = (char*)cast_away_const(string); + item->valuestring = (char*)_cast_away_const(string); } return item; } @@ -2332,10 +2368,10 @@ N_CJSON_PUBLIC(J *) JCreateObjectReference(const J *child) if (child == NULL) { return NULL; } - J *item = JNew_Item(); + J *item = _jNew_Item(); if (item != NULL) { item->type = JObject | JIsReference; - item->child = (J*)cast_away_const(child); + item->child = (J*)_cast_away_const(child); } return item; } @@ -2345,20 +2381,20 @@ N_CJSON_PUBLIC(J *) JCreateArrayReference(const J *child) if (child == NULL) { return NULL; } - J *item = JNew_Item(); + J *item = _jNew_Item(); if (item != NULL) { item->type = JArray | JIsReference; - item->child = (J*)cast_away_const(child); + item->child = (J*)_cast_away_const(child); } return item; } N_CJSON_PUBLIC(J *) JCreateRaw(const char *raw) { - J *item = JNew_Item(); + J *item = _jNew_Item(); if(item) { item->type = JRaw; - item->valuestring = (char*)Jstrdup((const unsigned char*)raw); + item->valuestring = (char*)_j_strdup((const unsigned char*)raw); if(!item->valuestring) { JDelete(item); return NULL; @@ -2369,7 +2405,7 @@ N_CJSON_PUBLIC(J *) JCreateRaw(const char *raw) N_CJSON_PUBLIC(J *) JCreateArray(void) { - J *item = JNew_Item(); + J *item = _jNew_Item(); if(item) { item->type=JArray; } @@ -2385,7 +2421,7 @@ N_CJSON_PUBLIC(J *) JCreateArray(void) */ N_CJSON_PUBLIC(J *) JCreateObject(void) { - J *item = JNew_Item(); + J *item = _jNew_Item(); if (item) { item->type = JObject; } @@ -2414,7 +2450,7 @@ N_CJSON_PUBLIC(J *) JCreateIntArray(const long int *numbers, int count) if(!i) { a->child = n; } else { - suffix_object(p, n); + _suffix_object(p, n); } p = n; } @@ -2444,7 +2480,7 @@ N_CJSON_PUBLIC(J *) JCreateNumberArray(const JNUMBER *numbers, int count) if(!i) { a->child = n; } else { - suffix_object(p, n); + _suffix_object(p, n); } p = n; } @@ -2474,7 +2510,7 @@ N_CJSON_PUBLIC(J *) JCreateStringArray(const char **strings, int count) if(!i) { a->child = n; } else { - suffix_object(p,n); + _suffix_object(p,n); } p = n; } @@ -2495,7 +2531,7 @@ N_CJSON_PUBLIC(J *) JDuplicate(const J *item, Jbool recurse) goto fail; } /* Create new item */ - newitem = JNew_Item(); + newitem = _jNew_Item(); if (!newitem) { goto fail; } @@ -2504,13 +2540,13 @@ N_CJSON_PUBLIC(J *) JDuplicate(const J *item, Jbool recurse) newitem->valueint = item->valueint; newitem->valuenumber = item->valuenumber; if (item->valuestring) { - newitem->valuestring = (char*)Jstrdup((unsigned char*)item->valuestring); + newitem->valuestring = (char*)_j_strdup((unsigned char*)item->valuestring); if (!newitem->valuestring) { goto fail; } } if (item->string) { - newitem->string = (item->type&JStringIsConst) ? item->string : (char*)Jstrdup((unsigned char*)item->string); + newitem->string = (item->type&JStringIsConst) ? item->string : (char*)_j_strdup((unsigned char*)item->string); if (!newitem->string) { goto fail; } @@ -2755,7 +2791,7 @@ N_CJSON_PUBLIC(Jbool) JCompare(const J * const a, const J * const b, const Jbool 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); + b_element = _get_object_item(b, a_element->string, case_sensitive); if (b_element == NULL) { return false; } @@ -2768,7 +2804,7 @@ N_CJSON_PUBLIC(Jbool) JCompare(const J * const a, const J * const b, const Jbool /* 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); + a_element = _get_object_item(a, b_element->string, case_sensitive); if (a_element == NULL) { return false; } diff --git a/src/note-c/n_cobs.c b/src/note-c/n_cobs.c index 426a5a1..caaec14 100644 --- a/src/note-c/n_cobs.c +++ b/src/note-c/n_cobs.c @@ -24,7 +24,7 @@ @return the length of the decoded data */ /**************************************************************************/ -uint32_t cobsDecode(uint8_t *ptr, uint32_t length, uint8_t eop, uint8_t *dst) +uint32_t _cobsDecode(uint8_t *ptr, uint32_t length, uint8_t eop, uint8_t *dst) { const uint8_t *start = dst, *end = ptr + length; uint8_t code = 0xFF, copy = 0; @@ -60,13 +60,13 @@ uint32_t cobsDecode(uint8_t *ptr, uint32_t length, uint8_t eop, uint8_t *dst) @return the length of the encoded data - @note You may use `cobsEncodedLength()` to calculate the required size for + @note You may use `_cobsEncodedLength()` to calculate the required size for the buffer pointed to by the `dst` parameter. - @see cobsEncodedLength() + @see _cobsEncodedLength() */ /**************************************************************************/ -uint32_t cobsEncode(uint8_t *ptr, uint32_t length, uint8_t eop, uint8_t *dst) +uint32_t _cobsEncode(uint8_t *ptr, uint32_t length, uint8_t eop, uint8_t *dst) { uint8_t ch; uint8_t *start = dst; @@ -100,7 +100,7 @@ uint32_t cobsEncode(uint8_t *ptr, uint32_t length, uint8_t eop, uint8_t *dst) @note The computed length does not include the EOP (end-of-packet) marker */ /**************************************************************************/ -uint32_t cobsEncodedLength(const uint8_t *ptr, uint32_t length) +uint32_t _cobsEncodedLength(const uint8_t *ptr, uint32_t length) { uint8_t ch; uint32_t dst = 1; @@ -135,7 +135,7 @@ uint32_t cobsEncodedLength(const uint8_t *ptr, uint32_t length) @note An additional byte is added for the EOP (end-of-packet) marker. */ /**************************************************************************/ -uint32_t cobsEncodedMaxLength(uint32_t length) +uint32_t _cobsEncodedMaxLength(uint32_t length) { const uint32_t overheadBytes = ((length / 254) + ((length % 254) > 0)); return (length + overheadBytes + COBS_EOP_OVERHEAD); @@ -154,7 +154,7 @@ uint32_t cobsEncodedMaxLength(uint32_t length) @note An additional byte is added for the EOP (end-of-packet) marker. */ /**************************************************************************/ -uint32_t cobsGuaranteedFit(uint32_t bufLen) +uint32_t _cobsGuaranteedFit(uint32_t bufLen) { uint32_t cobsOverhead = 1 + (bufLen / 254) + COBS_EOP_OVERHEAD; return (cobsOverhead > bufLen ? 0 : (bufLen - cobsOverhead)); diff --git a/src/note-c/n_helpers.c b/src/note-c/n_helpers.c index 131989b..ef9504c 100644 --- a/src/note-c/n_helpers.c +++ b/src/note-c/n_helpers.c @@ -19,12 +19,6 @@ #include "n_lib.h" -#ifdef NOTE_C_TEST -#include "test_static.h" -#else -#define NOTE_C_STATIC static -#endif - // When interfacing with the Notecard, it is generally encouraged that the JSON // object manipulation and calls to the note-arduino library are done directly // at point of need. However, there are cases in which it's convenient to have a @@ -77,12 +71,12 @@ static char scService[128] = {0}; #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 const char *daynames[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; +static const char *dayNames[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; // Forwards -NOTE_C_STATIC void setTime(JTIME seconds); -NOTE_C_STATIC bool timerExpiredSecs(uint32_t *timer, uint32_t periodSecs); -NOTE_C_STATIC int yToDays(int year); +NOTE_C_STATIC void _setTime(JTIME seconds); +NOTE_C_STATIC bool _timerExpiredSecs(uint32_t *timer, uint32_t periodSecs); +NOTE_C_STATIC int _yToDays(int year); static const char NOTE_C_BINARY_EOP = '\n'; @@ -114,11 +108,11 @@ uint32_t NoteBinaryCodecDecode(const uint8_t *encData, uint32_t encDataLen, if (encData == NULL || decBuf == NULL) { NOTE_C_LOG_ERROR(ERRSTR("NULL parameter", c_err)); result = 0; - } else if (decBufSize < cobsGuaranteedFit(encDataLen)) { + } else if (decBufSize < _cobsGuaranteedFit(encDataLen)) { NOTE_C_LOG_ERROR(ERRSTR("output buffer too small", c_err)); result = 0; } else { - result = cobsDecode((uint8_t *)encData, encDataLen, NOTE_C_BINARY_EOP, decBuf); + result = _cobsDecode((uint8_t *)encData, encDataLen, NOTE_C_BINARY_EOP, decBuf); } return result; @@ -156,15 +150,15 @@ uint32_t NoteBinaryCodecEncode(const uint8_t *decData, uint32_t decDataLen, if (decData == NULL || encBuf == NULL) { NOTE_C_LOG_ERROR(ERRSTR("NULL parameter", c_err)); result = 0; - } else if ((encBufSize < cobsEncodedMaxLength(decDataLen)) - && (encBufSize < cobsEncodedLength(decData, decDataLen))) { - // NOTE: `cobsEncodedMaxLength()` provides a constant time [O(1)] means + } else if ((encBufSize < _cobsEncodedMaxLength(decDataLen)) + && (encBufSize < _cobsEncodedLength(decData, decDataLen))) { + // NOTE: `_cobsEncodedMaxLength()` provides a constant time [O(1)] means // of checking the buffer size. Only when it fails will the linear - // time [O(n)] check, `cobsEncodedLength()`, be invoked. + // time [O(n)] check, `_cobsEncodedLength()`, be invoked. NOTE_C_LOG_ERROR(ERRSTR("output buffer too small", c_err)); result = 0; } else { - result = cobsEncode((uint8_t *)decData, decDataLen, NOTE_C_BINARY_EOP, encBuf); + result = _cobsEncode((uint8_t *)decData, decDataLen, NOTE_C_BINARY_EOP, encBuf); } return result; @@ -198,7 +192,7 @@ uint32_t NoteBinaryCodecEncode(const uint8_t *decData, uint32_t decDataLen, /**************************************************************************/ uint32_t NoteBinaryCodecMaxDecodedLength(uint32_t bufferSize) { - return cobsGuaranteedFit(bufferSize); + return _cobsGuaranteedFit(bufferSize); } //**************************************************************************/ @@ -213,7 +207,7 @@ uint32_t NoteBinaryCodecMaxDecodedLength(uint32_t bufferSize) /**************************************************************************/ uint32_t NoteBinaryCodecMaxEncodedLength(uint32_t unencodedLength) { - return cobsEncodedMaxLength(unencodedLength); + return _cobsEncodedMaxLength(unencodedLength); } //**************************************************************************/ @@ -346,7 +340,7 @@ const char * NoteBinaryStoreReceive(uint8_t *buffer, uint32_t bufLen, NOTE_C_LOG_ERROR(err); return err; } - if (bufLen < cobsEncodedMaxLength(decodedLen)) { + if (bufLen < _cobsEncodedMaxLength(decodedLen)) { const char *err = ERRSTR("insufficient buffer size", c_bad); NOTE_C_LOG_ERROR(err); return err; @@ -368,9 +362,9 @@ const char * NoteBinaryStoreReceive(uint8_t *buffer, uint32_t bufLen, JAddIntToObject(req, "length", decodedLen); // We already have the Notecard lock, so call - // noteTransactionShouldLock with `lockNotecard` set to false so we + // _noteTransactionShouldLock with `lockNotecard` set to false so we // don't try to lock again. - J *rsp = noteTransactionShouldLock(req, false); + J *rsp = _noteTransactionShouldLock(req, false); JDelete(req); // Ensure the transaction doesn't return an error. if (!rsp || NoteResponseError(rsp)) { @@ -525,11 +519,11 @@ const char * NoteBinaryStoreTransmit(uint8_t *unencodedData, uint32_t unencodedL const char *err = ERRSTR("unencodedData cannot be NULL", c_err); NOTE_C_LOG_ERROR(err); return err; - } else if ((bufLen < cobsEncodedMaxLength(unencodedLen)) - && (bufLen < (cobsEncodedLength(unencodedData, unencodedLen) + 1))) { - // NOTE: `cobsEncodedMaxLength()` provides a constant time [O(1)] means + } else if ((bufLen < _cobsEncodedMaxLength(unencodedLen)) + && (bufLen < (_cobsEncodedLength(unencodedData, unencodedLen) + 1))) { + // NOTE: `_cobsEncodedMaxLength()` provides a constant time [O(1)] means // of checking the buffer size. Only when it fails will the linear - // time [O(n)] check, `cobsEncodedLength()`, be invoked. + // time [O(n)] check, `_cobsEncodedLength()`, be invoked. const char *err = ERRSTR("insufficient buffer size", c_bad); NOTE_C_LOG_ERROR(err); return err; @@ -623,9 +617,9 @@ const char * NoteBinaryStoreTransmit(uint8_t *unencodedData, uint32_t unencodedL JAddStringToObject(req, "status", hashString); // We already have the Notecard lock, so call - // noteTransactionShouldLock with `lockNotecard` set to false so we + // _noteTransactionShouldLock with `lockNotecard` set to false so we // don't try to lock again. - rsp = noteTransactionShouldLock(req, false); + rsp = _noteTransactionShouldLock(req, false); JDelete(req); // Ensure the transaction doesn't return an error. if (!rsp || NoteResponseError(rsp)) { @@ -763,7 +757,7 @@ void NoteTimeRefreshMins(uint32_t mins) @param seconds The UNIX Epoch time. */ /**************************************************************************/ -NOTE_C_STATIC void setTime(JTIME seconds) +NOTE_C_STATIC void _setTime(JTIME seconds) { timeBaseSec = seconds; timeBaseSetAtMs = _GetMs(); @@ -823,8 +817,8 @@ bool NotePrint(const char *text) { bool success = false; - if (noteIsDebugOutputActive()) { - NoteDebug(text); + if (_noteIsDebugOutputActive()) { + _Debug(text); return true; } @@ -857,7 +851,7 @@ JTIME NoteTimeST(void) } // If it's time to refresh the time, do so - if (refreshTimerSecs != 0 && timerExpiredSecs(&timeRefreshTimer, refreshTimerSecs)) { + if (refreshTimerSecs != 0 && _timerExpiredSecs(&timeRefreshTimer, refreshTimerSecs)) { timeTimer = 0; } @@ -865,7 +859,7 @@ JTIME NoteTimeST(void) // 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 (!timeBaseSetManually && (timeTimer == 0 || timeBaseSec == 0 || zoneStillUnavailable || zoneForceRefresh)) { - if (timerExpiredSecs(&timeTimer, suppressionTimerSecs)) { + if (_timerExpiredSecs(&timeTimer, suppressionTimerSecs)) { // Request time and zone info from the card J *rsp = NoteRequestResponse(NoteNewRequest("card.time")); @@ -875,7 +869,7 @@ JTIME NoteTimeST(void) if (seconds != 0) { // Set the time - setTime(seconds); + _setTime(seconds); // Get the zone char *z = JGetString(rsp, "zone"); @@ -1040,9 +1034,9 @@ bool NoteLocalTimeST(uint16_t *retYear, uint8_t *retMonth, uint8_t *retDay, secs = (uint32_t) currentEpochTime + ((70*365L+17)*86400LU); days = secs / 86400; if (retWeekday != NULL) { - *retWeekday = (char *) daynames[(days + 1) % 7]; + *retWeekday = (char *) dayNames[(days + 1) % 7]; } - for (year = days / 365; days < (i = yToDays(year) + 365L * year); ) { + for (year = days / 365; days < (i = _yToDays(year) + 365L * year); ) { --year; } days -= i; @@ -1091,7 +1085,7 @@ bool NoteLocalTimeST(uint16_t *retYear, uint8_t *retMonth, uint8_t *retDay, } // Figure out how many days at start of the year -NOTE_C_STATIC int yToDays(int year) +NOTE_C_STATIC int _yToDays(int year) { int days = 0; if (0 < year) { @@ -1148,7 +1142,7 @@ bool NoteLocationValidST(char *errbuf, uint32_t errbuflen) // 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, suppressionTimerSecs)) { + if (!_timerExpiredSecs(&locationTimer, suppressionTimerSecs)) { return false; } @@ -1320,7 +1314,7 @@ bool NoteIsConnected(void) /**************************************************************************/ bool NoteIsConnectedST(void) { - if (timerExpiredSecs(&connectivityTimer, suppressionTimerSecs)) { + if (_timerExpiredSecs(&connectivityTimer, suppressionTimerSecs)) { J *rsp = NoteRequestResponse(NoteNewRequest("hub.status")); if (rsp != NULL) { if (!NoteResponseError(rsp)) { @@ -1559,7 +1553,7 @@ bool NoteGetServiceConfigST(char *productBuf, int productBufLen, char *serviceBu bool success = false; // Use cache except for a rare refresh - if (scProduct[0] == '\0' || scDevice[0] == '\0' || timerExpiredSecs(&serviceConfigTimer, 4*60*60)) { + if (scProduct[0] == '\0' || scDevice[0] == '\0' || _timerExpiredSecs(&serviceConfigTimer, 4*60*60)) { J *rsp = NoteRequestResponse(NoteNewRequest("hub.get")); if (rsp != NULL) { success = !NoteResponseError(rsp); @@ -1630,7 +1624,7 @@ bool NoteGetStatusST(char *statusBuf, int statusBufLen, JTIME *bootTime, bool *r static bool lastSignals = false; // Refresh if it's time to do so - if (timerExpiredSecs(&statusTimer, suppressionTimerSecs)) { + if (_timerExpiredSecs(&statusTimer, suppressionTimerSecs)) { J *rsp = NoteRequestResponse(NoteNewRequest("card.status")); if (rsp != NULL) { success = !NoteResponseError(rsp); @@ -1828,7 +1822,7 @@ bool NotePayloadRetrieveAfterSleep(NotePayloadDesc *desc) // Note the current time, if the field is present JTIME seconds = JGetInt(rsp, "time"); if (seconds != 0) { - setTime(seconds); + _setTime(seconds); } // If we didn't expect any state to be restored, we're done @@ -2273,7 +2267,7 @@ bool NoteSetContact(char *nameBuf, char *orgBuf, char *roleBuf, char *emailBuf) // 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. -NOTE_C_STATIC bool timerExpiredSecs(uint32_t *timer, uint32_t periodSecs) +NOTE_C_STATIC bool _timerExpiredSecs(uint32_t *timer, uint32_t periodSecs) { bool expired = false; @@ -2320,9 +2314,9 @@ bool NoteDebugSyncStatus(int pollFrequencyMs, int maxLevel) } JAddStringToObject(req, "file", "_synclog.qi"); JAddBoolToObject(req, "delete", true); - NoteSuspendTransactionDebug(); + _noteSuspendTransactionDebug(); J *rsp = NoteRequestResponse(req); - NoteResumeTransactionDebug(); + _noteResumeTransactionDebug(); if (rsp != NULL) { // If an error is returned, this means that no response is pending. Note diff --git a/src/note-c/n_hooks.c b/src/note-c/n_hooks.c index 3e00d0e..a75df4d 100644 --- a/src/note-c/n_hooks.c +++ b/src/note-c/n_hooks.c @@ -17,6 +17,7 @@ * */ +#include #include #include #include @@ -27,10 +28,11 @@ @brief Show malloc operations for debugging in very low mem environments. */ /**************************************************************************/ -#define NOTE_SHOW_MALLOC false -#if NOTE_SHOW_MALLOC +#ifndef NOTE_C_SHOW_MALLOC +#define NOTE_C_SHOW_MALLOC false +#endif +#if NOTE_C_SHOW_MALLOC #include -void *malloc_show(size_t len); #endif // Which I/O port to use @@ -243,7 +245,7 @@ void NoteSetFnDebugOutput(debugOutputFn fn) provided. */ /**************************************************************************/ -bool noteIsDebugOutputActive(void) +bool _noteIsDebugOutputActive(void) { return hookDebugOutput != NULL; } @@ -324,10 +326,10 @@ void NoteSetFnSerial(serialResetFn resetFn, serialTransmitFn transmitFn, hookSerialAvailable = availFn; hookSerialReceive = receiveFn; - notecardReset = serialNoteReset; - notecardTransaction = serialNoteTransaction; - notecardChunkedReceive = serialChunkedReceive; - notecardChunkedTransmit = serialChunkedTransmit; + notecardReset = _serialNoteReset; + notecardTransaction = _serialNoteTransaction; + notecardChunkedReceive = _serialChunkedReceive; + notecardChunkedTransmit = _serialChunkedTransmit; } /*! @@ -357,10 +359,10 @@ void NoteSetFnI2C(uint32_t notecardAddr, uint32_t maxTransmitSize, hookI2CTransmit = transmitFn; hookI2CReceive = receiveFn; - notecardReset = i2cNoteReset; - notecardTransaction = i2cNoteTransaction; - notecardChunkedReceive = i2cChunkedReceive; - notecardChunkedTransmit = i2cChunkedTransmit; + notecardReset = _i2cNoteReset; + notecardTransaction = _i2cNoteTransaction; + notecardChunkedReceive = _i2cChunkedReceive; + notecardChunkedTransmit = _i2cChunkedTransmit; } //**************************************************************************/ @@ -382,6 +384,30 @@ void NoteSetFnDisabled(void) // Runtime hook wrappers +//**************************************************************************/ +/*! + @brief Variable used to determine the runtime logging level +*/ +/**************************************************************************/ +#ifndef NOTE_NODEBUG +int noteLogLevel = NOTE_C_LOG_LEVEL; +#endif + +//**************************************************************************/ +/*! + @brief Set the log level for the _DebugWithLevel function. + @param level The log level to set. +*/ +/**************************************************************************/ +void NoteSetLogLevel(int level) +{ +#ifndef NOTE_NODEBUG + noteLogLevel = level; +#else + (void)level; +#endif +} + //**************************************************************************/ /*! @brief Write a number to the debug stream and output a newline. @@ -421,10 +447,12 @@ void NoteDebugln(const char *line) void NoteDebug(const char *line) { #ifndef NOTE_NODEBUG - if (hookDebugOutput != NULL) { + if (_noteIsDebugOutputActive()) { hookDebugOutput(line); } -#endif +#else + (void)line; +#endif // !NOTE_NODEBUG } //**************************************************************************/ @@ -439,13 +467,14 @@ void NoteDebug(const char *line) void NoteDebugWithLevel(uint8_t level, const char *msg) { #ifndef NOTE_NODEBUG - - if (level > NOTE_C_LOG_LEVEL) { + if (level > noteLogLevel) { return; } _Debug(msg); - +#else + (void)level; + (void)msg; #endif // !NOTE_NODEBUG } @@ -491,18 +520,18 @@ void NoteDelayMs(uint32_t ms) } } -#if NOTE_SHOW_MALLOC || !defined(NOTE_C_LOW_MEM) +#ifndef NOTE_C_LOW_MEM + //**************************************************************************/ /*! @brief Convert number to a hex string @param n the number @param p the buffer to return it into -*/ + */ /**************************************************************************/ -void n_htoa32(uint32_t n, char *p) +void _n_htoa32(uint32_t n, char *p) { - int i; - for (i=0; i<8; i++) { + for (int i=0; i<8; i++) { uint32_t nibble = (n >> 28) & 0xff; n = n << 4; if (nibble >= 10) { @@ -513,31 +542,17 @@ void n_htoa32(uint32_t n, char *p) } *p = '\0'; } -#endif -#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. -*/ -/**************************************************************************/ -void *malloc_show(size_t len) +#if NOTE_C_SHOW_MALLOC +static_assert(sizeof(void *) == sizeof(uint32_t), "Pointer size mismatch"); + +NOTE_C_STATIC void _n_ptoa32(void *ptr, char *str) { - char str[16]; - JItoA(len, str); - hookDebugOutput("malloc "); - hookDebugOutput(str); - void *p = hookMalloc(len); - if (p == NULL) { - hookDebugOutput("FAIL"); - } else { - n_htoa32((uint32_t)p, str); - hookDebugOutput(str); - } - return p; + _n_htoa32((uint32_t)ptr, str); } -#endif + +#endif // NOTE_C_SHOW_MALLOC +#endif // !NOTE_C_LOW_MEM //**************************************************************************/ /*! @@ -550,11 +565,25 @@ void *NoteMalloc(size_t size) if (hookMalloc == NULL) { return NULL; } -#if NOTE_SHOW_MALLOC - return malloc_show(size); -#else - return hookMalloc(size); -#endif + void *p = hookMalloc(size); +#if NOTE_C_SHOW_MALLOC && !defined(NOTE_C_LOW_MEM) + if (_noteIsDebugOutputActive()) { + hookDebugOutput("malloc "); + // Convert the size to a string and print + char str[16]; + JItoA(size, str); + hookDebugOutput(str); + if (p == NULL) { + hookDebugOutput(" FAIL"); + } else { + hookDebugOutput(" "); + // Convert the pointer to a string and print + _n_ptoa32(p, str); + hookDebugOutput(str); + } + } +#endif // NOTE_C_SHOW_MALLOC && !defined(NOTE_C_LOW_MEM) + return p; } //**************************************************************************/ @@ -566,12 +595,15 @@ void *NoteMalloc(size_t size) void NoteFree(void *p) { if (hookFree != NULL) { -#if NOTE_SHOW_MALLOC - char str[16]; - n_htoa32((uint32_t)p, str); - hookDebugOutput("free"); - hookDebugOutput(str); -#endif +#if NOTE_C_SHOW_MALLOC && !defined(NOTE_C_LOW_MEM) + if (_noteIsDebugOutputActive()) { + hookDebugOutput("free "); + // Convert the pointer to a string and print + char str[16]; + _n_ptoa32(p, str); + hookDebugOutput(str); + } +#endif // NOTE_C_SHOW_MALLOC && !defined(NOTE_C_LOW_MEM) hookFree(p); } } @@ -605,7 +637,7 @@ void NoteUnlockI2C(void) @brief Lock the Notecard using the platform-specific hook. */ /**************************************************************************/ -void noteLockNote(void) +void _noteLockNote(void) { if (hookLockNote != NULL) { hookLockNote(); @@ -617,7 +649,7 @@ void noteLockNote(void) @brief Unlock the Notecard using the platform-specific hook. */ /**************************************************************************/ -void noteUnlockNote(void) +void _noteUnlockNote(void) { if (hookUnlockNote != NULL) { hookUnlockNote(); @@ -629,7 +661,7 @@ void noteUnlockNote(void) @brief Indicate that we're initiating a transaction using the platform-specific hook. */ /**************************************************************************/ -bool noteTransactionStart(uint32_t timeoutMs) +bool _noteTransactionStart(uint32_t timeoutMs) { if (hookTransactionStart != NULL) { return hookTransactionStart(timeoutMs); @@ -642,20 +674,188 @@ bool noteTransactionStart(uint32_t timeoutMs) @brief Indicate that we've completed a transaction using the platform-specific hook. */ /**************************************************************************/ -void noteTransactionStop(void) +void _noteTransactionStop(void) { if (hookTransactionStop != NULL) { hookTransactionStop(); } } +/*! + @brief Get the platform-specific debug output function. + @param fn Pointer to store the debug output function pointer. +*/ +void NoteGetFnDebugOutput(debugOutputFn *fn) +{ + if (fn != NULL) { + *fn = hookDebugOutput; + } +} + +/*! + @brief Get the platform-specific transaction functions. + @param startFn Pointer to store the transaction start function pointer. + @param stopFn Pointer to store the transaction stop function pointer. +*/ +void NoteGetFnTransaction(txnStartFn *startFn, txnStopFn *stopFn) +{ + if (startFn != NULL) { + *startFn = hookTransactionStart; + } + if (stopFn != NULL) { + *stopFn = hookTransactionStop; + } +} + +/*! + @brief Get the platform-specific mutex functions for I2C and Notecard. + @param lockI2Cfn Pointer to store the I2C lock function pointer. + @param unlockI2Cfn Pointer to store the I2C unlock function pointer. + @param lockNotefn Pointer to store the Notecard lock function pointer. + @param unlockNotefn Pointer to store the Notecard unlock function pointer. +*/ +void NoteGetFnMutex(mutexFn *lockI2Cfn, mutexFn *unlockI2Cfn, mutexFn *lockNotefn, + mutexFn *unlockNotefn) +{ + if (lockI2Cfn != NULL) { + *lockI2Cfn = hookLockI2C; + } + if (unlockI2Cfn != NULL) { + *unlockI2Cfn = hookUnlockI2C; + } + if (lockNotefn != NULL) { + *lockNotefn = hookLockNote; + } + if (unlockNotefn != NULL) { + *unlockNotefn = hookUnlockNote; + } +} + +/*! + @brief Get the platform-specific mutex functions for I2C. + @param lockI2Cfn Pointer to store the I2C lock function pointer. + @param unlockI2Cfn Pointer to store the I2C unlock function pointer. +*/ +void NoteGetFnI2CMutex(mutexFn *lockI2Cfn, mutexFn *unlockI2Cfn) +{ + if (lockI2Cfn != NULL) { + *lockI2Cfn = hookLockI2C; + } + if (unlockI2Cfn != NULL) { + *unlockI2Cfn = hookUnlockI2C; + } +} + +/*! + @brief Get the platform-specific mutex functions for the Notecard. + @param lockFn Pointer to store the Notecard lock function pointer. + @param unlockFn Pointer to store the Notecard unlock function pointer. +*/ +void NoteGetFnNoteMutex(mutexFn *lockFn, mutexFn *unlockFn) +{ + if (lockFn != NULL) { + *lockFn = hookLockNote; + } + if (unlockFn != NULL) { + *unlockFn = hookUnlockNote; + } +} + +/*! + @brief Get the platform-specific memory and timing hooks. + @param mallocHook Pointer to store the memory allocation function pointer. + @param freeHook Pointer to store the memory free function pointer. + @param delayMsHook Pointer to store the delay function pointer. + @param getMsHook Pointer to store the millis function pointer. +*/ +void NoteGetFn(mallocFn *mallocHook, freeFn *freeHook, delayMsFn *delayMsHook, + getMsFn *getMsHook) +{ + if (mallocHook != NULL) { + *mallocHook = hookMalloc; + } + if (freeHook != NULL) { + *freeHook = hookFree; + } + if (delayMsHook != NULL) { + *delayMsHook = hookDelayMs; + } + if (getMsHook != NULL) { + *getMsHook = hookGetMs; + } +} + +/*! + @brief Get the platform-specific hooks for serial communication. + @param resetFn Pointer to store the serial reset function pointer. + @param transmitFn Pointer to store the serial transmit function pointer. + @param availFn Pointer to store the serial available function pointer. + @param receiveFn Pointer to store the serial receive function pointer. +*/ +void NoteGetFnSerial(serialResetFn *resetFn, serialTransmitFn *transmitFn, + serialAvailableFn *availFn, serialReceiveFn *receiveFn) +{ + if (resetFn != NULL) { + *resetFn = hookSerialReset; + } + if (transmitFn != NULL) { + *transmitFn = hookSerialTransmit; + } + if (availFn != NULL) { + *availFn = hookSerialAvailable; + } + if (receiveFn != NULL) { + *receiveFn = hookSerialReceive; + } +} + +/*! + @brief Get the platform-specific hooks for I2C communication. + @param notecardAddr Pointer to store the I2C address. + @param maxTransmitSize Pointer to store the I2C maximum segment size. + @param resetFn Pointer to store the I2C reset function pointer. + @param transmitFn Pointer to store the I2C transmit function pointer. + @param receiveFn Pointer to store the I2C receive function pointer. +*/ +void NoteGetFnI2C(uint32_t *notecardAddr, uint32_t *maxTransmitSize, + i2cResetFn *resetFn, i2cTransmitFn *transmitFn, + i2cReceiveFn *receiveFn) +{ + if (notecardAddr != NULL) { + *notecardAddr = i2cAddress; + } + if (maxTransmitSize != NULL) { + *maxTransmitSize = i2cMax; + } + if (resetFn != NULL) { + *resetFn = hookI2CReset; + } + if (transmitFn != NULL) { + *transmitFn = hookI2CTransmit; + } + if (receiveFn != NULL) { + *receiveFn = hookI2CReceive; + } +} + +/*! + @brief Get the I2C address of the Notecard. + @param i2caddress Pointer to store the I2C address. +*/ +void NoteGetI2CAddress(uint32_t *i2caddress) +{ + if (i2caddress != NULL) { + *i2caddress = i2cAddress; + } +} + //**************************************************************************/ /*! @brief Get the active interface's name @returns A string */ /**************************************************************************/ -const char *noteActiveInterface(void) +const char *_noteActiveInterface(void) { switch (hookActiveInterface) { case interfaceSerial: @@ -672,7 +872,7 @@ const char *noteActiveInterface(void) @returns A boolean indicating whether the Serial bus was reset successfully. */ /**************************************************************************/ -bool noteSerialReset(void) +bool _noteSerialReset(void) { if (hookActiveInterface == interfaceSerial && hookSerialReset != NULL) { return hookSerialReset(); @@ -688,7 +888,7 @@ bool noteSerialReset(void) @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); @@ -702,7 +902,7 @@ void noteSerialTransmit(uint8_t *text, size_t len, bool flush) @returns A boolean indicating whether the Serial bus is available to read. */ /**************************************************************************/ -bool noteSerialAvailable(void) +bool _noteSerialAvailable(void) { if (hookActiveInterface == interfaceSerial && hookSerialAvailable != NULL) { return hookSerialAvailable(); @@ -717,7 +917,7 @@ bool noteSerialAvailable(void) @returns A character from the Serial bus. */ /**************************************************************************/ -char noteSerialReceive(void) +char _noteSerialReceive(void) { if (hookActiveInterface == interfaceSerial && hookSerialReceive != NULL) { return hookSerialReceive(); @@ -731,7 +931,7 @@ char noteSerialReceive(void) @returns A boolean indicating whether the I2C bus was reset successfully. */ /**************************************************************************/ -bool noteI2CReset(uint16_t DevAddress) +bool _noteI2CReset(uint16_t DevAddress) { if (hookActiveInterface == interfaceI2C && hookI2CReset != NULL) { return hookI2CReset(DevAddress); @@ -749,7 +949,7 @@ bool noteI2CReset(uint16_t DevAddress) 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); @@ -768,7 +968,7 @@ const char *noteI2CTransmit(uint16_t DevAddress, uint8_t* pBuffer, uint16_t Size 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); @@ -830,7 +1030,7 @@ uint32_t NoteI2CMax(void) @returns A boolean indicating whether the Notecard has been reset successfully. */ /**************************************************************************/ -bool noteHardReset(void) +bool _noteHardReset(void) { if (notecardReset == NULL) { return true; @@ -857,7 +1057,7 @@ bool noteHardReset(void) or the hook has not been set. */ /**************************************************************************/ -const char *noteJSONTransaction(const char *request, size_t reqLen, char **response, uint32_t timeoutMs) +const char *_noteJSONTransaction(const char *request, size_t reqLen, char **response, uint32_t timeoutMs) { if (notecardTransaction == NULL || hookActiveInterface == interfaceNone) { return "i2c or serial interface must be selected"; @@ -883,8 +1083,8 @@ const char *noteJSONTransaction(const char *request, size_t reqLen, char **respo @returns A c-string with an error, or `NULL` if no error ocurred. */ /**************************************************************************/ -const char *noteChunkedReceive(uint8_t *buffer, uint32_t *size, bool delay, - uint32_t timeoutMs, uint32_t *available) +const char *_noteChunkedReceive(uint8_t *buffer, uint32_t *size, bool delay, + uint32_t timeoutMs, uint32_t *available) { if (notecardChunkedReceive == NULL || hookActiveInterface == interfaceNone) { return "i2c or serial interface must be selected"; @@ -902,7 +1102,7 @@ const char *noteChunkedReceive(uint8_t *buffer, uint32_t *size, bool delay, @returns A c-string with an error, or `NULL` if no error ocurred. */ /**************************************************************************/ -const char *noteChunkedTransmit(uint8_t *buffer, uint32_t size, bool delay) +const char *_noteChunkedTransmit(uint8_t *buffer, uint32_t size, bool delay) { if (notecardChunkedTransmit == NULL || hookActiveInterface == interfaceNone) { return "i2c or serial interface must be selected"; diff --git a/src/note-c/n_i2c.c b/src/note-c/n_i2c.c index deb2269..28d5733 100644 --- a/src/note-c/n_i2c.c +++ b/src/note-c/n_i2c.c @@ -15,15 +15,9 @@ #include "n_lib.h" -#ifdef NOTE_C_TEST -#include "test_static.h" -#else -#define NOTE_C_STATIC static -#endif - // Forwards -NOTE_C_STATIC void delayIO(void); -NOTE_C_STATIC const char * i2cNoteQueryLength(uint32_t * available, uint32_t timeoutMs); +NOTE_C_STATIC void _delayIO(void); +NOTE_C_STATIC const char * _i2cNoteQueryLength(uint32_t * available, uint32_t timeoutMs); /**************************************************************************/ /*! @@ -33,7 +27,7 @@ NOTE_C_STATIC const char * i2cNoteQueryLength(uint32_t * available, uint32_t tim empirically based on a number of commercial devices. */ /**************************************************************************/ -NOTE_C_STATIC void delayIO(void) +NOTE_C_STATIC void _delayIO(void) { if (!cardTurboIO) { _DelayMs(6); @@ -49,7 +43,7 @@ NOTE_C_STATIC void delayIO(void) I2C read request can be issued. */ /**************************************************************************/ -NOTE_C_STATIC const char * i2cNoteQueryLength(uint32_t * available, +NOTE_C_STATIC const char * _i2cNoteQueryLength(uint32_t * available, uint32_t timeoutMs) { uint8_t dummy_buffer = 0; @@ -88,14 +82,14 @@ NOTE_C_STATIC const char * i2cNoteQueryLength(uint32_t * available, @returns a c-string with an error, or `NULL` if no error occurred. */ /**************************************************************************/ -const char *i2cNoteTransaction(const char *request, size_t reqLen, char **response, uint32_t timeoutMs) +const char *_i2cNoteTransaction(const char *request, size_t reqLen, char **response, uint32_t timeoutMs) { const char *err = NULL; // Lock over the entire transaction _LockI2C(); - err = i2cChunkedTransmit((uint8_t *)request, reqLen, true); + err = _i2cChunkedTransmit((uint8_t *)request, reqLen, true); if (err) { _UnlockI2C(); return err; @@ -107,13 +101,13 @@ const char *i2cNoteTransaction(const char *request, size_t reqLen, char **respon return NULL; } - delayIO(); + _delayIO(); // 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. uint32_t available = 0; - err = i2cNoteQueryLength(&available, timeoutMs); + err = _i2cNoteQueryLength(&available, timeoutMs); if (err) { NOTE_C_LOG_ERROR(ERRSTR("failed to query Notecard", c_err)); _UnlockI2C(); @@ -137,7 +131,7 @@ const char *i2cNoteTransaction(const char *request, size_t reqLen, char **respon uint32_t jsonbufAvailLen = (jsonbufAllocLen - jsonbufLen); // Append into the json buffer - const char *err = i2cChunkedReceive((uint8_t *)(jsonbuf + jsonbufLen), &jsonbufAvailLen, true, (CARD_INTRA_TRANSACTION_TIMEOUT_SEC * 1000), &available); + const char *err = _i2cChunkedReceive((uint8_t *)(jsonbuf + jsonbufLen), &jsonbufAvailLen, true, (CARD_INTRA_TRANSACTION_TIMEOUT_SEC * 1000), &available); if (err) { if (jsonbuf) { _Free(jsonbuf); @@ -196,7 +190,7 @@ const char *i2cNoteTransaction(const char *request, size_t reqLen, char **respon @returns a boolean. `true` if the reset was successful, `false`, if not. */ /**************************************************************************/ -bool i2cNoteReset(void) +bool _i2cNoteReset(void) { bool notecardReady = false; @@ -212,7 +206,7 @@ bool i2cNoteReset(void) _UnlockI2C(); return false; } - delayIO(); + _delayIO(); // The guaranteed behavior for robust resyncing is to send two newlines // and wait for two echoed blank lines in return. @@ -300,7 +294,7 @@ bool i2cNoteReset(void) NOTE_C_LOG_ERROR(ERRSTR("error encountered during I2C reset hook execution", c_err)); break; } - delayIO(); + _delayIO(); } } else { notecardReady = true; @@ -336,7 +330,7 @@ bool i2cNoteReset(void) @returns A c-string with an error, or `NULL` if no error ocurred. */ /**************************************************************************/ -const char *i2cChunkedReceive(uint8_t *buffer, uint32_t *size, bool delay, uint32_t timeoutMs, uint32_t *available) +const char *_i2cChunkedReceive(uint8_t *buffer, uint32_t *size, bool delay, uint32_t timeoutMs, uint32_t *available) { // Load buffer with chunked I2C values size_t received = 0; @@ -427,7 +421,7 @@ const char *i2cChunkedReceive(uint8_t *buffer, uint32_t *size, bool delay, uint3 @returns A c-string with an error, or `NULL` if no error ocurred. */ /**************************************************************************/ -const char *i2cChunkedTransmit(uint8_t *buffer, uint32_t size, bool delay) +const char *_i2cChunkedTransmit(uint8_t *buffer, uint32_t size, bool delay) { // Transmit the request in chunks, but also in segments so as not to // overwhelm the notecard's interrupt buffers @@ -441,7 +435,7 @@ const char *i2cChunkedTransmit(uint8_t *buffer, uint32_t size, bool delay) // Constrain chunkLen to be <= _I2CMax(). chunkLen = (chunkLen > _I2CMax()) ? _I2CMax() : chunkLen; - delayIO(); + _delayIO(); estr = _I2CTransmit(_I2CAddress(), chunk, chunkLen); if (estr != NULL) { _I2CReset(_I2CAddress()); diff --git a/src/note-c/n_lib.h b/src/note-c/n_lib.h index 60d59b7..d528309 100644 --- a/src/note-c/n_lib.h +++ b/src/note-c/n_lib.h @@ -23,6 +23,17 @@ extern "C" { #endif +//**************************************************************************/ +/*! + @brief `NOTE_C_TEST` enables testing of static functions. +*/ +/**************************************************************************/ +#ifdef NOTE_C_TEST +#define NOTE_C_STATIC +#else +#define NOTE_C_STATIC static +#endif + /**************************************************************************/ /*! @brief How long to wait for the card for any given transaction. @@ -98,53 +109,55 @@ extern "C" { #define ALLOC_CHUNK 64 #else #define ALLOC_CHUNK 128 -#endif +#endif // NOTE_C_LOW_MEM #ifdef NOTE_C_LOW_MEM #define NOTE_DISABLE_USER_AGENT -#endif +#endif // NOTE_C_LOW_MEM // Transactions -J *noteTransactionShouldLock(J *req, bool lockNotecard); -const char *i2cNoteTransaction(const char *request, size_t reqLen, char **response, uint32_t timeoutMs); -bool i2cNoteReset(void); -const char *serialNoteTransaction(const char *request, size_t reqLen, char **response, uint32_t timeoutMs); -bool serialNoteReset(void); -const char *i2cChunkedReceive(uint8_t *buffer, uint32_t *size, bool delay, uint32_t timeoutMs, uint32_t *available); -const char *i2cChunkedTransmit(uint8_t *buffer, uint32_t size, bool delay); -const char *serialChunkedReceive(uint8_t *buffer, uint32_t *size, bool delay, uint32_t timeoutMs, uint32_t *available); -const char *serialChunkedTransmit(uint8_t *buffer, uint32_t size, bool delay); +void _noteResumeTransactionDebug(void); +void _noteSuspendTransactionDebug(void); +J *_noteTransactionShouldLock(J *req, bool lockNotecard); +const char *_i2cNoteTransaction(const char *request, size_t reqLen, char **response, uint32_t timeoutMs); +bool _i2cNoteReset(void); +const char *_serialNoteTransaction(const char *request, size_t reqLen, char **response, uint32_t timeoutMs); +bool _serialNoteReset(void); +const char *_i2cChunkedReceive(uint8_t *buffer, uint32_t *size, bool delay, uint32_t timeoutMs, uint32_t *available); +const char *_i2cChunkedTransmit(uint8_t *buffer, uint32_t size, bool delay); +const char *_serialChunkedReceive(uint8_t *buffer, uint32_t *size, bool delay, uint32_t timeoutMs, uint32_t *available); +const char *_serialChunkedTransmit(uint8_t *buffer, uint32_t size, bool delay); // Hooks -void noteLockNote(void); -void noteUnlockNote(void); -bool noteTransactionStart(uint32_t timeoutMs); -void noteTransactionStop(void); -const char *noteActiveInterface(void); -bool noteSerialReset(void); -void noteSerialTransmit(uint8_t *, size_t, bool); -bool noteSerialAvailable(void); -char noteSerialReceive(void); -bool noteI2CReset(uint16_t DevAddress); -const char *noteI2CTransmit(uint16_t DevAddress, uint8_t* pBuffer, uint16_t Size); -const char *noteI2CReceive(uint16_t DevAddress, uint8_t* pBuffer, uint16_t Size, uint32_t *avail); -bool noteHardReset(void); -const char *noteJSONTransaction(const char *request, size_t reqLen, char **response, uint32_t timeoutMs); -const char *noteChunkedReceive(uint8_t *buffer, uint32_t *size, bool delay, uint32_t timeoutMs, uint32_t *available); -const char *noteChunkedTransmit(uint8_t *buffer, uint32_t size, bool delay); -bool noteIsDebugOutputActive(void); +void _noteLockNote(void); +void _noteUnlockNote(void); +bool _noteTransactionStart(uint32_t timeoutMs); +void _noteTransactionStop(void); +const char *_noteActiveInterface(void); +bool _noteSerialReset(void); +void _noteSerialTransmit(uint8_t *, size_t, bool); +bool _noteSerialAvailable(void); +char _noteSerialReceive(void); +bool _noteI2CReset(uint16_t DevAddress); +const char *_noteI2CTransmit(uint16_t DevAddress, uint8_t* pBuffer, uint16_t Size); +const char *_noteI2CReceive(uint16_t DevAddress, uint8_t* pBuffer, uint16_t Size, uint32_t *avail); +bool _noteHardReset(void); +const char *_noteJSONTransaction(const char *request, size_t reqLen, char **response, uint32_t timeoutMs); +const char *_noteChunkedReceive(uint8_t *buffer, uint32_t *size, bool delay, uint32_t timeoutMs, uint32_t *available); +const char *_noteChunkedTransmit(uint8_t *buffer, uint32_t size, bool delay); +bool _noteIsDebugOutputActive(void); // Utilities -void n_htoa32(uint32_t n, char *p); -void n_htoa16(uint16_t n, unsigned char *p); -uint64_t n_atoh(char *p, int maxLen); +void _n_htoa32(uint32_t n, char *p); +void _n_htoa16(uint16_t n, unsigned char *p); +uint64_t _n_atoh(char *p, int maxLen); // COBS Helpers -uint32_t cobsDecode(uint8_t *ptr, uint32_t length, uint8_t eop, uint8_t *dst); -uint32_t cobsEncode(uint8_t *ptr, uint32_t length, uint8_t eop, uint8_t *dst); -uint32_t cobsEncodedLength(const uint8_t *ptr, uint32_t length); -uint32_t cobsEncodedMaxLength(uint32_t length); -uint32_t cobsGuaranteedFit(uint32_t bufLen); +uint32_t _cobsDecode(uint8_t *ptr, uint32_t length, uint8_t eop, uint8_t *dst); +uint32_t _cobsEncode(uint8_t *ptr, uint32_t length, uint8_t eop, uint8_t *dst); +uint32_t _cobsEncodedLength(const uint8_t *ptr, uint32_t length); +uint32_t _cobsEncodedMaxLength(uint32_t length); +uint32_t _cobsGuaranteedFit(uint32_t bufLen); // Turbo I/O mode extern bool cardTurboIO; @@ -197,21 +210,21 @@ extern const char *c_badbinerr; // Readability wrappers. Anything starting with _ is simply calling the wrapper // function. -#define _LockNote noteLockNote -#define _UnlockNote noteUnlockNote -#define _TransactionStart noteTransactionStart -#define _TransactionStop noteTransactionStop -#define _SerialReset noteSerialReset -#define _SerialTransmit noteSerialTransmit -#define _SerialAvailable noteSerialAvailable -#define _SerialReceive noteSerialReceive -#define _I2CReset noteI2CReset -#define _I2CTransmit noteI2CTransmit -#define _I2CReceive noteI2CReceive -#define _Reset noteHardReset -#define _Transaction noteJSONTransaction -#define _ChunkedReceive noteChunkedReceive -#define _ChunkedTransmit noteChunkedTransmit +#define _LockNote _noteLockNote +#define _UnlockNote _noteUnlockNote +#define _TransactionStart _noteTransactionStart +#define _TransactionStop _noteTransactionStop +#define _SerialReset _noteSerialReset +#define _SerialTransmit _noteSerialTransmit +#define _SerialAvailable _noteSerialAvailable +#define _SerialReceive _noteSerialReceive +#define _I2CReset _noteI2CReset +#define _I2CTransmit _noteI2CTransmit +#define _I2CReceive _noteI2CReceive +#define _Reset _noteHardReset +#define _Transaction _noteJSONTransaction +#define _ChunkedReceive _noteChunkedReceive +#define _ChunkedTransmit _noteChunkedTransmit #define _Malloc NoteMalloc #define _Free NoteFree #define _GetMs NoteGetMs diff --git a/src/note-c/n_printf.c b/src/note-c/n_printf.c index 6c95df4..2cbdc69 100644 --- a/src/note-c/n_printf.c +++ b/src/note-c/n_printf.c @@ -34,7 +34,7 @@ extern debugOutputFn hookDebugOutput; void NoteDebugf(const char *format, ...) { #ifndef NOTE_NODEBUG - if (hookDebugOutput != NULL) { + if (_noteIsDebugOutputActive()) { char line[256]; va_list args; va_start(args, format); diff --git a/src/note-c/n_request.c b/src/note-c/n_request.c index 9226d17..16b1531 100644 --- a/src/note-c/n_request.c +++ b/src/note-c/n_request.c @@ -12,12 +12,6 @@ #include "n_lib.h" -#ifdef NOTE_C_TEST -#include "test_static.h" -#else -#define NOTE_C_STATIC static -#endif - // For flow tracing static int suppressShowTransactions = 0; @@ -30,12 +24,13 @@ static uint16_t lastRequestSeqno = 0; #define CRC_FIELD_LENGTH 22 // ,"crc":"SSSS:CCCCCCCC" #define CRC_FIELD_NAME_OFFSET 1 #define CRC_FIELD_NAME_TEST "\"crc\":\"" -NOTE_C_STATIC int32_t crc32(const void* data, size_t length); -NOTE_C_STATIC char * crcAdd(char *json, uint16_t seqno); -NOTE_C_STATIC bool crcError(char *json, uint16_t shouldBeSeqno); +#define ERR_FIELD_NAME_TEST "\"err\":\"" +NOTE_C_STATIC int32_t _crc32(const void* data, size_t length); +NOTE_C_STATIC char * _crcAdd(char *json, uint16_t seqno); +NOTE_C_STATIC bool _crcError(char *json, uint16_t shouldBeSeqno); -static bool notecardSupportsCrc = false; -#endif +NOTE_C_STATIC bool notecardFirmwareSupportsCrc = false; +#endif // !NOTE_C_LOW_MEM /*! @internal @@ -73,7 +68,7 @@ NOTE_C_STATIC J * errDoc(uint32_t id, const char *errmsg) /*! @brief Suppress showing transaction details. */ -void NoteSuspendTransactionDebug(void) +void _noteSuspendTransactionDebug(void) { suppressShowTransactions++; } @@ -81,11 +76,27 @@ void NoteSuspendTransactionDebug(void) /*! @brief Resume showing transaction details. */ -void NoteResumeTransactionDebug(void) +void _noteResumeTransactionDebug(void) { suppressShowTransactions--; } +/*! + @brief Suppress showing transaction details. + */ +void NoteSuspendTransactionDebug(void) +{ + _noteSuspendTransactionDebug(); +} + +/*! + @brief Resume showing transaction details. + */ +void NoteResumeTransactionDebug(void) +{ + _noteResumeTransactionDebug(); +} + /*! @brief Create a new JSON request. @@ -212,10 +223,6 @@ J *NoteRequestResponse(J *req) } // Execute the transaction J *rsp = NoteTransaction(req); - if (rsp == NULL) { - JDelete(req); - return NULL; - } // Free the request and exit JDelete(req); return rsp; @@ -434,7 +441,7 @@ char * NoteRequestResponseJSON(const char *reqJSON) */ J *NoteTransaction(J *req) { - return noteTransactionShouldLock(req, true); + return _noteTransactionShouldLock(req, true); } /**************************************************************************/ @@ -449,7 +456,7 @@ J *NoteTransaction(J *req) insufficient memory. */ /**************************************************************************/ -J *noteTransactionShouldLock(J *req, bool lockNotecard) +J *_noteTransactionShouldLock(J *req, bool lockNotecard) { // Validate in case of memory failure of the requestor if (req == NULL) { @@ -479,7 +486,9 @@ J *noteTransactionShouldLock(J *req, bool lockNotecard) #endif // Determine whether or not a response will be expected, by virtue of "cmd" being present - bool noResponseExpected = (reqType[0] == '\0' && cmdType[0] != '\0'); + // Both `reqType` and `cmdType` are guaranteed to be NULL-terminated strings, but cppcheck + // doesn't know that (so we redundantly check for not NULL). + bool noResponseExpected = ((reqType && (reqType[0] == '\0')) && (cmdType && (cmdType[0] != '\0'))); // If a reset of the module is required for any reason, do it now. // We must do this before acquiring lock. @@ -516,13 +525,13 @@ J *noteTransactionShouldLock(J *req, bool lockNotecard) // modulus of seqno never are mistaken as being the same request being retried. uint8_t lastRequestRetries = 0; #ifndef NOTE_C_LOW_MEM - bool lastRequestCrcAdded = false; + bool lastRequest_crcAdded = false; if (!noResponseExpected) { - char *newJson = crcAdd(json, lastRequestSeqno); + char *newJson = _crcAdd(json, lastRequestSeqno); if (newJson != NULL) { JFree(json); json = newJson; - lastRequestCrcAdded = true; + lastRequest_crcAdded = true; } } #endif // !NOTE_C_LOW_MEM @@ -576,7 +585,7 @@ J *noteTransactionShouldLock(J *req, bool lockNotecard) // If no retry possibility, break out if (lastRequestRetries > CARD_REQUEST_RETRIES_ALLOWED) { break; - } else { + } else if (rsp != NULL) { // free on retry JDelete(rsp); } @@ -618,7 +627,7 @@ J *noteTransactionShouldLock(J *req, bool lockNotecard) // If we sent a CRC in the request, examine the response JSON to see if // it has a CRC error. Note that the CRC is stripped from the // responseJSON as a side-effect of this method. - if (lastRequestCrcAdded && crcError(responseJSON, lastRequestSeqno)) { + if (lastRequest_crcAdded && _crcError(responseJSON, lastRequestSeqno)) { JFree(responseJSON); errStr = "crc error {io}"; lastRequestRetries++; @@ -646,13 +655,18 @@ J *noteTransactionShouldLock(J *req, bool lockNotecard) _DebugWithLevel(NOTE_C_LOG_LEVEL_ERROR, responseJSON); #else NOTE_C_LOG_ERROR(c_ioerr); -#endif +#endif // !NOTE_C_LOW_MEM } isIoError = true; } if (isIoError || isBadBin) { - NOTE_C_LOG_ERROR(JGetString(rsp, c_err)); - JFree(responseJSON); + if (rsp != NULL) { + NOTE_C_LOG_ERROR(JGetString(rsp, c_err)); + } + if (responseJSON != NULL) { + JFree(responseJSON); + responseJSON = NULL; + } if (isBadBin) { errStr = ERRSTR("notecard binary i/o error {bad-bin}{io}", c_badbinerr); @@ -674,14 +688,17 @@ J *noteTransactionShouldLock(J *req, bool lockNotecard) // Bump the request sequence number now that we've processed this request, success or error #ifndef NOTE_C_LOW_MEM lastRequestSeqno++; -#endif +#endif // !NOTE_C_LOW_MEM // Free the original serialized JSON request JFree(json); // If error, queue up a reset if (errStr != NULL) { - JDelete(rsp); + if (rsp != NULL) { + JDelete(rsp); + rsp = NULL; + } NoteResetRequired(); J *errRsp = errDoc(id, errStr); if (lockNotecard) { @@ -797,10 +814,11 @@ void NoteErrorClean(char *begin) @returns The converted number. */ -uint64_t n_atoh(char *p, int maxLen) +uint64_t _n_atoh(char *p, int maxLen) { uint64_t n = 0; char *ep = p+maxLen; + while (p < ep) { char ch = *p++; bool digit = (ch >= '0' && ch <= '9'); @@ -819,6 +837,7 @@ uint64_t n_atoh(char *p, int maxLen) n += 10 + (ch - 'A'); } } + return (n); } @@ -839,16 +858,18 @@ static uint32_t lut[16] = { @returns The CRC32 of the buffer. */ -NOTE_C_STATIC int32_t crc32(const void* data, size_t length) +NOTE_C_STATIC int32_t _crc32(const void* data, size_t length) { uint32_t previousCrc32 = 0; uint32_t crc = ~previousCrc32; unsigned char* current = (unsigned char*) data; + while (length--) { crc = lut[(crc ^ *current ) & 0x0F] ^ (crc >> 4); crc = lut[(crc ^ (*current >> 4)) & 0x0F] ^ (crc >> 4); current++; } + return ~crc; } @@ -865,7 +886,7 @@ NOTE_C_STATIC int32_t crc32(const void* data, size_t length) @returns A dynamically-allocated version of the passed in buffer with the CRC field added or NULL on error. */ -NOTE_C_STATIC char *crcAdd(char *json, uint16_t seqno) +NOTE_C_STATIC char *_crcAdd(char *json, uint16_t seqno) { // Allocate a block the size of the input json plus the size of @@ -873,10 +894,12 @@ NOTE_C_STATIC char *crcAdd(char *json, uint16_t seqno) // this will be replaced with a combination of 4 hex digits of the // seqno plus 8 hex digits of the CRC32, and the '}' will be // transformed into ',"crc":"SSSS:CCCCCCCC"}' where SSSS is the - // seqno and CCCCCCCC is the crc32. Note that the comma is + // seqno and CCCCCCCC is the CRC32. Note that the comma is // replaced with a space if the input json doesn't contain // any fields, so that we always return compliant JSON. + size_t jsonLen = strlen(json); + // Minimum JSON is "{}" and must end with a closing "}". if (jsonLen < 2 || json[jsonLen-1] != '}') { return NULL; @@ -885,8 +908,10 @@ NOTE_C_STATIC char *crcAdd(char *json, uint16_t seqno) if (newJson == NULL) { return NULL; } + bool isEmptyObject = (memchr(json, ':', jsonLen) == NULL); size_t newJsonLen = jsonLen-1; + memcpy(newJson, json, newJsonLen); newJson[newJsonLen++] = (isEmptyObject ? ' ' : ','); // Replace } newJson[newJsonLen++] = '"'; // +1 @@ -896,14 +921,15 @@ NOTE_C_STATIC char *crcAdd(char *json, uint16_t seqno) newJson[newJsonLen++] = '"'; // +5 newJson[newJsonLen++] = ':'; // +6 newJson[newJsonLen++] = '"'; // +7 - n_htoa16(seqno, (uint8_t *) &newJson[newJsonLen]); + _n_htoa16(seqno, (uint8_t *) &newJson[newJsonLen]); newJsonLen += 4; // +11 newJson[newJsonLen++] = ':'; // +12 - n_htoa32(crc32(json, jsonLen), &newJson[newJsonLen]); + _n_htoa32(_crc32(json, jsonLen), &newJson[newJsonLen]); newJsonLen += 8; // +20 newJson[newJsonLen++] = '"'; // +21 newJson[newJsonLen++] = '}'; // +22 == CRC_FIELD_LENGTH newJson[newJsonLen] = '\0'; // null-terminated as it came in + return newJson; } @@ -923,31 +949,46 @@ NOTE_C_STATIC char *crcAdd(char *json, uint16_t seqno) @returns `true` if there's an error and `false` otherwise. */ -NOTE_C_STATIC bool crcError(char *json, uint16_t shouldBeSeqno) +NOTE_C_STATIC bool _crcError(char *json, uint16_t shouldBeSeqno) { - // Strip off any crlf for crc calculation + // Trim whitespace (specifically "\r\n") for CRC calculation size_t jsonLen = strlen(json); - while (jsonLen > 0 && json[jsonLen-1] <= ' ') { + while (jsonLen > 0 && json[jsonLen - 1] <= ' ') { jsonLen--; } - // Minimum valid JSON is "{}" (2 bytes) and must end with a closing "}". - if (jsonLen < CRC_FIELD_LENGTH+2 || json[jsonLen-1] != '}') { + + // Ignore CRC check if the response contains an error + // A valid JSON string begins with "{". Therefore, the presence of an error + // message in a well-formed JSON string MUST result in a non-zero response. + if (strstr(json, ERR_FIELD_NAME_TEST)) { return false; } + + // Skip if invalid JSON or is too short to contain a CRC parameter + // Minimum length is "{}" (2 bytes) + CRC_FIELD_LENGTH + // Valid JSON ends with a closing "}" + if ((jsonLen < (CRC_FIELD_LENGTH + 2)) || (json[jsonLen - 1] != '}')) { + return false; + } + // See if it has a compliant CRC field - size_t fieldOffset = ((jsonLen-1) - CRC_FIELD_LENGTH); - if (memcmp(&json[fieldOffset+CRC_FIELD_NAME_OFFSET], CRC_FIELD_NAME_TEST, sizeof(CRC_FIELD_NAME_TEST)-1) != 0) { + size_t fieldOffset = ((jsonLen - 1) - CRC_FIELD_LENGTH); + if (memcmp(&json[fieldOffset + CRC_FIELD_NAME_OFFSET], CRC_FIELD_NAME_TEST, ((sizeof(CRC_FIELD_NAME_TEST) - 1)) != 0)) { // If we've seen a CRC before, we should see one every time - return notecardSupportsCrc ? true : false; + return notecardFirmwareSupportsCrc; } + // If we get here, we've seen at least one CRC from the Notecard, so we should expect it. - notecardSupportsCrc = true; - char *p = &json[fieldOffset + CRC_FIELD_NAME_OFFSET + (sizeof(CRC_FIELD_NAME_TEST)-1)]; - uint16_t actualSeqno = (uint16_t) n_atoh(p, 4); - uint32_t actualCrc32 = (uint32_t) n_atoh(p+5, 8); + notecardFirmwareSupportsCrc = true; + + // Extract the CRC field and the sequence number + char *p = &json[fieldOffset + CRC_FIELD_NAME_OFFSET + (sizeof(CRC_FIELD_NAME_TEST) - 1)]; + uint16_t actualSeqno = (uint16_t) _n_atoh(p, 4); + uint32_t actualCrc32 = (uint32_t) _n_atoh(p+5, 8); json[fieldOffset++] = '}'; json[fieldOffset] = '\0'; - uint32_t shouldBeCrc32 = crc32(json, fieldOffset); + uint32_t shouldBeCrc32 = _crc32(json, fieldOffset); + return (shouldBeSeqno != actualSeqno || shouldBeCrc32 != actualCrc32); } diff --git a/src/note-c/n_serial.c b/src/note-c/n_serial.c index ede4189..a31f538 100644 --- a/src/note-c/n_serial.c +++ b/src/note-c/n_serial.c @@ -31,7 +31,7 @@ @returns a c-string with an error, or `NULL` if no error occurred. */ /**************************************************************************/ -const char *serialNoteTransaction(const char *request, size_t reqLen, char **response, uint32_t timeoutMs) +const char *_serialNoteTransaction(const char *request, size_t reqLen, char **response, uint32_t timeoutMs) { // Strip off the newline and optional carriage return characters. This // allows for standardized output to be reapplied. @@ -40,7 +40,7 @@ const char *serialNoteTransaction(const char *request, size_t reqLen, char **res reqLen--; // remove carriage return if it exists } - const char *err = serialChunkedTransmit((uint8_t *)request, reqLen, true); + const char *err = _serialChunkedTransmit((uint8_t *)request, reqLen, true); if (err) { NOTE_C_LOG_ERROR(err); return err; @@ -86,7 +86,7 @@ const char *serialNoteTransaction(const char *request, size_t reqLen, char **res uint32_t jsonbufAvailLen = (jsonbufAllocLen - jsonbufLen); // Append into the json buffer - const char *err = serialChunkedReceive((uint8_t *)(jsonbuf + jsonbufLen), &jsonbufAvailLen, true, (CARD_INTRA_TRANSACTION_TIMEOUT_SEC * 1000), &available); + const char *err = _serialChunkedReceive((uint8_t *)(jsonbuf + jsonbufLen), &jsonbufAvailLen, true, (CARD_INTRA_TRANSACTION_TIMEOUT_SEC * 1000), &available); if (err) { _Free(jsonbuf); NOTE_C_LOG_ERROR(ERRSTR("error occured during receive", c_iobad)); @@ -132,7 +132,7 @@ const char *serialNoteTransaction(const char *request, size_t reqLen, char **res @returns a boolean. `true` if the reset was successful, `false`, if not. */ /**************************************************************************/ -bool serialNoteReset(void) +bool _serialNoteReset(void) { NOTE_C_LOG_DEBUG("resetting Serial interface..."); @@ -213,7 +213,7 @@ bool serialNoteReset(void) @returns A c-string with an error, or `NULL` if no error ocurred. */ /**************************************************************************/ -const char *serialChunkedReceive(uint8_t *buffer, uint32_t *size, bool delay, uint32_t timeoutMs, uint32_t *available) +const char *_serialChunkedReceive(uint8_t *buffer, uint32_t *size, bool delay, uint32_t timeoutMs, uint32_t *available) { size_t received = 0; bool overflow = (received >= *size); @@ -279,7 +279,7 @@ const char *serialChunkedReceive(uint8_t *buffer, uint32_t *size, bool delay, ui @returns A c-string with an error, or `NULL` if no error ocurred. */ /**************************************************************************/ -const char *serialChunkedTransmit(uint8_t *buffer, uint32_t size, bool delay) +const char *_serialChunkedTransmit(uint8_t *buffer, uint32_t size, bool delay) { // Transmit the request in segments so as not to overwhelm the Notecard's // interrupt buffers diff --git a/src/note-c/n_ua.c b/src/note-c/n_ua.c index f4a46ac..f38b00b 100644 --- a/src/note-c/n_ua.c +++ b/src/note-c/n_ua.c @@ -129,7 +129,7 @@ __attribute__((weak)) J *NoteUserAgent() JAddStringToObject(ua, "agent", n_agent); JAddStringToObject(ua, "compiler", compiler); - JAddStringToObject(ua, "req_interface", noteActiveInterface()); + JAddStringToObject(ua, "req_interface", _noteActiveInterface()); // Add CPU Details if (n_cpu_cores != 0) { @@ -206,4 +206,4 @@ void NoteSetUserAgentCPU(int cpu_mem, int cpu_mhz, int cpu_cores, char *cpu_vend n_cpu_vendor = cpu_vendor; } -#endif +#endif // !NOTE_C_LOW_MEM diff --git a/src/note-c/note.h b/src/note-c/note.h index 045c5d5..b2dbecf 100644 --- a/src/note-c/note.h +++ b/src/note-c/note.h @@ -15,6 +15,15 @@ #pragma once +#if defined(__GNUC__) || defined(__clang__) +#define NOTE_C_DEPRECATED __attribute__((__deprecated__)) +#elif defined(_MSC_VER) +#define NOTE_C_DEPRECATED __declspec(deprecated) +#else +#define NOTE_C_DEPRECATED +#define NOTE_C_NO_DEPRECATED_ATTR +#endif // __GNUC__ || __clang__ + // In case they're not yet defined #include #include @@ -25,7 +34,7 @@ #define NOTE_C_STRINGIZE(x) _NOTE_C_STRINGIZE(x) #define NOTE_C_VERSION_MAJOR 2 -#define NOTE_C_VERSION_MINOR 2 +#define NOTE_C_VERSION_MINOR 3 #define NOTE_C_VERSION_PATCH 1 #define NOTE_C_VERSION NOTE_C_STRINGIZE(NOTE_C_VERSION_MAJOR) "." NOTE_C_STRINGIZE(NOTE_C_VERSION_MINOR) "." NOTE_C_STRINGIZE(NOTE_C_VERSION_PATCH) @@ -35,10 +44,12 @@ #if defined(FLT_MAX_EXP) && defined(DBL_MAX_EXP) #if (FLT_MAX_EXP == DBL_MAX_EXP) #define NOTE_C_LOW_MEM +#define NOTE_C_SINGLE_PRECISION #endif #elif defined(__FLT_MAX_EXP__) && defined(__DBL_MAX_EXP__) #if (__FLT_MAX_EXP__ == __DBL_MAX_EXP__) #define NOTE_C_LOW_MEM +#define NOTE_C_SINGLE_PRECISION #endif #else #error What are floating point exponent length symbols for this compiler? @@ -57,12 +68,12 @@ #define ERRSTR(x,y) (y) #else #define ERRSTR(x,y) (x) -#endif +#endif // NOTE_C_LOW_MEM /*! @brief The floating point type used for JSON handling in note-c. */ -#ifdef NOTE_C_TEST_SINGLE_PRECISION +#ifdef NOTE_C_SINGLE_PRECISION typedef float JNUMBER; #else typedef double JNUMBER; @@ -231,8 +242,8 @@ J *NoteNewCommand(const char *request); J *NoteRequestResponse(J *req); J *NoteRequestResponseWithRetry(J *req, uint32_t timeoutSeconds); char * NoteRequestResponseJSON(const char *reqJSON); -void NoteSuspendTransactionDebug(void); -void NoteResumeTransactionDebug(void); +NOTE_C_DEPRECATED void NoteSuspendTransactionDebug(void); +NOTE_C_DEPRECATED void NoteResumeTransactionDebug(void); #define SYNCSTATUS_LEVEL_MAJOR 0 #define SYNCSTATUS_LEVEL_MINOR 1 #define SYNCSTATUS_LEVEL_DETAILED 2 @@ -260,22 +271,36 @@ J *NoteTransaction(J *req); bool NoteErrorContains(const char *errstr, const char *errtype); void NoteErrorClean(char *errbuf); void NoteSetFnDebugOutput(debugOutputFn fn); +void NoteGetFnDebugOutput(debugOutputFn *fn); void NoteSetFnTransaction(txnStartFn startFn, txnStopFn stopFn); +void NoteGetFnTransaction(txnStartFn *startFn, txnStopFn *stopFn); void NoteSetFnMutex(mutexFn lockI2Cfn, mutexFn unlockI2Cfn, mutexFn lockNotefn, mutexFn unlockNotefn); +void NoteGetFnMutex(mutexFn *lockI2Cfn, mutexFn *unlockI2Cfn, mutexFn *lockNotefn, + mutexFn *unlockNotefn); void NoteSetFnI2CMutex(mutexFn lockI2Cfn, mutexFn unlockI2Cfn); +void NoteGetFnI2CMutex(mutexFn *lockI2Cfn, mutexFn *unlockI2Cfn); void NoteSetFnNoteMutex(mutexFn lockFn, mutexFn unlockFn); +void NoteGetFnNoteMutex(mutexFn *lockFn, mutexFn *unlockFn); void NoteSetFnDefault(mallocFn mallocfn, freeFn freefn, delayMsFn delayfn, getMsFn millisfn); void NoteSetFn(mallocFn mallocHook, freeFn freeHook, delayMsFn delayMsHook, getMsFn getMsHook); +void NoteGetFn(mallocFn *mallocHook, freeFn *freeHook, delayMsFn *delayMsHook, + getMsFn *getMsHook); void NoteSetFnSerial(serialResetFn resetFn, serialTransmitFn transmitFn, serialAvailableFn availFn, serialReceiveFn receiveFn); +void NoteGetFnSerial(serialResetFn *resetFn, serialTransmitFn *transmitFn, + serialAvailableFn *availFn, serialReceiveFn *receiveFn); void NoteSetFnI2C(uint32_t notecardAddr, uint32_t maxTransmitSize, i2cResetFn resetFn, i2cTransmitFn transmitFn, i2cReceiveFn receiveFn); +void NoteGetFnI2C(uint32_t *notecardAddr, uint32_t *maxTransmitSize, + i2cResetFn *resetFn, i2cTransmitFn *transmitFn, + i2cReceiveFn *receiveFn); void NoteSetFnDisabled(void); void NoteSetI2CAddress(uint32_t i2caddress); +void NoteGetI2CAddress(uint32_t *i2caddress); // The Notecard, whose default I2C address is below, uses a serial-to-i2c // protocol whose "byte count" must fit into a single byte and which must not @@ -370,11 +395,13 @@ void NoteDebugWithLevelLn(uint8_t level, const char *msg); NoteDebugWithLevelLn(NOTE_C_LOG_LEVEL_DEBUG, msg); \ } while (0); -// The max log level for NoteDebugWithLevel is only configurable at +// The max log level for NoteDebugWithLevel may be configured at // compile-time, via NOTE_C_LOG_LEVEL. #ifndef NOTE_C_LOG_LEVEL #define NOTE_C_LOG_LEVEL NOTE_C_LOG_LEVEL_INFO #endif +// Otherwise, it may be set at runtime, via NoteSetLogLevel. +void NoteSetLogLevel(int level); void *NoteMalloc(size_t size); void NoteFree(void *); @@ -490,7 +517,7 @@ bool NoteLocalTimeST(uint16_t *retYear, uint8_t *retMonth, uint8_t *retDay, uint bool NoteRegion(char **retCountry, char **retArea, char **retZone, int *retZoneOffset); bool NoteLocationValid(char *errbuf, uint32_t errbuflen); bool NoteLocationValidST(char *errbuf, uint32_t errbuflen); -void NoteTurboIO(bool enable); +NOTE_C_DEPRECATED void NoteTurboIO(bool enable); JINTEGER NoteGetEnvInt(const char *variable, JINTEGER defaultVal); JNUMBER NoteGetEnvNumber(const char *variable, JNUMBER defaultVal); bool NoteGetEnv(const char *variable, const char *defaultVal, char *buf, uint32_t buflen);