Created
October 11, 2015 17:40
-
-
Save mlt/d2e41c9855c2c993ab89 to your computer and use it in GitHub Desktop.
Sainsonic RST599 extraction
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
from __future__ import print_function | |
from datetime import timedelta | |
import argparse, os, sys | |
import logging | |
from serial import Serial, SerialException | |
from binascii import hexlify | |
import struct | |
import re | |
from chirp.bitwise import bcd_to_int | |
from chirp.chirp_common import Memory | |
_log = logging.getLogger(__name__) | |
CONNECT = bytearray.fromhex("06 59 41 53 48 45 ff ff") | |
ACK = bytearray.fromhex("02") | |
STUFF = bytearray.fromhex("00 91 52 16 b7 59 fa 9c 3d de 80 21 c2 64 05 86") | |
#00 3d 7f c3 64 05 a7 48 e9 8b 54 cd 6f 10 b1 9c | |
def get_parser(): | |
parser = argparse.ArgumentParser(description='Download stuff from RST599', \ | |
formatter_class=argparse.ArgumentDefaultsHelpFormatter) | |
parser.add_argument('--port', | |
default='COM3', | |
help='Virtual COM port') | |
return parser | |
class RST599: | |
def _read(self, where, amount): | |
cmd = struct.pack(">B", 0x52) | |
what = struct.pack(">HB", where, amount) | |
self.port.write(cmd + what) | |
res = self.port.read(1) | |
if res != "\x57": | |
raise Exception("WTF") | |
res = self.port.read(3) | |
if res != what: | |
raise Exception("zzz") | |
res = self.port.read(amount) | |
self.dump(res) | |
return res | |
def __init__(self, args): | |
self._log = logging.getLogger(__name__) | |
self._log.debug("Opening port") | |
self.port = Serial(args.port, 9600, timeout=1, writeTimeout=1) | |
self._log.debug("Sending connect") | |
self.port.write(CONNECT) | |
res = self.port.read(8) # TDXSD01\xff | |
self.dump(res) | |
self._log.debug("Checking") | |
self.port.write(ACK) | |
self.check_ok() | |
self._log.debug("Writing stuff") | |
self.port.write(STUFF) # TODO needs documentation badly. Changes often | |
self.check_ok() | |
self._log.debug("Getting channel bitmask") | |
mask = self._read(0x4000, 32) | |
chan = 0 | |
for x in mask[:31]: | |
x = struct.unpack("B", x)[0] | |
for bit in xrange(0, 8): | |
present = x & 1 > 0 | |
x >>= 1 | |
if present: | |
# mem = Memory() | |
res = self._read(chan * 0x16, 0x16) | |
name = res[16:22] | |
rx, tx = struct.unpack("<II", res[:8]) | |
rx = unpack_bcd(rx) / 1.e5 | |
tx = unpack_bcd(tx) / 1.e5 | |
self._log.debug("Got channel %d (%s), rx=%.5f MHz, tx=%.5f MHz", chan, name.strip("\x00"), rx, tx) | |
chan += 1 | |
# self._log.debug("Getting blocks 0x5214e010-0x5219e010") | |
# le = int("5214e010", 16) | |
# ue = int("5219e011", 16) | |
# for e in xrange(le, ue, 4096): | |
# cmd = struct.pack(">I", e) | |
# self.port.write(cmd) | |
# res = self.port.read(20) | |
# self.dump(res) | |
# self._log.debug("Getting blocks 0x52410010-0x52451010") | |
# le = int("52410010", 16) | |
# ue = int("52451011", 16) | |
# for e in xrange(le, ue, 4096): | |
# cmd = struct.pack(">I", e) | |
# self.port.write(cmd) | |
# res = self.port.read(20) | |
# self.dump(res) | |
self.port.write("\x45") | |
res = self.port.read(1) | |
a = hexlify(res) | |
self._log.debug(a) | |
def dump(self, val): | |
a = hexlify(val) | |
ascii = re.sub(r'[^a-zA-Z0-9]', '.', val) | |
self._log.debug("%s%s%s", a, " ", ascii) | |
def check_ok(self, expect="\x06"): | |
res = self.port.read(1) | |
if res != expect: | |
raise Exception("Failed check, expected 6 but got %s" % res) | |
def unpack_bcd(x0): | |
x00 = x0 | |
x = 0 | |
m = 0 | |
while x0: | |
digit = x0 & 0x000f | |
if digit>9: | |
raise Exception("Non-BCD argument {:X} in {:X}".format(digit, x00)) | |
x = x + digit * 10**m | |
m = m + 1 | |
x0 = x0 >> 4 | |
return x | |
def main(): | |
args = get_parser().parse_args() | |
try: | |
radio = RST599(args) | |
except SerialException as e: | |
_log.fatal("Port %s can't be opened :(", args.port) | |
sys.exit(-1) | |
print("Done") | |
if __name__ == '__main__': | |
# FORMAT = FORMAT = '%(asctime)-15s %(message)s' | |
# logging.basicConfig(level=logging.DEBUG, format=FORMAT) | |
logging.basicConfig(level=logging.DEBUG) | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment