From b8f34dd2a9a8f1002a3a079b56469c227bcf41bd Mon Sep 17 00:00:00 2001 From: edo-neo Date: Wed, 15 Oct 2025 15:03:50 +0200 Subject: [PATCH] dev free_fall --- src/components/tecna_marposs_provaset_t3.py | 45 ++++++++++++++++++--- src/ui/test/test.py | 23 +++++++++++ 2 files changed, 62 insertions(+), 6 deletions(-) diff --git a/src/components/tecna_marposs_provaset_t3.py b/src/components/tecna_marposs_provaset_t3.py index 24e3c67..6e2deb3 100644 --- a/src/components/tecna_marposs_provaset_t3.py +++ b/src/components/tecna_marposs_provaset_t3.py @@ -359,21 +359,23 @@ class TecnaMarpossProvasetT3(ModbusComponent): recipe_name += b"\x00" * (16 - len(recipe_name)) recipe_barcode = f"j{recipe.part_number}"[:16].encode("ascii") recipe_barcode += b"\x00" * (24 - len(recipe_barcode)) + # Base flags and PID mode test_flags = 0b0110100001010000 if (step.spec.get("autotest", False) in ["ko_check"]) else 0b0110000001010000 - pid_mode_text = step.spec.get("pid_mod_config","AUTO") # Get the selected text from the combobox + pid_mode_text = step.spec.get("pid_mod_config", "AUTO") # Get the selected text from the combobox pid_mode_value = { # Mapping of text to numeric values "AUTO": 5, "FAST": 0, "MEDIUM": 1, "SLOW": 2, }.get(pid_mode_text, 5) - + # Inject PID mode bits (bits 4..6) test_flags = (test_flags & ~(7 << 4)) | (pid_mode_value << 4) - pid_ramps=0b0000000000000000 | int(self.config["recipes_defaults"]["pid_level"])<<8 | int(self.config["recipes_defaults"]["pid_speed"])<<12 + pid_ramps = 0b0000000000000000 | int(self.config["recipes_defaults"]["pid_level"]) << 8 | int(self.config["recipes_defaults"]["pid_speed"]) << 12 # Build a robust map of parameters with safe defaults, so Free Fall (minimal spec) won't crash _defs = self.config.get("recipes_defaults", {}) or {} _s = step.spec or {} + def _gv(key, def_key=None, fallback_key=None): if key in _s: return _s.get(key) @@ -382,7 +384,38 @@ class TecnaMarpossProvasetT3(ModbusComponent): if def_key is not None: return int(_defs.get(def_key, 0)) if isinstance(_defs.get(def_key, 0), (int, float, str)) else 0 return 0 + + # Determine nominal pressure; for Free Fall we allow "filling_pressure" to be the nominal test_pressure_val = _gv("test_pressure", "pressione_di_test", fallback_key="filling_pressure") + + # Free Fall specific behavior + is_free_fall = (step.step_type == "test_freefall_leak") + test_type_value = "Leak Test" + if is_free_fall: + # Use Blockage test type for Free Fall as requested (code 2 in registers map) + test_type_value = "Blockage" + # Set/clear T1/Pr (bit 1) based on continuous_filling: True => pressure mode + if bool(_s.get("continuous_filling", False)): + test_flags |= (1 << 1) + else: + test_flags &= ~(1 << 1) + + # Compute pressure tolerances in % from absolute min/max if provided (for Free Fall) + pr_minus_percent = None + pr_plus_percent = None + try: + nominal = float(test_pressure_val) if test_pressure_val is not None else 0.0 + if is_free_fall and nominal > 0: + if _s.get("pressure_min") is not None: + pmin = max(0.0, float(_s.get("pressure_min"))) + pr_minus_percent = max(0.0, min(999.9, ((nominal - pmin) * 100.0) / nominal)) + if _s.get("pressure_max") is not None: + pmax = max(0.0, float(_s.get("pressure_max"))) + pr_plus_percent = max(0.0, min(999.9, ((pmax - nominal) * 100.0) / nominal)) + except Exception: + pr_minus_percent = pr_minus_percent if pr_minus_percent is not None else None + pr_plus_percent = pr_plus_percent if pr_plus_percent is not None else None + spec = { "Flag: Instrument settings": 0b0000000000000000, "Test program for read/write operation": table, @@ -391,14 +424,14 @@ class TecnaMarpossProvasetT3(ModbusComponent): **{761 - 1 + i: (recipe_name[i * 2 + 1] << 8) + recipe_name[i * 2] for i in range(8)}, # print field 1 # **{769 - 1 + i: (recipe_name[i * 2 + 1] << 8) + recipe_name[i * 2] for i in range(8)}, # print field 2 "Print options": 0b0000000000000000 | self.saver_label_count << 12 | self.saver_print_on_fail << 8 | self.saver_label_template, - "Test type": "Leak Test", + "Test type": test_type_value, "Test flags": test_flags, "T0 - Pre-filling time": _gv("pre_filling_time", "tempo_pre_riempimento"), "P0 - Pre-filling pressure": _gv("pre_filling_pressure", "pressione_pre_riempimento"), "T1 - Filling time": _gv("filling_time", "tempo_riempimento"), "T2 - Settling time": _gv("settling_time", "tempo_assestamento"), - "PR- - Min pressure tolerance %": _gv("settling_pressure_min_percent", "percentuale_minima_pressione_assestamento"), - "PR+ - Max pressure tolerance % (P+)": _gv("settling_pressure_max_percent", "percentuale_massima_pressione_assestamento"), + "PR- - Min pressure tolerance %": (pr_minus_percent if pr_minus_percent is not None else _gv("settling_pressure_min_percent", "percentuale_minima_pressione_assestamento")), + "PR+ - Max pressure tolerance % (P+)": (pr_plus_percent if pr_plus_percent is not None else _gv("settling_pressure_max_percent", "percentuale_massima_pressione_assestamento")), "T3 - Measure time": _gv("test_time", "tempo_di_test"), "Q- Lower test leak limit": _gv("test_pressure_qneg", "pressione_di_test_delta_minimo"), "PREL - Nominal test pressure": test_pressure_val, diff --git a/src/ui/test/test.py b/src/ui/test/test.py index 8c95638..27db990 100755 --- a/src/ui/test/test.py +++ b/src/ui/test/test.py @@ -403,6 +403,9 @@ class Test(Widget): else: self.log.info(f"cycle step: {self.step!r} action: {action!r} current index:{self.cycle_index}") + # Track the previous step type to enable transition hooks (e.g., Free Fall -> Leak_1) + prev_step_type = self.step.step_type if self.step is not None else None + current_w = self.centralWidget if hasattr(current_w, "stop"): @@ -523,6 +526,26 @@ class Test(Widget): if self.recipe is not None and "recipe" not in self.data: self.data["recipe"] = model_to_dict(self.recipe) + # If transitioning from Free Fall to Leak 1, preload Leak 1 parameters onto the tester + try: + if ( + prev_step_type == "test_freefall_leak" + and self.step is not None + and self.step.step_type == "leak_1" + and hasattr(self, "tester_component") + and self.tester_component in (self.components or {}) + ): + self.log.info("Transition detected: Free Fall -> Leak_1. Pre-writing Leak_1 recipe to tester.") + self.components[self.tester_component].write_recipe(self.recipe, self.step) + leak1 = self.cycle_available_steps.get("leak_1") + if leak1 is not None and getattr(leak1, "widget", None) is not None: + leak1.widget.recipe_written = True + except Exception as e: + try: + self.log.exception(f"Failed to pre-write Leak_1 recipe after Free Fall: {e}") + except Exception: + pass + # Remaining logic for updating widgets, starting timers, etc. w = self.cycle_available_steps[self.step.step_type] show = None