This commit is contained in:
david rice
2026-02-18 13:10:40 +00:00
parent 41803786aa
commit 768b7a21d0

154
looper.py Normal file
View File

@@ -0,0 +1,154 @@
import serial
import struct
import random
import threading
import time
import sys
from pathlib import Path
from datetime import datetime
# Initial state
toggle_state = 0
ser = serial.Serial(port='/dev/ttyACM0', baudrate=115200)
class Tee(object):
def __init__(self, filename):
self.terminal = sys.stdout
self.log = open(filename, "w") # Use "a" to append
def write(self, message):
self.terminal.write(message)
self.log.write(message)
def flush(self):
# This flush method is needed for python 3 compatibility.
self.terminal.flush()
self.log.flush()
def pack_integers_to_bytes(*integers: int) -> bytes:
# Setup Header (Sync bytes)
sync_bytes = [0x41, 0x52]
# Process Data
# Mask each input to 8-bit to prevent packing errors
data_bytes = [i & 0xFF for i in integers]
# Get length
data_length = [len(data_bytes) & 0xFF]
# Calculate Checksum
# Summing all data bytes, then applying bitwise NOT
total_sum = sum(data_bytes)
rx_checksum = ~total_sum
rx_checksum_h = (rx_checksum >> 8) & 0xFF
rx_checksum_l = rx_checksum & 0xFF
checksum_bytes = [rx_checksum_h, rx_checksum_l]
# Combine all components
full_packet = sync_bytes + data_length + data_bytes + checksum_bytes
# Dynamically create format string
# '!' = Network order, 'B' = unsigned char
# We need as many 'B's as there are elements in full_packet
format_string = f"!{len(full_packet)}B"
return struct.pack(format_string, *full_packet)
def trigger_serial_command():
global toggle_state
global ser
global min_delay_input_f
global max_delay_input_f
toggle_state = 1 - toggle_state
if toggle_state == 0:
voltage = 0
voltage_mv = 0
state = 0
print("VOLTAGE SET TO: OFF")
else:
# Generate voltage level
voltage = random.randint(9, 30)
voltage_mv = voltage * 1000
state = 1
print("VOLTAGE SET TO: " + str(voltage) + "V")
# Serial logic
print(f"[{time.strftime('%H:%M:%S')}] SENDING SERIAL COMMAND...")
command = 83 # 0x53 'S' ASCII
b1 = (voltage_mv >> 24) & 0xFF # Most Significant Byte
b2 = (voltage_mv >> 16) & 0xFF
b3 = (voltage_mv >> 8) & 0xFF
b4 = voltage_mv & 0xFF
data = (command, state, b1, b2, b3, b4)
byte_data = pack_integers_to_bytes(*data)
ser.write(serial.to_bytes(byte_data))
# Schedule the NEXT random trigger
# random.uniform(0.1, 100.0) provides the random delay in seconds
delay = random.uniform(min_delay_input_f, max_delay_input_f)
print(f"NEXT COMMAND IN {delay:.2f} SECONDS...")
# Create and start a new timer thread
timer = threading.Timer(delay, trigger_serial_command)
timer.start()
# Run main
if __name__ == '__main__':
now = datetime.now()
# Format as string: YYYY-MM-DD HH:MM:SS
timestamp_str = now.strftime("%Y_%m_%d_%H_%M_%S")
build_path = "~/Python/Automotive-Power-Simulator-App/LOGS/" + timestamp_str + ".txt"
log_file = Path(build_path).expanduser()
sys.stdout = Tee(log_file)
print("LOGGING TO: " + str(log_file))
# Get time constants
print ("PLEASE ENTER A MINIMUM DELAY VALUE...")
min_delay_input = input()
min_delay_input_f = float(min_delay_input)
print("MINIMUM TIME DELAY: " + str(min_delay_input_f))
# Get time constants
print ("PLEASE ENTER A MAXIMUM DELAY VALUE...")
max_delay_input = input()
max_delay_input_f = float(max_delay_input)
print("MAXIMUM TIME DELAY: " + str(max_delay_input_f))
# Start the very first trigger
trigger_serial_command()
# Setup serial port
try:
while (1):
time.sleep(1)
except KeyboardInterrupt:
state = 0
command = 83 # 0x53 'S' ASCII
voltage_mv = 0
b1 = (voltage_mv >> 24) & 0xFF # Most Significant Byte
b2 = (voltage_mv >> 16) & 0xFF
b3 = (voltage_mv >> 8) & 0xFF
b4 = voltage_mv & 0xFF
data = (command, state, b1, b2, b3, b4)
byte_data = pack_integers_to_bytes(*data)
ser.write(serial.to_bytes(byte_data))
ser.close()