forked from arti/vt1200
76 lines
2.4 KiB
Python
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())
|