• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

blues / note-arduino / 15449979450

04 Jun 2025 06:32PM UTC coverage: 88.189%. Remained the same
15449979450

Pull #145

github

web-flow
Merge dd818d16f into f7555f266
Pull Request #145: version v1.7.1

111 of 165 branches covered (67.27%)

Branch coverage included in aggregate %.

337 of 343 relevant lines covered (98.25%)

14.76 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.74
/src/Notecard.cpp
1
/*!
2
 * @file Notecard.cpp
3
 *
4
 * @mainpage Arduino Library for the Notecard
5
 *
6
 * @section intro_sec Introduction
7
 *
8
 * The note-arduino Arduino library for communicating with the
9
 * <a href="https://blues.com">Blues</a>
10
 * Notecard via serial or I2C.
11
 *
12
 * This library allows you to control a Notecard by writing an Arduino sketch in
13
 * C or C++. Your sketch may programmatically configure Notecard and send Notes
14
 * to <a href="https://notehub.io">Notehub.io</a>.
15
 *
16
 * @section dependencies Dependencies
17
 *
18
 * This library is a wrapper around and depends upon the
19
 * <a href="https://github.com/blues/note-c">note-c library</a>, which it
20
 * includes as a git subtree.
21
 *
22
 * In addition, this library requires a physical
23
 * connection to a Notecard over I2C or Serial to be functional.
24
 *
25
 * @section author Author
26
 *
27
 * Written by Ray Ozzie and Brandon Satrom for Blues Inc.
28
 *
29
 * @section license License
30
 *
31
 * Copyright (c) 2019 Blues Inc. MIT License. Use of this source code is
32
 * governed by licenses granted by the copyright holder including that found in
33
 * the
34
 * <a href="https://github.com/blues/note-arduino/blob/master/LICENSE">LICENSE</a>
35
 * file.
36
 *
37
 */
38

39
#include "Notecard.h"
40

41
#include <stdarg.h>
42
#include <stdio.h>
43
#include <stdlib.h>
44

45
#include "NoteTime.h"
46

47
/***************************************************************************
48
 SINGLETON ABSTRACTION (REQUIRED BY NOTE-C)
49
 ***************************************************************************/
50

51
namespace
52
{
53
NoteI2c *noteI2c(nullptr);
54

55
const char *noteI2cReceive(uint16_t device_address_, uint8_t *buffer_, uint16_t size_, uint32_t *available_)
8✔
56
{
57
    const char *result;
58
    if (noteI2c) {
8✔
59
        result = noteI2c->receive(device_address_, buffer_, size_, available_);
6✔
60
    } else {
61
        result = "i2c: A call to Notecard::begin() is required. {io}";
2✔
62
    }
63
    return result;
8✔
64
}
65

66
bool noteI2cReset(uint16_t device_address_)
5✔
67
{
68
    bool result;
69
    if (noteI2c) {
5✔
70
        result = noteI2c->reset(device_address_);
3✔
71
    } else {
72
        result = false;
2✔
73
    }
74
    return result;
5✔
75
}
76

77
const char *noteI2cTransmit(uint16_t device_address_, uint8_t *buffer_, uint16_t size_)
7✔
78
{
79
    const char *result;
80
    if (noteI2c) {
7✔
81
        result = noteI2c->transmit(device_address_, buffer_, size_);
5✔
82
    } else {
83
        result = "i2c: A call to Notecard::begin() is required. {io}";
2✔
84
    }
85
    return result;
7✔
86
}
87

88
NoteLog *noteLog(nullptr);
89

90
size_t noteLogPrint(const char * message_)
5✔
91
{
92
    size_t result;
93
    if (noteLog) {
5✔
94
        result = noteLog->print(message_);
3✔
95
    } else {
96
        result = 0;
2✔
97
    }
98
    return result;
5✔
99
}
100

101
NoteSerial *noteSerial(nullptr);
102

103
bool noteSerialAvailable(void)
4✔
104
{
105
    bool result;
106
    if (noteSerial) {
4✔
107
        result = noteSerial->available();
2✔
108
    } else {
109
        result = false;
2✔
110
    }
111
    return result;
4✔
112
}
113

114
char noteSerialReceive(void)
4✔
115
{
116
    char result;
117
    if (noteSerial) {
4✔
118
        result = noteSerial->receive();
2✔
119
    } else {
120
        result = '\0';
2✔
121
    }
122
    return result;
4✔
123
}
124

125
bool noteSerialReset(void)
4✔
126
{
127
    bool result;
128
    if (noteSerial) {
4✔
129
        result = noteSerial->reset();
2✔
130
    } else {
131
        result = false;
2✔
132
    }
133
    return result;
4✔
134
}
135

136
void noteSerialTransmit(uint8_t *text_, size_t len_, bool flush_)
5✔
137
{
138
    if (noteSerial) {
5✔
139
        noteSerial->transmit(text_, len_, flush_);
4✔
140
    }
141
}
5✔
142

143
NoteTxn *noteTxn(nullptr);
144

145
bool noteTransactionStart (uint32_t timeout_ms_) {
5✔
146
    bool result;
147
    if (noteTxn) {
5✔
148
        result = noteTxn->start(timeout_ms_);
3✔
149
    } else {
150
        // NoteTransaction not set, assume unnecessary
151
        result = true;
2✔
152
    }
153
    return result;
5✔
154
}
155

156
void noteTransactionStop (void) {
2✔
157
    if (noteTxn) {
2✔
158
        noteTxn->stop();
1✔
159
    }
160
}
2✔
161

162
}
163

