From 035e1c7750a9c03f3394b87213e927a366891617 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Thu, 31 Aug 2023 14:51:07 -0500 Subject: [PATCH 01/22] chore: support binary chunked receive --- n_helpers.c | 100 ++++++++++++++++++++++++++++++---------------------- note.h | 13 +++---- 2 files changed, 65 insertions(+), 48 deletions(-) diff --git a/n_helpers.c b/n_helpers.c index 3b32488d..7e2a5926 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -182,28 +182,33 @@ uint32_t NoteBinaryEncodedMaxLength(uint32_t len) @brief Receive a large binary object from the Notecard's binary buffer @param buffer A buffer to hold the binary object @param bufLen The total length of the provided buffer - @param dataLen An out parameter to hold the length of the decoded data in the - output buffer. + @param offset The offset to the unencoded binary data already residing on + the Notecard + @param dataLen [in/out] The length of the decoded data to fetch from the + Notecard. If you wish to fetch the entire buffer from the + given offset, set this value to `NOTE_C_BINARY_RX_ALL`. This + parameter will return the bytes actually received from the + Notecard, which is required when using `NOTE_C_BINARY_RX_ALL`. @returns NULL on success, else an error string pointer. - @note Buffers are decoded in place. The original contents of the buffer - will be modified. + @note The buffer must be large enough to hold the encoded value of the + original contents at the requested offset and length. @note To determine the necessary size for the buffer, use - NoteBinaryRequiredRxBuffer. + `NoteBinaryRequiredBuffer()`. */ /**************************************************************************/ const char * NoteBinaryReceive(uint8_t * buffer, size_t bufLen, - size_t * dataLen) + size_t offset, size_t * dataLen) { - size_t requiredRxBufLen = 0; - const char *err = NoteBinaryRequiredRxBuffer(&requiredRxBufLen); - if (err) { - return err; + // Validate parameter(s) + if (!buffer) { + NOTE_C_LOG_ERROR("NULL buffer"); + return ERRSTR("NULL buffer", c_err); } - if (!requiredRxBufLen) { - NOTE_C_LOG_ERROR("no data on notecard"); - return ERRSTR("no data on notecard", c_err); + if (!dataLen) { + NOTE_C_LOG_ERROR("dataLen cannot be NULL"); + return ERRSTR("dataLen cannot be NULL", c_err); } - if (requiredRxBufLen > bufLen) { + if (bufLen < (NoteBinaryEncodedMaxLength(*dataLen) + sizeof('\n'))) { NOTE_C_LOG_ERROR("insufficient buffer size"); return ERRSTR("insufficient buffer size", c_err); } @@ -215,10 +220,8 @@ const char * NoteBinaryReceive(uint8_t * buffer, size_t bufLen, char status[NOTE_MD5_HASH_STRING_SIZE] = {0}; J *req = NoteNewRequest("card.binary.get"); if (req) { - // This field must exactly match the number of binary bytes the Notecard - // will send. This doesn't include the terminating newline, hence the - // -1. - JAddIntToObject(req, "cobs", requiredRxBufLen - 1); + JAddIntToObject(req, "offset", offset); + JAddIntToObject(req, "length", *dataLen); // Ensure the transaction doesn't return an error. J *rsp = NoteRequestResponse(req); @@ -241,7 +244,7 @@ const char * NoteBinaryReceive(uint8_t * buffer, size_t bufLen, // Read raw bytes from the active interface into a predefined buffer uint32_t available = 0; - err = _ChunkedReceive(buffer, &bufLen, false, 60000, &available); + const char *err = _ChunkedReceive(buffer, &bufLen, false, 60000, &available); // Release Notecard Mutex _UnlockNote(); @@ -290,15 +293,38 @@ const char * NoteBinaryReceive(uint8_t * buffer, size_t bufLen, //**************************************************************************/ /*! - @brief Get the required buffer size to receive the binary object stored on - the Notecard. If there's no data to stored on the Notecard, *size will - be 0. - @param size Out parameter to hold the required size. + @brief Given the length of a binary payload, calculate the buffer size needed + to COBS-encode that payload in-place in the buffer, plus an additional + byte for an end-of-packet character (i.e. a newline). Because COBS + encoding adds some overhead, this size will be larger than the length + of the payload. + @param dataLen The length of the binary payload. + @returns The required buffer size in bytes. +*/ +/**************************************************************************/ +size_t NoteBinaryRequiredBuffer(size_t dataLen) +{ + return (NoteBinaryEncodedMaxLength(dataLen) + 1); +} + +//**************************************************************************/ +/*! + @brief Get the required buffer size to receive the entire binary object + stored on the Notecard. If there's no data to stored on the Notecard, + *size will return 0. + @param size [out] size required to hold the entire contents of the + Notecard's binary store. @returns An error string on error and NULL on success. */ /**************************************************************************/ -const char * NoteBinaryRequiredRxBuffer(size_t *size) +const char * NoteBinaryRequiredRxMaxBuffer(size_t *size) { + // Validate parameter(s) + if (!size) { + NOTE_C_LOG_ERROR("size cannot be NULL"); + return ERRSTR("size cannot be NULL", c_err); + } + // Issue a "card.binary" request. J *rsp = NoteRequestResponse(NoteNewRequest("card.binary")); if (!rsp) { @@ -333,22 +359,6 @@ const char * NoteBinaryRequiredRxBuffer(size_t *size) return NULL; } -//**************************************************************************/ -/*! - @brief Given the length of a binary payload, calculate the buffer size needed - to COBS-encode that payload in-place in the buffer, plus an additional - byte for an end-of-packet character (i.e. a newline). Because COBS - encoding adds some overhead, this size will be larger than the length - of the payload. - @param dataLen The length of the binary payload. - @returns The required buffer size in bytes. -*/ -/**************************************************************************/ -size_t NoteBinaryRequiredTxBuffer(size_t dataLen) -{ - return (NoteBinaryEncodedMaxLength(dataLen) + 1); -} - //**************************************************************************/ /*! @brief Reset the Notecard's binary buffer @@ -390,17 +400,23 @@ const char * NoteBinaryReset(void) @param offset The offset where the `data` buffer should be appended to the unencoded binary data already residing on the Notecard. This does not provide random access, but rather ensures alignment - between the callers expectation and Notecard. + across sequential writes. @returns NULL on success, else an error string pointer. @note Buffers are encoded in place, the buffer _MUST_ be larger than the data to be encoded. The original contents of the buffer will be modified. - @note You may use `NoteBinaryRequiredTxBuffer()` to calculate the required size + @note You may use `NoteBinaryRequiredBuffer()` to calculate the required size for the buffer pointed to by the `data` parameter. */ /**************************************************************************/ const char * NoteBinaryTransmit(uint8_t * data, size_t dataLen, size_t bufLen, size_t offset) { + // Validate parameter(s) + if (!dataLen) { + NOTE_C_LOG_ERROR("dataLen cannot be NULL"); + return ERRSTR("dataLen cannot be NULL", c_err); + } + // Issue a "card.binary" request. J *rsp = NoteRequestResponse(NoteNewRequest("card.binary")); if (!rsp) { diff --git a/note.h b/note.h index 596b8f5b..31e80c39 100644 --- a/note.h +++ b/note.h @@ -317,13 +317,14 @@ void NoteMD5HashToString(unsigned char *hash, char *strbuf, unsigned long buflen // High-level helper functions that are both useful and serve to show developers // how to call the API -const char * NoteBinaryReceive(uint8_t * buffer, size_t bufLen, - size_t * dataLen); -const char * NoteBinaryRequiredRxBuffer(size_t * size); -size_t NoteBinaryRequiredTxBuffer(size_t dataLen); +#define NOTE_C_BINARY_RX_ALL 0 +const char * NoteBinaryReceive(uint8_t *buffer, size_t bufLen, + size_t offset, size_t *dataLen); +const char * NoteBinaryRequiredRxMaxBuffer(size_t *size); +size_t NoteBinaryRequiredBuffer(size_t dataLen); const char * NoteBinaryReset(void); -const char * NoteBinaryTransmit(uint8_t * data, size_t dataLen, size_t bufLen, - size_t offset); +const char * NoteBinaryTransmit(uint8_t *data, size_t dataLen, + size_t bufLen, size_t offset); const char *NoteBinaryDecode(const uint8_t *inBuf, uint32_t inLen, uint8_t *outBuf, uint32_t *outLen); const char *NoteBinaryEncode(const uint8_t *inBuf, uint32_t inLen, From 867af1618e8db908cefd176d3ca301e59f263ed9 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Fri, 1 Sep 2023 07:21:32 -0500 Subject: [PATCH 02/22] fix: char/int bug --- n_helpers.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/n_helpers.c b/n_helpers.c index 7e2a5926..7fb504b1 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -208,7 +208,7 @@ const char * NoteBinaryReceive(uint8_t * buffer, size_t bufLen, NOTE_C_LOG_ERROR("dataLen cannot be NULL"); return ERRSTR("dataLen cannot be NULL", c_err); } - if (bufLen < (NoteBinaryEncodedMaxLength(*dataLen) + sizeof('\n'))) { + if (bufLen < NoteBinaryRequiredBuffer(*dataLen)) { NOTE_C_LOG_ERROR("insufficient buffer size"); return ERRSTR("insufficient buffer size", c_err); } From e706523c1fdfcac58441124f06f501d992803769 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Sat, 2 Sep 2023 09:29:20 -0500 Subject: [PATCH 03/22] chore: Add helper for length --- n_helpers.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++------- note.h | 15 +++++++------- 2 files changed, 57 insertions(+), 14 deletions(-) diff --git a/n_helpers.c b/n_helpers.c index 7fb504b1..0c18d535 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -86,6 +86,48 @@ NOTE_C_STATIC int ytodays(int year); static const char BINARY_EOP = '\n'; +//**************************************************************************/ +/*! + @brief Get the length of the data stored on the Notecard. If there's no data + stored on the Notecard, then `*len` will return 0. + @param len [out] the length of the decoded contents of the Notecard's binary + data store. + @returns An error string on error and NULL on success. +*/ +/**************************************************************************/ +const char * NoteBinaryDataLength(size_t *len) +{ + // Validate parameter(s) + if (!len) { + NOTE_C_LOG_ERROR("len cannot be NULL"); + return ERRSTR("len cannot be NULL", c_err); + } + + // Issue a "card.binary" request. + J *rsp = NoteRequestResponse(NoteNewRequest("card.binary")); + if (!rsp) { + NOTE_C_LOG_ERROR("unable to issue binary request"); + return ERRSTR("unable to issue binary request", c_err); + } + + // Ensure the transaction doesn't return an error and confirm the binary + // feature is available. + if (NoteResponseError(rsp)) { + const char *err = JGetString(rsp, "err"); + NOTE_C_LOG_ERROR(err); + JDelete(rsp); + NOTE_C_LOG_ERROR("unexpected error received during handshake"); + return ERRSTR("unexpected error received during handshake", c_bad); + } + + // Examine "length" from the response to evaluate the length of the decoded + // data residing on the Notecard. + *len = JGetInt(rsp, "length"); + JDelete(rsp); + + return NULL; +} + //**************************************************************************/ /*! @brief Decode a binary payload received from the Notecard. @@ -98,7 +140,7 @@ static const char BINARY_EOP = '\n'; @returns NULL on success, else an error string pointer. */ /**************************************************************************/ -const char *NoteBinaryDecode(const uint8_t *inBuf, uint32_t inLen, +const char * NoteBinaryDecode(const uint8_t *inBuf, uint32_t inLen, uint8_t *outBuf, uint32_t *outLen) { if (inBuf == NULL || outBuf == NULL || outLen == NULL) { @@ -128,7 +170,7 @@ const char *NoteBinaryDecode(const uint8_t *inBuf, uint32_t inLen, @returns NULL on success, else an error string pointer. */ /**************************************************************************/ -const char *NoteBinaryEncode(const uint8_t *inBuf, uint32_t inLen, +const char * NoteBinaryEncode(const uint8_t *inBuf, uint32_t inLen, uint8_t *outBuf, uint32_t *outLen) { if (inBuf == NULL || outBuf == NULL || outLen == NULL) { @@ -310,10 +352,10 @@ size_t NoteBinaryRequiredBuffer(size_t dataLen) //**************************************************************************/ /*! @brief Get the required buffer size to receive the entire binary object - stored on the Notecard. If there's no data to stored on the Notecard, - *size will return 0. - @param size [out] size required to hold the entire contents of the - Notecard's binary store. + stored on the Notecard. If there's no data stored on the Notecard, + then `*size` will return 0. + @param size [out] the size required to hold the entire contents of the + Notecard's binary data store. @returns An error string on error and NULL on success. */ /**************************************************************************/ @@ -343,7 +385,7 @@ const char * NoteBinaryRequiredRxMaxBuffer(size_t *size) } // Examine "cobs" from the response to evaluate the space required to hold - // the COBS-encoded data received from the Notecard. + // the COBS-encoded data to be received from the Notecard. long int cobs = JGetInt(rsp, "cobs"); JDelete(rsp); if (!cobs) { diff --git a/note.h b/note.h index 31e80c39..35c23797 100644 --- a/note.h +++ b/note.h @@ -318,19 +318,20 @@ void NoteMD5HashToString(unsigned char *hash, char *strbuf, unsigned long buflen // High-level helper functions that are both useful and serve to show developers // how to call the API #define NOTE_C_BINARY_RX_ALL 0 +const char * NoteBinaryDataLength(size_t *len); +const char * NoteBinaryDecode(const uint8_t *inBuf, uint32_t inLen, + uint8_t *outBuf, uint32_t *outLen); +const char * NoteBinaryEncode(const uint8_t *inBuf, uint32_t inLen, + uint8_t *outBuf, uint32_t *outLen); +uint32_t NoteBinaryEncodedLength(const uint8_t *buf, uint32_t len); +uint32_t NoteBinaryEncodedMaxLength(uint32_t len); const char * NoteBinaryReceive(uint8_t *buffer, size_t bufLen, size_t offset, size_t *dataLen); -const char * NoteBinaryRequiredRxMaxBuffer(size_t *size); size_t NoteBinaryRequiredBuffer(size_t dataLen); +const char * NoteBinaryRequiredRxMaxBuffer(size_t *size); const char * NoteBinaryReset(void); const char * NoteBinaryTransmit(uint8_t *data, size_t dataLen, size_t bufLen, size_t offset); -const char *NoteBinaryDecode(const uint8_t *inBuf, uint32_t inLen, - uint8_t *outBuf, uint32_t *outLen); -const char *NoteBinaryEncode(const uint8_t *inBuf, uint32_t inLen, - uint8_t *outBuf, uint32_t *outLen); -uint32_t NoteBinaryEncodedLength(const uint8_t *buf, uint32_t len); -uint32_t NoteBinaryEncodedMaxLength(uint32_t len); uint32_t NoteSetSTSecs(uint32_t secs); bool NoteTimeValid(void); bool NoteTimeValidST(void); From 2ea146fcf752d7315bb346b9dfe36c9dda0dfb49 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Tue, 5 Sep 2023 14:34:43 +0000 Subject: [PATCH 04/22] fix: appease astyle --- n_helpers.c | 4 ++-- note.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/n_helpers.c b/n_helpers.c index 0c18d535..07518ad4 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -141,7 +141,7 @@ const char * NoteBinaryDataLength(size_t *len) */ /**************************************************************************/ const char * NoteBinaryDecode(const uint8_t *inBuf, uint32_t inLen, - uint8_t *outBuf, uint32_t *outLen) + uint8_t *outBuf, uint32_t *outLen) { if (inBuf == NULL || outBuf == NULL || outLen == NULL) { NOTE_C_LOG_ERROR("NULL parameter"); @@ -171,7 +171,7 @@ const char * NoteBinaryDecode(const uint8_t *inBuf, uint32_t inLen, */ /**************************************************************************/ const char * NoteBinaryEncode(const uint8_t *inBuf, uint32_t inLen, - uint8_t *outBuf, uint32_t *outLen) + uint8_t *outBuf, uint32_t *outLen) { if (inBuf == NULL || outBuf == NULL || outLen == NULL) { NOTE_C_LOG_ERROR("NULL parameter"); diff --git a/note.h b/note.h index 35c23797..13adb5c6 100644 --- a/note.h +++ b/note.h @@ -320,9 +320,9 @@ void NoteMD5HashToString(unsigned char *hash, char *strbuf, unsigned long buflen #define NOTE_C_BINARY_RX_ALL 0 const char * NoteBinaryDataLength(size_t *len); const char * NoteBinaryDecode(const uint8_t *inBuf, uint32_t inLen, - uint8_t *outBuf, uint32_t *outLen); + uint8_t *outBuf, uint32_t *outLen); const char * NoteBinaryEncode(const uint8_t *inBuf, uint32_t inLen, - uint8_t *outBuf, uint32_t *outLen); + uint8_t *outBuf, uint32_t *outLen); uint32_t NoteBinaryEncodedLength(const uint8_t *buf, uint32_t len); uint32_t NoteBinaryEncodedMaxLength(uint32_t len); const char * NoteBinaryReceive(uint8_t *buffer, size_t bufLen, From dfc45333e6fd20a94e1e6cda27d0e584b326ea61 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Tue, 5 Sep 2023 15:09:32 +0000 Subject: [PATCH 05/22] test: refactor API calls --- test/CMakeLists.txt | 2 +- test/src/NoteBinaryReceive_test.cpp | 40 ++++++++++--------- ...=> NoteBinaryRequiredRxMaxBuffer_test.cpp} | 20 +++++----- 3 files changed, 32 insertions(+), 30 deletions(-) rename test/src/{NoteBinaryRequiredRxBuffer_test.cpp => NoteBinaryRequiredRxMaxBuffer_test.cpp} (80%) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c9154d55..49e3c991 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -146,7 +146,7 @@ add_test(i2cChunkedReceive_test) add_test(i2cChunkedTransmit_test) add_test(NoteBinaryReceive_test) add_test(NoteBinaryTransmit_test) -add_test(NoteBinaryRequiredRxBuffer_test) +add_test(NoteBinaryRequiredRxMaxBuffer_test) add_test(NoteBinaryReset_test) if(NOTE_C_COVERAGE) diff --git a/test/src/NoteBinaryReceive_test.cpp b/test/src/NoteBinaryReceive_test.cpp index 201fa8bd..4ac6f1d2 100644 --- a/test/src/NoteBinaryReceive_test.cpp +++ b/test/src/NoteBinaryReceive_test.cpp @@ -20,7 +20,7 @@ DEFINE_FFF_GLOBALS FAKE_VALUE_FUNC(J *, NoteNewRequest, const char *) -FAKE_VALUE_FUNC(const char *, NoteBinaryRequiredRxBuffer, size_t *) +FAKE_VALUE_FUNC(const char *, NoteBinaryRequiredRxMaxBuffer, size_t *) FAKE_VALUE_FUNC(J *, NoteRequestResponse, J *) FAKE_VALUE_FUNC(const char *, NoteChunkedReceive, uint8_t *, size_t *, bool, size_t, uint32_t *) @@ -43,15 +43,17 @@ size_t rawMsgLen = strlen(rawMsg); namespace { -SCENARIO("NoteBinaryReceive") +SCENARIO("NoteBinaryReceive all") { RESET_FAKE(NoteNewRequest); - RESET_FAKE(NoteBinaryRequiredRxBuffer); + RESET_FAKE(NoteBinaryRequiredRxMaxBuffer); RESET_FAKE(NoteRequestResponse); RESET_FAKE(NoteChunkedReceive); RESET_FAKE(NoteLockNote); RESET_FAKE(NoteUnlockNote); + const size_t offset = 0; + NoteSetFnDefault(malloc, free, NULL, NULL); // These fakes are the default. Tests below may override them to exercise @@ -59,7 +61,7 @@ SCENARIO("NoteBinaryReceive") NoteNewRequest_fake.custom_fake = [](const char *req) -> J* { return JCreateObject(); }; - NoteBinaryRequiredRxBuffer_fake.custom_fake = [](size_t *size) + NoteBinaryRequiredRxMaxBuffer_fake.custom_fake = [](size_t *size) -> const char * { *size = bufLen; @@ -76,8 +78,8 @@ SCENARIO("NoteBinaryReceive") return rsp; }; - GIVEN("NoteBinaryRequiredRxBuffer fails") { - NoteBinaryRequiredRxBuffer_fake.custom_fake = [](size_t *size) + GIVEN("NoteBinaryRequiredRxMaxBuffer fails") { + NoteBinaryRequiredRxMaxBuffer_fake.custom_fake = [](size_t *size) -> const char * { *size = 0; @@ -85,7 +87,7 @@ SCENARIO("NoteBinaryReceive") }; WHEN("NoteBinaryReceive is called") { - const char *err = NoteBinaryReceive(buf, bufLen, &dataLen); + const char *err = NoteBinaryReceive(buf, bufLen, offset, &dataLen); THEN("An error is returned") { CHECK(err != NULL); @@ -93,12 +95,12 @@ SCENARIO("NoteBinaryReceive") } } - GIVEN("NoteBinaryRequiredRxBuffer indicates there's no binary data") { - NoteBinaryRequiredRxBuffer_fake.custom_fake = NULL; - NoteBinaryRequiredRxBuffer_fake.return_val = "some error"; + GIVEN("NoteBinaryRequiredRxMaxBuffer indicates there's no binary data") { + NoteBinaryRequiredRxMaxBuffer_fake.custom_fake = NULL; + NoteBinaryRequiredRxMaxBuffer_fake.return_val = "some error"; WHEN("NoteBinaryReceive is called") { - const char *err = NoteBinaryReceive(buf, bufLen, &dataLen); + const char *err = NoteBinaryReceive(buf, bufLen, offset, &dataLen); THEN("An error is returned") { CHECK(err != NULL); @@ -107,7 +109,7 @@ SCENARIO("NoteBinaryReceive") } GIVEN("The receive buffer isn't big enough") { - NoteBinaryRequiredRxBuffer_fake.custom_fake = [](size_t *size) + NoteBinaryRequiredRxMaxBuffer_fake.custom_fake = [](size_t *size) -> const char * { *size = bufLen + 1; @@ -115,7 +117,7 @@ SCENARIO("NoteBinaryReceive") }; WHEN("NoteBinaryReceive is called") { - const char *err = NoteBinaryReceive(buf, bufLen, &dataLen); + const char *err = NoteBinaryReceive(buf, bufLen, offset, &dataLen); THEN("An error is returned") { CHECK(err != NULL); @@ -128,7 +130,7 @@ SCENARIO("NoteBinaryReceive") NoteNewRequest_fake.return_val = NULL; WHEN("NoteBinaryReceive is called") { - const char *err = NoteBinaryReceive(buf, bufLen, &dataLen); + const char *err = NoteBinaryReceive(buf, bufLen, offset, &dataLen); THEN("An error is returned") { CHECK(err != NULL); @@ -146,7 +148,7 @@ SCENARIO("NoteBinaryReceive") }; WHEN("NoteBinaryReceive is called") { - const char *err = NoteBinaryReceive(buf, bufLen, &dataLen); + const char *err = NoteBinaryReceive(buf, bufLen, offset, &dataLen); THEN("An error is returned") { CHECK(err != NULL); @@ -158,7 +160,7 @@ SCENARIO("NoteBinaryReceive") NoteChunkedReceive_fake.return_val = "some error"; WHEN("NoteBinaryReceive is called") { - const char *err = NoteBinaryReceive(buf, bufLen, &dataLen); + const char *err = NoteBinaryReceive(buf, bufLen, offset, &dataLen); THEN("An error is returned") { CHECK(err != NULL); @@ -176,7 +178,7 @@ SCENARIO("NoteBinaryReceive") }; WHEN("NoteBinaryReceive is called") { - const char *err = NoteBinaryReceive(buf, bufLen, &dataLen); + const char *err = NoteBinaryReceive(buf, bufLen, offset, &dataLen); THEN("An error is returned") { CHECK(err != NULL); @@ -207,7 +209,7 @@ SCENARIO("NoteBinaryReceive") }; WHEN("NoteBinaryReceive is called") { - const char *err = NoteBinaryReceive(buf, bufLen, &dataLen); + const char *err = NoteBinaryReceive(buf, bufLen, offset, &dataLen); THEN("An error is returned") { CHECK(err != NULL); @@ -217,7 +219,7 @@ SCENARIO("NoteBinaryReceive") AND_GIVEN("The computed MD5 matches the status field") { WHEN("NoteBinaryReceive is called") { - const char *err = NoteBinaryReceive(buf, bufLen, &dataLen); + const char *err = NoteBinaryReceive(buf, bufLen, offset, &dataLen); THEN("No error is returned") { CHECK(err == NULL); diff --git a/test/src/NoteBinaryRequiredRxBuffer_test.cpp b/test/src/NoteBinaryRequiredRxMaxBuffer_test.cpp similarity index 80% rename from test/src/NoteBinaryRequiredRxBuffer_test.cpp rename to test/src/NoteBinaryRequiredRxMaxBuffer_test.cpp index 3ac263b8..9a1ccc80 100644 --- a/test/src/NoteBinaryRequiredRxBuffer_test.cpp +++ b/test/src/NoteBinaryRequiredRxMaxBuffer_test.cpp @@ -1,5 +1,5 @@ /*! - * @file NoteBinaryRequiredRxBuffer_test.cpp + * @file NoteBinaryRequiredRxMaxBuffer_test.cpp * * Written by the Blues Inc. team. * @@ -26,7 +26,7 @@ const size_t cobsLen = 10; namespace { -SCENARIO("NoteBinaryRequiredRxBuffer") +SCENARIO("NoteBinaryRequiredRxMaxBuffer") { RESET_FAKE(NoteRequestResponse); @@ -41,8 +41,8 @@ SCENARIO("NoteBinaryRequiredRxBuffer") return NULL; }; - WHEN("NoteBinaryRequiredRxBuffer is called") { - const char *err = NoteBinaryRequiredRxBuffer(&size); + WHEN("NoteBinaryRequiredRxMaxBuffer is called") { + const char *err = NoteBinaryRequiredRxMaxBuffer(&size); THEN("An error is returned") { CHECK(err != NULL); @@ -59,8 +59,8 @@ SCENARIO("NoteBinaryRequiredRxBuffer") return rsp; }; - WHEN("NoteBinaryRequiredRxBuffer is called") { - const char *err = NoteBinaryRequiredRxBuffer(&size); + WHEN("NoteBinaryRequiredRxMaxBuffer is called") { + const char *err = NoteBinaryRequiredRxMaxBuffer(&size); THEN("An error is returned") { CHECK(err != NULL); @@ -78,8 +78,8 @@ SCENARIO("NoteBinaryRequiredRxBuffer") return rsp; }; - WHEN("NoteBinaryRequiredRxBuffer is called") { - const char *err = NoteBinaryRequiredRxBuffer(&size); + WHEN("NoteBinaryRequiredRxMaxBuffer is called") { + const char *err = NoteBinaryRequiredRxMaxBuffer(&size); THEN("An error is not returned") { CHECK(err == NULL); @@ -101,8 +101,8 @@ SCENARIO("NoteBinaryRequiredRxBuffer") return rsp; }; - WHEN("NoteBinaryRequiredRxBuffer is called") { - const char *err = NoteBinaryRequiredRxBuffer(&size); + WHEN("NoteBinaryRequiredRxMaxBuffer is called") { + const char *err = NoteBinaryRequiredRxMaxBuffer(&size); THEN("An error is not returned") { CHECK(err == NULL); From 3d3ad8294c9040bdf3b5f80f9c0444fa45a85488 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Tue, 5 Sep 2023 18:56:07 +0000 Subject: [PATCH 06/22] chore: refactor existing tests --- test/src/NoteBinaryReceive_test.cpp | 159 ++++++++-------------------- 1 file changed, 45 insertions(+), 114 deletions(-) diff --git a/test/src/NoteBinaryReceive_test.cpp b/test/src/NoteBinaryReceive_test.cpp index 4ac6f1d2..5ebe9024 100644 --- a/test/src/NoteBinaryReceive_test.cpp +++ b/test/src/NoteBinaryReceive_test.cpp @@ -43,7 +43,7 @@ size_t rawMsgLen = strlen(rawMsg); namespace { -SCENARIO("NoteBinaryReceive all") +SCENARIO("NoteBinaryReceive") { RESET_FAKE(NoteNewRequest); RESET_FAKE(NoteBinaryRequiredRxMaxBuffer); @@ -52,7 +52,7 @@ SCENARIO("NoteBinaryReceive all") RESET_FAKE(NoteLockNote); RESET_FAKE(NoteUnlockNote); - const size_t offset = 0; + const size_t OFFSET_ZERO = 0; NoteSetFnDefault(malloc, free, NULL, NULL); @@ -78,63 +78,22 @@ SCENARIO("NoteBinaryReceive all") return rsp; }; - GIVEN("NoteBinaryRequiredRxMaxBuffer fails") { - NoteBinaryRequiredRxMaxBuffer_fake.custom_fake = [](size_t *size) - -> const char * { - *size = 0; - - return NULL; - }; - - WHEN("NoteBinaryReceive is called") { - const char *err = NoteBinaryReceive(buf, bufLen, offset, &dataLen); - - THEN("An error is returned") { - CHECK(err != NULL); - } - } - } - - GIVEN("NoteBinaryRequiredRxMaxBuffer indicates there's no binary data") { - NoteBinaryRequiredRxMaxBuffer_fake.custom_fake = NULL; - NoteBinaryRequiredRxMaxBuffer_fake.return_val = "some error"; - - WHEN("NoteBinaryReceive is called") { - const char *err = NoteBinaryReceive(buf, bufLen, offset, &dataLen); - - THEN("An error is returned") { - CHECK(err != NULL); - } - } - } - - GIVEN("The receive buffer isn't big enough") { - NoteBinaryRequiredRxMaxBuffer_fake.custom_fake = [](size_t *size) - -> const char * { - *size = bufLen + 1; - - return NULL; - }; - - WHEN("NoteBinaryReceive is called") { - const char *err = NoteBinaryReceive(buf, bufLen, offset, &dataLen); - - THEN("An error is returned") { - CHECK(err != NULL); - } - } - } - GIVEN("Allocating the card.binary.get request fails") { NoteNewRequest_fake.custom_fake = NULL; NoteNewRequest_fake.return_val = NULL; WHEN("NoteBinaryReceive is called") { - const char *err = NoteBinaryReceive(buf, bufLen, offset, &dataLen); + const char *err = NoteBinaryReceive(buf, bufLen, OFFSET_ZERO, &dataLen); + REQUIRE(NoteNewRequest_fake.call_count > 0); THEN("An error is returned") { CHECK(err != NULL); } + + THEN("The Notecard is locked and unlocked the same number of times") { + CHECK(NoteLockNote_fake.call_count > 0); + CHECK(NoteLockNote_fake.call_count == NoteUnlockNote_fake.call_count); + } } } @@ -148,11 +107,17 @@ SCENARIO("NoteBinaryReceive all") }; WHEN("NoteBinaryReceive is called") { - const char *err = NoteBinaryReceive(buf, bufLen, offset, &dataLen); + const char *err = NoteBinaryReceive(buf, bufLen, OFFSET_ZERO, &dataLen); + REQUIRE(NoteRequestResponse_fake.call_count > 0); THEN("An error is returned") { CHECK(err != NULL); } + + THEN("The Notecard is locked and unlocked the same number of times") { + CHECK(NoteLockNote_fake.call_count > 0); + CHECK(NoteLockNote_fake.call_count == NoteUnlockNote_fake.call_count); + } } } @@ -160,11 +125,17 @@ SCENARIO("NoteBinaryReceive all") NoteChunkedReceive_fake.return_val = "some error"; WHEN("NoteBinaryReceive is called") { - const char *err = NoteBinaryReceive(buf, bufLen, offset, &dataLen); + const char *err = NoteBinaryReceive(buf, bufLen, OFFSET_ZERO, &dataLen); + REQUIRE(NoteChunkedReceive_fake.call_count > 0); THEN("An error is returned") { CHECK(err != NULL); } + + THEN("The Notecard is locked and unlocked the same number of times") { + CHECK(NoteLockNote_fake.call_count > 0); + CHECK(NoteLockNote_fake.call_count == NoteUnlockNote_fake.call_count); + } } } @@ -178,11 +149,17 @@ SCENARIO("NoteBinaryReceive all") }; WHEN("NoteBinaryReceive is called") { - const char *err = NoteBinaryReceive(buf, bufLen, offset, &dataLen); + const char *err = NoteBinaryReceive(buf, bufLen, OFFSET_ZERO, &dataLen); + REQUIRE(NoteChunkedReceive_fake.call_count > 0); THEN("An error is returned") { CHECK(err != NULL); } + + THEN("The Notecard is locked and unlocked the same number of times") { + CHECK(NoteLockNote_fake.call_count > 0); + CHECK(NoteLockNote_fake.call_count == NoteUnlockNote_fake.call_count); + } } } @@ -209,18 +186,26 @@ SCENARIO("NoteBinaryReceive all") }; WHEN("NoteBinaryReceive is called") { - const char *err = NoteBinaryReceive(buf, bufLen, offset, &dataLen); + const char *err = NoteBinaryReceive(buf, bufLen, OFFSET_ZERO, &dataLen); + REQUIRE(NoteChunkedReceive_fake.call_count > 0); + REQUIRE(NoteRequestResponse_fake.call_count > 0); THEN("An error is returned") { CHECK(err != NULL); } + + THEN("The Notecard is locked and unlocked the same number of times") { + CHECK(NoteLockNote_fake.call_count > 0); + CHECK(NoteLockNote_fake.call_count == NoteUnlockNote_fake.call_count); + } } } AND_GIVEN("The computed MD5 matches the status field") { WHEN("NoteBinaryReceive is called") { - const char *err = NoteBinaryReceive(buf, bufLen, offset, &dataLen); + const char *err = NoteBinaryReceive(buf, bufLen, OFFSET_ZERO, &dataLen); + REQUIRE(NoteChunkedReceive_fake.call_count > 0); THEN("No error is returned") { CHECK(err == NULL); } @@ -234,68 +219,14 @@ SCENARIO("NoteBinaryReceive all") "newline") { CHECK(memcmp(buf, rawMsg, dataLen) == 0); } + + THEN("The Notecard is locked and unlocked the same number of times") { + CHECK(NoteLockNote_fake.call_count > 0); + CHECK(NoteLockNote_fake.call_count == NoteUnlockNote_fake.call_count); + } } } - } - // GIVEN("The initial card.binary request fails") { - // NoteRequestResponse_fake.return_val = NULL; - - // WHEN("NoteBinaryReceive is called") { - // const char *err = NoteBinaryReceive(buf, size); - - // THEN("An error is returned") { - // CHECK(err != NULL); - // } - // } - // } - - // GIVEN("The response to the initial card.binary request has an error") { - // J *rsp = JCreateObject(); - // JAddStringToObject(rsp, "err", "some error"); - // NoteRequestResponse_fake.return_val = rsp; - - // WHEN("NoteBinaryReceive is called") { - // const char *err = NoteBinaryReceive(buf, size); - - // THEN("An error is returned") { - // CHECK(err != NULL); - // } - // } - // } - - // GIVEN("The response to the initial card.binary request indicates there's no" - // "binary data to read") { - // J *rsp = JCreateObject(); - // JAddIntToObject(rsp, "cobs", 0); - // NoteRequestResponse_fake.return_val = rsp; - - // WHEN("NoteBinaryReceive is called") { - // const char *err = NoteBinaryReceive(buf, size); - - // THEN("An error is returned") { - // CHECK(err != NULL); - // } - // } - // } - - // GIVEN("The response to the initial card.binary request indicates there's" - // "more data to read than will fit in the provided buffer") { - // J *rsp = JCreateObject(); - // JAddIntToObject(rsp, "cobs", size + 1); - // NoteRequestResponse_fake.return_val = rsp; - - // WHEN("NoteBinaryReceive is called") { - // const char *err = NoteBinaryReceive(buf, size); - - // THEN("An error is returned") { - // CHECK(err != NULL); - // } - // } - // } - - THEN("The Notecard is locked and unlocked the same number of times") { - CHECK(NoteLockNote_fake.call_count == NoteUnlockNote_fake.call_count); } } From 723ff4351e25a3026602655980de4575faf40a96 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Tue, 5 Sep 2023 22:32:17 +0000 Subject: [PATCH 07/22] test: NoteBinaryDataLength() --- test/CMakeLists.txt | 1 + test/src/NoteBinaryDataLength_test.cpp | 125 +++++++++++++++++++++++++ test/src/NoteBinaryReceive_test.cpp | 1 - 3 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 test/src/NoteBinaryDataLength_test.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 49e3c991..54530395 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -144,6 +144,7 @@ add_test(serialChunkedTransmit_test) add_test(i2cNoteQueryLength_test) add_test(i2cChunkedReceive_test) add_test(i2cChunkedTransmit_test) +add_test(NoteBinaryDataLength_test) add_test(NoteBinaryReceive_test) add_test(NoteBinaryTransmit_test) add_test(NoteBinaryRequiredRxMaxBuffer_test) diff --git a/test/src/NoteBinaryDataLength_test.cpp b/test/src/NoteBinaryDataLength_test.cpp new file mode 100644 index 00000000..b99d6369 --- /dev/null +++ b/test/src/NoteBinaryDataLength_test.cpp @@ -0,0 +1,125 @@ +/*! + * @file NoteBinaryDataLength_test.cpp + * + * Written by the Blues Inc. team. + * + * Copyright (c) 2023 Blues Inc. MIT License. Use of this source code is + * governed by licenses granted by the copyright holder including that found in + * the + * LICENSE + * file. + * + */ + +#ifdef NOTE_C_TEST + +#include +#include "fff.h" + +#include "n_lib.h" + +DEFINE_FFF_GLOBALS +FAKE_VALUE_FUNC(J *, NoteRequestResponse, J *) + +const size_t len = 10; + +namespace +{ + +SCENARIO("NoteBinaryDataLength") +{ + RESET_FAKE(NoteRequestResponse); + + NoteSetFnDefault(malloc, free, NULL, NULL); + + size_t size = 1; + + GIVEN("The card.binary request fails") { + NoteRequestResponse_fake.custom_fake = [](J *req) -> J * { + JDelete(req); + + return NULL; + }; + + WHEN("NoteBinaryDataLength is called") { + const char *err = NoteBinaryDataLength(&size); + + REQUIRE(NoteRequestResponse_fake.call_count > 0); + THEN("An error is returned") { + CHECK(err != NULL); + } + } + } + + GIVEN("The response to the card.binary request has an error") { + NoteRequestResponse_fake.custom_fake = [](J *req) -> J * { + JDelete(req); + J *rsp = JCreateObject(); + JAddStringToObject(rsp, "err", "some error"); + + return rsp; + }; + + WHEN("NoteBinaryDataLength is called") { + const char *err = NoteBinaryDataLength(&size); + + REQUIRE(NoteRequestResponse_fake.call_count > 0); + THEN("An error is returned") { + CHECK(err != NULL); + } + } + } + + GIVEN("The response to the card.binary request indicates there's nothing to" + " read") { + NoteRequestResponse_fake.custom_fake = [](J *req) -> J * { + JDelete(req); + J *rsp = JCreateObject(); + JAddIntToObject(rsp, "length", 0); + + return rsp; + }; + + WHEN("NoteBinaryDataLength is called") { + const char *err = NoteBinaryDataLength(&size); + + REQUIRE(NoteRequestResponse_fake.call_count > 0); + THEN("An error is not returned") { + CHECK(err == NULL); + } + + THEN("The size out parameter is 0") { + CHECK(size == 0); + } + } + } + + GIVEN("The response to the card.binary request indicates there's data " + "to read") { + NoteRequestResponse_fake.custom_fake = [](J *req) -> J * { + JDelete(req); + J *rsp = JCreateObject(); + JAddIntToObject(rsp, "length", len); + + return rsp; + }; + + WHEN("NoteBinaryDataLength is called") { + const char *err = NoteBinaryDataLength(&size); + + REQUIRE(NoteRequestResponse_fake.call_count > 0); + THEN("An error is not returned") { + CHECK(err == NULL); + } + + THEN("The size out parameter is the size in the card.binary " + "response, plus 1 for the trailing newline") { + CHECK(size == len); + } + } + } +} + +} + +#endif // NOTE_C_TEST diff --git a/test/src/NoteBinaryReceive_test.cpp b/test/src/NoteBinaryReceive_test.cpp index 5ebe9024..7afe43b4 100644 --- a/test/src/NoteBinaryReceive_test.cpp +++ b/test/src/NoteBinaryReceive_test.cpp @@ -226,7 +226,6 @@ SCENARIO("NoteBinaryReceive") } } } - } } From 826c3013c575bb4d06c603f6f916d28e74fd1621 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Tue, 5 Sep 2023 22:50:04 +0000 Subject: [PATCH 08/22] test: refactor binary tests --- test/src/NoteBinaryDataLength_test.cpp | 4 +-- test/src/NoteBinaryReceive_test.cpp | 32 ++----------------- .../NoteBinaryRequiredRxMaxBuffer_test.cpp | 2 +- 3 files changed, 5 insertions(+), 33 deletions(-) diff --git a/test/src/NoteBinaryDataLength_test.cpp b/test/src/NoteBinaryDataLength_test.cpp index b99d6369..62fc7220 100644 --- a/test/src/NoteBinaryDataLength_test.cpp +++ b/test/src/NoteBinaryDataLength_test.cpp @@ -112,8 +112,8 @@ SCENARIO("NoteBinaryDataLength") CHECK(err == NULL); } - THEN("The size out parameter is the size in the card.binary " - "response, plus 1 for the trailing newline") { + THEN("The size out parameter is the length value in the " + "card.binary response") { CHECK(size == len); } } diff --git a/test/src/NoteBinaryReceive_test.cpp b/test/src/NoteBinaryReceive_test.cpp index 7afe43b4..89330e18 100644 --- a/test/src/NoteBinaryReceive_test.cpp +++ b/test/src/NoteBinaryReceive_test.cpp @@ -89,11 +89,6 @@ SCENARIO("NoteBinaryReceive") THEN("An error is returned") { CHECK(err != NULL); } - - THEN("The Notecard is locked and unlocked the same number of times") { - CHECK(NoteLockNote_fake.call_count > 0); - CHECK(NoteLockNote_fake.call_count == NoteUnlockNote_fake.call_count); - } } } @@ -113,11 +108,6 @@ SCENARIO("NoteBinaryReceive") THEN("An error is returned") { CHECK(err != NULL); } - - THEN("The Notecard is locked and unlocked the same number of times") { - CHECK(NoteLockNote_fake.call_count > 0); - CHECK(NoteLockNote_fake.call_count == NoteUnlockNote_fake.call_count); - } } } @@ -131,11 +121,6 @@ SCENARIO("NoteBinaryReceive") THEN("An error is returned") { CHECK(err != NULL); } - - THEN("The Notecard is locked and unlocked the same number of times") { - CHECK(NoteLockNote_fake.call_count > 0); - CHECK(NoteLockNote_fake.call_count == NoteUnlockNote_fake.call_count); - } } } @@ -155,11 +140,6 @@ SCENARIO("NoteBinaryReceive") THEN("An error is returned") { CHECK(err != NULL); } - - THEN("The Notecard is locked and unlocked the same number of times") { - CHECK(NoteLockNote_fake.call_count > 0); - CHECK(NoteLockNote_fake.call_count == NoteUnlockNote_fake.call_count); - } } } @@ -193,11 +173,6 @@ SCENARIO("NoteBinaryReceive") THEN("An error is returned") { CHECK(err != NULL); } - - THEN("The Notecard is locked and unlocked the same number of times") { - CHECK(NoteLockNote_fake.call_count > 0); - CHECK(NoteLockNote_fake.call_count == NoteUnlockNote_fake.call_count); - } } } @@ -219,14 +194,11 @@ SCENARIO("NoteBinaryReceive") "newline") { CHECK(memcmp(buf, rawMsg, dataLen) == 0); } - - THEN("The Notecard is locked and unlocked the same number of times") { - CHECK(NoteLockNote_fake.call_count > 0); - CHECK(NoteLockNote_fake.call_count == NoteUnlockNote_fake.call_count); - } } } } + CHECK(NoteLockNote_fake.call_count > 0); + CHECK(NoteLockNote_fake.call_count == NoteUnlockNote_fake.call_count); } } diff --git a/test/src/NoteBinaryRequiredRxMaxBuffer_test.cpp b/test/src/NoteBinaryRequiredRxMaxBuffer_test.cpp index 9a1ccc80..366881e0 100644 --- a/test/src/NoteBinaryRequiredRxMaxBuffer_test.cpp +++ b/test/src/NoteBinaryRequiredRxMaxBuffer_test.cpp @@ -108,7 +108,7 @@ SCENARIO("NoteBinaryRequiredRxMaxBuffer") CHECK(err == NULL); } - THEN("The size out parameter is the size in the card.binary " + THEN("The size out parameter is the cobs value in the card.binary " "response, plus 1 for the trailing newline") { CHECK(size == cobsLen + 1); } From 2696a07aa6bcef8556ed6f3d571e2e6c583262e5 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Wed, 6 Sep 2023 18:53:11 +0000 Subject: [PATCH 09/22] chore: simply API --- n_helpers.c | 192 ++++++++---------- note.h | 17 +- test/CMakeLists.txt | 4 +- ...p => NoteBinaryDataDecodedLength_test.cpp} | 20 +- ...p => NoteBinaryDataEncodedLength_test.cpp} | 20 +- test/src/NoteBinaryReceive_test.cpp | 8 +- test/src/NoteBinaryTransmit_test.cpp | 7 +- 7 files changed, 129 insertions(+), 139 deletions(-) rename test/src/{NoteBinaryDataLength_test.cpp => NoteBinaryDataDecodedLength_test.cpp} (82%) rename test/src/{NoteBinaryRequiredRxMaxBuffer_test.cpp => NoteBinaryDataEncodedLength_test.cpp} (80%) diff --git a/n_helpers.c b/n_helpers.c index 07518ad4..9acafb4a 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -95,7 +95,7 @@ static const char BINARY_EOP = '\n'; @returns An error string on error and NULL on success. */ /**************************************************************************/ -const char * NoteBinaryDataLength(size_t *len) +const char * NoteBinaryDataDecodedLength(size_t *len) { // Validate parameter(s) if (!len) { @@ -128,6 +128,58 @@ const char * NoteBinaryDataLength(size_t *len) return NULL; } +//**************************************************************************/ +/*! + @brief Get the required buffer length to receive the entire binary object + stored on the Notecard. + @param len [out] the length required to hold the entire contents of the + Notecard's binary data store. If there's no data stored on the + Notecard, then `*len` will return 0. + @returns An error string on error and NULL on success. +*/ +/**************************************************************************/ +const char * NoteBinaryDataEncodedLength(size_t *len) +{ + // Validate parameter(s) + if (!len) { + NOTE_C_LOG_ERROR("size cannot be NULL"); + return ERRSTR("size cannot be NULL", c_err); + } + + // Issue a "card.binary" request. + J *rsp = NoteRequestResponse(NoteNewRequest("card.binary")); + if (!rsp) { + NOTE_C_LOG_ERROR("unable to issue binary request"); + return ERRSTR("unable to issue binary request", c_err); + } + + // Ensure the transaction doesn't return an error and confirm the binary + // feature is available. + if (NoteResponseError(rsp)) { + const char *err = JGetString(rsp, "err"); + NOTE_C_LOG_ERROR(err); + JDelete(rsp); + NOTE_C_LOG_ERROR("unexpected error received during handshake"); + return ERRSTR("unexpected error received during handshake", c_bad); + } + + // Examine "cobs" from the response to evaluate the space required to hold + // the COBS-encoded data to be received from the Notecard. + long int cobs = JGetInt(rsp, "cobs"); + JDelete(rsp); + if (!cobs) { + // If cobs is 0, the required buffer length is 0 because there's nothing + // to receive. + *len = 0; + } else { + // Otherwise, the required length is cobs + 1: the binary data plus + // 1 byte for the terminating newline. + *len = cobs + 1; + } + + return NULL; +} + //**************************************************************************/ /*! @brief Decode a binary payload received from the Notecard. @@ -140,8 +192,8 @@ const char * NoteBinaryDataLength(size_t *len) @returns NULL on success, else an error string pointer. */ /**************************************************************************/ -const char * NoteBinaryDecode(const uint8_t *inBuf, uint32_t inLen, - uint8_t *outBuf, uint32_t *outLen) +const char * NoteBinaryDecode(const uint8_t *inBuf, size_t inLen, + uint8_t *outBuf, size_t *outLen) { if (inBuf == NULL || outBuf == NULL || outLen == NULL) { NOTE_C_LOG_ERROR("NULL parameter"); @@ -170,8 +222,8 @@ const char * NoteBinaryDecode(const uint8_t *inBuf, uint32_t inLen, @returns NULL on success, else an error string pointer. */ /**************************************************************************/ -const char * NoteBinaryEncode(const uint8_t *inBuf, uint32_t inLen, - uint8_t *outBuf, uint32_t *outLen) +const char * NoteBinaryEncode(const uint8_t *inBuf, size_t inLen, + uint8_t *outBuf, size_t *outLen) { if (inBuf == NULL || outBuf == NULL || outLen == NULL) { NOTE_C_LOG_ERROR("NULL parameter"); @@ -191,32 +243,33 @@ const char * NoteBinaryEncode(const uint8_t *inBuf, uint32_t inLen, } //**************************************************************************/ -/*! - @brief Given an input buffer and its length, compute the exact number of - bytes required to binary encode that buffer. - @param buf The buffer to encode. - @param len The length of the buffer. - @note This function iterates over the entire buffer to compute the result. - For a constant-time alternative, see NoteBinaryEncodedMaxLength. - @returns The required buffer size to hold the encoded data. +/* + @brief Compute the worst-case (i.e. maximum) buffer size needed to encode + any decoded buffer of the given length. + + @param len The length of a decoded buffer. + + @returns The max required buffer size to hold the encoded data. */ /**************************************************************************/ -uint32_t NoteBinaryEncodedLength(const uint8_t *buf, uint32_t len) +uint32_t NoteBinaryMaxEncodedLengthForDecodedLength(uint32_t len) { - return cobsEncodedLength(buf, len); + return cobsEncodedMaxLength(len); } //**************************************************************************/ /*! - @brief Given an input buffer's length, compute the maximum output buffer size - needed to binary encode the input buffer. - @param len The length of the input buffer. - @returns The max required buffer size to hold the encoded data. + @brief Compute the worst-case (i.e. maximum) decoded buffer length + capable of fitting into a fixed-size buffer of the given size. + + @param size The size of the fixed-size buffer. + + @returns The max length of decoded data able to fit in the buffer. */ /**************************************************************************/ -uint32_t NoteBinaryEncodedMaxLength(uint32_t len) +uint32_t NoteBinaryMaxDecodedLengthForBufferSize(uint32_t size) { - return cobsEncodedMaxLength(len); + return cobsGuaranteedFit(size); } //**************************************************************************/ @@ -230,12 +283,13 @@ uint32_t NoteBinaryEncodedMaxLength(uint32_t len) Notecard. If you wish to fetch the entire buffer from the given offset, set this value to `NOTE_C_BINARY_RX_ALL`. This parameter will return the bytes actually received from the - Notecard, which is required when using `NOTE_C_BINARY_RX_ALL`. + Notecard. @returns NULL on success, else an error string pointer. @note The buffer must be large enough to hold the encoded value of the - original contents at the requested offset and length. - @note To determine the necessary size for the buffer, use - `NoteBinaryRequiredBuffer()`. + data store contents from the requested offset for the specified length. + @note To determine the necessary buffer size for a given `dataLen`, use + `NoteBinaryEncodingLength()`, or use `NoteBinaryDataEncodedLength()` + if you wish to consume the entire buffer. */ /**************************************************************************/ const char * NoteBinaryReceive(uint8_t * buffer, size_t bufLen, @@ -250,7 +304,7 @@ const char * NoteBinaryReceive(uint8_t * buffer, size_t bufLen, NOTE_C_LOG_ERROR("dataLen cannot be NULL"); return ERRSTR("dataLen cannot be NULL", c_err); } - if (bufLen < NoteBinaryRequiredBuffer(*dataLen)) { + if (bufLen < (cobsEncodedMaxLength(*dataLen) + sizeof(char))) { NOTE_C_LOG_ERROR("insufficient buffer size"); return ERRSTR("insufficient buffer size", c_err); } @@ -307,7 +361,7 @@ const char * NoteBinaryReceive(uint8_t * buffer, size_t bufLen, // part of the binary payload, so we decrement the length by 1 to remove it. --bufLen; - uint32_t decLen = bufLen; + size_t decLen = bufLen; // Decode it in-place, which is safe because decoding shrinks err = NoteBinaryDecode(buffer, bufLen, buffer, &decLen); if (err) { @@ -333,74 +387,6 @@ const char * NoteBinaryReceive(uint8_t * buffer, size_t bufLen, return NULL; } -//**************************************************************************/ -/*! - @brief Given the length of a binary payload, calculate the buffer size needed - to COBS-encode that payload in-place in the buffer, plus an additional - byte for an end-of-packet character (i.e. a newline). Because COBS - encoding adds some overhead, this size will be larger than the length - of the payload. - @param dataLen The length of the binary payload. - @returns The required buffer size in bytes. -*/ -/**************************************************************************/ -size_t NoteBinaryRequiredBuffer(size_t dataLen) -{ - return (NoteBinaryEncodedMaxLength(dataLen) + 1); -} - -//**************************************************************************/ -/*! - @brief Get the required buffer size to receive the entire binary object - stored on the Notecard. If there's no data stored on the Notecard, - then `*size` will return 0. - @param size [out] the size required to hold the entire contents of the - Notecard's binary data store. - @returns An error string on error and NULL on success. -*/ -/**************************************************************************/ -const char * NoteBinaryRequiredRxMaxBuffer(size_t *size) -{ - // Validate parameter(s) - if (!size) { - NOTE_C_LOG_ERROR("size cannot be NULL"); - return ERRSTR("size cannot be NULL", c_err); - } - - // Issue a "card.binary" request. - J *rsp = NoteRequestResponse(NoteNewRequest("card.binary")); - if (!rsp) { - NOTE_C_LOG_ERROR("unable to issue binary request"); - return ERRSTR("unable to issue binary request", c_err); - } - - // Ensure the transaction doesn't return an error and confirm the binary - // feature is available. - if (NoteResponseError(rsp)) { - const char *err = JGetString(rsp, "err"); - NOTE_C_LOG_ERROR(err); - JDelete(rsp); - NOTE_C_LOG_ERROR("unexpected error received during handshake"); - return ERRSTR("unexpected error received during handshake", c_bad); - } - - // Examine "cobs" from the response to evaluate the space required to hold - // the COBS-encoded data to be received from the Notecard. - long int cobs = JGetInt(rsp, "cobs"); - JDelete(rsp); - if (!cobs) { - // If cobs is 0, the required buffer length is 0 because there's nothing - // to receive. - *size = 0; - } else { - // Otherwise, the required length is cobs + 1: the binary data plus - // 1 byte for the terminating newline. - *size = cobs + 1; - } - - return NULL; -} - //**************************************************************************/ /*! @brief Reset the Notecard's binary buffer @@ -446,7 +432,7 @@ const char * NoteBinaryReset(void) @returns NULL on success, else an error string pointer. @note Buffers are encoded in place, the buffer _MUST_ be larger than the data to be encoded. The original contents of the buffer will be modified. - @note You may use `NoteBinaryRequiredBuffer()` to calculate the required size + @note You may use `NoteBinaryEncodingLength()` to calculate the required size for the buffer pointed to by the `data` parameter. */ /**************************************************************************/ @@ -518,7 +504,7 @@ const char * NoteBinaryTransmit(uint8_t * data, size_t dataLen, size_t bufLen, // one byte of space we need to save for a newline to mark the end of the // packet. When NoteBinaryEncode returns, outLen will hold the encoded // length. - uint32_t encLen = bufLen - 1; + size_t encLen = bufLen - 1; err = NoteBinaryEncode(data + dataShift, dataLen, data, &encLen); if (err) { return err; @@ -548,13 +534,13 @@ const char * NoteBinaryTransmit(uint8_t * data, size_t dataLen, size_t bufLen, // On errors, we restore the caller's input buffer by COBS // decoding it. The caller is then able to retry transmission // with their original pointer to this buffer. - NoteBinaryDecode(data, encLen, data, (uint32_t *)&bufLen); + NoteBinaryDecode(data, encLen, data, &bufLen); return ERRSTR("failed to initialize binary transaction", c_err); } } else { NOTE_C_LOG_ERROR("unable to allocate request"); _UnlockNote(); - NoteBinaryDecode(data, encLen, data, (uint32_t *)&bufLen); + NoteBinaryDecode(data, encLen, data, &bufLen); return ERRSTR("unable to allocate request", c_mem); } @@ -566,7 +552,7 @@ const char * NoteBinaryTransmit(uint8_t * data, size_t dataLen, size_t bufLen, // Ensure transaction was successful if (err) { - NoteBinaryDecode(data, encLen, data, (uint32_t *)&bufLen); + NoteBinaryDecode(data, encLen, data, &bufLen); return ERRSTR(err, c_err); } @@ -574,7 +560,7 @@ const char * NoteBinaryTransmit(uint8_t * data, size_t dataLen, size_t bufLen, rsp = NoteRequestResponse(NoteNewRequest("card.binary")); if (!rsp) { NOTE_C_LOG_ERROR("unable to validate request"); - NoteBinaryDecode(data, encLen, data, (uint32_t *)&bufLen); + NoteBinaryDecode(data, encLen, data, &bufLen); return ERRSTR("unable to validate request", c_err); } @@ -590,13 +576,13 @@ const char * NoteBinaryTransmit(uint8_t * data, size_t dataLen, size_t bufLen, continue; } NOTE_C_LOG_ERROR("binary data invalid"); - NoteBinaryDecode(data, encLen, data, (uint32_t *)&bufLen); + NoteBinaryDecode(data, encLen, data, &bufLen); return ERRSTR("binary data invalid", c_bad); } else { JDelete(rsp); NOTE_C_LOG_ERROR("unexpected error received during " "confirmation"); - NoteBinaryDecode(data, encLen, data, (uint32_t *)&bufLen); + NoteBinaryDecode(data, encLen, data, &bufLen); return ERRSTR("unexpected error received during confirmation", c_bad); } diff --git a/note.h b/note.h index 13adb5c6..29f38b61 100644 --- a/note.h +++ b/note.h @@ -318,17 +318,16 @@ void NoteMD5HashToString(unsigned char *hash, char *strbuf, unsigned long buflen // High-level helper functions that are both useful and serve to show developers // how to call the API #define NOTE_C_BINARY_RX_ALL 0 -const char * NoteBinaryDataLength(size_t *len); -const char * NoteBinaryDecode(const uint8_t *inBuf, uint32_t inLen, - uint8_t *outBuf, uint32_t *outLen); -const char * NoteBinaryEncode(const uint8_t *inBuf, uint32_t inLen, - uint8_t *outBuf, uint32_t *outLen); -uint32_t NoteBinaryEncodedLength(const uint8_t *buf, uint32_t len); -uint32_t NoteBinaryEncodedMaxLength(uint32_t len); +const char * NoteBinaryDataDecodedLength(size_t *len); +const char * NoteBinaryDataEncodedLength(size_t *len); +const char * NoteBinaryDecode(const uint8_t *inBuf, size_t inLen, + uint8_t *outBuf, size_t *outLen); +const char * NoteBinaryEncode(const uint8_t *inBuf, size_t inLen, + uint8_t *outBuf, size_t *outLen); +uint32_t NoteBinaryMaxDecodedLengthForBufferSize(uint32_t size); +uint32_t NoteBinaryMaxEncodedLengthForDecodedLength(uint32_t len); const char * NoteBinaryReceive(uint8_t *buffer, size_t bufLen, size_t offset, size_t *dataLen); -size_t NoteBinaryRequiredBuffer(size_t dataLen); -const char * NoteBinaryRequiredRxMaxBuffer(size_t *size); const char * NoteBinaryReset(void); const char * NoteBinaryTransmit(uint8_t *data, size_t dataLen, size_t bufLen, size_t offset); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 54530395..41e475d8 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -144,10 +144,10 @@ add_test(serialChunkedTransmit_test) add_test(i2cNoteQueryLength_test) add_test(i2cChunkedReceive_test) add_test(i2cChunkedTransmit_test) -add_test(NoteBinaryDataLength_test) +add_test(NoteBinaryDataDecodedLength_test) add_test(NoteBinaryReceive_test) add_test(NoteBinaryTransmit_test) -add_test(NoteBinaryRequiredRxMaxBuffer_test) +add_test(NoteBinaryDataEncodedLength_test) add_test(NoteBinaryReset_test) if(NOTE_C_COVERAGE) diff --git a/test/src/NoteBinaryDataLength_test.cpp b/test/src/NoteBinaryDataDecodedLength_test.cpp similarity index 82% rename from test/src/NoteBinaryDataLength_test.cpp rename to test/src/NoteBinaryDataDecodedLength_test.cpp index 62fc7220..226c8871 100644 --- a/test/src/NoteBinaryDataLength_test.cpp +++ b/test/src/NoteBinaryDataDecodedLength_test.cpp @@ -1,5 +1,5 @@ /*! - * @file NoteBinaryDataLength_test.cpp + * @file NoteBinaryDataDecodedLength_test.cpp * * Written by the Blues Inc. team. * @@ -26,7 +26,7 @@ const size_t len = 10; namespace { -SCENARIO("NoteBinaryDataLength") +SCENARIO("NoteBinaryDataDecodedLength") { RESET_FAKE(NoteRequestResponse); @@ -41,8 +41,8 @@ SCENARIO("NoteBinaryDataLength") return NULL; }; - WHEN("NoteBinaryDataLength is called") { - const char *err = NoteBinaryDataLength(&size); + WHEN("NoteBinaryDataDecodedLength is called") { + const char *err = NoteBinaryDataDecodedLength(&size); REQUIRE(NoteRequestResponse_fake.call_count > 0); THEN("An error is returned") { @@ -60,8 +60,8 @@ SCENARIO("NoteBinaryDataLength") return rsp; }; - WHEN("NoteBinaryDataLength is called") { - const char *err = NoteBinaryDataLength(&size); + WHEN("NoteBinaryDataDecodedLength is called") { + const char *err = NoteBinaryDataDecodedLength(&size); REQUIRE(NoteRequestResponse_fake.call_count > 0); THEN("An error is returned") { @@ -80,8 +80,8 @@ SCENARIO("NoteBinaryDataLength") return rsp; }; - WHEN("NoteBinaryDataLength is called") { - const char *err = NoteBinaryDataLength(&size); + WHEN("NoteBinaryDataDecodedLength is called") { + const char *err = NoteBinaryDataDecodedLength(&size); REQUIRE(NoteRequestResponse_fake.call_count > 0); THEN("An error is not returned") { @@ -104,8 +104,8 @@ SCENARIO("NoteBinaryDataLength") return rsp; }; - WHEN("NoteBinaryDataLength is called") { - const char *err = NoteBinaryDataLength(&size); + WHEN("NoteBinaryDataDecodedLength is called") { + const char *err = NoteBinaryDataDecodedLength(&size); REQUIRE(NoteRequestResponse_fake.call_count > 0); THEN("An error is not returned") { diff --git a/test/src/NoteBinaryRequiredRxMaxBuffer_test.cpp b/test/src/NoteBinaryDataEncodedLength_test.cpp similarity index 80% rename from test/src/NoteBinaryRequiredRxMaxBuffer_test.cpp rename to test/src/NoteBinaryDataEncodedLength_test.cpp index 366881e0..559f949b 100644 --- a/test/src/NoteBinaryRequiredRxMaxBuffer_test.cpp +++ b/test/src/NoteBinaryDataEncodedLength_test.cpp @@ -1,5 +1,5 @@ /*! - * @file NoteBinaryRequiredRxMaxBuffer_test.cpp + * @file NoteBinaryDataEncodedLength_test.cpp * * Written by the Blues Inc. team. * @@ -26,7 +26,7 @@ const size_t cobsLen = 10; namespace { -SCENARIO("NoteBinaryRequiredRxMaxBuffer") +SCENARIO("NoteBinaryDataEncodedLength") { RESET_FAKE(NoteRequestResponse); @@ -41,8 +41,8 @@ SCENARIO("NoteBinaryRequiredRxMaxBuffer") return NULL; }; - WHEN("NoteBinaryRequiredRxMaxBuffer is called") { - const char *err = NoteBinaryRequiredRxMaxBuffer(&size); + WHEN("NoteBinaryDataEncodedLength is called") { + const char *err = NoteBinaryDataEncodedLength(&size); THEN("An error is returned") { CHECK(err != NULL); @@ -59,8 +59,8 @@ SCENARIO("NoteBinaryRequiredRxMaxBuffer") return rsp; }; - WHEN("NoteBinaryRequiredRxMaxBuffer is called") { - const char *err = NoteBinaryRequiredRxMaxBuffer(&size); + WHEN("NoteBinaryDataEncodedLength is called") { + const char *err = NoteBinaryDataEncodedLength(&size); THEN("An error is returned") { CHECK(err != NULL); @@ -78,8 +78,8 @@ SCENARIO("NoteBinaryRequiredRxMaxBuffer") return rsp; }; - WHEN("NoteBinaryRequiredRxMaxBuffer is called") { - const char *err = NoteBinaryRequiredRxMaxBuffer(&size); + WHEN("NoteBinaryDataEncodedLength is called") { + const char *err = NoteBinaryDataEncodedLength(&size); THEN("An error is not returned") { CHECK(err == NULL); @@ -101,8 +101,8 @@ SCENARIO("NoteBinaryRequiredRxMaxBuffer") return rsp; }; - WHEN("NoteBinaryRequiredRxMaxBuffer is called") { - const char *err = NoteBinaryRequiredRxMaxBuffer(&size); + WHEN("NoteBinaryDataEncodedLength is called") { + const char *err = NoteBinaryDataEncodedLength(&size); THEN("An error is not returned") { CHECK(err == NULL); diff --git a/test/src/NoteBinaryReceive_test.cpp b/test/src/NoteBinaryReceive_test.cpp index 89330e18..ded7410b 100644 --- a/test/src/NoteBinaryReceive_test.cpp +++ b/test/src/NoteBinaryReceive_test.cpp @@ -20,7 +20,7 @@ DEFINE_FFF_GLOBALS FAKE_VALUE_FUNC(J *, NoteNewRequest, const char *) -FAKE_VALUE_FUNC(const char *, NoteBinaryRequiredRxMaxBuffer, size_t *) +FAKE_VALUE_FUNC(const char *, NoteBinaryDataEncodedLength, size_t *) FAKE_VALUE_FUNC(J *, NoteRequestResponse, J *) FAKE_VALUE_FUNC(const char *, NoteChunkedReceive, uint8_t *, size_t *, bool, size_t, uint32_t *) @@ -46,7 +46,7 @@ namespace SCENARIO("NoteBinaryReceive") { RESET_FAKE(NoteNewRequest); - RESET_FAKE(NoteBinaryRequiredRxMaxBuffer); + RESET_FAKE(NoteBinaryDataEncodedLength); RESET_FAKE(NoteRequestResponse); RESET_FAKE(NoteChunkedReceive); RESET_FAKE(NoteLockNote); @@ -61,7 +61,7 @@ SCENARIO("NoteBinaryReceive") NoteNewRequest_fake.custom_fake = [](const char *req) -> J* { return JCreateObject(); }; - NoteBinaryRequiredRxMaxBuffer_fake.custom_fake = [](size_t *size) + NoteBinaryDataEncodedLength_fake.custom_fake = [](size_t *size) -> const char * { *size = bufLen; @@ -146,7 +146,7 @@ SCENARIO("NoteBinaryReceive") GIVEN("The binary payload is received") { NoteChunkedReceive_fake.custom_fake = [](uint8_t *buffer, size_t *size, bool, size_t, uint32_t *available) -> const char* { - uint32_t outLen = *size; + size_t outLen = *size; NoteBinaryEncode((uint8_t *)rawMsg, rawMsgLen, buffer, &outLen); buffer[outLen] = '\n'; diff --git a/test/src/NoteBinaryTransmit_test.cpp b/test/src/NoteBinaryTransmit_test.cpp index a55a3f76..d99a8e59 100644 --- a/test/src/NoteBinaryTransmit_test.cpp +++ b/test/src/NoteBinaryTransmit_test.cpp @@ -180,7 +180,12 @@ SCENARIO("NoteBinaryTransmit") return rsp; }; - uint32_t newBufLen = NoteBinaryEncodedLength(buf, dataLen); + + // Discover the actual encoded length of the data + const size_t tempBufLen = NoteBinaryMaxEncodedLengthForDecodedLength(dataLen); + uint8_t *tempBuf = (uint8_t *)malloc(tempBufLen); + size_t newBufLen = tempBufLen; + REQUIRE(!NoteBinaryEncode(buf, dataLen, tempBuf, &newBufLen)); WHEN("NoteBinaryTransmit is called") { const char *err = NoteBinaryTransmit(buf, dataLen, newBufLen, 0); From 99148a9663445474bcd42f5bf191d239dc6ca873 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Wed, 6 Sep 2023 20:11:12 +0000 Subject: [PATCH 10/22] chore: update binary API to uint32_t --- n_helpers.c | 32 +++++++++---------- n_hooks.c | 9 +++--- n_i2c.c | 8 ++--- n_lib.h | 12 +++---- n_serial.c | 19 ++++++++--- note.h | 20 ++++++------ test/src/NoteBinaryDataDecodedLength_test.cpp | 2 +- test/src/NoteBinaryDataEncodedLength_test.cpp | 4 +-- test/src/NoteBinaryReceive_test.cpp | 20 ++++++------ test/src/NoteBinaryTransmit_test.cpp | 10 +++--- test/src/i2cChunkedReceive_test.cpp | 14 ++++---- test/src/i2cNoteTransaction_test.cpp | 12 +++---- test/src/serialChunkedReceive_test.cpp | 4 +-- test/src/serialNoteTransaction_test.cpp | 12 +++---- 14 files changed, 94 insertions(+), 84 deletions(-) diff --git a/n_helpers.c b/n_helpers.c index 9acafb4a..9d192335 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -95,7 +95,7 @@ static const char BINARY_EOP = '\n'; @returns An error string on error and NULL on success. */ /**************************************************************************/ -const char * NoteBinaryDataDecodedLength(size_t *len) +const char * NoteBinaryDataDecodedLength(uint32_t *len) { // Validate parameter(s) if (!len) { @@ -138,7 +138,7 @@ const char * NoteBinaryDataDecodedLength(size_t *len) @returns An error string on error and NULL on success. */ /**************************************************************************/ -const char * NoteBinaryDataEncodedLength(size_t *len) +const char * NoteBinaryDataEncodedLength(uint32_t *len) { // Validate parameter(s) if (!len) { @@ -192,8 +192,8 @@ const char * NoteBinaryDataEncodedLength(size_t *len) @returns NULL on success, else an error string pointer. */ /**************************************************************************/ -const char * NoteBinaryDecode(const uint8_t *inBuf, size_t inLen, - uint8_t *outBuf, size_t *outLen) +const char * NoteBinaryDecode(const uint8_t *inBuf, uint32_t inLen, + uint8_t *outBuf, uint32_t *outLen) { if (inBuf == NULL || outBuf == NULL || outLen == NULL) { NOTE_C_LOG_ERROR("NULL parameter"); @@ -222,8 +222,8 @@ const char * NoteBinaryDecode(const uint8_t *inBuf, size_t inLen, @returns NULL on success, else an error string pointer. */ /**************************************************************************/ -const char * NoteBinaryEncode(const uint8_t *inBuf, size_t inLen, - uint8_t *outBuf, size_t *outLen) +const char * NoteBinaryEncode(const uint8_t *inBuf, uint32_t inLen, + uint8_t *outBuf, uint32_t *outLen) { if (inBuf == NULL || outBuf == NULL || outLen == NULL) { NOTE_C_LOG_ERROR("NULL parameter"); @@ -292,8 +292,8 @@ uint32_t NoteBinaryMaxDecodedLengthForBufferSize(uint32_t size) if you wish to consume the entire buffer. */ /**************************************************************************/ -const char * NoteBinaryReceive(uint8_t * buffer, size_t bufLen, - size_t offset, size_t * dataLen) +const char * NoteBinaryReceive(uint8_t * buffer, uint32_t bufLen, + uint32_t offset, uint32_t * dataLen) { // Validate parameter(s) if (!buffer) { @@ -361,7 +361,7 @@ const char * NoteBinaryReceive(uint8_t * buffer, size_t bufLen, // part of the binary payload, so we decrement the length by 1 to remove it. --bufLen; - size_t decLen = bufLen; + uint32_t decLen = bufLen; // Decode it in-place, which is safe because decoding shrinks err = NoteBinaryDecode(buffer, bufLen, buffer, &decLen); if (err) { @@ -436,8 +436,8 @@ const char * NoteBinaryReset(void) for the buffer pointed to by the `data` parameter. */ /**************************************************************************/ -const char * NoteBinaryTransmit(uint8_t * data, size_t dataLen, size_t bufLen, - size_t offset) +const char * NoteBinaryTransmit(uint8_t *data, uint32_t dataLen, + uint32_t bufLen, uint32_t offset) { // Validate parameter(s) if (!dataLen) { @@ -468,8 +468,8 @@ const char * NoteBinaryTransmit(uint8_t * data, size_t dataLen, size_t bufLen, // Examine "length" and "max" from the response to evaluate the unencoded // space available to "card.binary.put" on the Notecard. - const size_t len = JGetInt(rsp,"length"); - const size_t max = JGetInt(rsp,"max"); + const long len = JGetInt(rsp,"length"); + const long max = JGetInt(rsp,"max"); JDelete(rsp); if (!max) { NOTE_C_LOG_ERROR("unexpected response: max is zero or not present"); @@ -485,7 +485,7 @@ const char * NoteBinaryTransmit(uint8_t * data, size_t dataLen, size_t bufLen, } // When `offset` is zero, the entire buffer is available - const size_t remaining = (offset ? (max - len) : max); + const uint32_t remaining = (offset ? (max - len) : max); if (dataLen > remaining) { NOTE_C_LOG_ERROR("buffer size exceeds available memory"); return ERRSTR("buffer size exceeds available memory", c_mem); @@ -497,14 +497,14 @@ const char * NoteBinaryTransmit(uint8_t * data, size_t dataLen, size_t bufLen, // Shift the data to the end of the buffer. Next, we'll encode the data, // outputting the encoded data to the front of the buffer. - const size_t dataShift = (bufLen - dataLen); + const uint32_t dataShift = (bufLen - dataLen); memmove(data + dataShift, data, dataLen); // outLen holds the buffer size available for encoding. The -1 accounts for // one byte of space we need to save for a newline to mark the end of the // packet. When NoteBinaryEncode returns, outLen will hold the encoded // length. - size_t encLen = bufLen - 1; + uint32_t encLen = (bufLen - sizeof(char)); err = NoteBinaryEncode(data + dataShift, dataLen, data, &encLen); if (err) { return err; diff --git a/n_hooks.c b/n_hooks.c index 05b7bea1..26059018 100644 --- a/n_hooks.c +++ b/n_hooks.c @@ -175,8 +175,8 @@ i2cReceiveFn hookI2CReceive = NULL; // Internal hooks typedef bool (*nNoteResetFn) (void); typedef const char * (*nTransactionFn) (char *, char **); -typedef const char * (*nReceiveFn) (uint8_t *, size_t *, bool, size_t, uint32_t *); -typedef const char * (*nTransmitFn) (uint8_t *, size_t, bool); +typedef const char * (*nReceiveFn) (uint8_t *, uint32_t *, bool, size_t, uint32_t *); +typedef const char * (*nTransmitFn) (uint8_t *, uint32_t, bool); static nNoteResetFn notecardReset = NULL; static nTransactionFn notecardTransaction = NULL; static nReceiveFn notecardChunkedReceive = NULL; @@ -877,7 +877,8 @@ const char *NoteJSONTransaction(char *request, char **response) @returns A c-string with an error, or `NULL` if no error ocurred. */ /**************************************************************************/ -const char *NoteChunkedReceive(uint8_t *buffer, size_t *size, bool delay, size_t timeoutMs, uint32_t *available) +const char *NoteChunkedReceive(uint8_t *buffer, uint32_t *size, bool delay, + size_t timeoutMs, uint32_t *available) { if (notecardChunkedReceive == NULL || hookActiveInterface == interfaceNone) { return "i2c or serial interface must be selected"; @@ -895,7 +896,7 @@ const char *NoteChunkedReceive(uint8_t *buffer, size_t *size, bool delay, size_t @returns A c-string with an error, or `NULL` if no error ocurred. */ /**************************************************************************/ -const char *NoteChunkedTransmit(uint8_t *buffer, size_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/n_i2c.c b/n_i2c.c index e1026093..48b78a02 100644 --- a/n_i2c.c +++ b/n_i2c.c @@ -137,9 +137,9 @@ const char *i2cNoteTransaction(char *request, char **response) } // Receive the Notecard response - size_t jsonbufLen = 0; + uint32_t jsonbufLen = 0; do { - size_t jsonbufAvailLen = (jsonbufAllocLen - jsonbufLen); + uint32_t jsonbufAvailLen = (jsonbufAllocLen - jsonbufLen); // Append into the json buffer const char *err = i2cChunkedReceive((uint8_t *)(jsonbuf + jsonbufLen), &jsonbufAvailLen, true, (NOTECARD_TRANSACTION_TIMEOUT_SEC * 1000), &available); @@ -296,7 +296,7 @@ bool i2cNoteReset() @returns A c-string with an error, or `NULL` if no error ocurred. */ /**************************************************************************/ -const char *i2cChunkedReceive(uint8_t *buffer, size_t *size, bool delay, size_t timeoutMs, uint32_t *available) +const char *i2cChunkedReceive(uint8_t *buffer, uint32_t *size, bool delay, size_t timeoutMs, uint32_t *available) { // Load buffer with chunked I2C values size_t received = 0; @@ -383,7 +383,7 @@ const char *i2cChunkedReceive(uint8_t *buffer, size_t *size, bool delay, size_t @returns A c-string with an error, or `NULL` if no error ocurred. */ /**************************************************************************/ -const char *i2cChunkedTransmit(uint8_t *buffer, size_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 diff --git a/n_lib.h b/n_lib.h index fb4383f2..14d3d72e 100644 --- a/n_lib.h +++ b/n_lib.h @@ -81,10 +81,10 @@ const char *i2cNoteTransaction(char *request, char **response); bool i2cNoteReset(void); const char *serialNoteTransaction(char *request, char **response); bool serialNoteReset(void); -const char *i2cChunkedReceive(uint8_t *buffer, size_t *size, bool delay, size_t timeoutMs, uint32_t *available); -const char *i2cChunkedTransmit(uint8_t *buffer, size_t size, bool delay); -const char *serialChunkedReceive(uint8_t *buffer, size_t *size, bool delay, size_t timeoutMs, uint32_t *available); -const char *serialChunkedTransmit(uint8_t *buffer, size_t size, bool delay); +const char *i2cChunkedReceive(uint8_t *buffer, uint32_t *size, bool delay, size_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, size_t timeoutMs, uint32_t *available); +const char *serialChunkedTransmit(uint8_t *buffer, uint32_t size, bool delay); // Hooks void NoteLockNote(void); @@ -101,8 +101,8 @@ 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(char *request, char **response); -const char *NoteChunkedReceive(uint8_t *buffer, size_t *size, bool delay, size_t timeoutMs, uint32_t *available); -const char *NoteChunkedTransmit(uint8_t *buffer, size_t size, bool delay); +const char *NoteChunkedReceive(uint8_t *buffer, uint32_t *size, bool delay, size_t timeoutMs, uint32_t *available); +const char *NoteChunkedTransmit(uint8_t *buffer, uint32_t size, bool delay); bool NoteIsDebugOutputActive(void); // Utilities diff --git a/n_serial.c b/n_serial.c index fabafedc..e63a7f5b 100644 --- a/n_serial.c +++ b/n_serial.c @@ -60,7 +60,7 @@ const char *serialNoteTransaction(char *request, char **response) // 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; - size_t jsonbufAllocLen = ALLOC_CHUNK; + uint32_t jsonbufAllocLen = ALLOC_CHUNK; uint8_t *jsonbuf = (uint8_t *)_Malloc(jsonbufAllocLen + 1); if (jsonbuf == NULL) { #ifdef ERRDBG @@ -70,9 +70,9 @@ const char *serialNoteTransaction(char *request, char **response) } // Receive the Notecard response - size_t jsonbufLen = 0; + uint32_t jsonbufLen = 0; do { - size_t jsonbufAvailLen = (jsonbufAllocLen - jsonbufLen); + uint32_t jsonbufAvailLen = (jsonbufAllocLen - jsonbufLen); // Append into the json buffer const char *err = serialChunkedReceive((uint8_t *)(jsonbuf + jsonbufLen), &jsonbufAvailLen, true, (NOTECARD_TRANSACTION_TIMEOUT_SEC * 1000), &available); @@ -200,7 +200,7 @@ bool serialNoteReset() @returns A c-string with an error, or `NULL` if no error ocurred. */ /**************************************************************************/ -const char *serialChunkedReceive(uint8_t *buffer, size_t *size, bool delay, size_t timeoutMs, uint32_t *available) +const char *serialChunkedReceive(uint8_t *buffer, uint32_t *size, bool delay, size_t timeoutMs, uint32_t *available) { size_t received = 0; bool overflow = (received >= *size); @@ -261,13 +261,22 @@ const char *serialChunkedReceive(uint8_t *buffer, size_t *size, bool delay, size @returns A c-string with an error, or `NULL` if no error ocurred. */ /**************************************************************************/ -const char *serialChunkedTransmit(uint8_t *buffer, size_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 uint32_t segOff = 0; uint32_t segLeft = size; + if (sizeof(size_t) != 4) { // Give the compiler a hint to eliminate the code + // Ensure truncation does not occur on 16-bit microcontrollers + const size_t castSize = (size_t)size; + if (castSize != size) { + NOTE_C_LOG_ERROR("Cannot transmit provided size; limit to `size_t`"); + return "Cannot transmit provided size; limit to `size_t`"; + } + } + while (true) { size_t segLen = segLeft; if (segLen > CARD_REQUEST_SERIAL_SEGMENT_MAX_LEN) { diff --git a/note.h b/note.h index 29f38b61..ca349d5f 100644 --- a/note.h +++ b/note.h @@ -318,19 +318,19 @@ void NoteMD5HashToString(unsigned char *hash, char *strbuf, unsigned long buflen // High-level helper functions that are both useful and serve to show developers // how to call the API #define NOTE_C_BINARY_RX_ALL 0 -const char * NoteBinaryDataDecodedLength(size_t *len); -const char * NoteBinaryDataEncodedLength(size_t *len); -const char * NoteBinaryDecode(const uint8_t *inBuf, size_t inLen, - uint8_t *outBuf, size_t *outLen); -const char * NoteBinaryEncode(const uint8_t *inBuf, size_t inLen, - uint8_t *outBuf, size_t *outLen); +const char * NoteBinaryDataDecodedLength(uint32_t *len); +const char * NoteBinaryDataEncodedLength(uint32_t *len); +const char * NoteBinaryDecode(const uint8_t *inBuf, uint32_t inLen, + uint8_t *outBuf, uint32_t *outLen); +const char * NoteBinaryEncode(const uint8_t *inBuf, uint32_t inLen, + uint8_t *outBuf, uint32_t *outLen); uint32_t NoteBinaryMaxDecodedLengthForBufferSize(uint32_t size); uint32_t NoteBinaryMaxEncodedLengthForDecodedLength(uint32_t len); -const char * NoteBinaryReceive(uint8_t *buffer, size_t bufLen, - size_t offset, size_t *dataLen); +const char * NoteBinaryReceive(uint8_t *buffer, uint32_t bufLen, + uint32_t offset, uint32_t *dataLen); const char * NoteBinaryReset(void); -const char * NoteBinaryTransmit(uint8_t *data, size_t dataLen, - size_t bufLen, size_t offset); +const char * NoteBinaryTransmit(uint8_t *data, uint32_t dataLen, + uint32_t bufLen, uint32_t offset); uint32_t NoteSetSTSecs(uint32_t secs); bool NoteTimeValid(void); bool NoteTimeValidST(void); diff --git a/test/src/NoteBinaryDataDecodedLength_test.cpp b/test/src/NoteBinaryDataDecodedLength_test.cpp index 226c8871..684ad035 100644 --- a/test/src/NoteBinaryDataDecodedLength_test.cpp +++ b/test/src/NoteBinaryDataDecodedLength_test.cpp @@ -32,7 +32,7 @@ SCENARIO("NoteBinaryDataDecodedLength") NoteSetFnDefault(malloc, free, NULL, NULL); - size_t size = 1; + uint32_t size = 1; GIVEN("The card.binary request fails") { NoteRequestResponse_fake.custom_fake = [](J *req) -> J * { diff --git a/test/src/NoteBinaryDataEncodedLength_test.cpp b/test/src/NoteBinaryDataEncodedLength_test.cpp index 559f949b..8a5bf973 100644 --- a/test/src/NoteBinaryDataEncodedLength_test.cpp +++ b/test/src/NoteBinaryDataEncodedLength_test.cpp @@ -21,7 +21,7 @@ DEFINE_FFF_GLOBALS FAKE_VALUE_FUNC(J *, NoteRequestResponse, J *) -const size_t cobsLen = 10; +const uint32_t cobsLen = 10; namespace { @@ -32,7 +32,7 @@ SCENARIO("NoteBinaryDataEncodedLength") NoteSetFnDefault(malloc, free, NULL, NULL); - size_t size = 1; + uint32_t size = 1; GIVEN("The card.binary request fails") { NoteRequestResponse_fake.custom_fake = [](J *req) -> J * { diff --git a/test/src/NoteBinaryReceive_test.cpp b/test/src/NoteBinaryReceive_test.cpp index ded7410b..e85edf72 100644 --- a/test/src/NoteBinaryReceive_test.cpp +++ b/test/src/NoteBinaryReceive_test.cpp @@ -20,9 +20,9 @@ DEFINE_FFF_GLOBALS FAKE_VALUE_FUNC(J *, NoteNewRequest, const char *) -FAKE_VALUE_FUNC(const char *, NoteBinaryDataEncodedLength, size_t *) +FAKE_VALUE_FUNC(const char *, NoteBinaryDataEncodedLength, uint32_t *) FAKE_VALUE_FUNC(J *, NoteRequestResponse, J *) -FAKE_VALUE_FUNC(const char *, NoteChunkedReceive, uint8_t *, size_t *, bool, +FAKE_VALUE_FUNC(const char *, NoteChunkedReceive, uint8_t *, uint32_t *, bool, size_t, uint32_t *) FAKE_VOID_FUNC(NoteLockNote) FAKE_VOID_FUNC(NoteUnlockNote) @@ -34,11 +34,11 @@ FAKE_VOID_FUNC(NoteUnlockNote) // If a lambda captures anything, it can't be converted in this way, and you get // a compiler error. uint8_t buf[32]; -size_t bufLen = sizeof(buf); -size_t dataLen = 0; +uint32_t bufLen = sizeof(buf); +uint32_t dataLen = 0; char rawMsg[] = "Hello Blues!"; -size_t rawMsgLen = strlen(rawMsg); +uint32_t rawMsgLen = strlen(rawMsg); namespace { @@ -52,7 +52,7 @@ SCENARIO("NoteBinaryReceive") RESET_FAKE(NoteLockNote); RESET_FAKE(NoteUnlockNote); - const size_t OFFSET_ZERO = 0; + const uint32_t OFFSET_ZERO = 0; NoteSetFnDefault(malloc, free, NULL, NULL); @@ -61,7 +61,7 @@ SCENARIO("NoteBinaryReceive") NoteNewRequest_fake.custom_fake = [](const char *req) -> J* { return JCreateObject(); }; - NoteBinaryDataEncodedLength_fake.custom_fake = [](size_t *size) + NoteBinaryDataEncodedLength_fake.custom_fake = [](uint32_t *size) -> const char * { *size = bufLen; @@ -126,7 +126,7 @@ SCENARIO("NoteBinaryReceive") GIVEN("NoteChunkedReceive indicates there's unexpectedly more data " "available") { - NoteChunkedReceive_fake.custom_fake = [](uint8_t *, size_t *, bool, + NoteChunkedReceive_fake.custom_fake = [](uint8_t *, uint32_t *, bool, size_t, uint32_t *available) -> const char* { *available = 1; @@ -144,9 +144,9 @@ SCENARIO("NoteBinaryReceive") } GIVEN("The binary payload is received") { - NoteChunkedReceive_fake.custom_fake = [](uint8_t *buffer, size_t *size, + NoteChunkedReceive_fake.custom_fake = [](uint8_t *buffer, uint32_t *size, bool, size_t, uint32_t *available) -> const char* { - size_t outLen = *size; + uint32_t outLen = *size; NoteBinaryEncode((uint8_t *)rawMsg, rawMsgLen, buffer, &outLen); buffer[outLen] = '\n'; diff --git a/test/src/NoteBinaryTransmit_test.cpp b/test/src/NoteBinaryTransmit_test.cpp index d99a8e59..9fe8f436 100644 --- a/test/src/NoteBinaryTransmit_test.cpp +++ b/test/src/NoteBinaryTransmit_test.cpp @@ -22,13 +22,13 @@ DEFINE_FFF_GLOBALS FAKE_VALUE_FUNC(J *, NoteNewRequest, const char *) FAKE_VALUE_FUNC(J *, NoteRequestResponse, J *) FAKE_VALUE_FUNC(bool, NoteRequest, J *) -FAKE_VALUE_FUNC(const char *, NoteChunkedTransmit, uint8_t *, size_t, bool) +FAKE_VALUE_FUNC(const char *, NoteChunkedTransmit, uint8_t *, uint32_t, bool) FAKE_VOID_FUNC(NoteLockNote) FAKE_VOID_FUNC(NoteUnlockNote) uint8_t buf[32] = {0xDE, 0xAD, 0xBE, 0xEF}; -size_t dataLen = 4; -size_t bufLen = sizeof(buf); +uint32_t dataLen = 4; +uint32_t bufLen = sizeof(buf); namespace { @@ -182,9 +182,9 @@ SCENARIO("NoteBinaryTransmit") }; // Discover the actual encoded length of the data - const size_t tempBufLen = NoteBinaryMaxEncodedLengthForDecodedLength(dataLen); + const uint32_t tempBufLen = NoteBinaryMaxEncodedLengthForDecodedLength(dataLen); uint8_t *tempBuf = (uint8_t *)malloc(tempBufLen); - size_t newBufLen = tempBufLen; + uint32_t newBufLen = tempBufLen; REQUIRE(!NoteBinaryEncode(buf, dataLen, tempBuf, &newBufLen)); WHEN("NoteBinaryTransmit is called") { diff --git a/test/src/i2cChunkedReceive_test.cpp b/test/src/i2cChunkedReceive_test.cpp index ee280129..755efcd9 100644 --- a/test/src/i2cChunkedReceive_test.cpp +++ b/test/src/i2cChunkedReceive_test.cpp @@ -51,7 +51,7 @@ SCENARIO("i2cChunkedReceive") GIVEN("0 is specified for the output buffer length") { uint8_t buf[] = {0xAB}; - size_t zeroSize = 0; + uint32_t zeroSize = 0; AND_GIVEN("NoteI2CReceive reports that here are bytes available from " "the Notecard") { @@ -80,7 +80,7 @@ SCENARIO("i2cChunkedReceive") GIVEN("NoteI2CReceive returns an error") { uint8_t buf[] = {0xAB}; - size_t size = sizeof(buf); + uint32_t size = sizeof(buf); NoteI2CReceive_fake.return_val = "some error"; WHEN("i2cChunkedReceive is called") { @@ -95,7 +95,7 @@ SCENARIO("i2cChunkedReceive") GIVEN("The output buffer is too small") { uint8_t buf[NOTE_I2C_MAX_DEFAULT] = {0}; - size_t size = sizeof(buf); + uint32_t size = sizeof(buf); NoteI2CReceive_fake.custom_fake = NoteI2CReceiveInfinite; WHEN("i2cChunkedReceive is called") { @@ -128,7 +128,7 @@ SCENARIO("i2cChunkedReceive") GIVEN("The output buffer is sufficiently large") { uint8_t buf[NOTE_I2C_MAX_DEFAULT * 3] = {0}; - size_t size = sizeof(buf); + uint32_t size = sizeof(buf); NoteI2CReceive_fake.custom_fake = [](uint16_t, uint8_t *buf, uint16_t size, uint32_t *available) -> const char* { @@ -229,7 +229,7 @@ SCENARIO("i2cChunkedReceive") GIVEN("End-of-packet (\\n) is received, but NoteI2CReceive indicates more " "is still available to read") { uint8_t buf[NOTE_I2C_MAX_DEFAULT * 3] = {0}; - size_t size = sizeof(buf); + uint32_t size = sizeof(buf); size_t numBytesExpected = NOTE_I2C_MAX_DEFAULT * 2; // On the first call, NoteI2CReceive reports back that @@ -306,7 +306,7 @@ SCENARIO("i2cChunkedReceive") return NULL; }; uint8_t buf[NOTE_I2C_MAX_DEFAULT] = {0}; - size_t size = sizeof(buf); + uint32_t size = sizeof(buf); WHEN("i2cChunkedReceive is called") { const char *err = i2cChunkedReceive(buf, &size, true, timeoutMs, @@ -388,7 +388,7 @@ SCENARIO("i2cChunkedReceive") SET_CUSTOM_FAKE_SEQ(NoteI2CReceive, recvFakeSequence, 3); uint8_t buf[NOTE_I2C_MAX_DEFAULT] = {0}; - size_t size = sizeof(buf); + uint32_t size = sizeof(buf); WHEN("i2cChunkedReceive is called") { const char *err = i2cChunkedReceive(buf, &size, true, timeoutMs, diff --git a/test/src/i2cNoteTransaction_test.cpp b/test/src/i2cNoteTransaction_test.cpp index c40ce892..efb9738a 100644 --- a/test/src/i2cNoteTransaction_test.cpp +++ b/test/src/i2cNoteTransaction_test.cpp @@ -23,9 +23,9 @@ DEFINE_FFF_GLOBALS FAKE_VALUE_FUNC(void *, NoteMalloc, size_t) FAKE_VOID_FUNC(NoteLockI2C) FAKE_VOID_FUNC(NoteUnlockI2C) -FAKE_VALUE_FUNC(const char *, i2cChunkedTransmit, uint8_t *, size_t, bool) +FAKE_VALUE_FUNC(const char *, i2cChunkedTransmit, uint8_t *, uint32_t, bool) FAKE_VALUE_FUNC(const char *, i2cNoteQueryLength, uint32_t *, size_t) -FAKE_VALUE_FUNC(const char *, i2cChunkedReceive, uint8_t *, size_t *, bool, +FAKE_VALUE_FUNC(const char *, i2cChunkedReceive, uint8_t *, uint32_t *, bool, size_t, uint32_t *) namespace @@ -126,7 +126,7 @@ TEST_CASE("i2cNoteTransaction") "the Notecard") { // Write out the number of bytes reported available on the prior // call to i2cNoteQueryLength and report no more bytes available. - i2cChunkedReceive_fake.custom_fake = [](uint8_t *buf, size_t *size, bool, size_t, + i2cChunkedReceive_fake.custom_fake = [](uint8_t *buf, uint32_t *size, bool, size_t, uint32_t *available) -> const char* { memset(buf, 'a', *available - 1); buf[*available - 1] = '\n'; @@ -168,7 +168,7 @@ TEST_CASE("i2cNoteTransaction") // On the first call to i2cChunkedReceive, a string of a's is // written to the output buffer, and the Notecard reports that there // are still ALLOC_CHUNK bytes to read. - auto firstChunk = [](uint8_t *buf, size_t *size, bool, size_t, + auto firstChunk = [](uint8_t *buf, uint32_t *size, bool, size_t, uint32_t *available) -> const char* { memset(buf, 'a', *available); *size = *available; @@ -179,7 +179,7 @@ TEST_CASE("i2cNoteTransaction") // On the second call, the remaining ALLOC_CHUNK bytes are written // out, which is a string of a's terminated with a newline. // available is set to 0, indicating there's nothing left to read. - auto secondChunk = [](uint8_t *buf, size_t *size, bool, size_t, + auto secondChunk = [](uint8_t *buf, uint32_t *size, bool, size_t, uint32_t *available) -> const char* { memset(buf, 'a', *available - 1); buf[*available - 1] = '\n'; @@ -188,7 +188,7 @@ TEST_CASE("i2cNoteTransaction") return NULL; }; - const char *(*recvFakeSequence[])(uint8_t *, size_t *, bool, + const char *(*recvFakeSequence[])(uint8_t *, uint32_t *, bool, size_t, uint32_t *) = { firstChunk, secondChunk diff --git a/test/src/serialChunkedReceive_test.cpp b/test/src/serialChunkedReceive_test.cpp index c550c59d..63d177ed 100644 --- a/test/src/serialChunkedReceive_test.cpp +++ b/test/src/serialChunkedReceive_test.cpp @@ -50,7 +50,7 @@ SCENARIO("serialChunkedReceive") NoteGetMs_fake.custom_fake = NoteGetMsIncrement; uint8_t buf[] = {0xDE, 0xAD, 0xBE, 0xEF, 0x00}; - size_t size = sizeof(buf); + uint32_t size = sizeof(buf); bool delay = false; const size_t timeoutMs = 3000; // 37 is not significant. serialChunkedReceive will return either a 1 or 0 @@ -174,7 +174,7 @@ SCENARIO("serialChunkedReceive") GIVEN("A 0-length output buffer is provided") { WHEN("serialChunkedReceive is called") { uint32_t originalAvailable = available; - size_t zeroSize = 0; + uint32_t zeroSize = 0; const char *err = serialChunkedReceive(buf, &zeroSize, delay, timeoutMs, &available); diff --git a/test/src/serialNoteTransaction_test.cpp b/test/src/serialNoteTransaction_test.cpp index da0357ba..01c2bc1f 100644 --- a/test/src/serialNoteTransaction_test.cpp +++ b/test/src/serialNoteTransaction_test.cpp @@ -24,8 +24,8 @@ FAKE_VALUE_FUNC(bool, NoteSerialAvailable) FAKE_VALUE_FUNC(char, NoteSerialReceive) FAKE_VALUE_FUNC(long unsigned int, NoteGetMs) FAKE_VOID_FUNC(NoteSerialTransmit, uint8_t *, size_t, bool) -FAKE_VALUE_FUNC(const char *, serialChunkedTransmit, uint8_t *, size_t, bool); -FAKE_VALUE_FUNC(const char *, serialChunkedReceive, uint8_t *, size_t *, bool, size_t, uint32_t *) +FAKE_VALUE_FUNC(const char *, serialChunkedTransmit, uint8_t *, uint32_t, bool); +FAKE_VALUE_FUNC(const char *, serialChunkedReceive, uint8_t *, uint32_t *, bool, size_t, uint32_t *) namespace { @@ -53,14 +53,14 @@ void NoteSerialTransmitAppend(uint8_t *buf, size_t len, bool) transmitBufLen += len; } -const char *serialChunkedTransmitAppend(uint8_t *buf, size_t len, bool) +const char *serialChunkedTransmitAppend(uint8_t *buf, uint32_t len, bool) { NoteSerialTransmitAppend(buf, len, true); return NULL; } -const char *serialChunkedReceiveNothing(uint8_t *, size_t *size, bool, size_t, +const char *serialChunkedReceiveNothing(uint8_t *, uint32_t *size, bool, size_t, uint32_t *available) { *size = 0; @@ -69,7 +69,7 @@ const char *serialChunkedReceiveNothing(uint8_t *, size_t *size, bool, size_t, return NULL; } -const char *serialChunkedReceiveOneAndDone(uint8_t *buf, size_t *size, bool, +const char *serialChunkedReceiveOneAndDone(uint8_t *buf, uint32_t *size, bool, size_t, uint32_t *available) { *buf = '\n'; @@ -83,7 +83,7 @@ const char *serialChunkedReceiveOneAndDone(uint8_t *buf, size_t *size, bool, size_t serialChunkedReceiveMultipleLeft = SERIAL_CHUNKED_RECEIVE_MULTIPLE_SIZE; -const char *serialChunkedReceiveMultiple(uint8_t *buf, size_t *size, bool, +const char *serialChunkedReceiveMultiple(uint8_t *buf, uint32_t *size, bool, size_t, uint32_t *available) { memset(buf, 1, *size); From 6e6ff5dc838dc6f2485c65e25cc1ea87ca762753 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Wed, 6 Sep 2023 20:13:26 +0000 Subject: [PATCH 11/22] remove settings.json from git consideration --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d21e9484..94aa176e 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ html/ # VS Code workspace files *.code-workspace *.orig +settings.json \ No newline at end of file From 165bd7d87fe437c8eddb8e87721654459dd0011f Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Wed, 6 Sep 2023 20:56:44 +0000 Subject: [PATCH 12/22] fix: bad param check --- n_helpers.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/n_helpers.c b/n_helpers.c index 9d192335..9b281b8f 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -440,9 +440,9 @@ const char * NoteBinaryTransmit(uint8_t *data, uint32_t dataLen, uint32_t bufLen, uint32_t offset) { // Validate parameter(s) - if (!dataLen) { - NOTE_C_LOG_ERROR("dataLen cannot be NULL"); - return ERRSTR("dataLen cannot be NULL", c_err); + if (!data) { + NOTE_C_LOG_ERROR("data cannot be NULL"); + return ERRSTR("data cannot be NULL", c_err); } // Issue a "card.binary" request. From 38bd9dcfe406bdbe53d74b5f3e73b34ba605940f Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Wed, 6 Sep 2023 20:59:03 +0000 Subject: [PATCH 13/22] fix: Test memory leak --- test/src/NoteBinaryTransmit_test.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/test/src/NoteBinaryTransmit_test.cpp b/test/src/NoteBinaryTransmit_test.cpp index 9fe8f436..0990f654 100644 --- a/test/src/NoteBinaryTransmit_test.cpp +++ b/test/src/NoteBinaryTransmit_test.cpp @@ -186,6 +186,7 @@ SCENARIO("NoteBinaryTransmit") uint8_t *tempBuf = (uint8_t *)malloc(tempBufLen); uint32_t newBufLen = tempBufLen; REQUIRE(!NoteBinaryEncode(buf, dataLen, tempBuf, &newBufLen)); + free(tempBuf); WHEN("NoteBinaryTransmit is called") { const char *err = NoteBinaryTransmit(buf, dataLen, newBufLen, 0); From df0f02b596ab3ce5271b10f7d29ba4e864217698 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Wed, 6 Sep 2023 23:38:40 +0000 Subject: [PATCH 14/22] chore: improve unit-test coverage --- n_helpers.c | 8 +- test/CMakeLists.txt | 8 +- test/src/NoteBinaryDataDecodedLength_test.cpp | 10 ++ test/src/NoteBinaryDataEncodedLength_test.cpp | 10 ++ test/src/NoteBinaryDecode_test.cpp | 95 ++++++++++++++++++ test/src/NoteBinaryEncode_test.cpp | 97 +++++++++++++++++++ ...naryMaxDecodedLengthForBufferSize_test.cpp | 56 +++++++++++ ...yMaxEncodedLengthForDecodedLength_test.cpp | 56 +++++++++++ 8 files changed, 334 insertions(+), 6 deletions(-) create mode 100644 test/src/NoteBinaryDecode_test.cpp create mode 100644 test/src/NoteBinaryEncode_test.cpp create mode 100644 test/src/NoteBinaryMaxDecodedLengthForBufferSize_test.cpp create mode 100644 test/src/NoteBinaryMaxEncodedLengthForDecodedLength_test.cpp diff --git a/n_helpers.c b/n_helpers.c index 9b281b8f..a0bedd85 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -186,7 +186,7 @@ const char * NoteBinaryDataEncodedLength(uint32_t *len) @param inBuf The binary payload. @param inLen The length of the binary payload. @param outBuf The buffer to write the decoded payload to. This can be the - same address as inBuf, allowing for in-place decoding. + same address as inBuf, allowing for in place decoding. @param outLen On input, holds the length of outBuf. On output, holds the length of the decoded data. @returns NULL on success, else an error string pointer. @@ -216,7 +216,7 @@ const char * NoteBinaryDecode(const uint8_t *inBuf, uint32_t inLen, @param inBuf The data to encode. @param inLen The length of the data to encode. @param outBuf The buffer to write the encoded data to. This can be the - same address as inBuf, allowing for in-place encoding. + same address as inBuf, allowing for in place encoding. @param outLen On input, holds the length of outBuf. On output, holds the length of the encoded data. @returns NULL on success, else an error string pointer. @@ -362,7 +362,7 @@ const char * NoteBinaryReceive(uint8_t * buffer, uint32_t bufLen, --bufLen; uint32_t decLen = bufLen; - // Decode it in-place, which is safe because decoding shrinks + // Decode it in place, which is safe because decoding shrinks err = NoteBinaryDecode(buffer, bufLen, buffer, &decLen); if (err) { return err; @@ -1728,7 +1728,7 @@ bool NotePayloadRetrieveAfterSleep(NotePayloadDesc *desc) return false; } - // Allocate a buffer for the payload. (We can't decode in-place because we + // Allocate a buffer for the payload. (We can't decode in place because we // can't risk overwriting memory if the actual payload is even slightly // different.) uint32_t allocLen = JB64DecodeLen(payload); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 41e475d8..15bfd3b3 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -145,10 +145,14 @@ add_test(i2cNoteQueryLength_test) add_test(i2cChunkedReceive_test) add_test(i2cChunkedTransmit_test) add_test(NoteBinaryDataDecodedLength_test) -add_test(NoteBinaryReceive_test) -add_test(NoteBinaryTransmit_test) add_test(NoteBinaryDataEncodedLength_test) +add_test(NoteBinaryDecode_test) +add_test(NoteBinaryEncode_test) +add_test(NoteBinaryMaxEncodedLengthForDecodedLength_test) +add_test(NoteBinaryMaxDecodedLengthForBufferSize_test) +add_test(NoteBinaryReceive_test) add_test(NoteBinaryReset_test) +add_test(NoteBinaryTransmit_test) if(NOTE_C_COVERAGE) find_program(LCOV lcov REQUIRED) diff --git a/test/src/NoteBinaryDataDecodedLength_test.cpp b/test/src/NoteBinaryDataDecodedLength_test.cpp index 684ad035..3a0dccb8 100644 --- a/test/src/NoteBinaryDataDecodedLength_test.cpp +++ b/test/src/NoteBinaryDataDecodedLength_test.cpp @@ -34,6 +34,16 @@ SCENARIO("NoteBinaryDataDecodedLength") uint32_t size = 1; + GIVEN("Bad parameters are supplied") { + WHEN("Length is NULL") { + const char *err = NoteBinaryDataDecodedLength(NULL); + + THEN("An error is returned") { + CHECK(err != NULL); + } + } + } + GIVEN("The card.binary request fails") { NoteRequestResponse_fake.custom_fake = [](J *req) -> J * { JDelete(req); diff --git a/test/src/NoteBinaryDataEncodedLength_test.cpp b/test/src/NoteBinaryDataEncodedLength_test.cpp index 8a5bf973..605e6cf4 100644 --- a/test/src/NoteBinaryDataEncodedLength_test.cpp +++ b/test/src/NoteBinaryDataEncodedLength_test.cpp @@ -34,6 +34,16 @@ SCENARIO("NoteBinaryDataEncodedLength") uint32_t size = 1; + GIVEN("Bad parameters are supplied") { + WHEN("Length is NULL") { + const char *err = NoteBinaryDataEncodedLength(NULL); + + THEN("An error is returned") { + CHECK(err != NULL); + } + } + } + GIVEN("The card.binary request fails") { NoteRequestResponse_fake.custom_fake = [](J *req) -> J * { JDelete(req); diff --git a/test/src/NoteBinaryDecode_test.cpp b/test/src/NoteBinaryDecode_test.cpp new file mode 100644 index 00000000..0dee3060 --- /dev/null +++ b/test/src/NoteBinaryDecode_test.cpp @@ -0,0 +1,95 @@ +/*! + * @file NoteBinaryDecode_test.cpp + * + * Written by the Blues Inc. team. + * + * Copyright (c) 2023 Blues Inc. MIT License. Use of this source code is + * governed by licenses granted by the copyright holder including that found in + * the + * LICENSE + * file. + * + */ + +#ifdef NOTE_C_TEST + +#include +#include "fff.h" + +#include "n_lib.h" + +DEFINE_FFF_GLOBALS +FAKE_VALUE_FUNC(uint32_t, cobsDecode, uint8_t *, uint32_t, uint8_t, uint8_t *) + +uint8_t inBuf[12]; +uint32_t inLen; +uint8_t outBuf[10]; +uint32_t outLen; + +namespace +{ + +SCENARIO("NoteBinaryDecode") +{ + RESET_FAKE(cobsDecode); + uint32_t inLen = sizeof(inBuf); + uint32_t outLen = sizeof(outBuf); + + GIVEN("Bad parameters are supplied") { + WHEN("inBuf is NULL") { + const char *err = NoteBinaryDecode(NULL, inLen, outBuf, &outLen); + + THEN("An error is returned") { + CHECK(err != NULL); + } + } + WHEN("outBuf is NULL") { + const char *err = NoteBinaryDecode(inBuf, inLen, NULL, &outLen); + + THEN("An error is returned") { + CHECK(err != NULL); + } + } + WHEN("outLen is NULL") { + const char *err = NoteBinaryDecode(inBuf, inLen, outBuf, NULL); + + THEN("An error is returned") { + CHECK(err != NULL); + } + } + WHEN("outLen is less than the size required for the worst-case decoding") { + uint32_t badOutLen = (cobsGuaranteedFit(inLen) - 1); + const char *err = NoteBinaryDecode(inBuf, inLen, outBuf, &badOutLen); + + THEN("An error is returned") { + CHECK(err != NULL); + } + } + } + + GIVEN("Parameters are in order") { + const uint32_t EXPECTED_RESULT = 79; + cobsDecode_fake.return_val = EXPECTED_RESULT; + const char *err = NoteBinaryDecode(inBuf, inLen, outBuf, &outLen); + + THEN("cobsDecode is invoked") { + CHECK(cobsDecode_fake.call_count > 0); + } + + WHEN("cobsDecode is invoked") { + THEN("The parameters are passed without modification") { + CHECK(cobsDecode_fake.arg0_history[0] == inBuf); + CHECK(cobsDecode_fake.arg1_history[0] == inLen); + CHECK(cobsDecode_fake.arg3_history[0] == outBuf); + } + + THEN("The result is returned without modification") { + CHECK(EXPECTED_RESULT == outLen); + } + } + } +} + +} + +#endif // NOTE_C_TEST diff --git a/test/src/NoteBinaryEncode_test.cpp b/test/src/NoteBinaryEncode_test.cpp new file mode 100644 index 00000000..cc29822f --- /dev/null +++ b/test/src/NoteBinaryEncode_test.cpp @@ -0,0 +1,97 @@ +/*! + * @file NoteBinaryEncode_test.cpp + * + * Written by the Blues Inc. team. + * + * Copyright (c) 2023 Blues Inc. MIT License. Use of this source code is + * governed by licenses granted by the copyright holder including that found in + * the + * LICENSE + * file. + * + */ + +#ifdef NOTE_C_TEST + +#include + +#include +#include "fff.h" + +#include "n_lib.h" + +DEFINE_FFF_GLOBALS +FAKE_VALUE_FUNC(uint32_t, cobsEncode, uint8_t *, uint32_t, uint8_t, uint8_t *) + +uint8_t inBuf[10] = "Hi there!"; +uint32_t inLen; +uint8_t outBuf[12]; +uint32_t outLen; + +namespace +{ + +SCENARIO("NoteBinaryEncode") +{ + RESET_FAKE(cobsEncode); + uint32_t inLen = strlen((const char *)inBuf); + uint32_t outLen = sizeof(outBuf); + + GIVEN("Bad parameters are supplied") { + WHEN("inBuf is NULL") { + const char *err = NoteBinaryEncode(NULL, inLen, outBuf, &outLen); + + THEN("An error is returned") { + CHECK(err != NULL); + } + } + WHEN("outBuf is NULL") { + const char *err = NoteBinaryEncode(inBuf, inLen, NULL, &outLen); + + THEN("An error is returned") { + CHECK(err != NULL); + } + } + WHEN("outLen is NULL") { + const char *err = NoteBinaryEncode(inBuf, inLen, outBuf, NULL); + + THEN("An error is returned") { + CHECK(err != NULL); + } + } + WHEN("outLen is less than the size required for in place encoding") { + uint32_t badOutLen = (cobsEncodedLength(inBuf, inLen) - 1); + const char *err = NoteBinaryEncode(inBuf, inLen, outBuf, &badOutLen); + + THEN("An error is returned") { + CHECK(err != NULL); + } + } + } + + GIVEN("Parameters are in order") { + const uint32_t EXPECTED_RESULT = 79; + cobsEncode_fake.return_val = EXPECTED_RESULT; + const char *err = NoteBinaryEncode(inBuf, inLen, outBuf, &outLen); + + THEN("cobsEncode is invoked") { + CHECK(cobsEncode_fake.call_count > 0); + } + + WHEN("cobsEncode is invoked") { + THEN("The parameters are passed without modification") { + CHECK(cobsEncode_fake.arg0_history[0] == inBuf); + CHECK(cobsEncode_fake.arg1_history[0] == inLen); + CHECK(cobsEncode_fake.arg3_history[0] == outBuf); + } + + THEN("The result is returned without modification") { + CHECK(EXPECTED_RESULT == outLen); + } + } + } +} + +} + +#endif // NOTE_C_TEST diff --git a/test/src/NoteBinaryMaxDecodedLengthForBufferSize_test.cpp b/test/src/NoteBinaryMaxDecodedLengthForBufferSize_test.cpp new file mode 100644 index 00000000..eb2d4b61 --- /dev/null +++ b/test/src/NoteBinaryMaxDecodedLengthForBufferSize_test.cpp @@ -0,0 +1,56 @@ +/*! + * @file NoteBinaryMaxDecodedLengthForBufferSize_test.cpp + * + * Written by the Blues Inc. team. + * + * Copyright (c) 2023 Blues Inc. MIT License. Use of this source code is + * governed by licenses granted by the copyright holder including that found in + * the + * LICENSE + * file. + * + */ + +#ifdef NOTE_C_TEST + +#include +#include "fff.h" + +#include "n_lib.h" + +DEFINE_FFF_GLOBALS +FAKE_VALUE_FUNC(uint32_t, cobsGuaranteedFit, uint32_t) + +const uint32_t len = 10; + +namespace +{ + +SCENARIO("NoteBinaryMaxDecodedLengthForBufferSize") +{ + RESET_FAKE(cobsGuaranteedFit); + + GIVEN("Parameters are in order") { + const uint32_t EXPECTED_RESULT = 79; + cobsGuaranteedFit_fake.return_val = EXPECTED_RESULT; + const uint32_t result = NoteBinaryMaxDecodedLengthForBufferSize(len); + + THEN("cobsGuaranteedFit is invoked") { + CHECK(cobsGuaranteedFit_fake.call_count > 0); + } + + WHEN("cobsGuaranteedFit is invoked") { + THEN("The parameters are passed without modification") { + CHECK(cobsGuaranteedFit_fake.arg0_history[0] == len); + } + + THEN("The result is returned without modification") { + CHECK(EXPECTED_RESULT == result); + } + } + } +} + +} + +#endif // NOTE_C_TEST diff --git a/test/src/NoteBinaryMaxEncodedLengthForDecodedLength_test.cpp b/test/src/NoteBinaryMaxEncodedLengthForDecodedLength_test.cpp new file mode 100644 index 00000000..3320677c --- /dev/null +++ b/test/src/NoteBinaryMaxEncodedLengthForDecodedLength_test.cpp @@ -0,0 +1,56 @@ +/*! + * @file NoteBinaryMaxEncodedLengthForDecodedLength_test.cpp + * + * Written by the Blues Inc. team. + * + * Copyright (c) 2023 Blues Inc. MIT License. Use of this source code is + * governed by licenses granted by the copyright holder including that found in + * the + * LICENSE + * file. + * + */ + +#ifdef NOTE_C_TEST + +#include +#include "fff.h" + +#include "n_lib.h" + +DEFINE_FFF_GLOBALS +FAKE_VALUE_FUNC(uint32_t, cobsEncodedMaxLength, uint32_t) + +const uint32_t len = 10; + +namespace +{ + +SCENARIO("NoteBinaryMaxEncodedLengthForDecodedLength") +{ + RESET_FAKE(cobsEncodedMaxLength); + + GIVEN("Parameters are in order") { + const uint32_t EXPECTED_RESULT = 79; + cobsEncodedMaxLength_fake.return_val = EXPECTED_RESULT; + const uint32_t result = NoteBinaryMaxEncodedLengthForDecodedLength(len); + + THEN("cobsEncodedMaxLength is invoked") { + CHECK(cobsEncodedMaxLength_fake.call_count > 0); + } + + WHEN("cobsEncodedMaxLength is invoked") { + THEN("The parameters are passed without modification") { + CHECK(cobsEncodedMaxLength_fake.arg0_history[0] == len); + } + + THEN("The result is returned without modification") { + CHECK(EXPECTED_RESULT == result); + } + } + } +} + +} + +#endif // NOTE_C_TEST From 20636401261cf2507e041f9b05e73bbd88aa3c36 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Thu, 7 Sep 2023 02:07:32 +0000 Subject: [PATCH 15/22] chore: refactor/clarify API --- n_helpers.c | 123 ++++++++++-------- note.h | 6 +- test/CMakeLists.txt | 6 +- ..._test.cpp => NoteBinaryDataReset_test.cpp} | 16 +-- ...pp => NoteBinaryMaxDecodedLength_test.cpp} | 10 +- ...pp => NoteBinaryMaxEncodedLength_test.cpp} | 10 +- test/src/NoteBinaryTransmit_test.cpp | 2 +- 7 files changed, 95 insertions(+), 78 deletions(-) rename test/src/{NoteBinaryReset_test.cpp => NoteBinaryDataReset_test.cpp} (82%) rename test/src/{NoteBinaryMaxDecodedLengthForBufferSize_test.cpp => NoteBinaryMaxDecodedLength_test.cpp} (84%) rename test/src/{NoteBinaryMaxEncodedLengthForDecodedLength_test.cpp => NoteBinaryMaxEncodedLength_test.cpp} (83%) diff --git a/n_helpers.c b/n_helpers.c index a0bedd85..17105745 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -90,10 +90,12 @@ static const char BINARY_EOP = '\n'; /*! @brief Get the length of the data stored on the Notecard. If there's no data stored on the Notecard, then `*len` will return 0. + @param len [out] the length of the decoded contents of the Notecard's binary data store. + @returns An error string on error and NULL on success. -*/ + */ /**************************************************************************/ const char * NoteBinaryDataDecodedLength(uint32_t *len) { @@ -132,11 +134,13 @@ const char * NoteBinaryDataDecodedLength(uint32_t *len) /*! @brief Get the required buffer length to receive the entire binary object stored on the Notecard. + @param len [out] the length required to hold the entire contents of the Notecard's binary data store. If there's no data stored on the Notecard, then `*len` will return 0. + @returns An error string on error and NULL on success. -*/ + */ /**************************************************************************/ const char * NoteBinaryDataEncodedLength(uint32_t *len) { @@ -180,17 +184,53 @@ const char * NoteBinaryDataEncodedLength(uint32_t *len) return NULL; } +//**************************************************************************/ +/*! + @brief Reset the Notecard's binary buffer + + @returns NULL on success, else an error string pointer. + + @note This operation is necessary to clear the Notecard's binary buffer after + a binary object is received from the Notecard, or if the Notecard's + binary buffer has been left in an unknown state due to an error arising + from a binary transfer to the Notecard. + */ +/**************************************************************************/ +const char * NoteBinaryDataReset(void) +{ + J *req = NoteNewRequest("card.binary"); + if (req) { + JAddBoolToObject(req, "delete", true); + + // Ensure the transaction doesn't return an error. + J *rsp = NoteRequestResponse(req); + if (NoteResponseError(rsp)) { + NOTE_C_LOG_ERROR(JGetString(rsp,"err")); + JDelete(rsp); + NOTE_C_LOG_ERROR("failed to reset binary buffer"); + return ERRSTR("failed to reset binary buffer", c_err); + } + } else { + NOTE_C_LOG_ERROR("unable to allocate request"); + return ERRSTR("unable to allocate request", c_mem); + } + + return NULL; +} + //**************************************************************************/ /*! @brief Decode a binary payload received from the Notecard. + @param inBuf The binary payload. @param inLen The length of the binary payload. @param outBuf The buffer to write the decoded payload to. This can be the same address as inBuf, allowing for in place decoding. @param outLen On input, holds the length of outBuf. On output, holds the length of the decoded data. + @returns NULL on success, else an error string pointer. -*/ + */ /**************************************************************************/ const char * NoteBinaryDecode(const uint8_t *inBuf, uint32_t inLen, uint8_t *outBuf, uint32_t *outLen) @@ -212,15 +252,18 @@ const char * NoteBinaryDecode(const uint8_t *inBuf, uint32_t inLen, //**************************************************************************/ /*! + @brief Binary encode a buffer to prepare it for transmission to the Notecard. + @param inBuf The data to encode. @param inLen The length of the data to encode. @param outBuf The buffer to write the encoded data to. This can be the same address as inBuf, allowing for in place encoding. @param outLen On input, holds the length of outBuf. On output, holds the length of the encoded data. + @returns NULL on success, else an error string pointer. -*/ + */ /**************************************************************************/ const char * NoteBinaryEncode(const uint8_t *inBuf, uint32_t inLen, uint8_t *outBuf, uint32_t *outLen) @@ -243,38 +286,39 @@ const char * NoteBinaryEncode(const uint8_t *inBuf, uint32_t inLen, } //**************************************************************************/ -/* - @brief Compute the worst-case (i.e. maximum) buffer size needed to encode - any decoded buffer of the given length. +/*! + @brief Compute the worst-case (i.e. maximum) decoded data length + guaranteed to fit into a fixed-size buffer of the given size. - @param len The length of a decoded buffer. + @param size The size of the fixed-size buffer. - @returns The max required buffer size to hold the encoded data. -*/ + @returns The max length of decoded data certain to fit in the buffer. + */ /**************************************************************************/ -uint32_t NoteBinaryMaxEncodedLengthForDecodedLength(uint32_t len) +uint32_t NoteBinaryMaxDecodedLength(uint32_t bufferSize) { - return cobsEncodedMaxLength(len); + return cobsGuaranteedFit(bufferSize); } //**************************************************************************/ /*! - @brief Compute the worst-case (i.e. maximum) decoded buffer length - capable of fitting into a fixed-size buffer of the given size. + @brief Compute the worst-case (i.e. maximum) buffer size needed to encode + any unencoded buffer of the given length. - @param size The size of the fixed-size buffer. + @param unencodedLength The length of an unencoded buffer. - @returns The max length of decoded data able to fit in the buffer. -*/ + @returns The max required buffer size to hold the encoded data. + */ /**************************************************************************/ -uint32_t NoteBinaryMaxDecodedLengthForBufferSize(uint32_t size) +uint32_t NoteBinaryMaxEncodedLength(uint32_t unencodedLength) { - return cobsGuaranteedFit(size); + return cobsEncodedMaxLength(unencodedLength); } //**************************************************************************/ /*! @brief Receive a large binary object from the Notecard's binary buffer + @param buffer A buffer to hold the binary object @param bufLen The total length of the provided buffer @param offset The offset to the unencoded binary data already residing on @@ -284,13 +328,15 @@ uint32_t NoteBinaryMaxDecodedLengthForBufferSize(uint32_t size) given offset, set this value to `NOTE_C_BINARY_RX_ALL`. This parameter will return the bytes actually received from the Notecard. + @returns NULL on success, else an error string pointer. + @note The buffer must be large enough to hold the encoded value of the data store contents from the requested offset for the specified length. @note To determine the necessary buffer size for a given `dataLen`, use `NoteBinaryEncodingLength()`, or use `NoteBinaryDataEncodedLength()` if you wish to consume the entire buffer. -*/ + */ /**************************************************************************/ const char * NoteBinaryReceive(uint8_t * buffer, uint32_t bufLen, uint32_t offset, uint32_t * dataLen) @@ -387,41 +433,10 @@ const char * NoteBinaryReceive(uint8_t * buffer, uint32_t bufLen, return NULL; } -//**************************************************************************/ -/*! - @brief Reset the Notecard's binary buffer - @returns NULL on success, else an error string pointer. - @note This operation is not necessary during typical use, but is useful - when the Notecard's binary buffer is in an unknown state. The buffer - will be automatically reset when a binary object is either received, - or transmitted with the offset parameter set to zero (0). -*/ -/**************************************************************************/ -const char * NoteBinaryReset(void) -{ - J *req = NoteNewRequest("card.binary"); - if (req) { - JAddBoolToObject(req, "delete", true); - - // Ensure the transaction doesn't return an error. - J *rsp = NoteRequestResponse(req); - if (NoteResponseError(rsp)) { - NOTE_C_LOG_ERROR(JGetString(rsp,"err")); - JDelete(rsp); - NOTE_C_LOG_ERROR("failed to reset binary buffer"); - return ERRSTR("failed to reset binary buffer", c_err); - } - } else { - NOTE_C_LOG_ERROR("unable to allocate request"); - return ERRSTR("unable to allocate request", c_mem); - } - - return NULL; -} - //**************************************************************************/ /*! @brief Transmit a large binary object to the Notecard's binary buffer + @param data A buffer with data to encode in place @param dataLen The length of the data in the buffer @param bufLen The total length of the buffer @@ -429,12 +444,14 @@ const char * NoteBinaryReset(void) unencoded binary data already residing on the Notecard. This does not provide random access, but rather ensures alignment across sequential writes. + @returns NULL on success, else an error string pointer. + @note Buffers are encoded in place, the buffer _MUST_ be larger than the data to be encoded. The original contents of the buffer will be modified. @note You may use `NoteBinaryEncodingLength()` to calculate the required size for the buffer pointed to by the `data` parameter. -*/ + */ /**************************************************************************/ const char * NoteBinaryTransmit(uint8_t *data, uint32_t dataLen, uint32_t bufLen, uint32_t offset) diff --git a/note.h b/note.h index ca349d5f..81ca6fd6 100644 --- a/note.h +++ b/note.h @@ -320,15 +320,15 @@ void NoteMD5HashToString(unsigned char *hash, char *strbuf, unsigned long buflen #define NOTE_C_BINARY_RX_ALL 0 const char * NoteBinaryDataDecodedLength(uint32_t *len); const char * NoteBinaryDataEncodedLength(uint32_t *len); +const char * NoteBinaryDataReset(void); const char * NoteBinaryDecode(const uint8_t *inBuf, uint32_t inLen, uint8_t *outBuf, uint32_t *outLen); const char * NoteBinaryEncode(const uint8_t *inBuf, uint32_t inLen, uint8_t *outBuf, uint32_t *outLen); -uint32_t NoteBinaryMaxDecodedLengthForBufferSize(uint32_t size); -uint32_t NoteBinaryMaxEncodedLengthForDecodedLength(uint32_t len); +uint32_t NoteBinaryMaxDecodedLength(uint32_t bufferSize); +uint32_t NoteBinaryMaxEncodedLength(uint32_t unencodedLength); const char * NoteBinaryReceive(uint8_t *buffer, uint32_t bufLen, uint32_t offset, uint32_t *dataLen); -const char * NoteBinaryReset(void); const char * NoteBinaryTransmit(uint8_t *data, uint32_t dataLen, uint32_t bufLen, uint32_t offset); uint32_t NoteSetSTSecs(uint32_t secs); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 15bfd3b3..3b621ef1 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -146,12 +146,12 @@ add_test(i2cChunkedReceive_test) add_test(i2cChunkedTransmit_test) add_test(NoteBinaryDataDecodedLength_test) add_test(NoteBinaryDataEncodedLength_test) +add_test(NoteBinaryDataReset_test) add_test(NoteBinaryDecode_test) add_test(NoteBinaryEncode_test) -add_test(NoteBinaryMaxEncodedLengthForDecodedLength_test) -add_test(NoteBinaryMaxDecodedLengthForBufferSize_test) +add_test(NoteBinaryMaxEncodedLength_test) +add_test(NoteBinaryMaxDecodedLength_test) add_test(NoteBinaryReceive_test) -add_test(NoteBinaryReset_test) add_test(NoteBinaryTransmit_test) if(NOTE_C_COVERAGE) diff --git a/test/src/NoteBinaryReset_test.cpp b/test/src/NoteBinaryDataReset_test.cpp similarity index 82% rename from test/src/NoteBinaryReset_test.cpp rename to test/src/NoteBinaryDataReset_test.cpp index dd625fe7..2ea6f5fe 100644 --- a/test/src/NoteBinaryReset_test.cpp +++ b/test/src/NoteBinaryDataReset_test.cpp @@ -1,5 +1,5 @@ /*! - * @file NoteBinaryReset_test.cpp + * @file NoteBinaryDataReset_test.cpp * * Written by the Blues Inc. team. * @@ -25,7 +25,7 @@ FAKE_VALUE_FUNC(J *, NoteRequestResponse, J *) namespace { -SCENARIO("NoteBinaryReset") +SCENARIO("NoteBinaryDataReset") { RESET_FAKE(NoteNewRequest); RESET_FAKE(NoteRequestResponse); @@ -43,8 +43,8 @@ SCENARIO("NoteBinaryReset") NoteNewRequest_fake.custom_fake = NULL; NoteNewRequest_fake.return_val = NULL; - WHEN("NoteBinaryReset is called") { - const char *err = NoteBinaryReset(); + WHEN("NoteBinaryDataReset is called") { + const char *err = NoteBinaryDataReset(); THEN("An error is returned") { CHECK(err != NULL); @@ -61,8 +61,8 @@ SCENARIO("NoteBinaryReset") return rsp; }; - WHEN("NoteBinaryReset is called") { - const char *err = NoteBinaryReset(); + WHEN("NoteBinaryDataReset is called") { + const char *err = NoteBinaryDataReset(); THEN("An error is returned") { CHECK(err != NULL); @@ -71,8 +71,8 @@ SCENARIO("NoteBinaryReset") } GIVEN("The response to the card.binary indicates success") { - WHEN("NoteBinaryReset is called") { - const char *err = NoteBinaryReset(); + WHEN("NoteBinaryDataReset is called") { + const char *err = NoteBinaryDataReset(); THEN("An error is not returned") { CHECK(err == NULL); diff --git a/test/src/NoteBinaryMaxDecodedLengthForBufferSize_test.cpp b/test/src/NoteBinaryMaxDecodedLength_test.cpp similarity index 84% rename from test/src/NoteBinaryMaxDecodedLengthForBufferSize_test.cpp rename to test/src/NoteBinaryMaxDecodedLength_test.cpp index eb2d4b61..81894220 100644 --- a/test/src/NoteBinaryMaxDecodedLengthForBufferSize_test.cpp +++ b/test/src/NoteBinaryMaxDecodedLength_test.cpp @@ -1,5 +1,5 @@ /*! - * @file NoteBinaryMaxDecodedLengthForBufferSize_test.cpp + * @file NoteBinaryMaxDecodedLength_test.cpp * * Written by the Blues Inc. team. * @@ -21,19 +21,19 @@ DEFINE_FFF_GLOBALS FAKE_VALUE_FUNC(uint32_t, cobsGuaranteedFit, uint32_t) -const uint32_t len = 10; +const uint32_t bufferSize = 10; namespace { -SCENARIO("NoteBinaryMaxDecodedLengthForBufferSize") +SCENARIO("NoteBinaryMaxDecodedLength") { RESET_FAKE(cobsGuaranteedFit); GIVEN("Parameters are in order") { const uint32_t EXPECTED_RESULT = 79; cobsGuaranteedFit_fake.return_val = EXPECTED_RESULT; - const uint32_t result = NoteBinaryMaxDecodedLengthForBufferSize(len); + const uint32_t result = NoteBinaryMaxDecodedLength(bufferSize); THEN("cobsGuaranteedFit is invoked") { CHECK(cobsGuaranteedFit_fake.call_count > 0); @@ -41,7 +41,7 @@ SCENARIO("NoteBinaryMaxDecodedLengthForBufferSize") WHEN("cobsGuaranteedFit is invoked") { THEN("The parameters are passed without modification") { - CHECK(cobsGuaranteedFit_fake.arg0_history[0] == len); + CHECK(cobsGuaranteedFit_fake.arg0_history[0] == bufferSize); } THEN("The result is returned without modification") { diff --git a/test/src/NoteBinaryMaxEncodedLengthForDecodedLength_test.cpp b/test/src/NoteBinaryMaxEncodedLength_test.cpp similarity index 83% rename from test/src/NoteBinaryMaxEncodedLengthForDecodedLength_test.cpp rename to test/src/NoteBinaryMaxEncodedLength_test.cpp index 3320677c..fb3227dc 100644 --- a/test/src/NoteBinaryMaxEncodedLengthForDecodedLength_test.cpp +++ b/test/src/NoteBinaryMaxEncodedLength_test.cpp @@ -1,5 +1,5 @@ /*! - * @file NoteBinaryMaxEncodedLengthForDecodedLength_test.cpp + * @file NoteBinaryMaxEncodedLength_test.cpp * * Written by the Blues Inc. team. * @@ -21,19 +21,19 @@ DEFINE_FFF_GLOBALS FAKE_VALUE_FUNC(uint32_t, cobsEncodedMaxLength, uint32_t) -const uint32_t len = 10; +const uint32_t unencodedLen = 10; namespace { -SCENARIO("NoteBinaryMaxEncodedLengthForDecodedLength") +SCENARIO("NoteBinaryMaxEncodedLength") { RESET_FAKE(cobsEncodedMaxLength); GIVEN("Parameters are in order") { const uint32_t EXPECTED_RESULT = 79; cobsEncodedMaxLength_fake.return_val = EXPECTED_RESULT; - const uint32_t result = NoteBinaryMaxEncodedLengthForDecodedLength(len); + const uint32_t result = NoteBinaryMaxEncodedLength(unencodedLen); THEN("cobsEncodedMaxLength is invoked") { CHECK(cobsEncodedMaxLength_fake.call_count > 0); @@ -41,7 +41,7 @@ SCENARIO("NoteBinaryMaxEncodedLengthForDecodedLength") WHEN("cobsEncodedMaxLength is invoked") { THEN("The parameters are passed without modification") { - CHECK(cobsEncodedMaxLength_fake.arg0_history[0] == len); + CHECK(cobsEncodedMaxLength_fake.arg0_history[0] == unencodedLen); } THEN("The result is returned without modification") { diff --git a/test/src/NoteBinaryTransmit_test.cpp b/test/src/NoteBinaryTransmit_test.cpp index 0990f654..701e0929 100644 --- a/test/src/NoteBinaryTransmit_test.cpp +++ b/test/src/NoteBinaryTransmit_test.cpp @@ -182,7 +182,7 @@ SCENARIO("NoteBinaryTransmit") }; // Discover the actual encoded length of the data - const uint32_t tempBufLen = NoteBinaryMaxEncodedLengthForDecodedLength(dataLen); + const uint32_t tempBufLen = cobsEncodedMaxLength(dataLen); uint8_t *tempBuf = (uint8_t *)malloc(tempBufLen); uint32_t newBufLen = tempBufLen; REQUIRE(!NoteBinaryEncode(buf, dataLen, tempBuf, &newBufLen)); From 39bd4804eb25b0434d010eb616cff8a6d5bd7c1e Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Thu, 7 Sep 2023 02:41:27 +0000 Subject: [PATCH 16/22] chore: clarify parameters --- n_helpers.c | 104 ++++++++++++++++++++++++++-------------------------- note.h | 6 +-- 2 files changed, 56 insertions(+), 54 deletions(-) diff --git a/n_helpers.c b/n_helpers.c index 17105745..7078a063 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -321,36 +321,36 @@ uint32_t NoteBinaryMaxEncodedLength(uint32_t unencodedLength) @param buffer A buffer to hold the binary object @param bufLen The total length of the provided buffer - @param offset The offset to the unencoded binary data already residing on - the Notecard - @param dataLen [in/out] The length of the decoded data to fetch from the - Notecard. If you wish to fetch the entire buffer from the - given offset, set this value to `NOTE_C_BINARY_RX_ALL`. This - parameter will return the bytes actually received from the - Notecard. + @param decodedOffset The offset to the decoded binary data already residing + on the Notecard + @param decodedLen [in/out] The length of the decoded data to fetch from the + Notecard. If you wish to fetch the entire buffer from the + given offset, set this value to `NOTE_C_BINARY_RX_ALL`. + This parameter will return the bytes actually received from + the Notecard. @returns NULL on success, else an error string pointer. @note The buffer must be large enough to hold the encoded value of the data store contents from the requested offset for the specified length. - @note To determine the necessary buffer size for a given `dataLen`, use - `NoteBinaryEncodingLength()`, or use `NoteBinaryDataEncodedLength()` - if you wish to consume the entire buffer. + @note To determine the necessary buffer size for a given data length, use + (`NoteBinaryMaxEncodedLength()` + 1), or use + `NoteBinaryDataEncodedLength()` if you wish to consume the entire buffer. */ /**************************************************************************/ const char * NoteBinaryReceive(uint8_t * buffer, uint32_t bufLen, - uint32_t offset, uint32_t * dataLen) + uint32_t decodedOffset, uint32_t * decodedLen) { // Validate parameter(s) if (!buffer) { NOTE_C_LOG_ERROR("NULL buffer"); return ERRSTR("NULL buffer", c_err); } - if (!dataLen) { - NOTE_C_LOG_ERROR("dataLen cannot be NULL"); - return ERRSTR("dataLen cannot be NULL", c_err); + if (!decodedLen) { + NOTE_C_LOG_ERROR("decodedLen cannot be NULL"); + return ERRSTR("decodedLen cannot be NULL", c_err); } - if (bufLen < (cobsEncodedMaxLength(*dataLen) + sizeof(char))) { + if (bufLen < (cobsEncodedMaxLength(*decodedLen) + sizeof(char))) { NOTE_C_LOG_ERROR("insufficient buffer size"); return ERRSTR("insufficient buffer size", c_err); } @@ -362,8 +362,8 @@ const char * NoteBinaryReceive(uint8_t * buffer, uint32_t bufLen, char status[NOTE_MD5_HASH_STRING_SIZE] = {0}; J *req = NoteNewRequest("card.binary.get"); if (req) { - JAddIntToObject(req, "offset", offset); - JAddIntToObject(req, "length", *dataLen); + JAddIntToObject(req, "offset", decodedOffset); + JAddIntToObject(req, "length", *decodedLen); // Ensure the transaction doesn't return an error. J *rsp = NoteRequestResponse(req); @@ -413,8 +413,8 @@ const char * NoteBinaryReceive(uint8_t * buffer, uint32_t bufLen, if (err) { return err; } - // Return the decoded length in the dataLen out parameter. - *dataLen = decLen; + // Return the decoded length in the decodedLen out parameter. + *decodedLen = decLen; // Put a hard marker at the end of the decoded portion of the buffer. This // enables easier human reasoning when interrogating the buffer, if the @@ -437,29 +437,30 @@ const char * NoteBinaryReceive(uint8_t * buffer, uint32_t bufLen, /*! @brief Transmit a large binary object to the Notecard's binary buffer - @param data A buffer with data to encode in place - @param dataLen The length of the data in the buffer - @param bufLen The total length of the buffer - @param offset The offset where the `data` buffer should be appended to the - unencoded binary data already residing on the Notecard. This - does not provide random access, but rather ensures alignment - across sequential writes. + @param unencodedData A buffer with data to encode in place + @param unencodedLen The length of the data in the buffer + @param bufLen The total length of the buffer + @param decodedOffset The offset where the data buffer should be appended + to the decoded binary data already residing on the + Notecard. This does not provide random access, but + rather ensures alignment across sequential writes. @returns NULL on success, else an error string pointer. @note Buffers are encoded in place, the buffer _MUST_ be larger than the data to be encoded. The original contents of the buffer will be modified. - @note You may use `NoteBinaryEncodingLength()` to calculate the required size - for the buffer pointed to by the `data` parameter. + @note You may use (`NoteBinaryMaxEncodedLength()` + 1) to calculate the + required size for the buffer pointed to by the `unencodedData` + parameter. */ /**************************************************************************/ -const char * NoteBinaryTransmit(uint8_t *data, uint32_t dataLen, - uint32_t bufLen, uint32_t offset) +const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, + uint32_t bufLen, uint32_t decodedOffset) { // Validate parameter(s) - if (!data) { - NOTE_C_LOG_ERROR("data cannot be NULL"); - return ERRSTR("data cannot be NULL", c_err); + if (!unencodedData) { + NOTE_C_LOG_ERROR("unencodedData cannot be NULL"); + return ERRSTR("unencodedData cannot be NULL", c_err); } // Issue a "card.binary" request. @@ -496,39 +497,40 @@ const char * NoteBinaryTransmit(uint8_t *data, uint32_t dataLen, // Validate the index provided by the caller, against the `length` value // returned from the Notecard to ensure the caller and Notecard agree on // how much data is residing on the Notecard. - if (offset != len) { + if (decodedOffset != len) { NOTE_C_LOG_ERROR("notecard data length is misaligned with offset"); return ERRSTR("notecard data length is misaligned with offset", c_mem); } - // When `offset` is zero, the entire buffer is available - const uint32_t remaining = (offset ? (max - len) : max); - if (dataLen > remaining) { + // When offset is zero, the entire buffer is available + const uint32_t remaining = (decodedOffset ? (max - len) : max); + if (unencodedLen > remaining) { NOTE_C_LOG_ERROR("buffer size exceeds available memory"); return ERRSTR("buffer size exceeds available memory", c_mem); } // Calculate MD5 char hashString[NOTE_MD5_HASH_STRING_SIZE] = {0}; - NoteMD5HashString(data, dataLen, hashString, NOTE_MD5_HASH_STRING_SIZE); + NoteMD5HashString(unencodedData, unencodedLen, hashString, NOTE_MD5_HASH_STRING_SIZE); // Shift the data to the end of the buffer. Next, we'll encode the data, // outputting the encoded data to the front of the buffer. - const uint32_t dataShift = (bufLen - dataLen); - memmove(data + dataShift, data, dataLen); + const uint32_t dataShift = (bufLen - unencodedLen); + memmove(unencodedData + dataShift, unencodedData, unencodedLen); // outLen holds the buffer size available for encoding. The -1 accounts for // one byte of space we need to save for a newline to mark the end of the // packet. When NoteBinaryEncode returns, outLen will hold the encoded // length. uint32_t encLen = (bufLen - sizeof(char)); - err = NoteBinaryEncode(data + dataShift, dataLen, data, &encLen); + uint8_t * const encodedData = unencodedData; + err = NoteBinaryEncode(unencodedData + dataShift, unencodedLen, encodedData, &encLen); if (err) { return err; } // Append the \n, which marks the end of a packet. - data[encLen] = '\n'; + encodedData[encLen] = '\n'; const size_t NOTE_C_BINARY_RETRIES = 3; for (size_t i = 0 ; i < NOTE_C_BINARY_RETRIES ; ++i) { @@ -539,8 +541,8 @@ const char * NoteBinaryTransmit(uint8_t *data, uint32_t dataLen, J *req = NoteNewRequest("card.binary.put"); if (req) { JAddIntToObject(req, "cobs", encLen); - if (offset) { - JAddIntToObject(req, "offset", offset); + if (decodedOffset) { + JAddIntToObject(req, "offset", decodedOffset); } JAddStringToObject(req, "status", hashString); @@ -551,25 +553,25 @@ const char * NoteBinaryTransmit(uint8_t *data, uint32_t dataLen, // On errors, we restore the caller's input buffer by COBS // decoding it. The caller is then able to retry transmission // with their original pointer to this buffer. - NoteBinaryDecode(data, encLen, data, &bufLen); + NoteBinaryDecode(encodedData, encLen, unencodedData, &bufLen); return ERRSTR("failed to initialize binary transaction", c_err); } } else { NOTE_C_LOG_ERROR("unable to allocate request"); _UnlockNote(); - NoteBinaryDecode(data, encLen, data, &bufLen); + NoteBinaryDecode(encodedData, encLen, unencodedData, &bufLen); return ERRSTR("unable to allocate request", c_mem); } // Immediately send the COBS binary. - const char *err = _ChunkedTransmit(data, (encLen + 1), false); + const char *err = _ChunkedTransmit(encodedData, (encLen + 1), false); // Release Notecard Mutex _UnlockNote(); // Ensure transaction was successful if (err) { - NoteBinaryDecode(data, encLen, data, &bufLen); + NoteBinaryDecode(encodedData, encLen, unencodedData, &bufLen); return ERRSTR(err, c_err); } @@ -577,7 +579,7 @@ const char * NoteBinaryTransmit(uint8_t *data, uint32_t dataLen, rsp = NoteRequestResponse(NoteNewRequest("card.binary")); if (!rsp) { NOTE_C_LOG_ERROR("unable to validate request"); - NoteBinaryDecode(data, encLen, data, &bufLen); + NoteBinaryDecode(encodedData, encLen, unencodedData, &bufLen); return ERRSTR("unable to validate request", c_err); } @@ -593,13 +595,13 @@ const char * NoteBinaryTransmit(uint8_t *data, uint32_t dataLen, continue; } NOTE_C_LOG_ERROR("binary data invalid"); - NoteBinaryDecode(data, encLen, data, &bufLen); + NoteBinaryDecode(encodedData, encLen, unencodedData, &bufLen); return ERRSTR("binary data invalid", c_bad); } else { JDelete(rsp); NOTE_C_LOG_ERROR("unexpected error received during " "confirmation"); - NoteBinaryDecode(data, encLen, data, &bufLen); + NoteBinaryDecode(encodedData, encLen, unencodedData, &bufLen); return ERRSTR("unexpected error received during confirmation", c_bad); } diff --git a/note.h b/note.h index 81ca6fd6..ce178e15 100644 --- a/note.h +++ b/note.h @@ -328,9 +328,9 @@ const char * NoteBinaryEncode(const uint8_t *inBuf, uint32_t inLen, uint32_t NoteBinaryMaxDecodedLength(uint32_t bufferSize); uint32_t NoteBinaryMaxEncodedLength(uint32_t unencodedLength); const char * NoteBinaryReceive(uint8_t *buffer, uint32_t bufLen, - uint32_t offset, uint32_t *dataLen); -const char * NoteBinaryTransmit(uint8_t *data, uint32_t dataLen, - uint32_t bufLen, uint32_t offset); + uint32_t decodedOffset, uint32_t *decodedLen); +const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, + uint32_t bufLen, uint32_t decodedOffset); uint32_t NoteSetSTSecs(uint32_t secs); bool NoteTimeValid(void); bool NoteTimeValidST(void); From 29ba8e6c5bc90c0f023326230e11de7cfe59468f Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Thu, 7 Sep 2023 12:36:53 +0000 Subject: [PATCH 17/22] chore: Clarify Doxygen comments --- n_helpers.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/n_helpers.c b/n_helpers.c index 7078a063..3670896e 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -287,8 +287,8 @@ const char * NoteBinaryEncode(const uint8_t *inBuf, uint32_t inLen, //**************************************************************************/ /*! - @brief Compute the worst-case (i.e. maximum) decoded data length - guaranteed to fit into a fixed-size buffer of the given size. + @brief Compute the worst-case (i.e. maximum) decoded data length, + prior to decoding, guaranteed to fit into a fixed-size buffer. @param size The size of the fixed-size buffer. From ebdd8a8e4f379c22e2587aab7ee6bb6af6053e8c Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Thu, 7 Sep 2023 14:26:45 +0000 Subject: [PATCH 18/22] chore: improved API documentation --- n_helpers.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/n_helpers.c b/n_helpers.c index 3670896e..de5eb883 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -288,11 +288,28 @@ const char * NoteBinaryEncode(const uint8_t *inBuf, uint32_t inLen, //**************************************************************************/ /*! @brief Compute the worst-case (i.e. maximum) decoded data length, - prior to decoding, guaranteed to fit into a fixed-size buffer. + prior to encoding, guaranteed to fit into a fixed-size buffer. + + This API is designed for a space constrained environment, where a + working buffer has been allocated to facilitate with binary + transactions. + + There are two primary use cases: + + 1. When data is retrieved from the Notecard, it must be requested in + terms of the unencoded offset and length. However, the data is + encoded prior to transmission, and, as a result, the buffer must be + capable of receiving the encoded (larger) data. This API returns a + length that is safe to request from the Notecard, because the + resulting encoded data is guaranteed to fit in the provided buffer. + 2. When data is transmitted to the Notecard, this API can be used to + verify whether or not unencoded data of a given length will fit in + the provided buffer after encoding. @param size The size of the fixed-size buffer. - @returns The max length of decoded data certain to fit in the buffer. + @returns The max length of unencoded data certain to fit in the buffer after + encoding. */ /**************************************************************************/ uint32_t NoteBinaryMaxDecodedLength(uint32_t bufferSize) @@ -497,7 +514,7 @@ const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, // Validate the index provided by the caller, against the `length` value // returned from the Notecard to ensure the caller and Notecard agree on // how much data is residing on the Notecard. - if (decodedOffset != len) { + if ((long)decodedOffset != len) { NOTE_C_LOG_ERROR("notecard data length is misaligned with offset"); return ERRSTR("notecard data length is misaligned with offset", c_mem); } From 36d5b16b4ae3f377e574dd7099da872cb9dc4198 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Thu, 7 Sep 2023 15:44:52 +0000 Subject: [PATCH 19/22] chore: more documentation clarificiation --- n_helpers.c | 18 +++++++++--------- note.h | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/n_helpers.c b/n_helpers.c index de5eb883..0211df2f 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -456,8 +456,8 @@ const char * NoteBinaryReceive(uint8_t * buffer, uint32_t bufLen, @param unencodedData A buffer with data to encode in place @param unencodedLen The length of the data in the buffer - @param bufLen The total length of the buffer - @param decodedOffset The offset where the data buffer should be appended + @param bufLen The total length of the buffer (see notes) + @param notecardOffset The offset where the data buffer should be appended to the decoded binary data already residing on the Notecard. This does not provide random access, but rather ensures alignment across sequential writes. @@ -466,13 +466,13 @@ const char * NoteBinaryReceive(uint8_t * buffer, uint32_t bufLen, @note Buffers are encoded in place, the buffer _MUST_ be larger than the data to be encoded. The original contents of the buffer will be modified. - @note You may use (`NoteBinaryMaxEncodedLength()` + 1) to calculate the + @note Use (`NoteBinaryMaxEncodedLength()` + sizeof(char)) to calculate the required size for the buffer pointed to by the `unencodedData` - parameter. + parameter, which accommodates the encoded data and newline terminator. */ /**************************************************************************/ const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, - uint32_t bufLen, uint32_t decodedOffset) + uint32_t bufLen, uint32_t notecardOffset) { // Validate parameter(s) if (!unencodedData) { @@ -514,13 +514,13 @@ const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, // Validate the index provided by the caller, against the `length` value // returned from the Notecard to ensure the caller and Notecard agree on // how much data is residing on the Notecard. - if ((long)decodedOffset != len) { + if ((long)notecardOffset != len) { NOTE_C_LOG_ERROR("notecard data length is misaligned with offset"); return ERRSTR("notecard data length is misaligned with offset", c_mem); } // When offset is zero, the entire buffer is available - const uint32_t remaining = (decodedOffset ? (max - len) : max); + const uint32_t remaining = (notecardOffset ? (max - len) : max); if (unencodedLen > remaining) { NOTE_C_LOG_ERROR("buffer size exceeds available memory"); return ERRSTR("buffer size exceeds available memory", c_mem); @@ -558,8 +558,8 @@ const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, J *req = NoteNewRequest("card.binary.put"); if (req) { JAddIntToObject(req, "cobs", encLen); - if (decodedOffset) { - JAddIntToObject(req, "offset", decodedOffset); + if (notecardOffset) { + JAddIntToObject(req, "offset", notecardOffset); } JAddStringToObject(req, "status", hashString); diff --git a/note.h b/note.h index ce178e15..e78757c9 100644 --- a/note.h +++ b/note.h @@ -330,7 +330,7 @@ uint32_t NoteBinaryMaxEncodedLength(uint32_t unencodedLength); const char * NoteBinaryReceive(uint8_t *buffer, uint32_t bufLen, uint32_t decodedOffset, uint32_t *decodedLen); const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, - uint32_t bufLen, uint32_t decodedOffset); + uint32_t bufLen, uint32_t notecardOffset); uint32_t NoteSetSTSecs(uint32_t secs); bool NoteTimeValid(void); bool NoteTimeValidST(void); From 081a9da5fe72d8d7416c2bb6758a29ae2f0f1368 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Thu, 7 Sep 2023 12:42:09 -0500 Subject: [PATCH 20/22] chore: doc wording --- n_helpers.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/n_helpers.c b/n_helpers.c index 0211df2f..28e064eb 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -287,8 +287,8 @@ const char * NoteBinaryEncode(const uint8_t *inBuf, uint32_t inLen, //**************************************************************************/ /*! - @brief Compute the worst-case (i.e. maximum) decoded data length, - prior to encoding, guaranteed to fit into a fixed-size buffer. + @brief Compute the maximum decoded data length, prior to encoding, + guaranteed to fit into a fixed-size buffer. This API is designed for a space constrained environment, where a working buffer has been allocated to facilitate with binary @@ -319,7 +319,7 @@ uint32_t NoteBinaryMaxDecodedLength(uint32_t bufferSize) //**************************************************************************/ /*! - @brief Compute the worst-case (i.e. maximum) buffer size needed to encode + @brief Compute the maximum buffer size needed to encode any unencoded buffer of the given length. @param unencodedLength The length of an unencoded buffer. From 76bf4c1c325fd172dd0ad9135f46c0c895ff13e6 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Thu, 7 Sep 2023 13:00:34 -0500 Subject: [PATCH 21/22] chore: reword doc --- n_helpers.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/n_helpers.c b/n_helpers.c index 28e064eb..8b031129 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -287,8 +287,8 @@ const char * NoteBinaryEncode(const uint8_t *inBuf, uint32_t inLen, //**************************************************************************/ /*! - @brief Compute the maximum decoded data length, prior to encoding, - guaranteed to fit into a fixed-size buffer. + @brief Compute the maximum decoded data length guaranteed + to fit into a fixed-size buffer, after being encoded. This API is designed for a space constrained environment, where a working buffer has been allocated to facilitate with binary @@ -308,8 +308,8 @@ const char * NoteBinaryEncode(const uint8_t *inBuf, uint32_t inLen, @param size The size of the fixed-size buffer. - @returns The max length of unencoded data certain to fit in the buffer after - encoding. + @returns The max length of unencoded data certain to fit in the fixed-size + buffer, after being encoded. */ /**************************************************************************/ uint32_t NoteBinaryMaxDecodedLength(uint32_t bufferSize) From 321b320260af8a29f3c9e80b19ccf643e04899b8 Mon Sep 17 00:00:00 2001 From: "Zachary J. Fields" Date: Thu, 7 Sep 2023 15:27:08 -0500 Subject: [PATCH 22/22] chore: final review comments --- n_helpers.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/n_helpers.c b/n_helpers.c index 8b031129..28ef2178 100644 --- a/n_helpers.c +++ b/n_helpers.c @@ -186,7 +186,7 @@ const char * NoteBinaryDataEncodedLength(uint32_t *len) //**************************************************************************/ /*! - @brief Reset the Notecard's binary buffer + @brief Reset the Notecard's binary buffer. @returns NULL on success, else an error string pointer. @@ -225,7 +225,7 @@ const char * NoteBinaryDataReset(void) @param inBuf The binary payload. @param inLen The length of the binary payload. @param outBuf The buffer to write the decoded payload to. This can be the - same address as inBuf, allowing for in place decoding. + same address as inBuf, allowing for in-place decoding. @param outLen On input, holds the length of outBuf. On output, holds the length of the decoded data. @@ -258,7 +258,7 @@ const char * NoteBinaryDecode(const uint8_t *inBuf, uint32_t inLen, @param inBuf The data to encode. @param inLen The length of the data to encode. @param outBuf The buffer to write the encoded data to. This can be the - same address as inBuf, allowing for in place encoding. + same address as inBuf, allowing for in-place encoding. @param outLen On input, holds the length of outBuf. On output, holds the length of the encoded data. @@ -291,8 +291,7 @@ const char * NoteBinaryEncode(const uint8_t *inBuf, uint32_t inLen, to fit into a fixed-size buffer, after being encoded. This API is designed for a space constrained environment, where a - working buffer has been allocated to facilitate with binary - transactions. + working buffer has been allocated to facilitate binary transactions. There are two primary use cases: @@ -350,9 +349,9 @@ uint32_t NoteBinaryMaxEncodedLength(uint32_t unencodedLength) @note The buffer must be large enough to hold the encoded value of the data store contents from the requested offset for the specified length. - @note To determine the necessary buffer size for a given data length, use - (`NoteBinaryMaxEncodedLength()` + 1), or use - `NoteBinaryDataEncodedLength()` if you wish to consume the entire buffer. + To determine the necessary buffer size for a given data length, use + `(NoteBinaryMaxEncodedLength() + 1)`, or if you wish to consume the + entire buffer use `NoteBinaryDataEncodedLength()` instead. */ /**************************************************************************/ const char * NoteBinaryReceive(uint8_t * buffer, uint32_t bufLen, @@ -367,7 +366,7 @@ const char * NoteBinaryReceive(uint8_t * buffer, uint32_t bufLen, NOTE_C_LOG_ERROR("decodedLen cannot be NULL"); return ERRSTR("decodedLen cannot be NULL", c_err); } - if (bufLen < (cobsEncodedMaxLength(*decodedLen) + sizeof(char))) { + if (bufLen < (cobsEncodedMaxLength(*decodedLen) + 1)) { NOTE_C_LOG_ERROR("insufficient buffer size"); return ERRSTR("insufficient buffer size", c_err); } @@ -466,9 +465,9 @@ const char * NoteBinaryReceive(uint8_t * buffer, uint32_t bufLen, @note Buffers are encoded in place, the buffer _MUST_ be larger than the data to be encoded. The original contents of the buffer will be modified. - @note Use (`NoteBinaryMaxEncodedLength()` + sizeof(char)) to calculate the - required size for the buffer pointed to by the `unencodedData` - parameter, which accommodates the encoded data and newline terminator. + Use `(NoteBinaryMaxEncodedLength() + 1)` to calculate the required size + for the buffer pointed to by the `bufLen` parameter, which MUST + accommodate the encoded data and newline terminator. */ /**************************************************************************/ const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, @@ -519,7 +518,7 @@ const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, return ERRSTR("notecard data length is misaligned with offset", c_mem); } - // When offset is zero, the entire buffer is available + // When offset is zero, the Notecard's entire binary buffer is available const uint32_t remaining = (notecardOffset ? (max - len) : max); if (unencodedLen > remaining) { NOTE_C_LOG_ERROR("buffer size exceeds available memory"); @@ -535,11 +534,11 @@ const char * NoteBinaryTransmit(uint8_t *unencodedData, uint32_t unencodedLen, const uint32_t dataShift = (bufLen - unencodedLen); memmove(unencodedData + dataShift, unencodedData, unencodedLen); - // outLen holds the buffer size available for encoding. The -1 accounts for - // one byte of space we need to save for a newline to mark the end of the - // packet. When NoteBinaryEncode returns, outLen will hold the encoded - // length. - uint32_t encLen = (bufLen - sizeof(char)); + // `encLen` holds the buffer size available for encoding. The `- 1` accounts + // for one byte of space we need to save for a newline to mark the end of + // the packet. When `NoteBinaryEncode()` returns, `encLen` will hold the + // encoded length. + uint32_t encLen = (bufLen - 1); uint8_t * const encodedData = unencodedData; err = NoteBinaryEncode(unencodedData + dataShift, unencodedLen, encodedData, &encLen); if (err) {