diff --git a/src/Notecard.cpp b/src/Notecard.cpp index e9af699..48df25f 100644 --- a/src/Notecard.cpp +++ b/src/Notecard.cpp @@ -44,6 +44,15 @@ #include "NoteTime.h" +// AUX serial throttling is based on the Arduino define `SERIAL_RX_BUFFER_SIZE`. +// Unfortunately, some platforms do NOT specify the define. In this case, 64 +// bytes is selected as the default value, because it is a common buffer size +// across several platforms. +#ifndef SERIAL_RX_BUFFER_SIZE +#define SERIAL_RX_BUFFER_SIZE 64 +#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" +#endif + /*************************************************************************** SINGLETON ABSTRACTION (REQUIRED BY NOTE-C) ***************************************************************************/ @@ -245,6 +254,15 @@ void Notecard::begin(NoteSerial * noteSerial_) if (noteSerial) { NoteSetFnSerial(noteSerialReset, noteSerialTransmit, noteSerialAvailable, noteSerialReceive); + + // Set the default debug serial throttling + J *req = NoteNewRequest("card.aux.serial"); + if (req != NULL) + { + JAddIntToObject(req, "max", SERIAL_RX_BUFFER_SIZE - 1); + JAddIntToObject(req, "ms", 1); + NoteRequestWithRetry(req, 15); + } } else { NoteSetFnSerial(nullptr, nullptr, nullptr, nullptr); } diff --git a/test/Notecard.test.cpp b/test/Notecard.test.cpp index 0546c67..3ad7c8a 100644 --- a/test/Notecard.test.cpp +++ b/test/Notecard.test.cpp @@ -1372,6 +1372,209 @@ int test_notecard_begin_serial_sets_serial_receive_function_pointer_to_nullptr_w return result; } +int test_notecard_begin_serial_sends_a_card_aux_serial_request_to_throttle_aux_serial_data() +{ + int result; + + // Arrange + //////////// + + Notecard notecard; + NoteSerial_Mock mockSerial; // Instantiate NoteSerial (mocked) + jAddNumberToObject_Parameters.reset(); + noteNewRequest_Parameters.reset(); + noteRequestWithRetry_Parameters.reset(); + noteSetFnDefault_Parameters.reset(); + + noteNewRequest_Parameters.result = reinterpret_cast(malloc(sizeof(J))); + + // Action + /////////// + + notecard.begin(&mockSerial); + + // Assert + /////////// + + if (noteRequestWithRetry_Parameters.invoked) + { + result = 0; + } + else + { + result = static_cast('n' + 'o' + 't' + 'e' + 'c' + 'a' + 'r' + 'd'); + std::cout << "\33[31mFAILED\33[0m] " << __FILE__ << ":" << __LINE__ << std::endl; + std::cout << "\tnoteRequestWithRetry_Parameters.invoked == " << std::dec << noteRequestWithRetry_Parameters.invoked << ", EXPECTED: > 0" << std::endl; + std::cout << "["; + } + + free(noteNewRequest_Parameters.result); + return result; +} + +int test_notecard_begin_serial_sends_a_card_aux_serial_request_with_15_second_retry() +{ + int result; + + // Arrange + //////////// + + Notecard notecard; + NoteSerial_Mock mockSerial; // Instantiate NoteSerial (mocked) + jAddNumberToObject_Parameters.reset(); + noteNewRequest_Parameters.reset(); + noteRequestWithRetry_Parameters.reset(); + noteSetFnDefault_Parameters.reset(); + + noteNewRequest_Parameters.result = reinterpret_cast(malloc(sizeof(J))); + + // Action + /////////// + + notecard.begin(&mockSerial); + + // Assert + /////////// + + if (15 == noteRequestWithRetry_Parameters.timeoutSeconds) + { + result = 0; + } + else + { + result = static_cast('n' + 'o' + 't' + 'e' + 'c' + 'a' + 'r' + 'd'); + std::cout << "\33[31mFAILED\33[0m] " << __FILE__ << ":" << __LINE__ << std::endl; + std::cout << "\tnoteRequestWithRetry_Parameters.timeoutSeconds == " << std::dec << noteRequestWithRetry_Parameters.timeoutSeconds << ", EXPECTED: 15" << std::endl; + std::cout << "["; + } + + free(noteNewRequest_Parameters.result); + return result; +} + +int test_notecard_begin_serial_sends_a_card_aux_serial_request_with_max_parameter_set_to_arduino_serial_rx_buffer_size_constant_minus_one() +{ + int result; + + // Arrange + //////////// + + Notecard notecard; + NoteSerial_Mock mockSerial; // Instantiate NoteSerial (mocked) + jAddNumberToObject_Parameters.reset(); + noteNewRequest_Parameters.reset(); + noteRequestWithRetry_Parameters.reset(); + noteSetFnDefault_Parameters.reset(); + + noteNewRequest_Parameters.result = reinterpret_cast(malloc(sizeof(J))); + + // Action + /////////// + + notecard.begin(&mockSerial); + + // Assert + /////////// + + if ("max" == jAddNumberToObject_Parameters.name[0] + && (SERIAL_RX_BUFFER_SIZE - 1) == jAddNumberToObject_Parameters.number[0] + ) { + result = 0; + } + else + { + result = static_cast('n' + 'o' + 't' + 'e' + 'c' + 'a' + 'r' + 'd'); + std::cout << "\33[31mFAILED\33[0m] " << __FILE__ << ":" << __LINE__ << std::endl; + std::cout << "\tjAddNumberToObject_Parameters.name == \"" << std::dec << jAddNumberToObject_Parameters.name[0] << "\", EXPECTED: \"max\"" << std::endl; + std::cout << "\tjAddNumberToObject_Parameters.number == " << std::dec << jAddNumberToObject_Parameters.number[0] << ", EXPECTED: " << (SERIAL_RX_BUFFER_SIZE - 1) << std::endl; + std::cout << "["; + } + + free(noteNewRequest_Parameters.result); + return result; +} + +int test_notecard_begin_serial_sends_a_card_aux_serial_request_with_ms_parameter_set_to_one() +{ + int result; + + // Arrange + //////////// + + Notecard notecard; + NoteSerial_Mock mockSerial; // Instantiate NoteSerial (mocked) + jAddNumberToObject_Parameters.reset(); + noteNewRequest_Parameters.reset(); + noteRequestWithRetry_Parameters.reset(); + noteSetFnDefault_Parameters.reset(); + + noteNewRequest_Parameters.result = reinterpret_cast(malloc(sizeof(J))); + + // Action + /////////// + + notecard.begin(&mockSerial); + + // Assert + /////////// + + if ("ms" == jAddNumberToObject_Parameters.name[1] + && 1 == jAddNumberToObject_Parameters.number[1] + ) { + result = 0; + } + else + { + result = static_cast('n' + 'o' + 't' + 'e' + 'c' + 'a' + 'r' + 'd'); + std::cout << "\33[31mFAILED\33[0m] " << __FILE__ << ":" << __LINE__ << std::endl; + std::cout << "\tjAddNumberToObject_Parameters.name == \"" << std::dec << jAddNumberToObject_Parameters.name[1] << "\", EXPECTED: \"ms\"" << std::endl; + std::cout << "\tjAddNumberToObject_Parameters.number == " << std::dec << jAddNumberToObject_Parameters.number[1] << ", EXPECTED: 1" << std::endl; + std::cout << "["; + } + + free(noteNewRequest_Parameters.result); + return result; +} + +int test_notecard_begin_serial_does_not_send_a_card_aux_serial_request_when_interface_has_not_been_instantiated() +{ + int result; + + // Arrange + //////////// + + Notecard notecard; + jAddNumberToObject_Parameters.reset(); + noteNewRequest_Parameters.reset(); + noteRequestWithRetry_Parameters.reset(); + noteSetFnDefault_Parameters.reset(); + + noteNewRequest_Parameters.result = reinterpret_cast(malloc(sizeof(J))); + + // Action + /////////// + + notecard.begin(static_cast(nullptr)); + + // Assert + /////////// + + if (!noteRequestWithRetry_Parameters.invoked) + { + result = 0; + } + else + { + result = static_cast('n' + 'o' + 't' + 'e' + 'c' + 'a' + 'r' + 'd'); + std::cout << "\33[31mFAILED\33[0m] " << __FILE__ << ":" << __LINE__ << std::endl; + std::cout << "\tnoteRequestWithRetry_Parameters.invoked == " << std::dec << noteRequestWithRetry_Parameters.invoked << ", EXPECTED: 0" << std::endl; + std::cout << "["; + } + + free(noteNewRequest_Parameters.result); + return result; +} + int test_notecard_setDebugOutputStream_shares_a_debug_log_function_pointer() { int result; @@ -4635,6 +4838,11 @@ int main(void) {test_notecard_begin_serial_sets_serial_available_function_pointer_to_nullptr_when_interface_has_not_been_instantiated, "test_notecard_begin_serial_sets_serial_available_function_pointer_to_nullptr_when_interface_has_not_been_instantiated"}, {test_notecard_begin_serial_shares_a_serial_receive_function_pointer, "test_notecard_begin_serial_shares_a_serial_receive_function_pointer"}, {test_notecard_begin_serial_sets_serial_receive_function_pointer_to_nullptr_when_interface_has_not_been_instantiated, "test_notecard_begin_serial_sets_serial_receive_function_pointer_to_nullptr_when_interface_has_not_been_instantiated"}, + {test_notecard_begin_serial_sends_a_card_aux_serial_request_to_throttle_aux_serial_data, "test_notecard_begin_serial_sends_a_card_aux_serial_request_to_throttle_aux_serial_data"}, + {test_notecard_begin_serial_sends_a_card_aux_serial_request_with_15_second_retry, "test_notecard_begin_serial_sends_a_card_aux_serial_request_with_15_second_retry"}, + {test_notecard_begin_serial_sends_a_card_aux_serial_request_with_max_parameter_set_to_arduino_serial_rx_buffer_size_constant_minus_one, "test_notecard_begin_serial_sends_a_card_aux_serial_request_with_max_parameter_set_to_arduino_serial_rx_buffer_size_constant_minus_one"}, + {test_notecard_begin_serial_sends_a_card_aux_serial_request_with_ms_parameter_set_to_one, "test_notecard_begin_serial_sends_a_card_aux_serial_request_with_ms_parameter_set_to_one"}, + {test_notecard_begin_serial_does_not_send_a_card_aux_serial_request_when_interface_has_not_been_instantiated, "test_notecard_begin_serial_does_not_send_a_card_aux_serial_request_when_interface_has_not_been_instantiated"}, {test_notecard_setDebugOutputStream_shares_a_debug_log_function_pointer, "test_notecard_setDebugOutputStream_shares_a_debug_log_function_pointer"}, {test_notecard_setDebugOutputStream_clears_the_debug_log_function_pointer_when_nullptr_is_provided, "test_notecard_setDebugOutputStream_clears_the_debug_log_function_pointer_when_nullptr_is_provided"}, {test_notecard_clearDebugOutputStream_clears_the_debug_log_function_pointer, "test_notecard_clearDebugOutputStream_clears_the_debug_log_function_pointer"}, diff --git a/test/mock/mock-arduino.hpp b/test/mock/mock-arduino.hpp index 49d7b9b..fe37fb9 100644 --- a/test/mock/mock-arduino.hpp +++ b/test/mock/mock-arduino.hpp @@ -8,6 +8,8 @@ #include #include +#define SERIAL_RX_BUFFER_SIZE 79 + enum PinMode { INPUT = 0x19, INPUT_PULLUP, diff --git a/test/mock/mock-note-c-note.c b/test/mock/mock-note-c-note.c index 535cecb..1a6f292 100644 --- a/test/mock/mock-note-c-note.c +++ b/test/mock/mock-note-c-note.c @@ -1,5 +1,6 @@ #include "mock-parameters.hpp" +JAddNumberToObject_Parameters jAddNumberToObject_Parameters; NoteDebug_Parameters noteDebug_Parameters; NoteDebugSyncStatus_Parameters noteDebugSyncStatus_Parameters; NoteDeleteResponse_Parameters noteDeleteResponse_Parameters; @@ -19,6 +20,28 @@ NoteSetFnSerial_Parameters noteSetFnSerial_Parameters; NoteSetFnTransaction_Parameters noteSetFnTransaction_Parameters; NoteSetUserAgent_Parameters noteSetUserAgent_Parameters; +J * +JAddNumberToObject ( + J * const object_, + const char * const name_, + const JNUMBER number_ +) { + // Record invocation(s) + ++jAddNumberToObject_Parameters.invoked; + + // Stash parameter(s) + jAddNumberToObject_Parameters.object.push_back(object_); + jAddNumberToObject_Parameters.name.push_back(name_); + jAddNumberToObject_Parameters.number.push_back(number_); + + // Return user-supplied result + if (jAddNumberToObject_Parameters.result.size() < jAddNumberToObject_Parameters.invoked) { + return jAddNumberToObject_Parameters.default_result; + } else { + return jAddNumberToObject_Parameters.result[(jAddNumberToObject_Parameters.invoked - 1)]; + } +} + void MockNoteDeleteResponse ( J * response_ diff --git a/test/mock/mock-parameters.hpp b/test/mock/mock-parameters.hpp index 5a7731f..bb35413 100644 --- a/test/mock/mock-parameters.hpp +++ b/test/mock/mock-parameters.hpp @@ -2,6 +2,7 @@ #define MOCK_PARAMETERS_HPP #include +#include #include "note-c/note.h" @@ -19,6 +20,32 @@ void MockNoteDeleteResponse(J*); bool MockNoteResponseError(J*); #define NoteResponseError(x) MockNoteResponseError(x) +struct JAddNumberToObject_Parameters { + JAddNumberToObject_Parameters( + void + ) : + invoked(0), + default_result(nullptr) + { } + void + reset ( + void + ) { + invoked = 0; + object.clear(); + name.clear(); + number.clear(); + result.clear(); + default_result = nullptr; + } + size_t invoked; + std::vector object; + std::vector name; + std::vector number; + std::vector result; + J *default_result; +}; + struct NoteDebug_Parameters { NoteDebug_Parameters( void @@ -423,6 +450,7 @@ struct NoteSetUserAgent_Parameters { std::string agent_cache; }; +extern JAddNumberToObject_Parameters jAddNumberToObject_Parameters; extern NoteDebug_Parameters noteDebug_Parameters; extern NoteDebugSyncStatus_Parameters noteDebugSyncStatus_Parameters; extern NoteDeleteResponse_Parameters noteDeleteResponse_Parameters;