diff --git a/src/NoteI2c_Arduino.cpp b/src/NoteI2c_Arduino.cpp index fb4cf3d..5bb6ec8 100644 --- a/src/NoteI2c_Arduino.cpp +++ b/src/NoteI2c_Arduino.cpp @@ -30,6 +30,15 @@ NoteI2c_Arduino::NoteI2c_Arduino _i2cPort.begin(); } +NoteI2c_Arduino::~NoteI2c_Arduino ( + void +) +{ +#if WIRE_HAS_END + _i2cPort.end(); +#endif +} + const char * NoteI2c_Arduino::receive ( uint16_t device_address_, diff --git a/src/NoteI2c_Arduino.hpp b/src/NoteI2c_Arduino.hpp index 8e256f6..6e5ddc3 100644 --- a/src/NoteI2c_Arduino.hpp +++ b/src/NoteI2c_Arduino.hpp @@ -16,6 +16,7 @@ class NoteI2c_Arduino final : public NoteI2c { public: NoteI2c_Arduino(TwoWire & i2c_bus); + ~NoteI2c_Arduino(void); const char * receive(uint16_t device_address, uint8_t * buffer, uint16_t requested_byte_count, uint32_t * available) override; bool reset(uint16_t device_address) override; const char * transmit(uint16_t device_address, uint8_t * buffer, uint16_t size) override; diff --git a/src/NoteSerial_Arduino.cpp b/src/NoteSerial_Arduino.cpp index b5adaf1..39ca49b 100644 --- a/src/NoteSerial_Arduino.cpp +++ b/src/NoteSerial_Arduino.cpp @@ -29,6 +29,13 @@ NoteSerial_Arduino::NoteSerial_Arduino _notecardSerial.begin(_notecardSerialSpeed); } +NoteSerial_Arduino::~NoteSerial_Arduino ( + void +) +{ + _notecardSerial.end(); +} + size_t NoteSerial_Arduino::available ( void diff --git a/src/NoteSerial_Arduino.hpp b/src/NoteSerial_Arduino.hpp index 0a337a6..ab99f49 100644 --- a/src/NoteSerial_Arduino.hpp +++ b/src/NoteSerial_Arduino.hpp @@ -25,6 +25,7 @@ class NoteSerial_Arduino final : public NoteSerial { public: NoteSerial_Arduino(HardwareSerial & hw_serial_, size_t baud_rate_); + ~NoteSerial_Arduino(void); size_t available(void) override; char receive(void) override; bool reset(void) override; diff --git a/src/Notecard.cpp b/src/Notecard.cpp index 567e507..8f9bcff 100644 --- a/src/Notecard.cpp +++ b/src/Notecard.cpp @@ -307,6 +307,27 @@ void Notecard::deleteResponse(J *rsp) const NoteDeleteResponse(rsp); } +/**************************************************************************/ +/*! + @brief Deinitialize the Notecard object communication. + This function clears the Notecard object's communication + interfaces, and frees all associated memory. +*/ +/**************************************************************************/ +void Notecard::end(void) const +{ + // Clear Communication Interfaces + NoteSetFnI2C(0, 0, nullptr, nullptr, nullptr); + NoteSetFnSerial(nullptr, nullptr, nullptr, nullptr); + + // Clear Platform Callbacks + platformInit(false); + + // Delete Singletons + noteI2c = make_note_i2c(nullptr); + noteSerial = make_note_serial(nullptr); +} + /**************************************************************************/ /*! @deprecated NoteDebug, which this function wraps, should be treated as an diff --git a/src/Notecard.h b/src/Notecard.h index 6c82eb0..737554f 100644 --- a/src/Notecard.h +++ b/src/Notecard.h @@ -98,6 +98,7 @@ class Notecard } bool debugSyncStatus (int pollFrequencyMs, int maxLevel) const; void deleteResponse(J *rsp) const; + void end(void) const; NOTE_ARDUINO_DEPRECATED void logDebug(const char *message) const; NOTE_ARDUINO_DEPRECATED void logDebugf(const char *format, ...) const; J *newCommand(const char *request) const; diff --git a/test/NoteI2c_Arduino.test.cpp b/test/NoteI2c_Arduino.test.cpp index bca0186..7523452 100644 --- a/test/NoteI2c_Arduino.test.cpp +++ b/test/NoteI2c_Arduino.test.cpp @@ -120,6 +120,66 @@ int test_notei2c_arduino_constructor_invokes_twowire_parameter_begin_method() return result; } +#if not defined(WIRE_HAS_END) + +int test_notei2c_arduino_deconstructor_does_not_invoke_twowire_end_method() +{ + int result; + + // Arrange + NoteI2c_Arduino * notei2c = new NoteI2c_Arduino(Wire); + twoWireEnd_Parameters.reset(); + + // Action + delete notei2c; + + // Assert + if (!twoWireEnd_Parameters.invoked) + { + result = 0; + } + else + { + result = static_cast('i' + '2' + 'c'); + std::cout << "\33[31mFAILED\33[0m] " << __FILE__ << ":" << __LINE__ << std::endl; + std::cout << "\ttwoWireEnd_Parameters.invoked == " << (!!twoWireEnd_Parameters.invoked ? "true" : "false") << ", EXPECTED: false" << std::endl; + std::cout << "["; + } + + return result; +} + +#else // defined(WIRE_HAS_END) + +int test_notei2c_arduino_deconstructor_invokes_twowire_end_method() +{ + int result; + + // Arrange + NoteI2c_Arduino * notei2c = new NoteI2c_Arduino(Wire); + twoWireEnd_Parameters.reset(); + + // Action + delete notei2c; + + // Assert + if (twoWireEnd_Parameters.invoked) + { + result = 0; + } + else + { + result = static_cast('i' + '2' + 'c'); + std::cout << "\33[31mFAILED\33[0m] " << __FILE__ << ":" << __LINE__ << std::endl; + std::cout << "\ttwoWireEnd_Parameters.invoked == " << (!!twoWireEnd_Parameters.invoked ? "true" : "false") << ", EXPECTED: true" << std::endl; + std::cout << "["; + } + + return result; +} + +#endif // not defined(WIRE_HAS_END) + int test_notei2c_arduino_receive_requests_response_data_from_notecard() { int result; @@ -1640,6 +1700,11 @@ int main(void) {test_make_note_i2c_enforces_singleton_by_returning_same_notei2c_object_for_all_calls, "test_make_note_i2c_enforces_singleton_by_returning_same_notei2c_object_for_all_calls"}, {test_make_note_i2c_deletes_singleton_when_nullptr_is_passed_as_parameter, "test_make_note_i2c_deletes_singleton_when_nullptr_is_passed_as_parameter"}, {test_notei2c_arduino_constructor_invokes_twowire_parameter_begin_method, "test_notei2c_arduino_constructor_invokes_twowire_parameter_begin_method"}, +#if not defined(WIRE_HAS_END) + {test_notei2c_arduino_deconstructor_does_not_invoke_twowire_end_method, "test_notei2c_arduino_deconstructor_does_not_invoke_twowire_end_method"}, +#else // defined(WIRE_HAS_END) + {test_notei2c_arduino_deconstructor_invokes_twowire_end_method, "test_notei2c_arduino_deconstructor_invokes_twowire_end_method"}, +#endif // not defined(WIRE_HAS_END) {test_notei2c_arduino_receive_requests_response_data_from_notecard, "test_notei2c_arduino_receive_requests_response_data_from_notecard"}, {test_notei2c_arduino_receive_will_retry_transmission_on_i2c_failure, "test_notei2c_arduino_receive_will_retry_transmission_on_i2c_failure"}, {test_notei2c_arduino_receive_will_not_retry_transmission_on_i2c_success, "test_notei2c_arduino_receive_will_not_retry_transmission_on_i2c_success"}, diff --git a/test/NoteSerial_Arduino.test.cpp b/test/NoteSerial_Arduino.test.cpp index 44f54c0..164aba0 100644 --- a/test/NoteSerial_Arduino.test.cpp +++ b/test/NoteSerial_Arduino.test.cpp @@ -151,6 +151,33 @@ int test_noteserial_arduino_constructor_does_not_modify_baud_parameter_before_pa return result; } +int test_noteserial_arduino_deconstructor_invokes_hardware_serial_end_method() +{ + int result; + + // Arrange + hardwareSerialEnd_Parameters.reset(); + NoteSerial_Arduino * noteserial = new NoteSerial_Arduino(Serial, 9600); + + // Action + delete noteserial; + + // Assert + if (hardwareSerialEnd_Parameters.invoked) + { + result = 0; + } + else + { + result = static_cast('s' + 'e' + 'r' + 'i' + 'a' + 'l'); + std::cout << "\33[31mFAILED\33[0m] " << __FILE__ << ":" << __LINE__ << std::endl; + std::cout << "\thardwareSerialEnd_Parameters.invoked == " << !!hardwareSerialEnd_Parameters.invoked << ", EXPECTED: " << true << std::endl; + std::cout << "["; + } + + return result; +} + int test_noteserial_arduino_available_invokes_hardware_serial_available() { int result; @@ -553,6 +580,7 @@ int main(void) {test_make_note_serial_deletes_singleton_when_nullptr_is_passed_as_parameter, "test_make_note_serial_deletes_singleton_when_nullptr_is_passed_as_parameter"}, {test_noteserial_arduino_constructor_invokes_hardware_serial_parameter_begin_method, "test_noteserial_arduino_constructor_invokes_hardware_serial_parameter_begin_method"}, {test_noteserial_arduino_constructor_does_not_modify_baud_parameter_before_passing_to_hardware_serial_begin, "test_noteserial_arduino_constructor_does_not_modify_baud_parameter_before_passing_to_hardware_serial_begin"}, + {test_noteserial_arduino_deconstructor_invokes_hardware_serial_end_method, "test_noteserial_arduino_deconstructor_invokes_hardware_serial_end_method"}, {test_noteserial_arduino_available_invokes_hardware_serial_available, "test_noteserial_arduino_available_invokes_hardware_serial_available"}, {test_noteserial_arduino_available_does_not_modify_hardware_serial_available_result_value_before_returning_to_caller, "test_noteserial_arduino_available_does_not_modify_hardware_serial_available_result_value_before_returning_to_caller"}, {test_noteserial_arduino_receive_invokes_hardware_serial_read, "test_noteserial_arduino_receive_invokes_hardware_serial_read"}, diff --git a/test/Notecard.test.cpp b/test/Notecard.test.cpp index e6f2c6b..a9bb5e7 100644 --- a/test/Notecard.test.cpp +++ b/test/Notecard.test.cpp @@ -1575,6 +1575,199 @@ int test_notecard_begin_serial_does_not_send_a_card_aux_serial_request_when_inte return result; } +int test_notecard_end_clears_all_i2c_interface_function_pointers() +{ + int result; + + // Arrange + //////////// + + Notecard notecard; + NoteI2c_Mock mockI2c; + noteSetFnI2C_Parameters.reset(); + notecard.begin(&mockI2c); + + // Action + /////////// + + notecard.end(); + + // Assert + /////////// + + if (!noteSetFnI2C_Parameters.resetfn + && !noteSetFnI2C_Parameters.transmitfn + && !noteSetFnI2C_Parameters.receivefn) + { + 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 << "\tnoteSetFnI2C_Parameters.resetfn == 0x" << std::hex << !!noteSetFnI2C_Parameters.resetfn << ", EXPECTED: 0x0 (`nullptr`)" << std::endl; + std::cout << "\tnoteSetFnI2C_Parameters.transmitfn == 0x" << std::hex << !!noteSetFnI2C_Parameters.transmitfn << ", EXPECTED: 0x0 (`nullptr`)" << std::endl; + std::cout << "\tnoteSetFnI2C_Parameters.receivefn == 0x" << std::hex << !!noteSetFnI2C_Parameters.receivefn << ", EXPECTED: 0x0 (`nullptr`)" << std::endl; + std::cout << "["; + } + + return result; +} + +int test_notecard_end_clears_all_serial_interface_function_pointers() +{ + int result; + + // Arrange + //////////// + + Notecard notecard; + NoteSerial_Mock mockSerial; // Instantiate NoteSerial (mocked) + noteSetFnDefault_Parameters.reset(); + notecard.begin(&mockSerial); + + // Action + /////////// + + notecard.end(); + + // Assert + /////////// + + if (!noteSetFnSerial_Parameters.resetfn + && !noteSetFnSerial_Parameters.writefn + && !noteSetFnSerial_Parameters.availfn + && !noteSetFnSerial_Parameters.readfn) + { + 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 << "\tnoteSetFnSerial_Parameters.readfn == 0x" << !!noteSetFnSerial_Parameters.readfn << ", EXPECTED: 0x0 (`nullptr`)" << std::endl; + std::cout << "\tnoteSetFnSerial_Parameters.writefn == 0x" << !!noteSetFnSerial_Parameters.writefn << ", EXPECTED: 0x0 (`nullptr`)" << std::endl; + std::cout << "\tnoteSetFnSerial_Parameters.availfn == 0x" << !!noteSetFnSerial_Parameters.availfn << ", EXPECTED: 0x0 (`nullptr`)" << std::endl; + std::cout << "\tnoteSetFnSerial_Parameters.resetfn == 0x" << !!noteSetFnSerial_Parameters.resetfn << ", EXPECTED: 0x0 (`nullptr`)" << std::endl; + std::cout << "["; + } + + return result; +} + +int test_notecard_end_clears_all_platform_interface_function_pointers() +{ + int result; + + // Arrange + //////////// + + Notecard notecard; + NoteI2c_Mock mockI2c; + noteSetFnDefault_Parameters.reset(); + notecard.begin(&mockI2c); + + // Action + /////////// + + notecard.end(); + + // Assert + /////////// + + if (!noteSetFnDefault_Parameters.mallocfn + && !noteSetFnDefault_Parameters.freefn + && !noteSetFnDefault_Parameters.delayfn + && !noteSetFnDefault_Parameters.millisfn) + { + 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 << "\tnoteSetFnDefault_Parameters.mallocfn == 0x" << std::hex << noteSetFnDefault_Parameters.mallocfn << ", EXPECTED: 0x0 (`nullptr`)" << std::endl; + std::cout << "\tnoteSetFnDefault_Parameters.freefn == 0x" << std::hex << noteSetFnDefault_Parameters.freefn << ", EXPECTED: 0x0 (`nullptr`)" << std::endl; + std::cout << "\tnoteSetFnDefault_Parameters.delayfn == 0x" << std::hex << noteSetFnDefault_Parameters.delayfn << ", EXPECTED: 0x0 (`nullptr`)" << std::endl; + std::cout << "\tnoteSetFnDefault_Parameters.millisfn == 0x" << std::hex << noteSetFnDefault_Parameters.millisfn << ", EXPECTED: 0x0 (`nullptr`)" << std::endl; + std::cout << "["; + } + + return result; +} + +int test_notecard_end_provides_nullptr_to_make_note_i2c_to_free_associated_memory() +{ + int result; + + // Arrange + //////////// + + Notecard notecard; + NoteI2c_Mock mockI2c; // Instantiate NoteI2c (mocked) + make_note_i2c_Parameters.reset(); + make_note_i2c_Parameters.i2c_parameters = &mockI2c; + notecard.begin(&mockI2c); + + // Action + //////////// + + notecard.end(); + + // Assert + //////////// + + if (nullptr == make_note_i2c_Parameters.i2c_parameters) + { + 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 << "\tmake_note_i2c_Parameters.i2c_parameters == 0x" << std::hex << !!make_note_i2c_Parameters.i2c_parameters << ", EXPECTED: 0x0 (nullptr)" << std::endl; + std::cout << "["; + } + + return result; +} + +int test_notecard_end_provides_nullptr_to_make_note_serial_to_free_associated_memory() +{ + int result; + + // Arrange + //////////// + + Notecard notecard; + NoteSerial_Mock mockSerial; // Instantiate NoteSerial (mocked) + make_note_serial_Parameters.reset(); + make_note_serial_Parameters.serial_parameters = &mockSerial; + notecard.begin(&mockSerial); + + // Action + //////////// + + notecard.end(); + + // Assert + //////////// + + if (nullptr == make_note_serial_Parameters.serial_parameters) + { + 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 << "\tmake_note_serial_Parameters.serial_parameters == 0x" << std::hex << !!make_note_serial_Parameters.serial_parameters << ", EXPECTED: 0x0 (nullptr)" << std::endl; + std::cout << "["; + } + + return result; +} + int test_notecard_setDebugOutputStream_shares_a_debug_log_function_pointer() { int result; @@ -4843,6 +5036,11 @@ int main(void) {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_end_clears_all_i2c_interface_function_pointers, "test_notecard_end_clears_all_i2c_interface_function_pointers"}, + {test_notecard_end_clears_all_serial_interface_function_pointers, "test_notecard_end_clears_all_serial_interface_function_pointers"}, + {test_notecard_end_clears_all_platform_interface_function_pointers, "test_notecard_end_clears_all_platform_interface_function_pointers"}, + {test_notecard_end_provides_nullptr_to_make_note_i2c_to_free_associated_memory, "test_notecard_end_provides_nullptr_to_make_note_i2c_to_free_associated_memory"}, + {test_notecard_end_provides_nullptr_to_make_note_serial_to_free_associated_memory, "test_notecard_end_provides_nullptr_to_make_note_serial_to_free_associated_memory"}, {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"},