Skip to content

Commit

Permalink
optimize transactions
Browse files Browse the repository at this point in the history
  • Loading branch information
zfields committed Jul 23, 2023
1 parent 132d389 commit e70a374
Show file tree
Hide file tree
Showing 12 changed files with 101 additions and 443 deletions.
1 change: 0 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ target_sources(
${NOTE_C_SRC_DIR}/n_b64.c
${NOTE_C_SRC_DIR}/n_cjson.c
${NOTE_C_SRC_DIR}/n_cjson_helpers.c
${NOTE_C_SRC_DIR}/n_cobs.c
${NOTE_C_SRC_DIR}/n_const.c
${NOTE_C_SRC_DIR}/n_ftoa.c
${NOTE_C_SRC_DIR}/n_helpers.c
Expand Down
135 changes: 0 additions & 135 deletions n_cobs.c

This file was deleted.

176 changes: 0 additions & 176 deletions n_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,182 +81,6 @@ NOTE_C_STATIC void setTime(JTIME seconds);
NOTE_C_STATIC bool timerExpiredSecs(uint32_t *timer, uint32_t periodSecs);
NOTE_C_STATIC int ytodays(int year);

//**************************************************************************/
/*!
@brief Receive a large binary object from the Notecard's binary buffer
@param buffer A buffer to hold the result
@param bufLen The total length of the buffer
@returns NULL on success, else an error string pointer.
@note Buffers are decoded in place, the original contents of the buffer will
be modified.
*/
/**************************************************************************/
const char * NoteBinaryReceive(uint8_t * buffer, size_t bufLen)
{
// Issue a "card.binary" request.
J *rsp = NoteRequestResponse(NoteNewRequest("card.binary"));
if (!rsp) {
return ERRSTR("unable to issue binary request", c_err);
}

// Ensure the transaction doesn't return an error
// to confirm the binary feature is available
if (NoteResponseError(rsp)) {
JDelete(rsp);
return ERRSTR("feature not implemented", c_bad);
}

// Examine "cobs" from the response to evaluate the space
// required to hold the COBS encoded data on the Notecard.
const size_t cobs = JGetInt(rsp,"cobs");
JDelete(rsp);
if (!cobs) {
return ERRSTR("no data on notecard", c_err);
}
if (cobs > bufLen) {
return ERRSTR("insufficient buffer size", c_err);
}

// Issue `card.binary.get` and capture `"status"` from response
char status[NOTE_MD5_HASH_STRING_SIZE] = {0};
J *req = NoteNewRequest("card.binary.get");
if (req) {
JAddIntToObject(req, "cobs", cobs);

// Ensure the transaction doesn't return an error.
J *rsp = NoteRequestResponse(req);
if NoteResponseError(rsp) {
JDelete(rsp);
return ERRSTR("failed to initialize binary transaction", c_err);
}

// Examine "status" from the response to evaluate the MD5 checksum.
strlcpy(status, JGetString(rsp,"status"), NOTE_MD5_HASH_STRING_SIZE);
JDelete(rsp);
}

// `NoteReceiveBytes()` of the COBS encoded bytes either in a single IO of
// `cobsLen`, OR receive until newline and verify that you received
// `cobsLen` bytes, depending upon platform API
(void)buffer;

// Decode it in-place which is safe because decoding shrinks
const size_t decLen = cobsDecode(buffer,bufLen,'\n',buffer);
buffer[decLen] = '\0';

// Verify MD5
char hash_string[NOTE_MD5_HASH_STRING_SIZE] = {0};
NoteMD5HashString(buffer, decLen, hash_string, NOTE_MD5_HASH_STRING_SIZE);
if (strncmp(hash_string, status, NOTE_MD5_HASH_STRING_SIZE)) {
return ERRSTR("data transfer error", c_err);
}

// Return `NULL` if success, else error string pointer
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
@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, and original contents of the buffer will be modified.
You may use `cobsEncodedLength()` to calculate the required size for
the buffer pointed to by the `dst` parameter.
*/
/**************************************************************************/
const char * NoteBinaryTransmit(uint8_t * data, size_t dataLen, size_t bufLen, bool append)
{
// Issue a "card.binary" request.
J *rsp = NoteRequestResponse(NoteNewRequest("card.binary"));
if (!rsp) {
return ERRSTR("unable to issue binary request", c_err);
}

// Ensure the transaction doesn't return an error
// to confirm the binary feature is available
if (NoteResponseError(rsp)) {
JDelete(rsp);
return ERRSTR("feature not implemented", c_bad);
}

// 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");
JDelete(rsp);
if (!max) {
return ERRSTR("unexpected response", c_err);
}
const size_t remaining = (max - len);
if (dataLen > remaining) {
return ERRSTR("buffer size exceeds available memory", c_mem);
}

// Calculate MD5
char hash_string[NOTE_MD5_HASH_STRING_SIZE] = {0};
NoteMD5HashString(data, dataLen, hash_string, NOTE_MD5_HASH_STRING_SIZE);

// Encode COBS data
uint32_t encLen = cobsEncodedLength(data,dataLen);
if (encLen > bufLen) {
return ERRSTR("buffer too small for encoding", c_mem);
}
const size_t data_shift = (bufLen - dataLen);
memmove(data + data_shift, data, dataLen);
encLen = cobsEncode(data + data_shift, dataLen, '\n', data);

// Claim Notecard Mutex
_LockNote();

// Issue a "card.binary.put"
J *req = NoteNewRequest("card.binary.put");
if (req) {
JAddIntToObject(req, "cobs", encLen);
if (append) {
JAddBoolToObject(req, "append", true);
}
JAddStringToObject(req, "status", hash_string);

// Ensure the transaction doesn't return an error.
if (!NoteRequest(req)) {
return ERRSTR("failed to initialize binary transaction", c_err);
}
}

// Immediately send the COBS binary.
const char *errstr = _RawTransaction((char *)data, NULL, false);

// Release Notecard Mutex
_UnlockNote();

// Ensure transaction was successful
if (errstr) {
return ERRSTR(errstr, c_err);
}

// Issue a `"card.binary"` request.
rsp = NoteRequestResponse(NoteNewRequest("card.binary"));
if (!rsp) {
return ERRSTR("unable to validate request", c_err);
}

// Ensure the transaction doesn't return an error
// to confirm your binary was received
if (NoteResponseError(rsp)) {
JDelete(rsp);
// input buffer is no longer valid
return ERRSTR("binary data invalid", c_bad);
}
JDelete(rsp);

// Return `NULL` on success
return NULL;
}

//**************************************************************************/
/*!
@brief Determine if the card time is "real" calendar/clock time, or if
Expand Down
4 changes: 2 additions & 2 deletions n_hooks.c
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ i2cReceiveFn hookI2CReceive = NULL;

// Internal hooks
typedef bool (*nNoteResetFn) (void);
typedef const char * (*nTransactionFn) (const char *, char **);
typedef const char * (*nTransactionFn) (char *, char **);
static nNoteResetFn notecardReset = NULL;
static nTransactionFn notecardTransaction = NULL;

Expand Down Expand Up @@ -827,7 +827,7 @@ bool NoteHardReset()
or the hook has not been set.
*/
/**************************************************************************/
const char *NoteJSONTransaction(const char *request, char **response)
const char *NoteJSONTransaction(char *request, char **response)
{
if (notecardTransaction == NULL || hookActiveInterface == interfaceNone) {
return "i2c or serial interface must be selected";
Expand Down
Loading

0 comments on commit e70a374

Please sign in to comment.