Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: support binary chunked receive #93

Merged
merged 22 commits into from
Sep 7, 2023
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 105 additions & 47 deletions n_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -98,8 +140,8 @@ 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,
uint8_t *outBuf, uint32_t *outLen)
const char * NoteBinaryDecode(const uint8_t *inBuf, uint32_t inLen,
haydenroche5 marked this conversation as resolved.
Show resolved Hide resolved
uint8_t *outBuf, uint32_t *outLen)
{
if (inBuf == NULL || outBuf == NULL || outLen == NULL) {
NOTE_C_LOG_ERROR("NULL parameter");
Expand Down Expand Up @@ -128,8 +170,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, uint32_t inLen,
uint8_t *outBuf, uint32_t *outLen)
{
if (inBuf == NULL || outBuf == NULL || outLen == NULL) {
NOTE_C_LOG_ERROR("NULL parameter");
Expand Down Expand Up @@ -182,28 +224,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 < NoteBinaryRequiredBuffer(*dataLen)) {
NOTE_C_LOG_ERROR("insufficient buffer size");
return ERRSTR("insufficient buffer size", c_err);
}
Expand All @@ -215,10 +262,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);
Expand All @@ -241,7 +286,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();
Expand Down Expand Up @@ -290,15 +335,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 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 * 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) {
Expand All @@ -317,7 +385,7 @@ const char * NoteBinaryRequiredRxBuffer(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) {
Expand All @@ -333,22 +401,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
Expand Down Expand Up @@ -390,17 +442,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
haydenroche5 marked this conversation as resolved.
Show resolved Hide resolved
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");
zfields marked this conversation as resolved.
Show resolved Hide resolved
return ERRSTR("dataLen cannot be NULL", c_err);
}

// Issue a "card.binary" request.
J *rsp = NoteRequestResponse(NoteNewRequest("card.binary"));
if (!rsp) {
Expand Down
24 changes: 13 additions & 11 deletions note.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,19 +317,21 @@ 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);
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);
#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);
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);
uint32_t NoteSetSTSecs(uint32_t secs);
bool NoteTimeValid(void);
bool NoteTimeValidST(void);
Expand Down
3 changes: 2 additions & 1 deletion test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,10 @@ 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(NoteBinaryRequiredRxBuffer_test)
add_test(NoteBinaryRequiredRxMaxBuffer_test)
add_test(NoteBinaryReset_test)

if(NOTE_C_COVERAGE)
Expand Down
Loading
Loading