Files
RadioPhotonic_PCB_PC_software/tests/conftest.py
2026-02-18 18:41:19 +03:00

109 lines
3.0 KiB
Python

"""
Shared fixtures for laser_control tests.
"""
import pytest
import struct
from unittest.mock import MagicMock, patch
from laser_control.protocol import Protocol, _build_crc, _flipfour, _int_to_hex4
from laser_control.controller import LaserController
from laser_control.conversions import (
current_n_to_ma, temp_n_to_c, temp_ext_n_to_c,
voltage_3v3_n_to_v, voltage_5v_n_to_v, voltage_7v_n_to_v,
)
def make_valid_response(
current1_n: int = 10000,
current2_n: int = 12000,
temp1_n: int = 30000,
temp2_n: int = 32000,
temp_ext1_n: int = 2048,
temp_ext2_n: int = 2048,
mon_3v3_n: int = 2703, # ~3.3V
mon_5v1_n: int = 2731, # ~5.0V
mon_5v2_n: int = 2731,
mon_7v0_n: int = 1042, # ~7.0V
message_id: int = 12345,
) -> bytes:
"""
Build a syntactically valid 30-byte DATA response.
Words (each 2 bytes, little-endian via flipfour):
0 header
1 I1
2 I2
3 TO6_LSB
4 TO6_MSB
5 Temp_1
6 Temp_2
7 Temp_Ext_1
8 Temp_Ext_2
9 MON_3V3
10 MON_5V1
11 MON_5V2
12 MON_7V0
13 Message_ID
14 CRC
"""
words_raw = [
0xABCD, # Word 0 header
current1_n, # Word 1
current2_n, # Word 2
0, # Word 3 TO6_LSB
0, # Word 4 TO6_MSB
temp1_n, # Word 5
temp2_n, # Word 6
temp_ext1_n, # Word 7
temp_ext2_n, # Word 8
mon_3v3_n, # Word 9
mon_5v1_n, # Word 10
mon_5v2_n, # Word 11
mon_7v0_n, # Word 12
message_id, # Word 13
0, # Word 14 CRC placeholder
]
# Build hex string with flipfour applied
hex_str = ""
for w in words_raw:
hex_str += _flipfour(_int_to_hex4(w))
# Compute CRC over words 1..13 (indices 4..55 in hex, i.e. skip word 0)
words_hex = [hex_str[i:i+4] for i in range(0, len(hex_str), 4)]
crc_words = words_hex[1:14] # words 1..13
crc_val = int(crc_words[0], 16)
for w in crc_words[1:]:
crc_val ^= int(w, 16)
# Replace CRC word (stored in wire order, no flipfour)
hex_str = hex_str[:56] + _int_to_hex4(crc_val)
return bytes.fromhex(hex_str)
@pytest.fixture
def valid_response_bytes():
"""Pre-built valid 30-byte device response."""
return make_valid_response()
@pytest.fixture
def mock_serial():
"""Mock serial.Serial object."""
with patch('serial.Serial') as mock_cls:
mock_instance = MagicMock()
mock_instance.is_open = True
mock_cls.return_value = mock_instance
yield mock_instance
@pytest.fixture
def connected_controller(mock_serial):
"""LaserController with mocked serial connection."""
mock_serial.read.return_value = make_valid_response()
ctrl = LaserController(port='/dev/ttyUSB0')
with patch('serial.Serial', return_value=mock_serial):
ctrl._protocol._serial = mock_serial
mock_serial.is_open = True
return ctrl