164
/**************************************************************************/
165
/*!
166
    @brief  Platform Initialization for the Notecard.
167
            This function configures system functions to be used
168
            by the Notecard.
169
    @param    assignCallbacks
170
              When `true` the system callbacks will be assigned,
171
              when `false` the system callbacks will be cleared.
172
    @param    i2cmax
173
              The max length of each message to send from the host to
174
              the Notecard. Used to ensure the messages are sized appropriately
175
              for the host.
176
    @param    wirePort
177
              The TwoWire implementation to use for I2C communication.
178
*/
179
/**************************************************************************/
180
void Notecard::platformInit (bool assignCallbacks)
104✔
181
{
182
    NoteSetUserAgent((char *) ("note-arduino " NOTE_ARDUINO_VERSION));
104✔
183
    if (assignCallbacks) {
104✔
184
        NoteSetFnDefault(malloc, free, noteDelay, noteMillis);
65✔
185
    } else {
186
        NoteSetFnDefault(nullptr, nullptr, nullptr, nullptr);
39✔
187
    }
188
}
104✔
189

190
/***************************************************************************
191
 PUBLIC FUNCTIONS
192
 ***************************************************************************/
193

194
Notecard::~Notecard (void)
133✔
195
{
196
    // Delete Singleton(s)
197
    noteI2c = make_note_i2c(nullptr);
133✔
198
    noteLog = make_note_log(nullptr);
133✔
199
    noteSerial = make_note_serial(nullptr);
133✔
200
    noteTxn = make_note_txn(nullptr);
133✔
201
}
133✔
202

203
/**************************************************************************/
204
/*!
205
    @brief  Initialize the Notecard for I2C.
206
            This function configures the Notecard to use the I2C
207
            bus for communication with the host.
208
    @param    noteI2c
209
              A platform specific I2C implementation to use for
210
              communicating with the Notecard from the host.
211
    @param    i2cAddress
212
              The I2C Address to use for the Notecard.
213
    @param    i2cMax
214
              The max length of each message to send from the host
215
              to the Notecard. Used to ensure the messages are sized
216
              appropriately for the host.
217
*/
218
/**************************************************************************/
219
void Notecard::begin(NoteI2c * noteI2c_, uint32_t i2cAddress_, uint32_t i2cMax_)
51✔
220
{
221
    noteI2c = noteI2c_;
51✔
222
    platformInit(noteI2c);
51✔
223
    if (noteI2c) {
51✔
224
        NoteSetFnI2C(i2cAddress_, i2cMax_, noteI2cReset,
35✔
225
                    noteI2cTransmit, noteI2cReceive);
226
    } else {
227
        NoteSetFnI2C(0, 0, nullptr, nullptr, nullptr);
16✔
228
    }
229
}
51✔
230

