Skip to content

Commit 7311e54

Browse files
Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
1 parent 8b62c15 commit 7311e54

3 files changed

Lines changed: 35 additions & 20 deletions

File tree

src/openlifu/io/LIFUDFU.py

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@
1313
import logging
1414
import struct
1515
import time
16-
from typing import TYPE_CHECKING, Callable
1716
import unittest
17+
from typing import TYPE_CHECKING, Callable
18+
19+
import pytest
1820

1921
from openlifu.io.LIFUConfig import OW_ERROR, OW_I2C_PASSTHRU
2022

@@ -230,10 +232,10 @@ def test_parse_signed_package_valid(self) -> None:
230232

231233
parsed = parse_signed_package(pkg)
232234

233-
self.assertEqual(parsed["fw_address"], fw_addr)
234-
self.assertEqual(parsed["meta_address"], meta_addr)
235-
self.assertEqual(parsed["fw"], fw)
236-
self.assertEqual(parsed["meta"], meta)
235+
assert parsed["fw_address"] == fw_addr
236+
assert parsed["meta_address"] == meta_addr
237+
assert parsed["fw"] == fw
238+
assert parsed["meta"] == meta
237239

238240
def test_parse_signed_package_header_crc_mismatch(self) -> None:
239241
"""Corrupt the header so header CRC verification fails."""
@@ -248,7 +250,7 @@ def test_parse_signed_package_header_crc_mismatch(self) -> None:
248250
pkg_bytes[4] ^= 0x01
249251
corrupted = bytes(pkg_bytes)
250252

251-
with self.assertRaises(ValueError):
253+
with pytest.raises(ValueError, match="header CRC mismatch"):
252254
parse_signed_package(corrupted)
253255

254256
def test_parse_signed_package_payload_crc_mismatch(self) -> None:
@@ -265,7 +267,7 @@ def test_parse_signed_package_payload_crc_mismatch(self) -> None:
265267
pkg_bytes[hdr_size] ^= 0x01
266268
corrupted = bytes(pkg_bytes)
267269

268-
with self.assertRaises(ValueError):
270+
with pytest.raises(ValueError, match="payload CRC mismatch"):
269271
parse_signed_package(corrupted)
270272

271273

@@ -531,7 +533,6 @@ def __init__(self, uart: LIFUUart,
531533
write_read_delay_s: float = 0.005):
532534
self._uart = uart
533535
self._addr = i2c_addr
534-
self._wr_delay = write_read_delay_s
535536

536537
# --- low-level transport primitives ---
537538

@@ -554,11 +555,14 @@ def _write(self, payload: bytes) -> None:
554555

555556
def _exchange(self, payload: bytes, read_len: int,
556557
pre_read_delay_s: float | None = None) -> bytes:
557-
"""Write *payload* to the I2C slave, wait, then read *read_len* bytes back.
558-
559-
The firmware inserts a fixed 5 ms gap between write and read.
560-
An optional extra host-side delay can be added via *pre_read_delay_s*
561-
(not usually needed).
558+
"""Write *payload* to the I2C slave and read *read_len* bytes back.
559+
560+
The firmware executes a combined write+read transaction and inserts a
561+
fixed 5 ms gap between the write and read phases internally.
562+
The optional *pre_read_delay_s* parameter adds an extra host-side delay
563+
**before** issuing the passthrough transaction (i.e. before the
564+
firmware performs the write+read). This does *not* change the internal
565+
5 ms gap handled by the firmware and is rarely needed.
562566
"""
563567
if pre_read_delay_s and pre_read_delay_s > 0:
564568
time.sleep(pre_read_delay_s)

src/openlifu/io/LIFUTXDevice.py

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import re
66
import struct
77
from dataclasses import dataclass, field
8-
from typing import TYPE_CHECKING, Annotated, Dict, List, Literal, Optional
8+
from typing import TYPE_CHECKING, Annotated, Dict, List, Literal
99

1010
import numpy as np
1111

@@ -397,7 +397,7 @@ def get_hardware_id(self, module:int=0) -> str:
397397
logger.error("Unexpected error during process: %s", e)
398398
raise # Re-raise the exception for the caller to handle
399399

400-
def read_config(self, module:int=0) -> Optional[LifuUserConfig]:
400+
def read_config(self, module:int=0) -> LifuUserConfig | None:
401401
"""
402402
Read the user configuration from device flash.
403403
@@ -450,7 +450,7 @@ def read_config(self, module:int=0) -> Optional[LifuUserConfig]:
450450
logger.exception("Unexpected error reading config")
451451
raise
452452

