# YMODEM-1K-Sender über /dev/ttyACM0; argv: datei, u-boot-ladeadresse
import os,sys,termios,time,select
path,addr=sys.argv[1],sys.argv[2]
fd=os.open('/dev/ttyACM0',os.O_RDWR|os.O_NOCTTY)
a=termios.tcgetattr(fd); a[0]=0;a[1]=0;a[2]=termios.CS8|termios.CREAD|termios.CLOCAL;a[3]=0;a[4]=a[5]=termios.B115200
a[6][termios.VMIN]=0;a[6][termios.VTIME]=0; termios.tcsetattr(fd,termios.TCSANOW,a)
def crc16(d):
    c=0
    for b in d:
        c^=b<<8
        for _ in range(8): c=((c<<1)^0x1021)&0xffff if c&0x8000 else (c<<1)&0xffff
    return c
def rd(t):
    end=time.time()+t; out=b''
    while time.time()<end:
        r,_,_=select.select([fd],[],[],0.05)
        if r:
            d=os.read(fd,1024); out+=d
            return out
    return out
def waitfor(chars,t):
    end=time.time()+t; seen=b''
    while time.time()<end:
        d=rd(0.2); seen+=d
        for ch in d:
            if bytes([ch]) in chars: return bytes([ch]),seen
    return None,seen
def log(*x): print(*x,flush=True)
os.write(fd,('loady %s\r'%addr).encode())
c,s=waitfor(b'C',20); log('Start:',s[-200:]);
if not c: log('kein C'); sys.exit(2)
data=open(path,'rb').read()
def block(seq,payload,size):
    payload=payload.ljust(size,b'\x1a' if seq else b'\0')
    hdr=(b'\x01' if size==128 else b'\x02')+bytes([seq&0xff,0xff-(seq&0xff)])
    cr=crc16(payload); return hdr+payload+bytes([cr>>8,cr&0xff])
def send(pkt,label):
    for tr in range(10):
        os.write(fd,pkt)
        r,s=waitfor(b'\x06\x15\x18',10)
        if r==b'\x06': return True
        if r==b'\x18': log('CAN empfangen',label); sys.exit(3)
        log('Wiederholung',label,r,s[-40:])
    log('Abbruch',label); sys.exit(4)
name=os.path.basename(path).encode()
send(block(0,name+b'\0'+str(len(data)).encode()+b'\0',128),'hdr')
waitfor(b'C',10)
seq=1; t0=time.time()
for off in range(0,len(data),1024):
    send(block(seq,data[off:off+1024],1024),seq); seq+=1
    if seq%500==0: log('Block',seq,'%.0f%%'%(100*off/len(data)),'%.0fs'%(time.time()-t0))
os.write(fd,b'\x04'); r,_=waitfor(b'\x15\x06',10)
if r!=b'\x06': os.write(fd,b'\x04'); waitfor(b'\x06',10)
waitfor(b'C',10); send(block(0,b'',128),'end')
time.sleep(1); log('Fertig',len(data),'Bytes in %.0fs'%(time.time()-t0)); log(rd(3).decode(errors='replace'))