231
/**************************************************************************/
232
/*!
233
    @brief  Initialize the Notecard for Serial communication.
234
            This function configures the Notecard to use Serial
235
            for communication with the host.
236
    @param    noteSerial
237
              A platform specific serial implementation to use for
238
              communicating with the Notecard from the host.
239
*/
240
/**************************************************************************/
241
void Notecard::begin(NoteSerial * noteSerial_)
46✔
242
{
243
    noteSerial = noteSerial_;
46✔
244
    platformInit(noteSerial);
46✔
245
    if (noteSerial) {
46✔
246
        NoteSetFnSerial(noteSerialReset, noteSerialTransmit,
30✔
247
                        noteSerialAvailable, noteSerialReceive);
248
    } else {
249
        NoteSetFnSerial(nullptr, nullptr, nullptr, nullptr);
16✔
250
    }
251
}
46✔
252

253
/**************************************************************************/
254
/*!
255
    @brief  Periodically show Notecard sync status, returning `TRUE`
256
            if something was displayed to the debug stream.
257
    @param    pollFrequencyMs
258
              The frequency to poll the Notecard for sync status.
259
    @param    maxLevel
260
              The maximum log level to output to the debug console. Pass
261
              -1 for all.
262
    @return `true` if a pending response was displayed to the debug stream.
263
*/
264
/**************************************************************************/
265
bool Notecard::debugSyncStatus(int pollFrequencyMs, int maxLevel)
3✔
266
{
267
    return NoteDebugSyncStatus(pollFrequencyMs, maxLevel);
3✔
268
}
269

270
/**************************************************************************/
271
/*!
272
    @brief  Deletes a `J` JSON response object from memory.
273
    @param    rsp
274
              A `J` JSON response object.
275
*/
276
/**************************************************************************/
277
void Notecard::deleteResponse(J *rsp) const
1✔
278
{
279
    NoteDeleteResponse(rsp);
1✔
280
}
1✔
281

282
/**************************************************************************/
283
/*!
284
    @brief  Deinitialize the Notecard object communication.
285
            This function clears the Notecard object's communication
286
            interfaces, and frees all associated memory.
287
*/
288
/**************************************************************************/
289
void Notecard::end(void)
7✔
290
{
291
    // Clear I2C Interface
292
    i2cTransmitFn i2c_is_set = nullptr;
7✔
293
    NoteGetFnI2C(nullptr, nullptr, nullptr, &i2c_is_set, nullptr);
7!
294
    if (i2c_is_set) {
7✔
295
        // Delete Singletons
296
        noteI2c = make_note_i2c(nullptr);
2!
297
        NoteSetFnI2C(0, 0, nullptr, nullptr, nullptr);
2!
298
    }
299

300
    // Clear Serial Interface
301
    serialTransmitFn serial_is_set = nullptr;
7✔
302
    NoteGetFnSerial(nullptr, &serial_is_set, nullptr, nullptr);
7!
303
    if (serial_is_set) {
7✔
304
        // Delete Singletons
305
        noteSerial = make_note_serial(nullptr);
3!
306
        NoteSetFnSerial(nullptr, nullptr, nullptr, nullptr);
3!
307
    }
308

309
    // Clear Platform Callbacks
310
    platformInit(false);
7!
311
}
7✔
312

313
/**************************************************************************/
314
/*!
315
    @deprecated NoteDebug, which this function wraps, should be treated as an
316
    internal Notecard logging function, used only by the library itself
317
    (note-arduino and note-c) and not its users.
318
    @brief  Write a message to the serial debug stream.
319
    @param    message
320
              A string to log to the serial debug stream.
321
*/
322
/**************************************************************************/
323
NOTE_ARDUINO_DEPRECATED void Notecard::logDebug(const char *message) const
1✔
324
{
325
#ifdef NOTE_ARDUINO_NO_DEPRECATED_ATTR
326
    NOTE_C_LOG_WARN("logDebug is deprecated.")
327
#endif
328
    NoteDebug(message);
1✔
329
}
1✔
330

