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

blues / note-arduino / 13531037848

25 Feb 2025 09:12PM UTC coverage: 90.526%. Remained the same
13531037848

Pull #138

github

web-flow
Merge 9c9afc296 into 9a3a2641e
Pull Request #138: Test

98 of 137 branches covered (71.53%)

Branch coverage included in aggregate %.

332 of 338 relevant lines covered (98.22%)

15.22 hits per line

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

99.4
/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
// AUX serial throttling is based on the Arduino define `SERIAL_RX_BUFFER_SIZE`.
48
// Unfortunately, some platforms do NOT specify the define. In this case, 64
49
// bytes is selected as the default value, because it is a common buffer size
50
// across several platforms.
51
#ifndef SERIAL_RX_BUFFER_SIZE
52
#define SERIAL_RX_BUFFER_SIZE 64
53
#pragma message "\n\x1B[0;33mSERIAL_RX_BUFFER_SIZE has not been specified for this platform!\n\nThe value is used to set the default Notecard AUX Serial write speeds.\nA value (" NOTE_C_STRINGIZE(SERIAL_RX_BUFFER_SIZE) ") has been specified on your behalf. Use the 'card.aux.serial'\nrequest to tailor the AUX Serial speed to your board and/or application.\nhttps://dev.blues.io/api-reference/notecard-api/card-requests/#card-aux-serial\x1B[0;0m"
54
#endif
55

56
/***************************************************************************
57
 SINGLETON ABSTRACTION (REQUIRED BY NOTE-C)
58
 ***************************************************************************/
59

60
namespace
61
{
62
NoteI2c *noteI2c(nullptr);
63

64
const char *noteI2cReceive(uint16_t device_address_, uint8_t *buffer_, uint16_t size_, uint32_t *available_)
8✔
65
{
66
    const char *result;
67
    if (noteI2c) {
8✔
68
        result = noteI2c->receive(device_address_, buffer_, size_, available_);
6✔
69
    } else {
70
        result = "i2c: A call to Notecard::begin() is required. {io}";
2✔
71
    }
72
    return result;
8✔
73
}
74

75
bool noteI2cReset(uint16_t device_address_)
5✔
76
{
77
    bool result;
78
    if (noteI2c) {
5✔
79
        result = noteI2c->reset(device_address_);
3✔
80
    } else {
81
        result = false;
2✔
82
    }
83
    return result;
5✔
84
}
85

86
const char *noteI2cTransmit(uint16_t device_address_, uint8_t *buffer_, uint16_t size_)
7✔
87
{
88
    const char *result;
89
    if (noteI2c) {
7✔
90
        result = noteI2c->transmit(device_address_, buffer_, size_);
5✔
91
    } else {
92
        result = "i2c: A call to Notecard::begin() is required. {io}";
2✔
93
    }
94
    return result;
7✔
95
}
96

97
NoteLog *noteLog(nullptr);
98

99
size_t noteLogPrint(const char * message_)
5✔
100
{
101
    size_t result;
102
    if (noteLog) {
5✔
103
        result = noteLog->print(message_);
3✔
104
    } else {
105
        result = 0;
2✔
106
    }
107
    return result;
5✔
108
}
109

110
NoteSerial *noteSerial(nullptr);
111

112
bool noteSerialAvailable(void)
4✔
113
{
114
    bool result;
115
    if (noteSerial) {
4✔
116
        result = noteSerial->available();
2✔
117
    } else {
118
        result = false;
2✔
119
    }
120
    return result;
4✔
121
}
122

123
char noteSerialReceive(void)
4✔
124
{
125
    char result;
126
    if (noteSerial) {
4✔
127
        result = noteSerial->receive();
2✔
128
    } else {
129
        result = '\0';
2✔
130
    }
131
    return result;
4✔
132
}
133

134
bool noteSerialReset(void)
4✔
135
{
136
    bool result;
137
    if (noteSerial) {
4✔
138
        result = noteSerial->reset();
2✔
139
    } else {
140
        result = false;
2✔
141
    }
142
    return result;
4✔
143
}
144

145
void noteSerialTransmit(uint8_t *text_, size_t len_, bool flush_)
5✔
146
{
147
    if (noteSerial) {
5✔
148
        noteSerial->transmit(text_, len_, flush_);
4✔
149
    }
150
}
5✔
151

152
NoteTxn *noteTxn(nullptr);
153

154
bool noteTransactionStart (uint32_t timeout_ms_) {
5✔
155
    bool result;
156
    if (noteTxn) {
5✔
157
        result = noteTxn->start(timeout_ms_);
3✔
158
    } else {
159
        // NoteTransaction not set, assume unnecessary
160
        result = true;
2✔
161
    }
162
    return result;
5✔
163
}
164

165
void noteTransactionStop (void) {
2✔
166
    if (noteTxn) {
2✔
167
        noteTxn->stop();
1✔
168
    }
169
}
2✔
170

171
}
172

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

