vl600: add some reverse engineering docs and an AT com utility
This commit is contained in:
147
vl600/atcom.py
Executable file
147
vl600/atcom.py
Executable file
@@ -0,0 +1,147 @@
|
||||
#! /bin/env python
|
||||
# -*- Mode: python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details:
|
||||
#
|
||||
# Copyright (C) 2012 Red Hat, Inc.
|
||||
#
|
||||
|
||||
import os
|
||||
import sys
|
||||
import select
|
||||
import struct
|
||||
import string
|
||||
from termios import *
|
||||
|
||||
debug = False
|
||||
|
||||
def lg_pack(data, seqno):
|
||||
l = len(data)
|
||||
|
||||
fmt = "<"
|
||||
fmt += "I" # magic
|
||||
fmt += "I" # sequence number
|
||||
fmt += "I" # data length
|
||||
fmt += "H" # MUX channel
|
||||
fmt += "%ds" % l # AT data
|
||||
|
||||
# Packets always padded to 4-byte boundaries
|
||||
sz = struct.calcsize(fmt)
|
||||
padding = 0
|
||||
if sz % 4 > 0:
|
||||
padding = 4 - (sz % 4)
|
||||
fmt += "%ds" % padding
|
||||
|
||||
return struct.pack(fmt, 0xa512485a, seqno, l, 0xf011, data, "\0" * padding)
|
||||
|
||||
def lg_unpack(data):
|
||||
fmt = "<"
|
||||
fmt += "I" # magic
|
||||
fmt += "I" # sequence number
|
||||
fmt += "I" # data length
|
||||
fmt += "H" # MUX channel
|
||||
fmt += "%ds" % (len(data) - 14) # AT data
|
||||
|
||||
(magic, seq, l, chan, resp) = struct.unpack(fmt, data)
|
||||
|
||||
if magic != 0xa512485a:
|
||||
raise Exception("Bad magic: 0x%08x" % magic)
|
||||
if chan != 0xf011:
|
||||
print "Unhandled channel 0x%04x" % chan
|
||||
|
||||
# It appears that we're supposed to ignore any data after \r\n, or if
|
||||
# we don't get a \r\n we ignore all of it. The modem adds random
|
||||
# data to the end of the response, for example:
|
||||
#
|
||||
# > 5a 48 12 a5 08 00 00 00 0a 00 00 00 11 f0 41 54 2b 43 45 52 45 47 3f 0a
|
||||
# < 5a 48 12 a5 4e 00 00 00 15 00 00 00 11 f0 2b 43 45 52 45 47 3a 20 30 2c 31 0d 0a 00 00 4f 4b 0d 0a 00 47 74
|
||||
#
|
||||
# where there's a trailing "00 47 74". The trailing bytes appear
|
||||
# totally random in value and length.
|
||||
|
||||
crlf = resp.rfind("\r\n")
|
||||
if crlf == -1:
|
||||
return ""
|
||||
|
||||
return resp[:crlf + 2]
|
||||
|
||||
def dump_raw(data, to_modem):
|
||||
if debug:
|
||||
line = ""
|
||||
if to_modem:
|
||||
line += "> "
|
||||
else:
|
||||
line += "< "
|
||||
for c in data:
|
||||
line += "%02x " % ord(c)
|
||||
print line
|
||||
|
||||
def make_printable(data):
|
||||
p = ""
|
||||
for c in data:
|
||||
if c in string.printable and ord(c) >= 32 or c == '\n' or c == '\r':
|
||||
p += c
|
||||
else:
|
||||
p += "<%2x>" % ord(c)
|
||||
return p
|
||||
|
||||
|
||||
#########################################
|
||||
|
||||
if len(sys.argv) != 2 and len(sys.argv) != 3:
|
||||
print "Usage: %s <port> [--debug]" % sys.argv[0]
|
||||
sys.exit(1)
|
||||
|
||||
if len(sys.argv) > 2 and sys.argv[2] == "--debug":
|
||||
debug = True
|
||||
|
||||
fd = os.open(sys.argv[1], os.O_RDWR)
|
||||
|
||||
# read existing port attributes and mask the ones we don't want
|
||||
attrs = tcgetattr(fd)
|
||||
attrs[0] = attrs[0] & ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON) # iflag
|
||||
attrs[1] = attrs[1] & ~OPOST # oflag
|
||||
attrs[2] = attrs[2] & ~(CSIZE | PARENB) # cflag
|
||||
attrs[3] = attrs[3] & ~(ECHO | ICANON | IEXTEN | ISIG) # lflag
|
||||
|
||||
# Set up the attributes we do want
|
||||
attrs[2] = attrs[2] | CS8 # cflag
|
||||
attrs[4] = B115200 # ispeed
|
||||
attrs[5] = B115200 # ospeed
|
||||
attrs[6][VMIN] = 1 # cc
|
||||
attrs[6][VTIME] = 0 # cc
|
||||
tcsetattr(fd, TCSAFLUSH, attrs)
|
||||
|
||||
infd = sys.stdin.fileno()
|
||||
seqno = 0
|
||||
while 1:
|
||||
try:
|
||||
rfd, wfd, xfd = select.select([ fd, infd ], [], [])
|
||||
except KeyboardInterrupt:
|
||||
print ""
|
||||
break
|
||||
|
||||
if fd in rfd:
|
||||
data = os.read(fd, 4096)
|
||||
dump_raw(data, False)
|
||||
line = lg_unpack(data)
|
||||
if line:
|
||||
print make_printable(line)
|
||||
|
||||
if infd in rfd:
|
||||
line = os.read(infd, 512)
|
||||
if line:
|
||||
data = lg_pack(line, seqno)
|
||||
seqno += 1
|
||||
dump_raw(data, True)
|
||||
os.write(fd, data)
|
||||
|
||||
os.close(fd)
|
38
vl600/vl600.txt
Normal file
38
vl600/vl600.txt
Normal file
@@ -0,0 +1,38 @@
|
||||
Device uses an LG L2000 LTE chip and a Qualcomm MDM6800A for CDMA/EVDO.
|
||||
|
||||
The firmware flasher tool speaks DIAG and includes a lot of LTE-related
|
||||
NV items.
|
||||
|
||||
Device has two USB interfaces:
|
||||
|
||||
0 - Proprietary ethernet interface
|
||||
1 - CDC-ACM serial port
|
||||
|
||||
The ACM port speaks a proprietary protocol that MUX-es traffic from the
|
||||
following virtual interfaces (according to Windows):
|
||||
|
||||
0: LGE LTE DM Port
|
||||
1: LGE USB Modem Port
|
||||
2: LGE LTE RF Serial Port (com)
|
||||
3: LGE CDMA USB Serial Port (com)
|
||||
4: LGE CDMA USB GPS NMEA Port (com)
|
||||
5: LGE CDMA LBS Serial Port (com)
|
||||
|
||||
MUX Header Format
|
||||
-----------------
|
||||
|
||||
u32: magic, always [ 0x5a 0x48 0x12 0xa5 ]
|
||||
u32: sequence number (unpaired; host and device use separate sequence numbers)
|
||||
u32: length (not including this header, but including any padding)
|
||||
u16: MUX channel (21 f0: CMD) (11 f0: AT)
|
||||
<data>
|
||||
|
||||
|
||||
Packets are 4-byte aligned with padding of zeros, and this padding is included
|
||||
in the length given in the header.
|
||||
|
||||
AT commands may have trailing junk bytes. It appears that interpreters should
|
||||
simply ignore any data in AT packets after the last CRLF.
|
||||
|
||||
CMD packets are terminated with a standard HDLC CRC-16 and 0x7E.
|
||||
|
Reference in New Issue
Block a user