331
/**************************************************************************/
332
/*!
333
    @deprecated NoteDebug, which this function wraps, should be treated as an
334
    internal Notecard logging function, used only by the library itself
335
    (note-arduino and note-c) and not its users.
336
    @brief  Write a formatted message to the serial debug stream.
337
    @param    format
338
              A format string to log to the serial debug stream.
339
    @param    ... one or more values to interpolate into the format string.
340
*/
341
/**************************************************************************/
342
NOTE_ARDUINO_DEPRECATED void Notecard::logDebugf(const char *format, ...) const
1✔
343
{
344
    char message[256];
345
    va_list args;
346
    va_start(args, format);
1✔
347
    vsnprintf(message, sizeof(message), format, args);
1✔
348
    va_end(args);
1✔
349

350
#ifdef NOTE_ARDUINO_NO_DEPRECATED_ATTR
351
    NOTE_C_LOG_WARN("logDebugf is deprecated.")
352
#endif
353
    NoteDebug(message);
1!
354
}
1✔
355

356
/**************************************************************************/
357
/*!
358
    @brief  Creates a new command object for population by the host.
359
            This function accepts a command string (for example, `"note.add"`)
360
            and initializes a JSON Object to return to the host.
361
    @param    request
362
              The command name, for example, `note.add`.
363
    @return A `J` JSON Object populated with the request name.
364
*/
365
/**************************************************************************/
366
J *Notecard::newCommand(const char *request) const
2✔
367
{
368
    return NoteNewCommand(request);
2✔
369
}
370

371
/**************************************************************************/
372
/*!
373
    @brief  Creates a new request object for population by the host.
374
            This function accepts a request string (for example, `"note.add"`)
375
            and initializes a JSON Object to return to the host.
376
    @param    request
377
              The request name, for example, `note.add`.
378
    @return A `J` JSON Object populated with the request name.
379
*/
380
/**************************************************************************/
381
J *Notecard::newRequest(const char *request) const
2✔
382
{
383
    return NoteNewRequest(request);
2✔
384
}
385

386
/**************************************************************************/
387
/*!
388
    @brief  Sends a request to the Notecard and returns the JSON Response.
389
            This function takes a populated `J` JSON request object
390
            and sends it to the Notecard.
391
    @param    req
392
              A `J` JSON request object.
393
    @return `J` JSON Object with the response from the Notecard.
394
*/
395
/**************************************************************************/
396
J *Notecard::requestAndResponse(J *req) const
2✔
397
{
398
    return NoteRequestResponse(req);
2✔
399
}
400

401
/**************************************************************************/
402
/*!
403
    @brief  Sends a request to the Notecard, retrying it on failure until the
404
            provided timeout interval lapses, and returns the JSON response.
405
    @param    req
406
              A `J` JSON request object.
407
    @param    timeoutSeconds
408
              The timeout interval, in seconds.
409
    @return `J` JSON Object with the response from the Notecard.
410
*/
411
/**************************************************************************/
412
J *Notecard::requestAndResponseWithRetry(J *req, uint32_t timeoutSeconds) const
3✔
413
{
414
    return NoteRequestResponseWithRetry(req, timeoutSeconds);
3✔
415
}
416

417
/**************************************************************************/
418
/*!
419
    @brief  Determines if there is an error string present in a response object.
420
    @param    rsp
421
              A `J` JSON Response object.
422
    @return `true` if the response object contains an error.
423
*/
424
/**************************************************************************/
425
bool Notecard::responseError(J *rsp) const
2✔
426
{
427
    return NoteResponseError(rsp);
2✔
428
}
429

430
/**************************************************************************/
431
/*!
432
    @brief  Sends a request to the Notecard.
433
            This function takes a populated `J` JSON request object
434
            and sends it to the Notecard.
435
    @param    req
436
              A `J` JSON request object.
437
    @return `True` if the message was successfully sent to the Notecard,
438
            `False` if there was an error.
439
*/
440
/**************************************************************************/
441
bool Notecard::sendRequest(J *req) const
2✔
442
{
443
    return NoteRequest(req);
2✔
444
}
445

446
/**************************************************************************/
447
/*!
448
    @brief  Sends a request to the Notecard, retrying it on failure until the
449
            provided timeout interval lapses.
450
    @param    req
451
              A `J` JSON request object.
452
    @param    timeoutSeconds
453
              The timeout interval, in seconds.
454
    @return `True` if the message was successfully sent to the Notecard,
455
            `False` if the message couldn't be sent.
456
*/
457
/**************************************************************************/
458
bool Notecard::sendRequestWithRetry(J *req, uint32_t timeoutSeconds) const
3✔
459
{
460
    return NoteRequestWithRetry(req, timeoutSeconds);
3✔
461
}
462