199
/***************************************************************************
200
 PUBLIC FUNCTIONS
201
 ***************************************************************************/
202

203
Notecard::~Notecard (void)
132✔
204
{
205
    // Delete Singleton(s)
206
    noteI2c = make_note_i2c(nullptr);
132✔
207
    noteLog = make_note_log(nullptr);
132✔
208
    noteSerial = make_note_serial(nullptr);
132✔
209
    noteTxn = make_note_txn(nullptr);
132✔
210
}
132✔
211

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

240
/**************************************************************************/
241
/*!
242
    @brief  Initialize the Notecard for Serial communication.
243
            This function configures the Notecard to use Serial
244
            for communication with the host.
245
    @param    noteSerial
246
              A platform specific serial implementation to use for
247
              communicating with the Notecard from the host.
248
*/
249
/**************************************************************************/
250
void Notecard::begin(NoteSerial * noteSerial_)
49✔
251
{
252
    noteSerial = noteSerial_;
49✔
253
    platformInit(noteSerial);
49✔
254
    if (noteSerial) {
49✔
255
        NoteSetFnSerial(noteSerialReset, noteSerialTransmit,
32✔
256
                        noteSerialAvailable, noteSerialReceive);
257

258
        // Set the default debug serial throttling
259
        J *req = NoteNewRequest("card.aux.serial");
32✔
260
        if (req != NULL)
32✔
261
        {
262
            JAddIntToObject(req, "max", SERIAL_RX_BUFFER_SIZE - 1);
23✔
263
            JAddIntToObject(req, "ms", 1);
23✔
264
            NoteRequestWithRetry(req, 15);
23✔
265
        }
266
    } else {
267
        NoteSetFnSerial(nullptr, nullptr, nullptr, nullptr);
17✔
268
    }
269
}
49✔
270

271
/**************************************************************************/
272
/*!
273
    @brief  Periodically show Notecard sync status, returning `TRUE`
274
            if something was displayed to the debug stream.
275
    @param    pollFrequencyMs
276
              The frequency to poll the Notecard for sync status.
277
    @param    maxLevel
278
              The maximum log level to output to the debug console. Pass
279
              -1 for all.
280
    @return `true` if a pending response was displayed to the debug stream.
281
*/
282
/**************************************************************************/
283
bool Notecard::debugSyncStatus(int pollFrequencyMs, int maxLevel)
3✔
284
{
285
    return NoteDebugSyncStatus(pollFrequencyMs, maxLevel);
3✔
286
}
287

288
/**************************************************************************/
289
/*!
290
    @brief  Deletes a `J` JSON response object from memory.
291
    @param    rsp
292
              A `J` JSON response object.
293
*/
294
/**************************************************************************/
295
void Notecard::deleteResponse(J *rsp) const
1✔
296
{
297
    NoteDeleteResponse(rsp);
1✔
298
}
1✔
299

300
/**************************************************************************/
301
/*!
302
    @brief  Deinitialize the Notecard object communication.
303
            This function clears the Notecard object's communication
304
            interfaces, and frees all associated memory.
305
*/
306
/**************************************************************************/
307
void Notecard::end(void)
5✔
308
{
309
    // Clear Communication Interfaces
310
    NoteSetFnI2C(0, 0, nullptr, nullptr, nullptr);
5✔
311
    NoteSetFnSerial(nullptr, nullptr, nullptr, nullptr);
5✔
312

313
    // Clear Platform Callbacks
314
    platformInit(false);
5✔
315

316
    // Delete Singletons
317
    noteI2c = make_note_i2c(nullptr);
5✔
318
    noteSerial = make_note_serial(nullptr);
5✔
319
}
5✔
320

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

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

358
#ifdef NOTE_ARDUINO_NO_DEPRECATED_ATTR
359
    NOTE_C_LOG_WARN("logDebugf is deprecated.")
360
#endif
361
    NoteDebug(message);
1!
362
}
1✔
363

364
/**************************************************************************/
365
/*!
366
    @brief  Creates a new command object for population by the host.
367
            This function accepts a command string (for example, `"note.add"`)
368
            and initializes a JSON Object to return to the host.
369
    @param    request
370
              The command name, for example, `note.add`.
371
    @return A `J` JSON Object populated with the request name.
372
*/
373
/**************************************************************************/
374
J *Notecard::newCommand(const char *request) const
2✔
375
{
376
    return NoteNewCommand(request);
2✔
377
}
378

379
/**************************************************************************/
380
/*!
381
    @brief  Creates a new request object for population by the host.
382
            This function accepts a request string (for example, `"note.add"`)
383
            and initializes a JSON Object to return to the host.
384
    @param    request
385
              The request name, for example, `note.add`.
386
    @return A `J` JSON Object populated with the request name.
387
*/
388
/**************************************************************************/
389
J *Notecard::newRequest(const char *request) const
2✔
390
{
391
    return NoteNewRequest(request);
2✔
392
}
393

