"""Trusted native parameter refinement; no fitting or control authority.""" from dataclasses import dataclass import math import struct def _f32(value): # Both lateralTorqueParameters and CarParams.Torque store Float32. return struct.unpack(' _f32(min(.5, .5 * factor)) or not _f32(.5 * friction) <= actual[2] <= _f32(max(.1, 1.5 * friction))): return False positive = controller.lateral_accel_from_torque(controller.steer_max, tune) negative = controller.lateral_accel_from_torque(-controller.steer_max, tune) return controller.pid.pos_limit == positive and controller.pid.neg_limit == negative except (AttributeError, TypeError, ValueError, OverflowError): return False def native_source(sm, cp, now_ns): try: name = 'lateralTorqueParameters' if type(now_ns) is not int or now_ns <= 0 or not sm.all_checks([name]): return None stamp, received = int(sm.logMonoTime[name]), int(round(sm.recv_time[name] * 1e9)) row = sm[name] values = (float(row.latAccelFactorFiltered), float(row.latAccelOffsetFiltered), float(row.frictionCoefficientFiltered)) base = cp.lateralTuning.torque if (not row.useParams or not row.valid or int(row.version) != 1 or not 0 < stamp <= now_ns <= stamp + 500_000_000 or not 0 < stamp <= received <= now_ns <= received + 500_000_000 or not all(math.isfinite(value) for value in values) or not _f32(.7 * float(base.latAccelFactor)) <= values[0] <= _f32(1.3 * float(base.latAccelFactor)) or abs(values[1]) > _f32(min(.5, .5 * float(base.latAccelFactor))) or not _f32(.5 * float(base.friction)) <= values[2] <= _f32(max(.1, 1.5 * float(base.friction)))): return None return stamp, values except (AttributeError, KeyError, TypeError, ValueError, OverflowError): return None def apply_native_refinement(controller, cp, sm, *, now_ns, apply, host=False): """Run the selected writer once; return whether it ran, not receipt validity. Only an exact validated mutation gets a NativeRefinement. An unexpected writer result remains unreceipted and therefore invalidates optional FLM. """ from openpilot.starpilot.flm.runtime_adapter_registry import baseline_values source = native_source(sm, cp, now_ns) if source is None: return False stamp, values = source previous_source = getattr(controller, 'native_learning_source', None) if previous_source is not None and (stamp < previous_source[0] or stamp == previous_source[0] and values != previous_source[1]): return False controller.native_learning_source = (stamp, values) anchor = tuple(controller.native_learning_baseline) last_tick = getattr(controller, 'native_learning_last_tick', 0) dt = (now_ns - last_tick) / 1e9 if last_tick else .01 controller.native_learning_last_tick = now_ns before, fixed = baseline_values(controller), static_values(controller) apply() after = baseline_values(controller) if (static_values(controller) != fixed or not effective_native_valid(controller, cp) or not _valid_transition(controller, cp, before, after, values, host, dt)): # The selected writer ran once; an unreceipted change invalidates FLM. return True if before != after: controller.native_learning_refinement = NativeRefinement(anchor, before, after, fixed, stamp, now_ns, values) controller.native_learning_provenance = (1., *_words(stamp), *_words(now_ns), float(host), dt, float(len(before)), *values, *before, *after) return True def accepts_refinement(controller, receipt, *, before, after, now_ns): return bool(isinstance(receipt, NativeRefinement) and receipt.anchor == tuple(controller.native_learning_baseline) and receipt.before == before and receipt.after == after and receipt.static_before == static_values(controller) and 0 < receipt.applied_ns <= now_ns <= receipt.applied_ns + 50_000_000 and 0 < receipt.source_ns <= receipt.applied_ns <= receipt.source_ns + 500_000_000) def _raw_effective(controller, values): extension = getattr(controller, 'starpilot_extension', None) transformed = values if extension is None else extension.transform_torque_parameters(*values) return tuple(_f32(value) for value in transformed) def _valid_transition(controller, cp, before, after, target, host, dt): if len(before) != len(after) or len(before) < 5 or not 0 < dt or host and dt > .05: return False expected = _raw_effective(controller, target) if not host: return tuple(after[1:4]) == tuple(expected) base = cp.lateralTuning.torque multiplier = float(getattr(getattr(controller, 'starpilot_extension', None), 'parameter_factor', None) or 1.) caps = (.5 * float(base.latAccelFactor) * multiplier * dt, .1 * dt, max(.05, float(base.friction)) * dt) for old, new, wanted, cap in zip(before[1:4], after[1:4], expected, caps, strict=True): if not min(old, wanted) <= new <= max(old, wanted) or abs(new - old) > cap + 1e-12: return False return True def _words(ns): return float(ns >> 32), float(ns & 0xffffffff) def checkpoint_native_valid(controller, cp, *, now_ns): """A changed checkpoint requires its exact source-to-applied receipt.""" from openpilot.starpilot.flm.runtime_adapter_registry import baseline_values try: values = tuple(controller.native_learning_provenance) if not values: return baseline_values(controller) == tuple(controller.native_learning_baseline) if len(values) < 14 or values[0] != 1. or any(not math.isfinite(value) for value in values): return False source_ns = (int(values[1]) << 32) | int(values[2]) applied_ns = (int(values[3]) << 32) | int(values[4]) host, dt, count = int(values[5]), values[6], int(values[7]) if host not in (0, 1) or values[5] != host or count < 5 or count > 32 or values[7] != count or len(values) != 11 + 2 * count: return False if any(value < 0 or value > 0xffffffff or int(value) != value for value in values[1:5]): return False target = values[8:11] before, after = values[11:11 + count], values[11 + count:] base = cp.lateralTuning.torque if (not _f32(.7 * float(base.latAccelFactor)) <= target[0] <= _f32(1.3 * float(base.latAccelFactor)) or abs(target[1]) > _f32(min(.5, .5 * float(base.latAccelFactor))) or not _f32(.5 * float(base.friction)) <= target[2] <= _f32(max(.1, 1.5 * float(base.friction)))): return False return bool(0 < source_ns <= applied_ns <= source_ns + 500_000_000 and 0 < applied_ns <= now_ns and baseline_values(controller) == after and effective_native_valid(controller, cp) and _valid_transition(controller, cp, before, after, target, bool(host), dt)) except (AttributeError, IndexError, TypeError, ValueError, OverflowError): return False