463
/**************************************************************************/
464
/*!
465
    @brief  Set the debug output source.
466
            A NoteLog object will be constructed via `make_note_log()`
467
            using a platform specific logging channel (for example, `Serial`
468
            on Arduino). The specified channel will be configured as the
469
            source for debug messages provided to `notecard.logDebug()`.
470
    @param    noteLog
471
              A platform specific log implementation to be used for
472
              debug output.
473
*/
474
/**************************************************************************/
475
void Notecard::setDebugOutputStream(NoteLog * noteLog_)
10✔
476
{
477
    noteLog = noteLog_;
10✔
478
    if (noteLog) {
10✔
479
        NoteSetFnDebugOutput(noteLogPrint);
6✔
480
    } else {
481
        make_note_log(nullptr);  // Clear singleton
4✔
482
        NoteSetFnDebugOutput(nullptr);
4✔
483
    }
484
}
10✔
485

486
/**************************************************************************/
487
/*!
488
    @brief  Override default memory management and timing functions.
489
    @param    mallocHook
490
              A memory allocation hook.
491
    @param    freeHook
492
              A memory deallocation hook.
493
    @param    delayMsHook
494
              A delay execution hook.
495
    @param    getMsHook
496
              A get current time hook.
497
*/
498
/**************************************************************************/
499
void Notecard::setFn(mallocFn mallocHook, freeFn freeHook, delayMsFn delayMsHook, getMsFn getMsHook) {
4✔
500
    NoteSetFn(mallocHook, freeHook, delayMsHook, getMsHook);
4✔
501
}
4✔
502

503
/**************************************************************************/
504
/*!
505
    @brief  Set the lock/unlock functions the Notecard uses for I2C access.
506
    @param    lockI2cFn
507
              A user-defined callback that blocks until access to the I2C
508
              bus has become available, then returns with ownership of the
509
              I2C bus.
510
    @param    unlockI2cFn
511
              A user-defined callback that releases ownership of the
512
              I2C bus taken during the call to `lockI2cFn()`.
513
*/
514
/**************************************************************************/
515
void Notecard::setFnI2cMutex(mutexFn lockI2cFn_, mutexFn unlockI2cFn_) {
2✔
516
    NoteSetFnI2CMutex(lockI2cFn_, unlockI2cFn_);
2✔
517
}
2✔
518

519
/**************************************************************************/
520
/*!
521
    @brief  Set the lock/unlock functions the host MCU uses to ensure
522
            a complete transaction with the Notecard.
523
    @param    lockNoteFn
524
              A user-defined callback that blocks until the Notecard has
525
              completed any previous transactions, then returns with
526
              ownership of the next Notecard transaction.
527
    @param    unlockNoteFn
528
              A user-defined callback that releases ownership of the
529
              Notecard transaction taken during the call to `lockNoteFn()`.
530
*/
531
/**************************************************************************/
532
void Notecard::setFnNoteMutex(mutexFn lockNoteFn_, mutexFn unlockNoteFn_) {
2✔
533
    NoteSetFnNoteMutex(lockNoteFn_, unlockNoteFn_);
2✔
534
}
2✔
535

536
/**************************************************************************/
537
/*!
538
    @brief  Set the transaction pins.
539
            A NoteTxn object will be constructed via `make_note_txn()`
540
            using a platform specific tuple of digital I/O pins. The
541
            pins are used to send a request to transact and to listen
542
            for the clear to transact signal. Transaction pins are not
543
            necessary on any legacy Notecards, and are only necessary
544
            for certain Notecard SKUs. The pins allow the Notecard to
545
            inform the host it has had time to awaken from deep sleep
546
            and is ready to process commands.
547
    @param    noteTxn
548
              A platform specific tuple of digital I/O pins.
549
*/
550
/**************************************************************************/
551
void Notecard::setTransactionPins(NoteTxn * noteTxn_) {
14✔
552
    noteTxn = noteTxn_;  // Set global interface
14✔
553
    if (noteTxn_) {
14✔
554
        NoteSetFnTransaction(noteTransactionStart, noteTransactionStop);
9✔
555
    } else {
556
        make_note_txn(nullptr);  // Clear singleton
5✔
557
        NoteSetFnTransaction(nullptr, nullptr);
5✔
558
    }
559
}
14✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc