fix(wafer): derive family sensor counts from YAML layouts, bound frame decode to layout
This commit is contained in:
@@ -1,9 +1,14 @@
|
|||||||
"""Single source of truth for the wafer sensor-count partition."""
|
"""Single source of truth for the wafer sensor-count partition."""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from pygui.backend.wafer.wafer_layouts import load_layout_for_wafer_id
|
||||||
|
|
||||||
|
|
||||||
def sensor_count_for(family_code: str) -> int:
|
def sensor_count_for(family_code: str) -> int:
|
||||||
"""Return the number of valid sensor readings for a wafer family code.
|
"""Real sensor count for a wafer family code, from its YAML layout.
|
||||||
|
|
||||||
Returns 80 for the "X" family. Returns 244 for every other family
|
0 for an unknown/empty family code."""
|
||||||
code."""
|
try:
|
||||||
return 80 if family_code == "X" else 244
|
return len(load_layout_for_wafer_id(family_code))
|
||||||
|
except KeyError:
|
||||||
|
return 0
|
||||||
|
|||||||
@@ -20,17 +20,7 @@ log = logging.getLogger(__name__)
|
|||||||
|
|
||||||
def csv_column_count(family_code: str) -> int:
|
def csv_column_count(family_code: str) -> int:
|
||||||
"""Return the number of columns to display for a family code."""
|
"""Return the number of columns to display for a family code."""
|
||||||
mapping = {
|
return sensor_count_for(family_code)
|
||||||
"A": 48,
|
|
||||||
"E": 48,
|
|
||||||
"P": 48,
|
|
||||||
"B": 29,
|
|
||||||
"C": 29,
|
|
||||||
"D": 29,
|
|
||||||
"F": 22,
|
|
||||||
"X": 80,
|
|
||||||
}
|
|
||||||
return mapping.get(family_code, 0)
|
|
||||||
|
|
||||||
|
|
||||||
def _hex_to_binary(hex_str: str) -> list[int]:
|
def _hex_to_binary(hex_str: str) -> list[int]:
|
||||||
|
|||||||
@@ -42,8 +42,13 @@ class TestCsvColumnCount:
|
|||||||
def test_x_family(self):
|
def test_x_family(self):
|
||||||
assert csv_column_count("X") == 80
|
assert csv_column_count("X") == 80
|
||||||
|
|
||||||
|
def test_z_family(self):
|
||||||
|
# Z has a real YAML layout (zwafer.yaml) — not "unknown" like the
|
||||||
|
# old hardcoded table implied by omitting it.
|
||||||
|
assert csv_column_count("Z") == 65
|
||||||
|
|
||||||
def test_unknown_family_returns_zero(self):
|
def test_unknown_family_returns_zero(self):
|
||||||
assert csv_column_count("Z") == 0
|
assert csv_column_count("Q") == 0
|
||||||
|
|
||||||
def test_empty_string_returns_zero(self):
|
def test_empty_string_returns_zero(self):
|
||||||
assert csv_column_count("") == 0
|
assert csv_column_count("") == 0
|
||||||
@@ -134,11 +139,11 @@ class TestParseBinaryData:
|
|||||||
assert result is not None
|
assert result is not None
|
||||||
assert len(result) == 1
|
assert len(result) == 1
|
||||||
|
|
||||||
def test_p_family_single_block_row_has_244_sensors(self):
|
def test_p_family_single_block_row_has_48_sensors(self):
|
||||||
data = _make_p_block(1)
|
data = _make_p_block(1)
|
||||||
result = parse_binary_data(data, "P")
|
result = parse_binary_data(data, "P")
|
||||||
assert result is not None
|
assert result is not None
|
||||||
assert len(result[0]) == 244
|
assert len(result[0]) == 48
|
||||||
|
|
||||||
def test_p_family_two_blocks_returns_two_rows(self):
|
def test_p_family_two_blocks_returns_two_rows(self):
|
||||||
data = _make_p_block(2)
|
data = _make_p_block(2)
|
||||||
@@ -170,7 +175,7 @@ class TestParseBinaryData:
|
|||||||
data = _make_p_block(1)
|
data = _make_p_block(1)
|
||||||
result = parse_binary_data(data, "A")
|
result = parse_binary_data(data, "A")
|
||||||
assert result is not None
|
assert result is not None
|
||||||
assert len(result[0]) == 244
|
assert len(result[0]) == 48
|
||||||
|
|
||||||
def test_empty_bytes_returns_empty_list(self):
|
def test_empty_bytes_returns_empty_list(self):
|
||||||
result = parse_binary_data(b"", "P")
|
result = parse_binary_data(b"", "P")
|
||||||
|
|||||||
@@ -85,6 +85,10 @@ def test_clear_activity_log(controller):
|
|||||||
controller.clearActivityLog()
|
controller.clearActivityLog()
|
||||||
assert len(controller._activity_log) == 0
|
assert len(controller._activity_log) == 0
|
||||||
|
|
||||||
|
def test_append_activity_log_appends_to_activity_log(controller):
|
||||||
|
controller.appendActivityLog("Review trial expired")
|
||||||
|
assert "Review trial expired" in controller.activityLog
|
||||||
|
|
||||||
def test_clear_session(controller):
|
def test_clear_session(controller):
|
||||||
controller._connection_status = "Connected"
|
controller._connection_status = "Connected"
|
||||||
controller._selected_port = "COM1"
|
controller._selected_port = "COM1"
|
||||||
@@ -236,12 +240,12 @@ def test_parse_and_save_data_and_get_chart_data(controller):
|
|||||||
assert emitted_result is not None
|
assert emitted_result is not None
|
||||||
assert emitted_result.get("success") is True
|
assert emitted_result.get("success") is True
|
||||||
assert controller.dataRowCount == 1
|
assert controller.dataRowCount == 1
|
||||||
assert controller.dataColCount == 244
|
assert controller.dataColCount == 48
|
||||||
|
|
||||||
chart_res = controller.getChartData()
|
chart_res = controller.getChartData()
|
||||||
assert chart_res.get("success") is True
|
assert chart_res.get("success") is True
|
||||||
assert "Sensor1" in chart_res.get("sensor_names")
|
assert "Sensor1" in chart_res.get("sensor_names")
|
||||||
assert len(chart_res.get("series")) == 244
|
assert len(chart_res.get("series")) == 48
|
||||||
|
|
||||||
def test_logging_handler(controller):
|
def test_logging_handler(controller):
|
||||||
logger = logging.getLogger("test_logger")
|
logger = logging.getLogger("test_logger")
|
||||||
|
|||||||
+23
-10
@@ -1,4 +1,8 @@
|
|||||||
"""Tests for the shared wafer family sensor-count lookup."""
|
"""Tests for the shared wafer family sensor-count lookup.
|
||||||
|
|
||||||
|
Real counts, one per YAML layout file — this is the ground truth every
|
||||||
|
caller (streaming decode, NVRAM parsing, CSV column count) must agree on.
|
||||||
|
"""
|
||||||
from pygui.backend.wafer.family_spec import sensor_count_for
|
from pygui.backend.wafer.family_spec import sensor_count_for
|
||||||
|
|
||||||
|
|
||||||
@@ -6,18 +10,27 @@ def test_x_family_returns_80():
|
|||||||
assert sensor_count_for("X") == 80
|
assert sensor_count_for("X") == 80
|
||||||
|
|
||||||
|
|
||||||
def test_p_family_returns_244():
|
def test_aep_family_returns_48():
|
||||||
assert sensor_count_for("P") == 244
|
for code in ("A", "E", "P"):
|
||||||
|
assert sensor_count_for(code) == 48
|
||||||
|
|
||||||
|
|
||||||
def test_other_known_families_return_244():
|
def test_bcd_family_returns_29():
|
||||||
for code in ("A", "B", "C", "D", "E", "F"):
|
for code in ("B", "C", "D"):
|
||||||
assert sensor_count_for(code) == 244
|
assert sensor_count_for(code) == 29
|
||||||
|
|
||||||
|
|
||||||
def test_unknown_family_returns_244():
|
def test_f_family_returns_22():
|
||||||
assert sensor_count_for("Z") == 244
|
assert sensor_count_for("F") == 22
|
||||||
|
|
||||||
|
|
||||||
def test_empty_string_returns_244():
|
def test_z_family_returns_65():
|
||||||
assert sensor_count_for("") == 244
|
assert sensor_count_for("Z") == 65
|
||||||
|
|
||||||
|
|
||||||
|
def test_unknown_family_returns_zero():
|
||||||
|
assert sensor_count_for("Q") == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_empty_string_returns_zero():
|
||||||
|
assert sensor_count_for("") == 0
|
||||||
|
|||||||
Reference in New Issue
Block a user