Skip to content

Commit dd0f1ab

Browse files
authored
chore:update note-c (#79)
1 parent c6648e5 commit dd0f1ab

File tree

5 files changed

+303
-31
lines changed

5 files changed

+303
-31
lines changed

library.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=Blues Wireless Notecard
2-
version=1.3.12
2+
version=1.3.13
33
author=Blues Wireless
44
maintainer=Blues Wireless <[email protected]>
55
sentence=An easy to use Notecard Library for Arduino.

src/note-c/n_helpers.c

+261-27
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,8 @@ JTIME NoteTime()
105105
//**************************************************************************/
106106
/*!
107107
@brief Set the number of minutes between refreshes of the time
108-
from the Notecard, to help minimize clock drift on this host.
109-
Set this to 0 for no auto-refresh; it defaults to daily.
108+
from the Notecard, to help minimize clock drift on this host.
109+
Set this to 0 for no auto-refresh; it defaults to daily.
110110
@returns Nothing
111111
*/
112112
/**************************************************************************/
@@ -1043,29 +1043,78 @@ bool NoteGetStatusST(char *statusBuf, int statusBufLen, JTIME *bootTime, bool *r
10431043
return success;
10441044
}
10451045

1046+
//**************************************************************************/
1047+
/*!
1048+
@brief Save the current state and use `card.attn` to set a host
1049+
sleep interval.
1050+
@param payload An optional binary payload to keep in memory while the host sleeps.
1051+
@param seconds The duration to sleep.
1052+
@param modes Optional list of additional `card.attn` modes.
1053+
@returns boolean. `true` if request was successful.
1054+
*/
1055+
/**************************************************************************/
1056+
bool NotePayloadSaveAndSleep(NotePayloadDesc *desc, uint32_t seconds, const char *modes)
1057+
{
1058+
char *stateB64 = NULL;
1059+
1060+
// If specified, encode
1061+
if (desc->data != NULL && desc->length != 0) {
1062+
1063+
// Get length that it will be when converted to base64
1064+
unsigned b64Len = JB64EncodeLen(desc->length);
1065+
1066+
// Convert the state to base64
1067+
stateB64 = _Malloc(b64Len);
1068+
if (stateB64 == NULL) {
1069+
return false;
1070+
}
1071+
1072+
// Encode the state buffer into a string
1073+
JB64Encode(stateB64, (const char *) desc->data, desc->length);
1074+
1075+
}
1076+
1077+
// Sleep
1078+
bool success = NoteSleep(stateB64, seconds, modes);
1079+
1080+
// Free the temp buffer
1081+
if (stateB64 != NULL) {
1082+
_Free(stateB64);
1083+
}
1084+
1085+
// Done
1086+
return success;
1087+
1088+
}
1089+
10461090
//**************************************************************************/
10471091
/*!
10481092
@brief Save the current state and use `card.attn` to set a host
10491093
sleep interval.
10501094
@param stateb64 A base64 payload to keep in memory while the host sleeps.
10511095
@param seconds The duration to sleep.
1052-
@param modes A list of `card.attn` modes.
1096+
@param modes Optional list of additional `card.attn` modes.
10531097
@returns boolean. `true` if request was successful.
10541098
*/
10551099
/**************************************************************************/
10561100
bool NoteSleep(char *stateb64, uint32_t seconds, const char *modes)
10571101
{
10581102
bool success = false;
10591103

1104+
// Trace
1105+
_Debug("ABOUT TO SLEEP\n");
1106+
10601107
// Use a Command rather than a Request so that the Notecard doesn't try to send
10611108
// a response back to us, which would cause a communications error on that end.
10621109
_Debug("requesting sleep\n");
10631110
J *req = NoteNewCommand("card.attn");
10641111
if (req != NULL) {
10651112
// Add the base64 item in a wonderful way that doesn't strdup the huge string
1066-
J *stringReferenceItem = JCreateStringReference(stateb64);
1067-
if (stringReferenceItem != NULL) {
1068-
JAddItemToObject(req, "payload", stringReferenceItem);
1113+
if (stateb64 != NULL) {
1114+
J *stringReferenceItem = JCreateStringReference(stateb64);
1115+
if (stringReferenceItem != NULL) {
1116+
JAddItemToObject(req, "payload", stringReferenceItem);
1117+
}
10691118
}
10701119
char modestr[64];
10711120
strlcpy(modestr, "sleep", sizeof(modestr));
@@ -1078,6 +1127,9 @@ bool NoteSleep(char *stateb64, uint32_t seconds, const char *modes)
10781127
success = NoteRequest(req);
10791128
}
10801129

1130+
// Trace
1131+
_Debug("DIDN'T SLEEP\n");
1132+
10811133
// Done
10821134
return success;
10831135
}
@@ -1094,13 +1146,42 @@ bool NoteSleep(char *stateb64, uint32_t seconds, const char *modes)
10941146
/**************************************************************************/
10951147
bool NoteWake(int stateLen, void *state)
10961148
{
1149+
NotePayloadDesc desc;
1150+
bool success = NotePayloadRetrieveAfterSleep(&desc);
1151+
if (!success) {
1152+
return false;
1153+
}
1154+
if (desc.length != (uint32_t)stateLen) {
1155+
NotePayloadFree(&desc);
1156+
return false;
1157+
}
1158+
memcpy(state, desc.data, stateLen);
1159+
NotePayloadFree(&desc);
1160+
return true;
1161+
}
10971162

1163+
//**************************************************************************/
1164+
/*!
1165+
@brief Wake the module by restoring state into a state buffer, returning
1166+
its length, and fail if it isn't available.
1167+
@param payloadLen (out) Optional place to receive the length of the returned buffer
1168+
@param payload (out) The place to store address of returned in-memory payload
1169+
@returns boolean. `true` if request was successful.
1170+
*/
1171+
/**************************************************************************/
1172+
bool NotePayloadRetrieveAfterSleep(NotePayloadDesc *desc)
1173+
{
1174+
1175+
// Initialize payload descriptor
1176+
if (desc != NULL) {
1177+
memset(desc, 0, sizeof(NotePayloadDesc));
1178+
}
1179+
1180+
// Send the Notecard a request to retrieve the saved state
10981181
J *req = NoteNewRequest("card.attn");
10991182
if (req == NULL) {
11001183
return false;
11011184
}
1102-
1103-
// Send it a command to request the saved state
11041185
JAddBoolToObject(req, "start", true);
11051186
J *rsp = NoteRequestResponse(req);
11061187
if (rsp == NULL) {
@@ -1117,39 +1198,36 @@ bool NoteWake(int stateLen, void *state)
11171198
setTime(seconds);
11181199
}
11191200

1120-
// Exit if no payload
1121-
char *payload = JGetString(rsp, "payload");
1122-
if (payload[0] == '\0') {
1201+
// If we didn't expect any state to be restored, we're done
1202+
if (desc == NULL) {
11231203
NoteDeleteResponse(rsp);
1124-
return false;
1204+
return true;
11251205
}
11261206

1127-
// Exit if the purpose of the call was to intentionally discard saved state
1128-
if (state == NULL) {
1207+
// Exit if no payload, knowing that we expected one
1208+
char *payload = JGetString(rsp, "payload");
1209+
if (payload[0] == '\0') {
11291210
NoteDeleteResponse(rsp);
1130-
return true;
1211+
return false;
11311212
}
11321213

11331214
// Allocate a buffer for the payload. (We can't decode in-place because we can't
11341215
// risk overwriting memory if the actual payload is even slightly different.)
1135-
char *p = (char *) _Malloc(JB64DecodeLen(payload));
1216+
uint32_t allocLen = JB64DecodeLen(payload);
1217+
uint8_t *p = (uint8_t *) _Malloc(allocLen);
11361218
if (p == NULL) {
11371219
NoteDeleteResponse(rsp);
11381220
return false;
11391221
}
1140-
int actualLen = JB64Decode(p, payload);
1141-
if (actualLen != stateLen) {
1142-
_Free(p);
1143-
_Debug("*** discarding saved state\n");
1144-
NoteDeleteResponse(rsp);
1145-
return false;
1146-
}
1147-
memcpy(state, p, stateLen);
1148-
_Free(p);
1222+
uint32_t actualLen = (uint32_t) JB64Decode((char *)p, payload);
11491223

1150-
// State restored
1151-
_Debug("STATE RESTORED\n");
1224+
// Fill out the payload descriptor
1225+
desc->data = p;
1226+
desc->alloc = allocLen;
1227+
desc->length = actualLen;
11521228

1229+
// State restored
1230+
_Debug("AWAKENED SUCCESSFULLY\n");
11531231
NoteDeleteResponse(rsp);
11541232
return true;
11551233
}
@@ -1692,3 +1770,159 @@ uint32_t NoteMemAvailable()
16921770
return total;
16931771

16941772
}
1773+
1774+
//**************************************************************************/
1775+
/*!
1776+
@brief Create a desc from a buffer, or initialize a new to-be-allocated desc
1777+
if the buf is null
1778+
@param desc Pointer to the payload descriptor
1779+
@param buf Pointer to the buffer to initialize the desc with (or NULL)
1780+
@param buflen Length of the buffer to initialize the desc with (or 0)
1781+
*/
1782+
/**************************************************************************/
1783+
void NotePayloadSet(NotePayloadDesc *desc, uint8_t *buf, uint32_t buflen)
1784+
{
1785+
desc->data = buf;
1786+
desc->alloc = buflen;
1787+
desc->length = buflen;
1788+
}
1789+
1790+
//**************************************************************************/
1791+
/*!
1792+
@brief Free the payload pointed to by the descriptor
1793+
@param desc Pointer to the payload descriptor
1794+
*/
1795+
/**************************************************************************/
1796+
void NotePayloadFree(NotePayloadDesc *desc)
1797+
{
1798+
if (desc->data != NULL) {
1799+
_Free(desc->data);
1800+
}
1801+
desc->data = NULL;
1802+
desc->alloc = 0;
1803+
desc->length = 0;
1804+
}
1805+
1806+
//**************************************************************************/
1807+
/*!
1808+
@brief Add a segment to the specified binary with 4-character type code
1809+
@param desc Pointer to the payload descriptor
1810+
@param segtype Pointer to the 4-character payload identifier
1811+
@param data Pointer to the data segment to be appended
1812+
@param len Length of data segment
1813+
@returns boolean. `true` if named segment is appended successfully
1814+
*/
1815+
/**************************************************************************/
1816+
bool NotePayloadAddSegment(NotePayloadDesc *desc, const char segtype[NP_SEGTYPE_LEN], void *data, uint32_t len)
1817+
{
1818+
uint32_t alloc = 512;
1819+
uint32_t hlen = len + NP_SEGHDR_LEN;
1820+
if (hlen > alloc) {
1821+
alloc += hlen;
1822+
}
1823+
if (desc->data == NULL) {
1824+
uint8_t *base = _Malloc(alloc);
1825+
if (base == NULL) {
1826+
return false;
1827+
}
1828+
uint8_t *p = base;
1829+
memcpy(p, segtype, NP_SEGTYPE_LEN);
1830+
p += NP_SEGTYPE_LEN;
1831+
memcpy(p, &len, NP_SEGLEN_LEN);
1832+
p += NP_SEGLEN_LEN;
1833+
memcpy(p, data, len);
1834+
desc->data = base;
1835+
desc->alloc = alloc;
1836+
desc->length = hlen;
1837+
} else if ((desc->alloc - desc->length) < hlen) {
1838+
uint8_t *base = _Malloc(desc->alloc + alloc);
1839+
if (base == NULL) {
1840+
return false;
1841+
}
1842+
uint8_t *p = base;
1843+
memcpy(p, desc->data, desc->length);
1844+
p += desc->length;
1845+
memcpy(p, segtype, NP_SEGTYPE_LEN);
1846+
p += NP_SEGTYPE_LEN;
1847+
memcpy(p, &len, NP_SEGLEN_LEN);
1848+
p += NP_SEGLEN_LEN;
1849+
memcpy(p, data, len);
1850+
_Free(desc->data);
1851+
desc->data = base;
1852+
desc->alloc = desc->alloc + alloc;
1853+
desc->length += hlen;
1854+
} else {
1855+
uint8_t *p = desc->data + desc->length;
1856+
memcpy(p, segtype, NP_SEGTYPE_LEN);
1857+
p += NP_SEGTYPE_LEN;
1858+
memcpy(p, &len, NP_SEGLEN_LEN);
1859+
p += NP_SEGLEN_LEN;
1860+
memcpy(p, data, len);
1861+
desc->length += hlen;
1862+
}
1863+
return true;
1864+
}
1865+
1866+
//**************************************************************************/
1867+
/*!
1868+
@brief Find and copy a named segment from a segmented payload
1869+
@param desc Pointer to the payload descriptor
1870+
@param segtype Pointer to the 4-character payload identifier
1871+
@param pdata Pointer to the found segment if return is true
1872+
@param len The expected length of the returned segment
1873+
@returns boolean. `true` if named segment is restored successfully
1874+
*/
1875+
/**************************************************************************/
1876+
bool NotePayloadGetSegment(NotePayloadDesc *desc, const char segtype[NP_SEGTYPE_LEN], void *pdata, uint32_t len)
1877+
{
1878+
uint8_t *data;
1879+
uint32_t datalen;
1880+
bool success = NotePayloadFindSegment(desc, segtype, &data, &datalen);
1881+
if (success && datalen == len) {
1882+
memcpy(pdata, data, len);
1883+
return true;
1884+
}
1885+
return false;
1886+
}
1887+
1888+
//**************************************************************************/
1889+
/*!
1890+
@brief Find a named segment within a segmented payload
1891+
@param desc Pointer to the payload descriptor
1892+
@param segtype Pointer to the 4-character payload identifier
1893+
@param pdata Pointer to the found segment if return is true
1894+
@param plen Pointer to the returned segment length if return is true
1895+
@returns boolean. `true` if named segment is found
1896+
*/
1897+
/**************************************************************************/
1898+
bool NotePayloadFindSegment(NotePayloadDesc *desc, const char segtype[NP_SEGTYPE_LEN], void *pdata, uint32_t *plen)
1899+
{
1900+
1901+
// Preset returns
1902+
* (uint8_t **) pdata = NULL;
1903+
*plen = 0;
1904+
1905+
// Locate the segment
1906+
uint8_t *p = desc->data;
1907+
uint32_t left = desc->length;
1908+
if (p == NULL) {
1909+
return false;
1910+
}
1911+
while (left >= NP_SEGHDR_LEN) {
1912+
uint32_t len;
1913+
memcpy(&len, p + NP_SEGTYPE_LEN, sizeof(len));
1914+
if (memcmp(p, segtype, NP_SEGTYPE_LEN) == 0) {
1915+
*plen = len;
1916+
* (uint8_t **) pdata = p + NP_SEGHDR_LEN;
1917+
return true;
1918+
}
1919+
len += NP_SEGHDR_LEN;
1920+
p += len;
1921+
if (len > left) {
1922+
left = 0;
1923+
} else {
1924+
left -= len;
1925+
}
1926+
}
1927+
return false;
1928+
}

src/note-c/n_hooks.c

+18-1
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,24 @@ void NoteSetFnDisabled()
323323

324324
//**************************************************************************/
325325
/*!
326-
@brief Write a to the debug stream and output a newline.
326+
@brief Write a number to the debug stream and output a newline.
327+
@param line A debug string for output.
328+
*/
329+
/**************************************************************************/
330+
void NoteDebugIntln(const char *line, int n)
331+
{
332+
if (line != NULL) {
333+
NoteDebug(line);
334+
}
335+
char str[16];
336+
JItoA(n, str);
337+
NoteDebug(str);
338+
NoteDebug(c_newline);
339+
}
340+
341+
//**************************************************************************/
342+
/*!
343+
@brief Write text to the debug stream and output a newline.
327344
@param line A debug string for output.
328345
*/
329346
/**************************************************************************/

0 commit comments

Comments
 (0)