Files
vt1200/bad-apple/tools/send_movie.py
T

76 lines
2.4 KiB
Python

#!/usr/bin/env python3
"""Send movie.bin to the payload's UDP receiver (port 7001).
Packet: u32 offset, u16 length, u16 seq, u16 crc16, then length bytes.
A zero-length packet ends the load. This uses the VT1200 OS stack while it
is still alive; the payload disables interrupts only after the last byte.
"""
from __future__ import annotations
import argparse
import socket
import struct
import sys
import time
from pathlib import Path
def crc16(data: bytes) -> int:
return sum(data) & 0xFFFF
def checksum32(data: bytes) -> int:
return sum(data) & 0xFFFFFFFF
def pack_packet(offset: int, seq: int, body: bytes) -> bytes:
return struct.pack("<IHHH", offset, len(body), seq, crc16(body)) + body
def parse_ack(data: bytes) -> int:
if len(data) < 8 or data[:4] != b"BAK1":
raise ValueError("not a BAK1 ack")
return struct.unpack_from("<I", data, 4)[0]
def send_movie(host: str, port: int, path: str, chunk: int = 1450,
delay: float = 0.0005, passes: int = 3) -> int:
data = Path(path).read_bytes()
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
try:
for _ in range(passes):
offset = 0
seq = 0
while offset < len(data):
part = data[offset:offset + chunk]
sock.sendto(pack_packet(offset, seq, part), (host, port))
offset += len(part)
seq += 1
if delay:
time.sleep(delay)
sock.sendto(pack_packet(len(data), seq,
checksum32(data).to_bytes(4, "little")),
(host, port))
time.sleep(0.05)
finally:
sock.close()
print("sent %d bytes in %d pass(es)" % (len(data), passes))
return 0
def main(argv=None) -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--host", default="192.168.99.2")
parser.add_argument("--port", type=int, default=7001)
parser.add_argument("--movie", required=True)
parser.add_argument("--chunk", type=int, default=1450)
parser.add_argument("--delay", type=float, default=0.0005)
parser.add_argument("--passes", type=int, default=3)
args = parser.parse_args(argv)
return send_movie(args.host, args.port, args.movie, args.chunk,
args.delay, args.passes)
if __name__ == "__main__":
raise SystemExit(main())