Skip to content

Commit

Permalink
Merge pull request #104 from norberttak/blank-display-digits
Browse files Browse the repository at this point in the history
Blank leading zeros and not used displays
  • Loading branch information
norberttak authored Apr 28, 2024
2 parents fcfc43a + 984fc1f commit f4d8ca3
Show file tree
Hide file tree
Showing 14 changed files with 221 additions and 42 deletions.
33 changes: 31 additions & 2 deletions doc/documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -488,8 +488,35 @@ Every LED has a predefined symbolic name that can be seen in this table:
</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"<br>min_char_count:2 | blank_leading_zeros="yes"<br>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
Expand All @@ -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
Expand Down Expand Up @@ -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).

41 changes: 37 additions & 4 deletions src/core/ConfigParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,20 @@ std::vector<std::string> Configparser::tokenize(std::string line)
return tokens;
}

bool Configparser::get_and_remove_token_pair(std::vector<std::string>& 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 = "";
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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"
Expand All @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions src/core/ConfigParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class Configparser

std::map<std::string, f_handle_on_key_value> process_functions;
std::vector<std::string> tokenize(std::string line);
bool get_and_remove_token_pair(std::vector<std::string>& 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);

Expand All @@ -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);
Expand Down Expand Up @@ -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";
Expand Down
3 changes: 2 additions & 1 deletion src/core/Device.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ void Device::register_buttons(std::vector<PanelButton>& _buttons)

void Device::register_selectors(std::vector<PanelButton>& _selectors)
{
selectors = _selectors;
for (auto& sel : _selectors)
selectors.push_back(sel);
}

void Device::register_lights(std::vector<PanelLight>& _lights)
Expand Down
57 changes: 53 additions & 4 deletions src/core/GenericDisplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -19,6 +21,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)
Expand All @@ -32,7 +36,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)
Expand All @@ -45,9 +51,27 @@ 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;
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)
Expand Down Expand Up @@ -115,7 +139,7 @@ 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)
{
bool negative = false;
if (number < 0)
Expand All @@ -134,6 +158,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

Expand Down Expand Up @@ -165,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;
Expand All @@ -175,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;
}
12 changes: 10 additions & 2 deletions src/core/GenericDisplay.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -33,19 +35,25 @@ 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;
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_decimal_components(int number, unsigned char* buffer, int _minimum_number_of_digits);
bool get_binary_components(int number, unsigned char* buffer);
};
28 changes: 27 additions & 1 deletion src/core/MultiPurposeDisplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
#include "LuaHelper.h"
#include "Logger.h"

MultiPurposeDisplay::MultiPurposeDisplay()
MultiPurposeDisplay::MultiPurposeDisplay():
GenericDisplay()
{
active_condition = "";
display_value = 0;
Expand All @@ -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)
Expand Down Expand Up @@ -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()
{
Expand Down
4 changes: 4 additions & 0 deletions src/core/MultiPurposeDisplay.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -34,6 +37,7 @@ class MultiPurposeDisplay : public GenericDisplay
std::map<std::string, double> const_values;
std::map<std::string, std::string> lua_functions;
std::map<std::string, XPLMDataTypeID> data_ref_types;
std::map<std::string, int> minimum_number_of_digits_for_condtions;
std::string active_condition;
double display_value;
double display_value_old;
Expand Down
3 changes: 2 additions & 1 deletion src/core/UsbHidDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,8 @@ bool UsbHidDevice::updateOneDisplay(std::pair<std::string, GenericDisplay*> 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;
Expand Down
Loading

0 comments on commit f4d8ca3

Please sign in to comment.