#!/usr/bin/env python3
# clone_eeprom.py — простой клонер 1-Wire EEPROM (DS2433 style)
# Run with sudo: sudo python3 clone_eeprom.py
import time, os, glob, hashlib, subprocess, sys
W1_PATH = "/sys/bus/w1/devices"
DUMP_DIR = "dumps"
READ_TIMEOUT = 12 # seconds for read (adjust if needed)
HOLD_SECONDS = 6 # how long user should hold the button
def list_devices():
# look for 1-wire device ids that typically start with "23-" (DS2433 family)
ids = []
for p in glob.glob(os.path.join(W1_PATH, "23-*")):
ids.append(os.path.basename(p))
return sorted(ids)
def wait_for_device(prompt):
print(prompt)
print(f"Нажмите и держите кнопку ~{HOLD_SECONDS}s, затем Enter чтобы начать ожидание...")
input()
print("Ожидаю появления устройства на шине 1-Wire...")
# poll for device for up to 20 seconds
for i in range(30):
ids = list_devices()
if ids:
uid = ids[0]
print("Найдено устройство:", uid)
return uid
time.sleep(1)
print("Устройство не появилось. Проверьте проводку/кнопку и попробуйте снова.")
return None
def read_eeprom(uid, outpath):
eeprom_path = os.path.join(W1_PATH, uid, "eeprom")
if not os.path.exists(eeprom_path):
# sometimes device layout includes w1_bus_master1 folder variant
alt = glob.glob(os.path.join(W1_PATH, "w1_bus_master1", uid, "eeprom"))
if alt:
eeprom_path = alt[0]
if not os.path.exists(eeprom_path):
raise FileNotFoundError("eeprom path not found for " + uid)
print("Читаю EEPROM из", eeprom_path)
# use dd via shell with timeout to avoid hangs
cmd = f"timeout {READ_TIMEOUT} dd if={eeprom_path} bs=1 count=512 of={outpath}"
rc = subprocess.call(cmd, shell=True)
if rc != 0:
raise RuntimeError("Чтение EEPROM не удалось (dd rc="+str(rc)+")")
size = os.path.getsize(outpath)
if size != 512:
raise RuntimeError(f"Неполный дамп: {size} байт (ожидалось 512)")
print("Записал дамп в", outpath)
return outpath
def write_eeprom(uid, inpath):
eeprom_path = os.path.join(W1_PATH, uid, "eeprom")
if not os.path.exists(eeprom_path):
alt = glob.glob(os.path.join(W1_PATH, "w1_bus_master1", uid, "eeprom"))
if alt:
eeprom_path = alt[0]
if not os.path.exists(eeprom_path):
raise FileNotFoundError("eeprom path not found for " + uid)
print("Записываю", inpath, "->", eeprom_path)
# use cat with sudo via shell; assume script runs as root, so direct redirect works
cmd = f"dd if={inpath} bs=1 count=512 of={eeprom_path}"
rc = subprocess.call(cmd, shell=True)
if rc != 0:
raise RuntimeError("Запись EEPROM не удалась (rc="+str(rc)+")")
print("Запись завершена.")
return eeprom_path
def sha1(path):
h = hashlib.sha1()
with open(path,"rb") as f:
h.update(f.read())
return h.hexdigest()
def ensure_dir(d):
if not os.path.exists(d):
os.makedirs(d, exist_ok=True)
def main():
if os.geteuid() != 0:
print("Запускать нужно с sudo: sudo python3 clone_eeprom.py")
sys.exit(1)
ensure_dir(DUMP_DIR)
# First chip
uid1 = wait_for_device("Подключите ПЕРВЫЙ чип.")
if not uid1:
return
time.sleep(0.5)
out1 = os.path.join(DUMP_DIR, f"{uid1}.bin")
try:
print(f"Держите кнопку ещё {HOLD_SECONDS}s...")
time.sleep(HOLD_SECONDS)
read_eeprom(uid1, out1)
except Exception as e:
print("Ошибка при чтении первого чипа:", e)
return
print("SHA1:", sha1(out1))
# Second chip
print("\nОтключите ПЕРВЫЙ чип и ПОДКЛЮЧИТЕ ВТОРОЙ чип.")
input("Когда второй чип подключён — нажмите Enter...")
uid2 = wait_for_device("Подключите ВТОРОЙ чип.")
if not uid2:
return
if uid2 == uid1:
print("Обнаружен тот же UID! Убедитесь, что второй чип подключён.")
# still allow: continue
out2 = os.path.join(DUMP_DIR, f"{uid2}.bin")
try:
print(f"Держите кнопку ещё {HOLD_SECONDS}s...")
time.sleep(HOLD_SECONDS)
# before writing, read existing content (backup)
try:
read_eeprom(uid2, out2+".backup")
print("Сделан бэкап второго чипа:", out2+".backup")
except Exception as be:
print("Не удалось снять бэкап второго (может быть пустой), продолжаем:", be)
# write first dump to second
write_eeprom(uid2, out1)
# read back and compare
read_eeprom(uid2, out2)
print("SHA1 source:", sha1(out1))
print("SHA1 target:", sha1(out2))
if sha1(out1) == sha1(out2):
print("\nКлонирование успешно! (хеши совпадают)")
else:
print("\nВнимание: хеши не совпадают. Проверьте соединения и повтрите процедуру.")
except Exception as e:
print("Ошибка при записи/проверке:", e)
if __name__ == "__main__":
main()