Skip to content

Commit 124eca3

Browse files
authored
feat: v1.8.5 (#164)
* Remove `note-c` before re-add * Squashed 'src/note-c/' content from commit 693d3eb0 git-subtree-dir: src/note-c git-subtree-split: 693d3eb0b10729548668cf770844be1011ec24bc * Remove unneeded directories from `note-c` * feat: v1.8.5 Updated `note-c` dependency
1 parent 39dbf47 commit 124eca3

14 files changed

Lines changed: 185 additions & 122 deletions

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -322,11 +322,11 @@ Inside the dev container:
322322
```sh
323323
tio ~/.notestation/pid-<pid>_<hostname>/host_mcu_usb
324324
```
325-
325+
326326
> _**HINT:** The pseudo-tty devices are located in a folder related to the Notestattion reservations (e.g. `~/.notestation/pid-<pid>_<hostname>/<ptty_device>`)._
327327
328328
> _**HINT:** The devices are named according to their function, for example `host_mcu_usb` is a connection to the host MCU USB._
329-
329+
330330
### Troubleshooting
331331

332332
- Tailscale errors: Verify TS_AUTHKEY, restart containers.

library.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=Blues Wireless Notecard
2-
version=1.8.4
2+
version=1.8.5
33
author=Blues
44
maintainer=Blues <info@blues.com>
55
sentence=An easy to use Notecard Library for Arduino.

src/NoteDefines.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
// Define the version of the `note-arduino` library
55
#define NOTE_ARDUINO_VERSION_MAJOR 1
66
#define NOTE_ARDUINO_VERSION_MINOR 8
7-
#define NOTE_ARDUINO_VERSION_PATCH 4
7+
#define NOTE_ARDUINO_VERSION_PATCH 5
88

99
#define NOTE_ARDUINO_VERSION NOTE_C_STRINGIZE(NOTE_ARDUINO_VERSION_MAJOR) "." NOTE_C_STRINGIZE(NOTE_ARDUINO_VERSION_MINOR) "." NOTE_C_STRINGIZE(NOTE_ARDUINO_VERSION_PATCH)
1010

src/note-c/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# note-c
44

55
The note-c C library for communicating with the
6-
[Blues Wireless][blues] Notecard via serial or I²C.
6+
[Blues Wireless][blues] Notecard via serial or I2C.
77

88
This library allows you to control a Notecard by writing a C
99
or C++ program. Your program may programmatically configure Notecard and send

src/note-c/n_atof.c

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -68,21 +68,22 @@
6868
*/
6969

7070
JNUMBER
71-
JAtoN(string, endPtr)
72-
const char *string; /* A decimal ASCII floating-point number,
73-
* optionally preceded by white space.
74-
* Must have form "-I.FE-X", where I is the
75-
* integer part of the mantissa, F is the
76-
* fractional part of the mantissa, and X
77-
* is the exponent. Either of the signs
78-
* may be "+", "-", or omitted. Either I
79-
* or F may be omitted, or both. The decimal
80-
* point isn't necessary unless F is present.
81-
* The "E" may actually be an "e". E and X
82-
* may both be omitted (but not just one).
83-
*/
84-
char **endPtr; /* If non-NULL, store terminating character's
85-
* address here. */
71+
JAtoN(
72+
const char *string, /* A decimal ASCII floating-point number,
73+
* optionally preceded by white space.
74+
* Must have form "-I.FE-X", where I is the
75+
* integer part of the mantissa, F is the
76+
* fractional part of the mantissa, and X
77+
* is the exponent. Either of the signs
78+
* may be "+", "-", or omitted. Either I
79+
* or F may be omitted, or both. The decimal
80+
* point isn't necessary unless F is present.
81+
* The "E" may actually be an "e". E and X
82+
* may both be omitted (but not just one).
83+
*/
84+
char **endPtr /* If non-NULL, store terminating character's
85+
* address here. */
86+
)
8687
{
8788
int sign, expSign = FALSE;
8889
JNUMBER fraction;

src/note-c/n_cjson.c

Lines changed: 52 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -362,12 +362,12 @@ NOTE_C_STATIC unsigned char* _ensure(printbuffer * const p, size_t needed)
362362
return NULL;
363363
}
364364

365+
needed += p->offset + 1;
365366
if (needed > INT_MAX) {
366367
/* sizes bigger than INT_MAX are currently not supported */
367368
return NULL;
368369
}
369370

370-
needed += p->offset + 1;
371371
if (needed <= p->length) {
372372
return p->buffer + p->offset;
373373
}
@@ -376,19 +376,8 @@ NOTE_C_STATIC unsigned char* _ensure(printbuffer * const p, size_t needed)
376376
return NULL;
377377
}
378378

