Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Segment Displays: Stack vs Replace Option #1779

Merged
merged 6 commits into from
Mar 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions mpf/config_spec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1479,6 +1479,7 @@ segment_displays:
default_transition_update_hz: single|float_or_token|30
platform_settings: single|dict|None
platform: single|str|None
update_method: single|str|None
light_segment_displays_device:
lights: list|dict(str:machine(lights))|None
light_groups: list|machine(neoseg_displays)|None
Expand Down
34 changes: 29 additions & 5 deletions mpf/devices/segment_display/segment_display.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,18 +127,38 @@ def validate_and_parse_config(self, config: dict, is_mode_config: bool, debug_pr
platform.assert_has_feature("segment_displays")
config['platform_settings'] = platform.validate_segment_display_section(self,
config.get('platform_settings', None))

# For backwards compatibility, an undefined update_method config will be mapped
# to "stack". However the default in a future version will be "replace", so inform
# the user that they should explicitly define "stack" to avoid a breaking change.
if config['update_method'] is None:
self.warning_log("Segment display update_method will default to 'replace' in a future MPF release. "
"You have no config value specified and are currently getting 'stack' for backwards "
"compatibility. To avoid a breaking change, please set 'update_method: \"stack\"' "
"in your segment display config.")
config['update_method'] = "stack"
return config

# pylint: disable-msg=too-many-arguments
def add_text_entry(self, text, color, flashing, flash_mask, transition, transition_out, priority, key):
"""Add text to display stack.
"""Add text to display stack, or send it directly to the display.

This will replace texts with the same key.
"""
# remove old text in case it has the same key
self._text_stack[key] = TextStackEntry(
text, color, flashing, flash_mask, transition, transition_out, priority, key)
self._update_stack()
if self.config['update_method'] == "stack":
self._text_stack[key] = TextStackEntry(
text, color, flashing, flash_mask, transition, transition_out, priority, key)
self._update_stack()
return

if self.config['update_method'] != "replace":
raise ValueError(f"Unknown update_method '{self.config['update_method']}' for segment display {self.name}")

# For the replace-text update method, skip the stack and write straight to the display
new_text = TextTemplate(self.machine, text).evaluate({})
text = SegmentDisplayText.from_str(new_text, self.size, self.config['integrated_dots'],
self.config['integrated_commas'], color)
self._update_display(SegmentDisplayState(text, flashing, flash_mask))

def add_text(self, text: str, priority: int = 0, key: str = None) -> None:
"""Add text to display stack.
Expand All @@ -149,6 +169,10 @@ def add_text(self, text: str, priority: int = 0, key: str = None) -> None:

def remove_text_by_key(self, key: Optional[str]):
"""Remove entry from text stack."""
if self.config['update_method'] != "stack":
self.info_log("Segment display 'remove' action is TBD.")
return

if key in self._text_stack:
del self._text_stack[key]
self._update_stack()
Expand Down
2 changes: 2 additions & 0 deletions mpf/platforms/fast/communicators/seg.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ def _update_segs(self, **kwargs):

if s.next_color:
self.send_and_forget(('PC:{},{}').format(s.hex_id, s.next_color))
s.current_color = s.next_color
s.next_color = None

async def soft_reset(self):
Expand All @@ -49,3 +50,4 @@ def stopping(self):
self.send_and_forget(f'PA:{s.hex_id},')
s.next_text = None
s.next_color = None
s.current_color = None
13 changes: 10 additions & 3 deletions mpf/platforms/fast/fast_segment_display.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class FASTSegmentDisplay(SegmentDisplayPlatformInterface):

"""FAST segment display."""

__slots__ = ["serial", "hex_id", "next_color", "next_text"]
__slots__ = ["serial", "hex_id", "next_color", "next_text", "current_color"]

def __init__(self, index, communicator):
"""Initialize alpha numeric display."""
Expand All @@ -23,6 +23,7 @@ def __init__(self, index, communicator):
self.hex_id = Util.int_to_hex_string(index * 7)
self.next_color = None
self.next_text = None
self.current_color = None

def set_text(self, text: ColoredSegmentDisplayText, flashing: FlashingType, flash_mask: str) -> None:
"""Set digits to display."""
Expand All @@ -36,6 +37,12 @@ def set_text(self, text: ColoredSegmentDisplayText, flashing: FlashingType, flas
def _set_color(self, colors: List[RGBColor]) -> None:
"""Set display color."""
if len(colors) == 1:
self.next_color = (RGBColor(colors[0]).hex + ',') * 7
next_color = (RGBColor(colors[0]).hex + ',') * 7
else:
self.next_color = ','.join([RGBColor(color).hex for color in colors]) + ','
next_color = ','.join([RGBColor(color).hex for color in colors]) + ','

# Current color is set by the FastSegCommunicator after the serial
# command is written to set the color (which happens automatically
# on the next loop whenever self.next_color is set).
if next_color != self.current_color:
self.next_color = next_color
6 changes: 6 additions & 0 deletions mpf/tests/machine_files/segment_display/config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ segment_displays:
number: 1
size: 10
integrated_dots: true
display_stack:
number: 4
update_method: stack
display_replace:
number: 5
update_method: replace

segment_display_player:
test_event1:
Expand Down
15 changes: 15 additions & 0 deletions mpf/tests/test_SegmentDisplay.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,21 @@ def test_game(self):
self.assertEqual(" ", display5.hw_display.text)
self.assertEqual(FlashingType.NO_FLASH, display5.hw_display.flashing)

def test_update_method(self):
display_stack = self.machine.segment_displays["display_stack"]
display_replace = self.machine.segment_displays["display_replace"]

for i in range(0, 10):
display_stack.add_text(f"STACK {i}", key=i, priority=i)
display_replace.add_text(f"REPLC {i}", key=i, priority=i)
self.advance_time_and_run(0.5)

self.assertEqual("STACK 9", display_stack.hw_display.text)
self.assertEqual("REPLC 9", display_replace.hw_display.text)

self.assertEqual(len(display_stack._text_stack), 10)
self.assertEqual(len(display_replace._text_stack), 0)

def test_player(self):
display1 = self.machine.segment_displays["display1"]
display2 = self.machine.segment_displays["display2"]
Expand Down
Loading