diff --git a/include/protocol/haier_protocol.h b/include/protocol/haier_protocol.h index 5476fec..61054ef 100644 --- a/include/protocol/haier_protocol.h +++ b/include/protocol/haier_protocol.h @@ -65,6 +65,8 @@ class ProtocolHandler void send_message_without_answer(const HaierMessage& message, bool use_crc); void send_answer(const HaierMessage& answer); void send_answer(const HaierMessage& answer, bool use_crc); + // Use this function to suppress warning if you don't answer an appliance request on purpose + void no_answer(); void set_message_handler(FrameType message_type, MessageHandler handler); void remove_message_handler(FrameType message_type); void set_default_message_handler(MessageHandler handler); diff --git a/library.json b/library.json index 28a3668..58e5be2 100644 --- a/library.json +++ b/library.json @@ -1,6 +1,6 @@ { "name": "HaierProtocol", - "version": "0.9.27", + "version": "0.9.28", "description": "A library to control Haier smart appliances using serial protocol", "keywords": "haier, hOn, air-conditioner, washing-machine, uart, serial", "repository": diff --git a/src/protocol/haier_protocol.cpp b/src/protocol/haier_protocol.cpp index 444b184..5b81281 100644 --- a/src/protocol/haier_protocol.cpp +++ b/src/protocol/haier_protocol.cpp @@ -72,7 +72,7 @@ void ProtocolHandler::loop() } else if (!this->answer_sent_) { - HAIER_LOGI("No answer sent in incoming messages handler, message type %02X", msg_type); + HAIER_LOGW("No answer sent in incoming messages handler, message type %02X", msg_type); } } { @@ -226,6 +226,13 @@ void ProtocolHandler::send_answer(const HaierMessage& answer, bool use_crc) } } +void ProtocolHandler::no_answer() +{ + if (this->processing_message_) + this->answer_sent_ = true; +} + + void ProtocolHandler::set_message_handler(FrameType message_type, MessageHandler handler) { this->message_handlers_map_[message_type] = handler; diff --git a/test/hon_test/CMakeLists.txt b/test/hon_test/CMakeLists.txt index dd4efb7..a8afa69 100644 --- a/test/hon_test/CMakeLists.txt +++ b/test/hon_test/CMakeLists.txt @@ -8,6 +8,7 @@ set(LIB_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../..") set(TOOLS_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../tools") add_compile_options(-DHAIER_LOG_LEVEL=5) +add_compile_options(-DRUN_ALL_TESTS) include_directories("${LIB_ROOT}/include" "${CMAKE_CURRENT_SOURCE_DIR}/../utils" "${TOOLS_PATH}/utils") diff --git a/test/hon_test/main.cpp b/test/hon_test/main.cpp index f38f5c0..e3b7f64 100644 --- a/test/hon_test/main.cpp +++ b/test/hon_test/main.cpp @@ -43,6 +43,30 @@ haier_protocol::HandlerError client_answers_handler(haier_protocol::FrameType me return haier_protocol::HandlerError::HANDLER_OK; } +haier_protocol::HandlerError get_status_message_handler(haier_protocol::ProtocolHandler* protocol_handler, haier_protocol::FrameType type, const uint8_t* buffer, size_t size) { + // This function is processing answer as incomming message + // Some of the appliances (washing machines) take longer than a second to send the status answer + // For these devices, it is better to request data without waiting for an answerand process the answer as the incoming message. + // Testing mechanism to request message without expecting answer and process answer as a new message + static bool do_not_supress_warning = true; + if (type == haier_protocol::FrameType::STATUS) + HAIER_LOGI("Received an answer as a new message, type 0x%02X", type); + else + return haier_protocol::default_message_handler(type, buffer, size); + if (!do_not_supress_warning) + protocol_handler->no_answer(); + else + do_not_supress_warning = false; + return haier_protocol::HandlerError::HANDLER_OK; +} + +#define CLIENT_SERVER_LOOP() { \ + hon_client.loop(); \ + hon_server.loop(); \ + hon_client.loop(); \ + hon_server.loop(); \ + } while(0) + int main(int argc, char** argv) { VirtualStreamHolder stream_holder; haier_protocol::set_log_handler(console_logger); @@ -58,63 +82,66 @@ int main(int argc, char** argv) { haier_protocol::ProtocolHandler hon_client(client_stream); ac_full_state = get_ac_state_ref(); hon_client.set_default_answer_handler(client_answers_handler); + hon_client.set_message_handler(haier_protocol::FrameType::STATUS, std::bind(get_status_message_handler, &hon_client, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); +#if defined(RUN_ALL_TESTS) || defined(RUN_TEST1) { + HAIER_LOGI("Test #1"); uint8_t module_capabilities[2] = { 0b00000000, 0b00000111 }; const haier_protocol::HaierMessage device_version_request_message(haier_protocol::FrameType::GET_DEVICE_VERSION, module_capabilities, sizeof(module_capabilities)); hon_client.send_message(device_version_request_message, false); - hon_client.loop(); - hon_server.loop(); - hon_client.loop(); - hon_server.loop(); + CLIENT_SERVER_LOOP(); } std::this_thread::sleep_for(std::chrono::milliseconds(500)); +#endif +#if defined(RUN_ALL_TESTS) || defined(RUN_TEST2) { + HAIER_LOGI("Test #2"); const haier_protocol::HaierMessage device_request_message(haier_protocol::FrameType::GET_DEVICE_ID); hon_client.send_message(device_request_message, true); - hon_client.loop(); - hon_server.loop(); - hon_client.loop(); - hon_server.loop(); + CLIENT_SERVER_LOOP(); } std::this_thread::sleep_for(std::chrono::milliseconds(500)); +#endif +#if defined(RUN_ALL_TESTS) || defined(RUN_TEST3) { + HAIER_LOGI("Test #3"); const haier_protocol::HaierMessage status_request_message(haier_protocol::FrameType::CONTROL, (uint16_t)SubcommandsControl::GET_USER_DATA); hon_client.send_message(status_request_message, true); - hon_client.loop(); - hon_server.loop(); - hon_client.loop(); - hon_server.loop(); + CLIENT_SERVER_LOOP(); } std::this_thread::sleep_for(std::chrono::milliseconds(500)); +#endif +#if defined(RUN_ALL_TESTS) || defined(RUN_TEST4) { + HAIER_LOGI("Test #4"); const haier_protocol::HaierMessage alarm_status_request_message(haier_protocol::FrameType::GET_ALARM_STATUS); hon_client.send_message(alarm_status_request_message, true); - hon_client.loop(); - hon_server.loop(); - hon_client.loop(); - hon_server.loop(); + CLIENT_SERVER_LOOP(); } std::this_thread::sleep_for(std::chrono::milliseconds(500)); +#endif +#if defined(RUN_ALL_TESTS) || defined(RUN_TEST5) { + HAIER_LOGI("Test #5"); const haier_protocol::HaierMessage update_signal_request(haier_protocol::FrameType::GET_MANAGEMENT_INFORMATION); hon_client.send_message(update_signal_request, true); - hon_client.loop(); - hon_server.loop(); - hon_client.loop(); - hon_server.loop(); + CLIENT_SERVER_LOOP(); } std::this_thread::sleep_for(std::chrono::milliseconds(500)); +#endif +#if defined(RUN_ALL_TESTS) || defined(RUN_TEST6) { + HAIER_LOGI("Test #6"); const uint8_t wifi_status_data[4] = { 0x00, 0x01, 0x00, 0x37 }; haier_protocol::HaierMessage wifi_status_request(haier_protocol::FrameType::REPORT_NETWORK_STATUS, wifi_status_data, sizeof(wifi_status_data)); hon_client.send_message(wifi_status_request, true); - hon_client.loop(); - hon_server.loop(); - hon_client.loop(); - hon_server.loop(); + CLIENT_SERVER_LOOP(); } std::this_thread::sleep_for(std::chrono::milliseconds(500)); +#endif +#if defined(RUN_ALL_TESTS) || defined(RUN_TEST7) { + HAIER_LOGI("Test #7"); ac_full_state.control.ac_power = true; ac_full_state.control.ac_mode = (uint8_t) ConditioningMode::HEALTHY_DRY; ac_full_state.control.fan_mode = (uint8_t) FanMode::FAN_MID; @@ -123,39 +150,38 @@ int main(int argc, char** argv) { ac_full_state.control.display_status = 0; haier_protocol::HaierMessage control_message(haier_protocol::FrameType::CONTROL, (uint16_t)SubcommandsControl::SET_GROUP_PARAMETERS, (uint8_t*)&ac_full_state.control, sizeof(HaierPacketControl)); hon_client.send_message(control_message, true); - hon_client.loop(); - hon_server.loop(); - hon_client.loop(); - hon_server.loop(); + CLIENT_SERVER_LOOP(); + if (memcmp(&ac_full_state.control, &get_ac_state_ref().control, sizeof(HaierPacketControl)) == 0) { + HAIER_LOGI("AC control processed correctly"); + } + else { + HAIER_LOGW("AC control not OK"); + } } - // Some of the appliances (washing machines) take longer than a second to send the status answer - // For these devices, it is better to request data without waiting for an answerand process the answer as the incoming message. - // Testing mechanism to request message without expecting answer and process answer as a new message - hon_client.set_message_handler(haier_protocol::FrameType::STATUS, - [] (haier_protocol::FrameType message_type, const uint8_t* data, size_t data_size) -> haier_protocol::HandlerError { - if (message_type == haier_protocol::FrameType::STATUS) - HAIER_LOGI("Received an answer as a new message, type 0x%02X", message_type); - else - return haier_protocol::default_message_handler(message_type, data, data_size); - return haier_protocol::HandlerError::HANDLER_OK; - }); std::this_thread::sleep_for(std::chrono::milliseconds(500)); +#endif +#if defined(RUN_ALL_TESTS) || defined(RUN_TEST8) { + // Sending status request without answer, first time we will get warning + HAIER_LOGI("Test #8"); const haier_protocol::HaierMessage status_request_message(haier_protocol::FrameType::CONTROL, (uint16_t)SubcommandsControl::GET_USER_DATA); hon_client.send_message_without_answer(status_request_message, true); - hon_client.loop(); - hon_server.loop(); - hon_client.loop(); - hon_server.loop(); - } - if (memcmp(&ac_full_state.control, &get_ac_state_ref().control, sizeof(HaierPacketControl)) == 0) { - HAIER_LOGI("AC control processed correctly"); - } else { - HAIER_LOGW("AC control not OK"); + CLIENT_SERVER_LOOP(); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + // Sending another status request. Should be no warning this time + hon_client.send_message_without_answer(status_request_message, true); + CLIENT_SERVER_LOOP(); } +#endif unsigned int warn = get_warnings_count(); unsigned int errors = get_errors_count(); - std::cout << "Test results, warning: " << warn << " errors: " << errors << std::endl; - if ((warn != 0) || (errors != 0)) + constexpr int expected_warnings = 0 + +#if defined(RUN_ALL_TESTS) || defined(RUN_TEST8) + 1 + +#endif + 0; + + std::cout << "Test results, warning: " << warn << ", expected: " << expected_warnings << ", errors: " << errors << std::endl; + if ((warn != expected_warnings) || (errors != 0)) exit(1); }