From e1deb4f7dfabc066ab21869bc9583d5f1343f6c4 Mon Sep 17 00:00:00 2001 From: Norbert Takacs Date: Sat, 20 Apr 2024 06:48:30 +0200 Subject: [PATCH 01/10] GenericDisplay: blank leading zeros option Signed-off-by: Norbert Takacs --- src/core/GenericDisplay.cpp | 30 +++++++++++++++++++++++++++++- src/core/GenericDisplay.h | 4 ++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/core/GenericDisplay.cpp b/src/core/GenericDisplay.cpp index ee76d59..7a4a02b 100644 --- a/src/core/GenericDisplay.cpp +++ b/src/core/GenericDisplay.cpp @@ -19,6 +19,8 @@ GenericDisplay::GenericDisplay(bool _use_bcd) data_ref_type = xplmType_Unknown; lua_function = ""; const_value = DBL_MIN; + blank_leading_zeros = true; + minimum_number_of_digits = 1; } GenericDisplay::GenericDisplay(GenericDisplay* other) @@ -32,7 +34,9 @@ GenericDisplay::GenericDisplay(GenericDisplay* other) data_ref_type = other->data_ref_type; const_value = other->const_value; nr_of_bytes = other->nr_of_bytes; + minimum_number_of_digits = other->minimum_number_of_digits; dataref_index = other->dataref_index; + blank_leading_zeros = other->blank_leading_zeros; } GenericDisplay::GenericDisplay():GenericDisplay(true) @@ -45,11 +49,21 @@ void GenericDisplay::set_nr_bytes(int _nr_of_bytes) nr_of_bytes = _nr_of_bytes; } +void GenericDisplay::set_minimum_number_of_digits(int _minimum_number_of_digits) +{ + minimum_number_of_digits = _minimum_number_of_digits; +} + void GenericDisplay::set_bcd(bool _use_bcd) { use_bcd = _use_bcd; } +void GenericDisplay::set_blank_leading_zeros(bool _blank_leading_zeros) +{ + blank_leading_zeros = _blank_leading_zeros; +} + void GenericDisplay::add_dataref(XPLMDataRef _data_ref) { dataref_index = -1; @@ -117,6 +131,9 @@ void GenericDisplay::evaluate_and_store_dataref_value() bool GenericDisplay::get_decimal_components(int number, unsigned char* buffer) { + const unsigned char BLANK_CHAR = 0xFF; + const unsigned char ZERO_CHAR = 0x00; + bool negative = false; if (number < 0) { @@ -134,6 +151,17 @@ bool GenericDisplay::get_decimal_components(int number, unsigned char* buffer) remain = remain % (int)pow(10, dec_pos); } + if (blank_leading_zeros) + { + for (int i = 0; i < nr_of_bytes - minimum_number_of_digits; i++) + { + if (buffer[i] == ZERO_CHAR) + buffer[i] = BLANK_CHAR; + else + break; + } + } + if (negative) buffer[0] = 0xfe; // minus sign @@ -176,4 +204,4 @@ bool GenericDisplay::get_display_value(unsigned char* buffer) guard.unlock(); return use_bcd ? get_decimal_components((int)_val, buffer) : get_binary_components(int(_val), buffer); -} +} \ No newline at end of file diff --git a/src/core/GenericDisplay.h b/src/core/GenericDisplay.h index 7caa637..f4d4306 100644 --- a/src/core/GenericDisplay.h +++ b/src/core/GenericDisplay.h @@ -33,12 +33,16 @@ class GenericDisplay void add_const(double _const_value); void add_lua(std::string _lua_function); void set_bcd(bool _use_bcd); + void set_blank_leading_zeros(bool _blank_leading_zeros); + void set_minimum_number_of_digits(int _minimum_number_of_digits); protected: double display_value; double display_value_old; bool display_value_changed; std::mutex guard; bool use_bcd; + bool blank_leading_zeros; + int minimum_number_of_digits; std::string lua_function; XPLMDataRef condition; XPLMDataTypeID data_ref_type; From 137f6516b1f4cea35eface8db46b2a640499e7c4 Mon Sep 17 00:00:00 2001 From: Norbert Takacs Date: Sat, 20 Apr 2024 12:44:03 +0200 Subject: [PATCH 02/10] test: followup of the blank leading zero property change Signed-off-by: Norbert Takacs --- test/test_multi_panel.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/test_multi_panel.cpp b/test/test_multi_panel.cpp index 97a8ace..a436379 100644 --- a/test/test_multi_panel.cpp +++ b/test/test_multi_panel.cpp @@ -208,10 +208,10 @@ namespace test std::this_thread::sleep_for(150ms); test_hid_get_write_data(write_buffer, sizeof(write_buffer)); - Assert::AreEqual(0, (int)write_buffer[1]); - Assert::AreEqual(0, (int)write_buffer[2]); - Assert::AreEqual(0, (int)write_buffer[3]); - Assert::AreEqual(0, (int)write_buffer[4]); + Assert::AreEqual(255, (int)write_buffer[1]); + Assert::AreEqual(255, (int)write_buffer[2]); + Assert::AreEqual(255, (int)write_buffer[3]); + Assert::AreEqual(255, (int)write_buffer[4]); Assert::AreEqual(0, (int)write_buffer[5]); } From 46944d3ba4159ccf9eba0232f7ef04ccad2f77a8 Mon Sep 17 00:00:00 2001 From: Norbert Takacs Date: Sat, 20 Apr 2024 12:39:41 +0200 Subject: [PATCH 03/10] Device: append selector switch list insted of overwrite Signed-off-by: Norbert Takacs --- src/core/Device.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/core/Device.cpp b/src/core/Device.cpp index 7a8566c..bd45ccc 100644 --- a/src/core/Device.cpp +++ b/src/core/Device.cpp @@ -59,7 +59,8 @@ void Device::register_buttons(std::vector& _buttons) void Device::register_selectors(std::vector& _selectors) { - selectors = _selectors; + for (auto& sel : _selectors) + selectors.push_back(sel); } void Device::register_lights(std::vector& _lights) From d42fd640bd67854c35b33162bee1f8dabe21d3a1 Mon Sep 17 00:00:00 2001 From: Norbert Takacs Date: Sat, 20 Apr 2024 12:40:36 +0200 Subject: [PATCH 04/10] GenericDisplay: Add new constants ZERO and BLANK Signed-off-by: Norbert Takacs --- src/core/GenericDisplay.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/GenericDisplay.h b/src/core/GenericDisplay.h index f4d4306..c5a4595 100644 --- a/src/core/GenericDisplay.h +++ b/src/core/GenericDisplay.h @@ -49,6 +49,8 @@ class GenericDisplay double const_value; int nr_of_bytes; private: + const unsigned char BLANK_CHAR = 0xFF; + const unsigned char ZERO_CHAR = 0x00; int dataref_index; bool get_decimal_components(int number, unsigned char* buffer); bool get_binary_components(int number, unsigned char* buffer); From 5d30920f8493e0d5712c51bc3c8db5f3b2b44689 Mon Sep 17 00:00:00 2001 From: Norbert Takacs Date: Sat, 20 Apr 2024 12:41:12 +0200 Subject: [PATCH 05/10] GenericDisplay: blank display if no valid data set If set MAX_VALUE we turn off the display Signed-off-by: Norbert Takacs --- src/core/GenericDisplay.cpp | 35 ++++++++++++++++++++++++++++------- src/core/GenericDisplay.h | 6 ++++-- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/core/GenericDisplay.cpp b/src/core/GenericDisplay.cpp index 7a4a02b..c10c0ff 100644 --- a/src/core/GenericDisplay.cpp +++ b/src/core/GenericDisplay.cpp @@ -10,6 +10,8 @@ #include "LuaHelper.h" #include "Logger.h" +const double GenericDisplay::MAX_VALUE = 10000000; + GenericDisplay::GenericDisplay(bool _use_bcd) { use_bcd = _use_bcd; @@ -52,16 +54,24 @@ void GenericDisplay::set_nr_bytes(int _nr_of_bytes) void GenericDisplay::set_minimum_number_of_digits(int _minimum_number_of_digits) { minimum_number_of_digits = _minimum_number_of_digits; + Logger(TLogLevel::logDEBUG) << "GenericDisplay: set minimum number of digits: " << _minimum_number_of_digits << std::endl; +} + +int GenericDisplay::get_minimum_number_of_digits() +{ + return minimum_number_of_digits; } void GenericDisplay::set_bcd(bool _use_bcd) { use_bcd = _use_bcd; + Logger(TLogLevel::logDEBUG) << "GenericDisplay: set bcd: " << (_use_bcd ? "yes" : "no") << std::endl; } void GenericDisplay::set_blank_leading_zeros(bool _blank_leading_zeros) { blank_leading_zeros = _blank_leading_zeros; + Logger(TLogLevel::logDEBUG) << "GenericDisplay: set blank leading zero: " << (_blank_leading_zeros ? "yes" : "no") << std::endl; } void GenericDisplay::add_dataref(XPLMDataRef _data_ref) @@ -129,11 +139,8 @@ void GenericDisplay::evaluate_and_store_dataref_value() display_value_old = display_value; } -bool GenericDisplay::get_decimal_components(int number, unsigned char* buffer) +bool GenericDisplay::get_decimal_components(int number, unsigned char* buffer, int _minimum_number_of_digits) { - const unsigned char BLANK_CHAR = 0xFF; - const unsigned char ZERO_CHAR = 0x00; - bool negative = false; if (number < 0) { @@ -153,7 +160,7 @@ bool GenericDisplay::get_decimal_components(int number, unsigned char* buffer) if (blank_leading_zeros) { - for (int i = 0; i < nr_of_bytes - minimum_number_of_digits; i++) + for (int i = 0; i < nr_of_bytes - _minimum_number_of_digits; i++) { if (buffer[i] == ZERO_CHAR) buffer[i] = BLANK_CHAR; @@ -193,7 +200,7 @@ bool GenericDisplay::get_binary_components(int number, unsigned char* buffer) } // called from UsbHidDevice worker thread -bool GenericDisplay::get_display_value(unsigned char* buffer) +bool GenericDisplay::get_display_value(unsigned char* buffer, int _minimum_number_of_digits) { if (!display_value_changed) return false; @@ -203,5 +210,19 @@ bool GenericDisplay::get_display_value(unsigned char* buffer) display_value_changed = false; guard.unlock(); - return use_bcd ? get_decimal_components((int)_val, buffer) : get_binary_components(int(_val), buffer); + bool buffer_changed = false; + if (_val > MAX_VALUE) // display shall be turned off + { + for (int i = 0; i < nr_of_bytes; i++) + { + buffer[i] = BLANK_CHAR; + } + buffer_changed = true; + } + else + { + buffer_changed = use_bcd ? get_decimal_components((int)_val, buffer, _minimum_number_of_digits) : get_binary_components(int(_val), buffer); + } + + return buffer_changed; } \ No newline at end of file diff --git a/src/core/GenericDisplay.h b/src/core/GenericDisplay.h index c5a4595..1db8f86 100644 --- a/src/core/GenericDisplay.h +++ b/src/core/GenericDisplay.h @@ -21,10 +21,12 @@ class GenericDisplay GenericDisplay(bool _use_bcd); // bcd: binary encoded decimal GenericDisplay(GenericDisplay* other); + static const double MAX_VALUE; void set_nr_bytes(int _nr_of_bytes); // called from UsbHidDevice worker thread - virtual bool get_display_value(unsigned char* buffer); + virtual bool get_display_value(unsigned char* buffer, int _minimum_number_of_digits); + virtual int get_minimum_number_of_digits(); // called from XPLane flight loop virtual void evaluate_and_store_dataref_value(); @@ -52,6 +54,6 @@ class GenericDisplay const unsigned char BLANK_CHAR = 0xFF; const unsigned char ZERO_CHAR = 0x00; int dataref_index; - bool get_decimal_components(int number, unsigned char* buffer); + bool get_decimal_components(int number, unsigned char* buffer, int _minimum_number_of_digits); bool get_binary_components(int number, unsigned char* buffer); }; From 55782472b22a12c000da3103801d0a73142dc9fb Mon Sep 17 00:00:00 2001 From: Norbert Takacs Date: Sat, 20 Apr 2024 12:42:23 +0200 Subject: [PATCH 06/10] RadioDevice: Add default constants to not used slector positions If configuration doesn't contain definition for a selector switch position then we set a default const value with DBL_MAX. This will case the display will be blank Signed-off-by: Norbert Takacs --- src/devices/saitek-radio/SaitekRadioPanel.cpp | 52 +++++++++++++------ src/devices/saitek-radio/SaitekRadioPanel.h | 3 +- 2 files changed, 37 insertions(+), 18 deletions(-) diff --git a/src/devices/saitek-radio/SaitekRadioPanel.cpp b/src/devices/saitek-radio/SaitekRadioPanel.cpp index fcdf0a8..a460bb2 100644 --- a/src/devices/saitek-radio/SaitekRadioPanel.cpp +++ b/src/devices/saitek-radio/SaitekRadioPanel.cpp @@ -6,6 +6,7 @@ #include #include +#include #include "core/UsbHidDevice.h" #include "saitek-radio/SaitekRadioPanel.h" #include "core/Logger.h" @@ -17,22 +18,23 @@ SaitekRadioPanel::SaitekRadioPanel(ClassConfiguration& config) :UsbHidDevice(con { // mode selector switch - radio_selectors.push_back(PanelButton(0 * 8 + 0, "SW_UP_COM1")); - radio_selectors.push_back(PanelButton(0 * 8 + 1, "SW_UP_COM2")); - radio_selectors.push_back(PanelButton(0 * 8 + 2, "SW_UP_NAV1")); - radio_selectors.push_back(PanelButton(0 * 8 + 3, "SW_UP_NAV2")); - radio_selectors.push_back(PanelButton(0 * 8 + 4, "SW_UP_ADF")); - radio_selectors.push_back(PanelButton(0 * 8 + 5, "SW_UP_DME")); - radio_selectors.push_back(PanelButton(0 * 8 + 6, "SW_UP_IDT")); - - radio_selectors.push_back(PanelButton(0 * 8 + 7, "SW_DOWN_COM1")); - radio_selectors.push_back(PanelButton(1 * 8 + 0, "SW_DOWN_COM2")); - radio_selectors.push_back(PanelButton(1 * 8 + 1, "SW_DOWN_NAV1")); - radio_selectors.push_back(PanelButton(1 * 8 + 2, "SW_DOWN_NAV2")); - radio_selectors.push_back(PanelButton(1 * 8 + 3, "SW_DOWN_ADF")); - radio_selectors.push_back(PanelButton(1 * 8 + 4, "SW_DOWN_DME")); - radio_selectors.push_back(PanelButton(1 * 8 + 5, "SW_DOWN_IDT")); - register_selectors(radio_selectors); + radio_selectors_up.push_back(PanelButton(0 * 8 + 0, "SW_UP_COM1")); + radio_selectors_up.push_back(PanelButton(0 * 8 + 1, "SW_UP_COM2")); + radio_selectors_up.push_back(PanelButton(0 * 8 + 2, "SW_UP_NAV1")); + radio_selectors_up.push_back(PanelButton(0 * 8 + 3, "SW_UP_NAV2")); + radio_selectors_up.push_back(PanelButton(0 * 8 + 4, "SW_UP_ADF")); + radio_selectors_up.push_back(PanelButton(0 * 8 + 5, "SW_UP_DME")); + radio_selectors_up.push_back(PanelButton(0 * 8 + 6, "SW_UP_IDT")); + register_selectors(radio_selectors_up); + + radio_selectors_down.push_back(PanelButton(0 * 8 + 7, "SW_DOWN_COM1")); + radio_selectors_down.push_back(PanelButton(1 * 8 + 0, "SW_DOWN_COM2")); + radio_selectors_down.push_back(PanelButton(1 * 8 + 1, "SW_DOWN_NAV1")); + radio_selectors_down.push_back(PanelButton(1 * 8 + 2, "SW_DOWN_NAV2")); + radio_selectors_down.push_back(PanelButton(1 * 8 + 3, "SW_DOWN_ADF")); + radio_selectors_down.push_back(PanelButton(1 * 8 + 4, "SW_DOWN_DME")); + radio_selectors_down.push_back(PanelButton(1 * 8 + 5, "SW_DOWN_IDT")); + register_selectors(radio_selectors_down); // buttons & rotation knobs radio_buttons.push_back(PanelButton(2 * 8 + 2, "KNOB_UP_BIG_PLUS")); @@ -56,9 +58,25 @@ SaitekRadioPanel::SaitekRadioPanel(ClassConfiguration& config) :UsbHidDevice(con register_displays(radio_displays); - for (auto &config_display : get_config().multi_displays) + for (auto& config_display : get_config().multi_displays) { config_display.second->set_nr_bytes(display_width); + + if (config_display.first == "RADIO_DISPLAY_STBY_UP" || config_display.first == "RADIO_DISPLAY_ACTIVE_UP") + { + // if no dataref or lua or const registered for a selector position -> turn it off + for (auto& selector : radio_selectors_up) + if (!config_display.second->is_registered_selector(selector.config_name)) + config_display.second->add_condition(selector.config_name, GenericDisplay::MAX_VALUE + 1); + } + + if (config_display.first == "RADIO_DISPLAY_STBY_DOWN" || config_display.first == "RADIO_DISPLAY_ACTIVE_DOWN") + { + // if no dataref or lua or const registered for a selector position -> turn it off + for (auto& selector : radio_selectors_down) + if (!config_display.second->is_registered_selector(selector.config_name)) + config_display.second->add_condition(selector.config_name, GenericDisplay::MAX_VALUE + 1); + } } } diff --git a/src/devices/saitek-radio/SaitekRadioPanel.h b/src/devices/saitek-radio/SaitekRadioPanel.h index e949d5c..0e36448 100644 --- a/src/devices/saitek-radio/SaitekRadioPanel.h +++ b/src/devices/saitek-radio/SaitekRadioPanel.h @@ -14,7 +14,8 @@ class SaitekRadioPanel : public UsbHidDevice { private: std::vector radio_buttons; - std::vector radio_selectors; + std::vector radio_selectors_up; + std::vector radio_selectors_down; std::vector radio_displays; public: SaitekRadioPanel(ClassConfiguration& config); From a761281de42cc18bb6d507897b8029e4d6a83e9a Mon Sep 17 00:00:00 2001 From: Norbert Takacs Date: Thu, 25 Apr 2024 08:45:39 +0200 Subject: [PATCH 07/10] ConfigParser: add blank_leading_zeros and minimum_digit_number options Signed-off-by: Norbert Takacs --- src/core/ConfigParser.cpp | 41 ++++++++++++++++++++++++++++++++++---- src/core/ConfigParser.h | 4 ++++ test/test-valid-config.ini | 6 +++--- 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/src/core/ConfigParser.cpp b/src/core/ConfigParser.cpp index a6a1c81..97d7cca 100644 --- a/src/core/ConfigParser.cpp +++ b/src/core/ConfigParser.cpp @@ -58,6 +58,20 @@ std::vector Configparser::tokenize(std::string line) return tokens; } +bool Configparser::get_and_remove_token_pair(std::vector& tokens, std::string name, std::string& out_value) +{ + for (int i = 0; i < tokens.size(); i += 2) + { + if ((i+1) < tokens.size() && tokens[i] == name) + { + out_value = tokens[i + 1]; + tokens.erase(tokens.begin() + i, tokens.begin() + i + 2); + return true; + } + } + return false; +} + int Configparser::parse_file(std::string file_name, Configuration& config) { last_error_message = ""; @@ -145,11 +159,17 @@ int Configparser::process_ini_section(IniFileSection& section, Configuration& co if (section.header.properties.count(TOKEN_BCD) > 0) config.class_configs.back().generic_displays[section.header.id]->set_bcd(section.header.properties[TOKEN_BCD] == "yes" ? true : false); + if (section.header.properties.count(TOKEN_BLANK_LEADING_ZEROS) > 0) + config.class_configs.back().generic_displays[section.header.id]->set_blank_leading_zeros(section.header.properties[TOKEN_BLANK_LEADING_ZEROS] == "yes" ? true : false); + Logger(TLogLevel::logDEBUG) << "parser: display detected " << section.header.id << std::endl; } else if (section.header.name == TOKEN_SECTION_MULTI_DISPLAY) { config.class_configs.back().multi_displays[section.header.id] = new MultiPurposeDisplay(); + if (section.header.properties.count(TOKEN_BLANK_LEADING_ZEROS) > 0) + config.class_configs.back().multi_displays[section.header.id]->set_blank_leading_zeros(section.header.properties[TOKEN_BLANK_LEADING_ZEROS] == "yes" ? true : false); + Logger(TLogLevel::logDEBUG) << "parser: multi display detected " << section.header.id << std::endl; } else if (section.header.name == TOKEN_SECTION_FIP_SCREEN) @@ -606,6 +626,7 @@ int Configparser::handle_on_lit_or_unlit_or_blink(IniFileSectionHeader section_h int Configparser::handle_on_line_add(IniFileSectionHeader section_header, std::string key, std::string value, Configuration& config) { //line="on_select:SW_ALT,dataref:sim/custom/gauges/compas/pkp_helper_course_L" + //line="on_select:SW_ALT,dataref:sim/custom/gauges/compas/pkp_helper_course_L, minimum_digit_number: 3" //line="dataref:sim/custom/gauges/compas/pkp_helper_course_L" //line="dataref:sim/custom/gauges/compas/test[0] //line="const:1.5" @@ -620,13 +641,25 @@ int Configparser::handle_on_line_add(IniFileSectionHeader section_header, std::s } std::string condition = ""; - if (m[0] == TOKEN_ON_SELECT) + get_and_remove_token_pair(m, TOKEN_ON_SELECT, condition); + + std::string min_digit_number = ""; + get_and_remove_token_pair(m, TOKEN_MIN_DIGIT_NUMBER, min_digit_number); + if (min_digit_number != "") { - condition = m[1]; - m.erase(m.begin(), m.begin() + 2); + if (section_header.name == TOKEN_SECTION_MULTI_DISPLAY) + config.class_configs.back().multi_displays[section_header.id]->set_minimum_number_of_digits(condition, stoi(min_digit_number)); + else if(section_header.name == TOKEN_SECTION_DISPLAY) + config.class_configs.back().generic_displays[section_header.id]->set_minimum_number_of_digits(stoi(min_digit_number)); + else + { + Logger(TLogLevel::logERROR) << "parser: invalid line for device type: " << section_header.name << std::endl; + return EXIT_FAILURE; + } } - if (m.size() < 2) + // at this point only the dataref/lua/const key-value pair shall remain + if (m.size() != 2) { Logger(TLogLevel::logERROR) << "parser: invalid syntax (section starts at line: " << section_header.line << "): " << value << std::endl; return EXIT_FAILURE; diff --git a/src/core/ConfigParser.h b/src/core/ConfigParser.h index 65b0211..67fd91b 100644 --- a/src/core/ConfigParser.h +++ b/src/core/ConfigParser.h @@ -17,6 +17,7 @@ class Configparser std::map process_functions; std::vector tokenize(std::string line); + bool get_and_remove_token_pair(std::vector& tokens, std::string name, std::string& out_value); void check_and_get_array_index(std::string& dataref, int& index); int process_ini_section(IniFileSection& section, Configuration& config); @@ -32,6 +33,7 @@ class Configparser int handle_on_script_file(IniFileSectionHeader section_header, std::string key, std::string value, Configuration& config); int handle_on_line_add(IniFileSectionHeader section_header, std::string key, std::string value, Configuration& config); int handle_on_set_bcd(IniFileSectionHeader section_header, std::string key, std::string value, Configuration& config); + int handle_on_set_blank_leading_zeros(IniFileSectionHeader section_header, std::string key, std::string value, Configuration& config); int handle_on_encoder_inc_or_dec(IniFileSectionHeader section_header, std::string key, std::string value, Configuration& config); int handle_on_fip_serial(IniFileSectionHeader section_header, std::string key, std::string value, Configuration& config); int handle_on_fip_offset(IniFileSectionHeader section_header, std::string key, std::string value, Configuration& config); @@ -80,6 +82,8 @@ class Configparser const std::string TOKEN_LUA = "lua"; const std::string TOKEN_CONST = "const"; const std::string TOKEN_BCD = "bcd"; + const std::string TOKEN_BLANK_LEADING_ZEROS = "blank_leading_zeros"; + const std::string TOKEN_MIN_DIGIT_NUMBER = "minimum_digit_number"; const std::string TOKEN_ON_SELECT = "on_select"; const std::string TOKEN_BEGIN = "begin"; const std::string TOKEN_END = "end"; diff --git a/test/test-valid-config.ini b/test/test-valid-config.ini index de15fa8..5afd148 100644 --- a/test/test-valid-config.ini +++ b/test/test-valid-config.ini @@ -58,11 +58,11 @@ trigger_lit="lua:get_led_status():1" trigger_unlit="lua:get_led_status():0" ;-------- Multi purpose display --- -[multi_display:id="MULTI_DISPLAY_UP"] +[multi_display:id="MULTI_DISPLAY_UP", blank_leading_zeros="yes"] line="on_select:SW_ALT,dataref:sim/custom/gauges/compas/pkp_helper_course_L" line="on_select:SW_VS,dataref:sim/custom/gauges/compas/pkp_helper_course_L" -line="on_select:SW_HDG,dataref:sim/custom/gauges/compas/pkp_helper_course_L" +line="on_select:SW_HDG,dataref:sim/custom/gauges/compas/pkp_helper_course_L, minimum_digit_number: 3" -[multi_display:id="MULTI_DISPLAY_DOWN"] +[multi_display:id="MULTI_DISPLAY_DOWN", bcd="yes", blank_leading_zeros="yes"] line="on_select:SW_ALT,dataref:sim/custom/gauges/compas/pkp_helper_course_L" line="on_select:SW_VS,dataref:sim/custom/gauges/compas/pkp_helper_course_L" From 7b711036614e3c76b84f0045040fd742e1a5edd6 Mon Sep 17 00:00:00 2001 From: Norbert Takacs Date: Sun, 28 Apr 2024 12:04:11 +0200 Subject: [PATCH 08/10] MultipurposeDisplay: Handle minimum_digit_number line option Signed-off-by: Norbert Takacs --- src/core/MultiPurposeDisplay.cpp | 28 +++++++++++++++++++++++++++- src/core/MultiPurposeDisplay.h | 4 ++++ src/core/UsbHidDevice.cpp | 3 ++- 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/core/MultiPurposeDisplay.cpp b/src/core/MultiPurposeDisplay.cpp index bc7bd80..62d6ae1 100644 --- a/src/core/MultiPurposeDisplay.cpp +++ b/src/core/MultiPurposeDisplay.cpp @@ -10,7 +10,8 @@ #include "LuaHelper.h" #include "Logger.h" -MultiPurposeDisplay::MultiPurposeDisplay() +MultiPurposeDisplay::MultiPurposeDisplay(): + GenericDisplay() { active_condition = ""; display_value = 0; @@ -32,6 +33,9 @@ MultiPurposeDisplay::MultiPurposeDisplay(MultiPurposeDisplay* other) const_values = other->const_values; lua_functions = other->lua_functions; data_ref_types = other->data_ref_types; + minimum_number_of_digits = other->minimum_number_of_digits; + blank_leading_zeros = other->blank_leading_zeros; + minimum_number_of_digits_for_condtions = other->minimum_number_of_digits_for_condtions; } void MultiPurposeDisplay::add_condition(std::string selector_sw_name, XPLMDataRef data) @@ -91,6 +95,28 @@ bool MultiPurposeDisplay::is_registered_selector(std::string selector_sw_name) return _registered; } +void MultiPurposeDisplay::set_minimum_number_of_digits(std::string _condition, int _minimum_number_of_digits) +{ + minimum_number_of_digits_for_condtions[_condition] = _minimum_number_of_digits; + Logger(TLogLevel::logDEBUG) << "MultiPurposeDisplay: set minimum number of digits [" + _condition + "]: " << _minimum_number_of_digits << std::endl; +} + +int MultiPurposeDisplay::get_minimum_number_of_digits() +{ + int result = 1; + + guard.lock(); + + if (minimum_number_of_digits_for_condtions.count(active_condition) != 0) + result = minimum_number_of_digits_for_condtions[active_condition]; + else + result = 1; //default 1 + + guard.unlock(); + + return result; +} + /* call this function only from XPlane flight loop */ void MultiPurposeDisplay::evaluate_and_store_dataref_value() { diff --git a/src/core/MultiPurposeDisplay.h b/src/core/MultiPurposeDisplay.h index d384c7b..72bd063 100644 --- a/src/core/MultiPurposeDisplay.h +++ b/src/core/MultiPurposeDisplay.h @@ -23,6 +23,9 @@ class MultiPurposeDisplay : public GenericDisplay void add_condition(std::string selector_sw_name, double const_value); void add_condition(std::string selector_sw_name, std::string lua_str); + void set_minimum_number_of_digits(std::string _condition, int _minimum_number_of_digits); + int get_minimum_number_of_digits(); + // called from UsbHidDevice worker thread void set_condition_active(std::string selector_sw_name); bool is_registered_selector(std::string); @@ -34,6 +37,7 @@ class MultiPurposeDisplay : public GenericDisplay std::map const_values; std::map lua_functions; std::map data_ref_types; + std::map minimum_number_of_digits_for_condtions; std::string active_condition; double display_value; double display_value_old; diff --git a/src/core/UsbHidDevice.cpp b/src/core/UsbHidDevice.cpp index b539ce1..d60a8ab 100644 --- a/src/core/UsbHidDevice.cpp +++ b/src/core/UsbHidDevice.cpp @@ -191,7 +191,8 @@ bool UsbHidDevice::updateOneDisplay(std::pair conf } if (reg_index != -1 && config_display.second != NULL) { - write_buffer_changed |= config_display.second->get_display_value(&write_buffer[reg_index]); + int minimum_number_of_digits = config_display.second->get_minimum_number_of_digits(); + write_buffer_changed |= config_display.second->get_display_value(&write_buffer[reg_index], minimum_number_of_digits); } return write_buffer_changed; From 4fe55371cc435b5cb3afd36237f384106b744349 Mon Sep 17 00:00:00 2001 From: Norbert Takacs Date: Sun, 28 Apr 2024 12:05:06 +0200 Subject: [PATCH 09/10] MultiDevice: Add default constants to not used selector positions Signed-off-by: Norbert Takacs --- src/devices/saitek-multi/SaitekMultiPanel.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/devices/saitek-multi/SaitekMultiPanel.cpp b/src/devices/saitek-multi/SaitekMultiPanel.cpp index 753e334..6b68daf 100644 --- a/src/devices/saitek-multi/SaitekMultiPanel.cpp +++ b/src/devices/saitek-multi/SaitekMultiPanel.cpp @@ -61,9 +61,14 @@ SaitekMultiPanel::SaitekMultiPanel(ClassConfiguration& config) :UsbHidDevice(con register_displays(multi_displays); - for (auto &config_display : get_config().multi_displays) + for (auto& config_display : get_config().multi_displays) { config_display.second->set_nr_bytes(display_width); + + // if no dataref or lua or const registered for a selector position -> turn it off + for (auto& selector : multi_selectors) + if (!config_display.second->is_registered_selector(selector.config_name)) + config_display.second->add_condition(selector.config_name, GenericDisplay::MAX_VALUE + 1); } } @@ -122,7 +127,7 @@ void SaitekMultiPanel::stop(int timeout) Logger(TLogLevel::logDEBUG) << "SaitekMultiPanel::stop called" << std::endl; // Blank the display before exit - unsigned char buff[WRITE_BUFFER_SIZE] = {0,15,15,15,15,15,15,15,15,15,15,0,0}; + unsigned char buff[WRITE_BUFFER_SIZE] = { 0,15,15,15,15,15,15,15,15,15,15,0,0 }; if (send_feature_report(buff, sizeof(buff)) != EXIT_SUCCESS) { Logger(TLogLevel::logERROR) << "SaitekMultiPanel stop. error in write_device" << std::endl; From 984fc1fde0cb16fd6bd2f0765572c5e71a3b81e4 Mon Sep 17 00:00:00 2001 From: Norbert Takacs Date: Sun, 28 Apr 2024 12:34:11 +0200 Subject: [PATCH 10/10] Documentation: Add display properties Signed-off-by: Norbert Takacs --- doc/documentation.md | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) diff --git a/doc/documentation.md b/doc/documentation.md index 05fe67d..05f455f 100644 --- a/doc/documentation.md +++ b/doc/documentation.md @@ -488,8 +488,35 @@ Every LED has a predefined symbolic name that can be seen in this table: ## Displays -A display is a character based 7 segment display device or an analog gauge. It can be used to display numeric values. Please note: Saitek's FIP graphical device has specific device type and config options as it can be seen in [FIP](#ChapterFIP) chapter. -The display value can be either from a dataref or from a LUA function. The display value can be a conditional display which means the value to display depends on the position of a switch. A display that contains conditions called multi-purpose display (multi_display). +Display can be used to display numeric values. It could be a 7 segment LED display or any other type (analogue gauge for example) Please note: Saitek's FIP graphical device has specific device type and config options as it can be seen in [FIP](#ChapterFIP) chapter. +The display value can be either from a dataref or from a LUA function or it can be a constant value. + +### Properties of a display +*Character encoding*: Depends on the HW device, the character encoding could be either binary or BCD (binary coded decimal). This is how the numerical value is coded into bytes. By default, all displays are set to BCD type. If you want to overwrite this behavior, please set it in the config: +``` +[multi_display:id="MULTI_DISPLAY_UP", bcd="no"] +``` + +*Blank leading zeros*: This property does matter only in the case of BCD encoding and 7 digit displays. If it is enabled, then all the leading zeros are blanked. By default, it is turned on. To turn it off, please set it in the config: +``` +[multi_display:id="MULTI_DISPLAY_UP", blank_leading_zeros="no"] +``` + +*Minimum character number*: In case of ```blank_leading_zeros="yes"``` is active, we can set the minimum character number for each line. It will stop removing of leading zeros when the minimum character count has been reached(set the ```min_char_count```): +``` +[multi_display:id="MULTI_DISPLAY_UP"] +line="on_select:SW_ALT,dataref:sim/custom/gauges/compas/pkp_helper_course_L,min_char_count:2" +``` + +The below table contains some examples of different options. We suppose the display is a 5 character wide, BCD encoded display: + +| value | blank_leading_zeros="no" | blank_leading_zeros="yes"
min_char_count:2 | blank_leading_zeros="yes"
min_char_count:1 | +| ----- | ------------------------ | --------------------------------------------- | --------------------------------------------- | +| 100 | 00100 | 100 | 100 | +| 1500 | 01500 | 1500 | 1500 | + +### Multipurpose displays +The display value can be a conditional display which means the value to display depends on the position of a switch. A display that contains conditions called multi-purpose display (multi_display). The 'on_select:HW input name' part defines a condition. If the HW input is in logical 1 state the display will show you the dataref or lua script value in that line, Thi is somehow similar to a @@ -506,6 +533,7 @@ call the LUA function and displays the return value of the function. The SW_ALT or SW_VS will determine which value will be displayed. +### Generic displays If you need a display device without any condition (it means the display will show the same dataeref or lua value all the time) you can define a simple display device in the configuration like this: ```ini @@ -956,3 +984,4 @@ end # Trouble shooting {#trouble-shooting} Xpanel plugin has log mechnism to put log messages into XPlane's main log. Every error detected by the plugin will be put into the main log file (c:\X-Plane12\log.txt in my setup). +