394
/**************************************************************************/
395
/*!
396
    @brief  Sends a request to the Notecard and returns the JSON Response.
397
            This function takes a populated `J` JSON request object
398
            and sends it to the Notecard.
399
    @param    req
400
              A `J` JSON request object.
401
    @return `J` JSON Object with the response from the Notecard.
402
*/
403
/**************************************************************************/
404
J *Notecard::requestAndResponse(J *req) const
2✔
405
{
406
    return NoteRequestResponse(req);
2✔
407
}
408

409
/**************************************************************************/
410
/*!
411
    @brief  Sends a request to the Notecard, retrying it on failure until the
412
            provided timeout interval lapses, and returns the JSON response.
413
    @param    req
414
              A `J` JSON request object.
415
    @param    timeoutSeconds
416
              The timeout interval, in seconds.
417
    @return `J` JSON Object with the response from the Notecard.
418
*/
419
/**************************************************************************/
420
J *Notecard::requestAndResponseWithRetry(J *req, uint32_t timeoutSeconds) const
3✔
421
{
422
    return NoteRequestResponseWithRetry(req, timeoutSeconds);
3✔
423
}
424

425
/**************************************************************************/
426
/*!
427
    @brief  Determines if there is an error string present in a response object.
428
    @param    rsp
429
              A `J` JSON Response object.
430
    @return `true` if the response object contains an error.
431
*/
432
/**************************************************************************/
433
bool Notecard::responseError(J *rsp) const
2✔
434
{
435
    return NoteResponseError(rsp);
2✔
436
}
437

438
/**************************************************************************/
439
/*!
440
    @brief  Sends a request to the Notecard.
441
            This function takes a populated `J` JSON request object
442
            and sends it to the Notecard.
443
    @param    req
444
              A `J` JSON request object.
445
    @return `True` if the message was successfully sent to the Notecard,
446
            `False` if there was an error.
447
*/
448
/**************************************************************************/
449
bool Notecard::sendRequest(J *req) const
2✔
450
{
451
    return NoteRequest(req);
2✔
452
}
453

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

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

494
/**************************************************************************/
495
/*!
496
    @brief  Set the lock/unlock functions the Notecard uses for I2C access.
497
    @param    lockI2cFn
498
              A user-defined callback that blocks until access to the I2C
499
              bus has become available, then returns with ownership of the
500
              I2C bus.
501
    @param    unlockI2cFn
502
              A user-defined callback that releases ownership of the
503
              I2C bus taken during the call to `lockI2cFn()`.
504
*/
505
/**************************************************************************/
506
void Notecard::setFnI2cMutex(mutexFn lockI2cFn_, mutexFn unlockI2cFn_) {
2✔
507
    NoteSetFnI2CMutex(lockI2cFn_, unlockI2cFn_);
2✔
508
}
2✔
509

510
/**************************************************************************/
511
/*!
512
    @brief  Set the lock/unlock functions the host MCU uses to ensure
513
            a complete transaction with the Notecard.
514
    @param    lockNoteFn
515
              A user-defined callback that blocks until the Notecard has
516
              completed any previous transactions, then returns with
517
              ownership of the next Notecard transaction.
518
    @param    unlockNoteFn
519
              A user-defined callback that releases ownership of the
520
              Notecard transaction taken during the call to `lockNoteFn()`.
521
*/
522
/**************************************************************************/
523
void Notecard::setFnNoteMutex(mutexFn lockNoteFn_, mutexFn unlockNoteFn_) {
2✔
524
    NoteSetFnNoteMutex(lockNoteFn_, unlockNoteFn_);
2✔
525
}
2✔
526

527
/**************************************************************************/
528
/*!
529
    @brief  Set the transaction pins.
530
            A NoteTxn object will be constructed via `make_note_txn()`
531
            using a platform specific tuple of digital I/O pins. The
532
            pins are used to send a request to transact and to listen
533
            for the clear to transact signal. Transaction pins are not
534
            necessary on any legacy Notecards, and are only necessary
535
            for certain Notecard SKUs. The pins allow the Notecard to
536
            inform the host it has had time to awaken from deep sleep
537
            and is ready to process commands.
538
    @param    noteTxn
539
              A platform specific tuple of digital I/O pins.
540
*/
541
/**************************************************************************/
542
void Notecard::setTransactionPins(NoteTxn * noteTxn_) {
14✔
543
    noteTxn = noteTxn_;  // Set global interface
14✔
544
    if (noteTxn_) {
14✔
545
        NoteSetFnTransaction(noteTransactionStart, noteTransactionStop);
9✔
546
    } else {
547
        make_note_txn(nullptr);  // Clear singleton
5✔
548
        NoteSetFnTransaction(nullptr, nullptr);
5✔
549
    }
550
}
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