379-
/* calculate new buffer size */
380-
if (needed > (INT_MAX / 2)) {
381-
/* overflow of int, use INT_MAX if possible */
382-
if (needed <= INT_MAX) {
383-
newsize = INT_MAX;
384-
} else {
385-
return NULL;
386-
}
387-
} else {
388-
newsize = needed * 2;
389-
}
390-
391379
/* otherwise reallocate manually */
380+
newsize = (ALLOC_CHUNK * ((needed / ALLOC_CHUNK) + ((needed % ALLOC_CHUNK) > 0))); // chunked, linear calculation for new buffer to reduce memory waste
392381
newbuffer = (unsigned char*)_Malloc(newsize);
393382
if (!newbuffer) {
394383
_Free(p->buffer);
@@ -1819,9 +1808,12 @@ NOTE_C_STATIC Jbool _add_item_to_array(J *array, J *item)
18191808
N_CJSON_PUBLIC(void) JAddItemToArray(J *array, J *item)
18201809
{
18211810
if (array == NULL || item == NULL) {
1811+
JDelete(item);
18221812
return;
18231813
}
1824-
_add_item_to_array(array, item);
1814+
if (!_add_item_to_array(array, item)) {
1815+
JDelete(item);
1816+
}
18251817
}
18261818

18271819
#if defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
@@ -1874,34 +1866,46 @@ NOTE_C_STATIC Jbool _add_item_to_object(J * const object, const char * const str
18741866
N_CJSON_PUBLIC(void) JAddItemToObject(J *object, const char *string, J *item)
18751867
{
18761868
if (object == NULL || string == NULL || item == NULL) {
1869+
JDelete(item);
18771870
return;
18781871
}
1879-
_add_item_to_object(object, string, item, false);
1872+
if (!_add_item_to_object(object, string, item, false)) {
1873+
JDelete(item);
1874+
}
18801875
}
18811876

18821877
/* Add an item to an object with constant string as key */
18831878
N_CJSON_PUBLIC(void) JAddItemToObjectCS(J *object, const char *string, J *item)
18841879
{
18851880
if (object == NULL || string == NULL || item == NULL) {
1881+
JDelete(item);
18861882
return;
18871883
}
1888-
_add_item_to_object(object, string, item, true);
1884+
if (!_add_item_to_object(object, string, item, true)) {
1885+
JDelete(item);
1886+
}
18891887
}
18901888

18911889
N_CJSON_PUBLIC(void) JAddItemReferenceToArray(J *array, J *item)
18921890
{
18931891
if (array == NULL || item == NULL) {
18941892
return;
18951893
}
1896-
_add_item_to_array(array, _create_reference(item));
1894+
J *ref = _create_reference(item);
1895+
if (!_add_item_to_array(array, ref)) {
1896+
JDelete(ref);
1897+
}
18971898
}
18981899

18991900
N_CJSON_PUBLIC(void) JAddItemReferenceToObject(J *object, const char *string, J *item)
19001901
{
19011902
if (object == NULL || string == NULL || item == NULL) {
19021903
return;
19031904
}
1904-
_add_item_to_object(object, string, _create_reference(item), false);
1905+
J *ref = _create_reference(item);
1906+
if (!_add_item_to_object(object, string, ref, false)) {
1907+
JDelete(ref);
1908+
}
19051909
}
19061910

19071911
N_CJSON_PUBLIC(J*) JAddTrueToObject(J * const object, const char * const name)
@@ -2170,18 +2174,22 @@ N_CJSON_PUBLIC(void) JDeleteItemFromObjectCaseSensitive(J *object, const char *s
21702174
N_CJSON_PUBLIC(void) JInsertItemInArray(J *array, int which, J *newitem)
21712175
{
21722176
if (array == NULL || newitem == NULL) {
2177+
JDelete(newitem);
21732178
return;
21742179
}
21752180

21762181
J *after_inserted = NULL;
21772182

21782183
if (which < 0) {
2184+
JDelete(newitem);
21792185
return;
21802186
}
21812187

21822188
after_inserted = _get_array_item(array, (size_t)which);
21832189
if (after_inserted == NULL) {
2184-
_add_item_to_array(array, newitem);
2190+
if (!_add_item_to_array(array, newitem)) {
2191+
JDelete(newitem);
2192+
}
21852193
return;
21862194
}
21872195

@@ -2228,14 +2236,18 @@ N_CJSON_PUBLIC(Jbool) JReplaceItemViaPointer(J * const parent, J * const item, J
22282236
N_CJSON_PUBLIC(void) JReplaceItemInArray(J *array, int which, J *newitem)
22292237
{
22302238
if (array == NULL || newitem == NULL) {
2239+
JDelete(newitem);
22312240
return;
22322241
}
22332242

22342243
if (which < 0) {
2244+
JDelete(newitem);
22352245
return;
22362246
}
22372247

2238-
JReplaceItemViaPointer(array, _get_array_item(array, (size_t)which), newitem);
2248+
if (!JReplaceItemViaPointer(array, _get_array_item(array, (size_t)which), newitem)) {
2249+
JDelete(newitem);
2250+
}
22392251
}
22402252

22412253
NOTE_C_STATIC Jbool _replace_item_in_object(J *object, const char *string, J *replacement, Jbool case_sensitive)
@@ -2244,32 +2256,48 @@ NOTE_C_STATIC Jbool _replace_item_in_object(J *object, const char *string, J *re
22442256
return false;
22452257
}
22462258

2259+
J *existing = _get_object_item(object, string, case_sensitive);
2260+
if (existing == NULL) {
2261+
return false;
2262+
}
2263+
2264+
char *new_key = (char*)_j_strdup((const unsigned char*)string);
2265+
if (new_key == NULL) {
2266+
return false;
2267+
}
2268+
22472269
/* replace the name in the replacement */
22482270
if (!(replacement->type & JStringIsConst) && (replacement->string != NULL)) {
22492271
_Free(replacement->string);
22502272
}
2251-
replacement->string = (char*)_j_strdup((const unsigned char*)string);
2273+
replacement->string = new_key;
22522274
replacement->type &= ~JStringIsConst;
22532275

2254-
JReplaceItemViaPointer(object, _get_object_item(object, string, case_sensitive), replacement);
2276+
JReplaceItemViaPointer(object, existing, replacement);
22552277

22562278
return true;
22572279
}
22582280

22592281
N_CJSON_PUBLIC(void) JReplaceItemInObject(J *object, const char *string, J *newitem)
22602282
{
22612283
if (object == NULL || newitem == NULL) {
2284+
JDelete(newitem);
22622285
return;
22632286
}
2264-
_replace_item_in_object(object, string, newitem, false);
2287+
if (!_replace_item_in_object(object, string, newitem, false)) {
2288+
JDelete(newitem);
2289+
}
22652290
}
22662291

22672292
N_CJSON_PUBLIC(void) JReplaceItemInObjectCaseSensitive(J *object, const char *string, J *newitem)
22682293
{
22692294
if (object == NULL || newitem == NULL) {
2295+
JDelete(newitem);
22702296
return;
22712297
}
2272-
_replace_item_in_object(object, string, newitem, true);
2298+
if (!_replace_item_in_object(object, string, newitem, true)) {
2299+
JDelete(newitem);
2300+
}
22732301
}
22742302

22752303
N_CJSON_PUBLIC(J *) JCreateTrue(void)

src/note-c/n_cjson_helpers.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ bool JAddBinaryToObject(J *json, const char *fieldName, const void *binaryData,
229229
return false;
230230
}
231231
JAddItemToObject(json, fieldName, stringItem);
232-
return true;
232+
return JIsPresent(json, fieldName);
233233
}
234234

235235
bool JGetBinaryFromObject(J *json, const char *fieldName, uint8_t **retBinaryData, uint32_t *retBinaryDataLen)

src/note-c/n_cobs.c

Lines changed: 45 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -244,20 +244,26 @@ uint32_t _cobsEncodedLength(const uint8_t *ptr, uint32_t length)
244244
245245
@param length Length of the data to encode
246246
247-
@return The max length required to encode the data
247+
@return The max length required to encode the data (including EOP byte)
248+
249+
@note Worst case is input with no zero bytes (no EOP markers to replace).
250+
The COBS encoder always emits 1 initial code byte, then 1 additional
251+
code byte for every 254 data bytes processed:
252+
253+
codeBytes = floor(length / 254) + 1
254+
255+
IMPORTANT: This is NOT ceil(length / 254). They differ at exact
256+
multiples of 254. Example: encoding 254 non-zero bytes produces
257+
code byte 0xFF, 254 data bytes, then a final code byte 0x01.
258+
That's 2 code bytes, but ceil(254/254) = 1 (wrong).
248259
249-
@note Since the contents of the buffer are unknown, then we must assume
250-
that the entire buffer has no end-of-packet markers. This would
251-
require the injection of overhead bytes (as opposed to the
252-
replacement of end-of-packet markers with overhead bytes) at
253-
intervals of 255, thus producing the worst case scenario.
254260
@note An additional byte is added for the EOP (end-of-packet) marker.
255261
*/
256262
/**************************************************************************/
257263
uint32_t _cobsEncodedMaxLength(uint32_t length)
258264
{
259-
const uint32_t overheadBytes = (length == 0) + ((length != 0) * ((length / COBS_MAX_PACKET_SIZE) + ((length % COBS_MAX_PACKET_SIZE) > 0)));
260-
return (length + overheadBytes + COBS_EOP_OVERHEAD);
265+
const uint32_t codeBytes = (length / COBS_MAX_PACKET_SIZE) + 1;
266+
return (length + codeBytes + COBS_EOP_OVERHEAD);
261267
}
262268

263269
//**************************************************************************/
@@ -267,36 +273,40 @@ uint32_t _cobsEncodedMaxLength(uint32_t length)
267273
268274
@param bufLen Length of the buffer in bytes
269275
270-
@return the length of unencoded data
276+
@return the length of unencoded data that is guaranteed to fit when
277+
COBS-encoded into bufLen bytes (including EOP)
278+
279+
@note The COBS encoder always emits 1 initial code byte, then 1 additional
280+
code byte for every 254 data bytes. Therefore:
281+
282+
codeBytes(u) = floor(u / 254) + 1
283+
284+
IMPORTANT: This is NOT ceil(u / 254). They differ at exact multiples
285+
of 254. Example: encoding 254 non-zero bytes produces code 0xFF,
286+
254 data bytes, then final code 0x01 -- that's 2 code bytes, but
287+
ceil(254/254) = 1 (wrong).
271288
272-
@note An additional byte for the EOP (end-of-packet) marker is assumed.
289+
Buffer requirement: bufLen >= u + floor(u/254) + 1 + 1(EOP)
290+
= u + floor(u/254) + 2
291+
292+
Inversion: find max u where u + floor(u/254) <= t, with t = bufLen-2.
293+
Substituting u = 254q + r (0 <= r <= 253): 255q + r <= t.
294+
295+
Closed form: u = t - floor((t + 1) / 255)
296+
297+
Proof: Let t+1 = 255k + j (0 <= j <= 254), so u = 254k + j - 1.
298+
j >= 1: floor(u/254)=k, u+floor(u/254) = 255k+j-1 = t. Exact fit.
299+
j = 0: u=254(k-1)+253, floor(u/254)=k-1, sum = t-1. One byte slack.
300+
In both cases u+1 would exceed t, confirming u is the maximum.
301+
302+
@see _cobsEncodedMaxLength()
273303
*/
274304
/**************************************************************************/
275305
uint32_t _cobsGuaranteedFit(uint32_t bufLen)
276306
{
277-
// encodedLen = unencodedLen + codeBytesLen
278-
// e = u + c (e = encoded (sorry Euler), and c = code bytes (sorry Einstein))
279-
// u = e - c
280-
// c = ⌈u / 254⌉ (the ceiling of u divided by 254)
281-
//
282-
// Rearranging the ceiling equation:
283-
// (c - 1) < u / 254 <= c
284-
// 254(c - 1) < u <= 254c
285-
//
286-
// Substitute u from first equation:
287-
// 254(c - 1) < e - c <= 254c
288-
// 254c - 254 < e - c <= 254c
289-
// 255c < e + 254 AND e <= 255c
290-
//
291-
// Thus:
292-
// e <= 255c < e + 254
293-
// e / 255 <= c < (e + 254) / 255
294-
//
295-
// Knowing that c is an integer, we can express c as:
296-
// c = ⌊(e + 254) / 255⌋ (the floor of (e + 254) divided by 255)
297-
//
298-
// Substitute c back into the original equation for u:
299-
// u = e - ⌊(e + 254) / 255⌋
300-
const uint32_t encodedLen = (bufLen == 0) + ((bufLen != 0) * (bufLen - COBS_EOP_OVERHEAD));
301-
return (encodedLen - ((encodedLen + COBS_MAX_PACKET_SIZE) / 255));
307+
if (bufLen <= 2) {
308+
return 0;
309+
}
310+
const uint32_t t = bufLen - 2;
311+
return (t - ((t + 1) / 255));
302312
}

0 commit comments

Comments
 (0)