"""Send AMI 0x182 display values through a python-can adapter (no motor actuation).""" import argparse from decimal import Decimal, InvalidOperation import os import struct import time def temperature_raw(value): try: scaled = Decimal(value) * 10 if not scaled.is_finite() or scaled != scaled.to_integral_value(): raise ValueError('temperature must have at most one decimal place') raw = int(scaled) except (InvalidOperation, OverflowError) as exc: raise ValueError('invalid temperature') from exc if not -32768 <= raw <= 32767: raise ValueError('temperature must be -3276.8..3276.7 degC') return raw def build_payload(torque, motor_temp, mcu_temp, valid=7): if not -1000 <= torque <= 1000: raise ValueError('torque must be -1000..1000 permille') if not 0 <= valid <= 7: raise ValueError('valid must be 0..7 (bit0 torque, bit1 motor, bit2 MCU)') return struct.pack('0 and <=2 seconds; duration must be positive and finite') print(f'Standard ID 0x182, DLC 8, data {payload.hex(" ").upper()}, bitrate {args.bitrate}', flush=True) if args.dry_run: return dll_handle = None if args.dll_dir: path = os.path.abspath(args.dll_dir) os.environ['PATH'] = path + os.pathsep + os.environ['PATH'] if hasattr(os, 'add_dll_directory'): dll_handle = os.add_dll_directory(path) import can count = 0 try: with can.Bus(interface=args.interface, channel=args.channel, bitrate=args.bitrate) as bus: message = can.Message(arbitration_id=0x182, is_extended_id=False, data=payload) started = time.monotonic() deadline = started while time.monotonic() < started + args.duration: bus.send(message, timeout=0.2) count += 1 deadline += args.period time.sleep(max(0, min(deadline, started + args.duration) - time.monotonic())) finally: if dll_handle is not None: dll_handle.close() print(f'Sent {count} frames. Values expire after 2 seconds without valid input.') if __name__ == '__main__': main()