453-
def write_config(self, config: LifuUserConfig, module:int=0) -> Optional[LifuUserConfig]:
453+
def write_config(self, config: LifuUserConfig, module:int=0) -> LifuUserConfig | None:
454454
"""
455455
Write user configuration to device flash.
456456
@@ -517,7 +517,7 @@ def write_config(self, config: LifuUserConfig, module:int=0) -> Optional[LifuUse
517517
logger.exception("Unexpected error writing config")
518518
raise
519519

520-
def write_config_json(self, json_str: str, module:int=0) -> Optional[LifuUserConfig]:
520+
def write_config_json(self, json_str: str, module:int=0) -> LifuUserConfig | None:
521521
"""
522522
Write user configuration from a JSON string.
523523
@@ -540,6 +540,13 @@ def write_config_json(self, json_str: str, module:int=0) -> Optional[LifuUserCon
540540
return self.write_config(module=module, config=config)
541541
except json.JSONDecodeError as e:
542542
logger.error(f"Invalid JSON: {e}")
543+
raise ValueError(f"Invalid JSON: {e}") from e
544+
except ValueError as v:
545+
logger.error("ValueError: %s", v)
546+
raise
547+
except (OSError, RuntimeError, AttributeError) as e:
548+
logger.exception("Unexpected error writing config from JSON")
549+
raise
543550

544551
def get_temperature(self, module:int=1) -> float:
545552
"""
@@ -982,7 +989,7 @@ def async_mode(self, enable: bool | None = None) -> bool:
982989
else:
983990
payload = None
984991

985-
r = self.uart.send_packet(id=None, packetType=OW_CONTROLLER, command=OW_CMD_ASYNC, addr=0, data=payload)
992+
r = self.uart.send_packet(id=None, packetType=OW_CMD, command=OW_CMD_ASYNC, addr=0, data=payload)
986993
self.uart.clear_buffer()
987994
# r.print_packet()
988995
if r.packet_type == OW_ERROR:
@@ -1332,7 +1339,7 @@ def write_block(self, identifier: int, start_address: int, reg_values: List[int]
13321339
logger.error("Unexpected error in write_block: %s", e)
13331340
raise # Re-raise the exception for the caller to handle
13341341

1335-
def read_block(self, identifier: int, start_address: int, count: int) -> Optional[List[int]]:
1342+
def read_block(self, identifier: int, start_address: int, count: int) -> List[int] | None:
13361343
"""
13371344
Read a block of consecutive register values from the TX device.
13381345

src/openlifu/io/LIFUUserConfig.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@
33
import json
44
import logging
55
import struct
6+
import zlib
67
from dataclasses import dataclass
78
from typing import Any, Dict
89

910
logger = logging.getLogger(__name__)
1011

1112
# Constants from C code
1213
LIFU_MAGIC = 0x4C494655 # 'LIFU'
13-
LIFU_VER = 0x00010002 # v1.0.0
14+
LIFU_VER = 0x00010002 # v1.0.2
1415

1516
@dataclass
1617
class LifuUserConfigHeader:
@@ -139,6 +140,9 @@ def to_wire_bytes(self) -> bytes:
139140
# Update header with JSON length
140141
self.header.json_len = len(json_bytes)
141142

143+
# Update header CRC based on JSON payload (16-bit from CRC32)
144+
self.header.crc = zlib.crc32(json_bytes) & 0xFFFF
145+
142146
# Build wire format
143147
return self.header.to_bytes() + json_bytes
144148

0 commit comments

Comments
 (0)