SEDbgMuxApp: employ DbgMuxFrameDisp, implement basic handlers
This commit is contained in:
parent
91abeb7220
commit
c81e0e2ad8
3
peer.py
3
peer.py
|
@ -112,12 +112,12 @@ class DbgMuxPeer:
|
||||||
# Init frame dispatcher
|
# Init frame dispatcher
|
||||||
self.disp = DbgMuxFrameDisp(self._rx_queue,
|
self.disp = DbgMuxFrameDisp(self._rx_queue,
|
||||||
self._tx_queue)
|
self._tx_queue)
|
||||||
# TODO: self.disp.start()
|
|
||||||
|
|
||||||
def start(self) -> None:
|
def start(self) -> None:
|
||||||
self._shutdown.clear()
|
self._shutdown.clear()
|
||||||
self._rx_thread.start()
|
self._rx_thread.start()
|
||||||
self._tx_thread.start()
|
self._tx_thread.start()
|
||||||
|
self.disp.start()
|
||||||
|
|
||||||
def stop(self) -> None:
|
def stop(self) -> None:
|
||||||
# Set the shutdown event
|
# Set the shutdown event
|
||||||
|
@ -125,6 +125,7 @@ class DbgMuxPeer:
|
||||||
# Wait for both threads to terminate
|
# Wait for both threads to terminate
|
||||||
self._tx_thread.join()
|
self._tx_thread.join()
|
||||||
self._rx_thread.join()
|
self._rx_thread.join()
|
||||||
|
self.disp.stop()
|
||||||
|
|
||||||
def _rx_worker(self) -> None:
|
def _rx_worker(self) -> None:
|
||||||
while not self._shutdown.is_set():
|
while not self._shutdown.is_set():
|
||||||
|
|
136
sedbgmux.py
136
sedbgmux.py
|
@ -23,11 +23,74 @@ import argparse
|
||||||
import cmd2
|
import cmd2
|
||||||
import enum
|
import enum
|
||||||
import sys
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
from transport import TransportModem
|
from transport import TransportModem
|
||||||
from proto import DbgMuxFrame
|
from proto import DbgMuxFrame
|
||||||
from peer import DbgMuxPeer
|
from peer import DbgMuxPeer
|
||||||
|
|
||||||
|
from construct import Container
|
||||||
|
from handlers import DbgMuxFrameHandler
|
||||||
|
from handlers import DbgMuxConnUdpBridge
|
||||||
|
from handlers import DbgMuxConnInteractiveTerminal
|
||||||
|
|
||||||
|
|
||||||
|
class CommonFrameHandler(DbgMuxFrameHandler):
|
||||||
|
''' Handles some common messages '''
|
||||||
|
|
||||||
|
def __init__(self, cmd2):
|
||||||
|
self.cmd2 = cmd2
|
||||||
|
|
||||||
|
def _handle_frame(self, frame: Container) -> None:
|
||||||
|
if frame['MsgType'] == DbgMuxFrame.MsgType.Ident:
|
||||||
|
log.info("Identified target: '%s', IMEI=%s",
|
||||||
|
frame['Msg']['Ident'][:-15],
|
||||||
|
frame['Msg']['Ident'][-15:])
|
||||||
|
elif frame['MsgType'] == DbgMuxFrame.MsgType.DPAnnounce:
|
||||||
|
log.info("Data Provider available (DPRef=0x%04x): '%s'",
|
||||||
|
frame['Msg']['DPRef'], frame['Msg']['Name'])
|
||||||
|
elif frame['MsgType'] == DbgMuxFrame.MsgType.FlowControl:
|
||||||
|
log.warning("Rx FlowControl message, which is not yet supported")
|
||||||
|
elif frame['MsgType'] == DbgMuxFrame.MsgType.ConnEstablished \
|
||||||
|
and frame['Msg']['ConnRef'] == 0xffff:
|
||||||
|
log.warning("Connection establishment failed, "
|
||||||
|
"no such DPRef=0x%04x?", frame['Msg']['DPRef'])
|
||||||
|
elif frame['MsgType'] == DbgMuxFrame.MsgType.ConnTerminated \
|
||||||
|
and frame['Msg']['ConnRef'] == 0xffff:
|
||||||
|
log.warning("Connection termination failed, "
|
||||||
|
"no such DPRef=0x%04x?", frame['Msg']['DPRef'])
|
||||||
|
elif frame['MsgType'] == DbgMuxFrame.MsgType.Ack:
|
||||||
|
raise StopIteration
|
||||||
|
else: # To be consumed by other handlers
|
||||||
|
return
|
||||||
|
self.send(DbgMuxFrame.MsgType.Ack)
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
|
||||||
|
class PingPongHandler(DbgMuxFrameHandler):
|
||||||
|
''' Handles DbgMuxFrame.MsgType.Pong '''
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.expect_pong: bool = False
|
||||||
|
|
||||||
|
def ping(self, payload: str):
|
||||||
|
log.info('Tx Ping with payload \'%s\'', payload)
|
||||||
|
self.send(DbgMuxFrame.MsgType.Ping, payload)
|
||||||
|
self.expect_pong = True
|
||||||
|
# TODO: start a timer?
|
||||||
|
|
||||||
|
def handle_pong(self, payload: str):
|
||||||
|
if not self.expect_pong:
|
||||||
|
log.warning('Rx unexpected Pong, sending ACK anyway')
|
||||||
|
return
|
||||||
|
log.info('Rx Pong with payload \'%s\'', payload)
|
||||||
|
self.expect_pong = False
|
||||||
|
|
||||||
|
def _handle_frame(self, frame: Container) -> None:
|
||||||
|
if frame['MsgType'] == DbgMuxFrame.MsgType.Pong:
|
||||||
|
self.handle_pong(frame['Msg'])
|
||||||
|
self.send(DbgMuxFrame.MsgType.Ack)
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
class SEDbgMuxApp(cmd2.Cmd):
|
class SEDbgMuxApp(cmd2.Cmd):
|
||||||
DESC = 'DebugMux client for [Sony] Ericsson phones and modems'
|
DESC = 'DebugMux client for [Sony] Ericsson phones and modems'
|
||||||
|
@ -48,6 +111,10 @@ class SEDbgMuxApp(cmd2.Cmd):
|
||||||
self.transport = TransportModem(self.argv)
|
self.transport = TransportModem(self.argv)
|
||||||
self.peer = DbgMuxPeer(self.transport)
|
self.peer = DbgMuxPeer(self.transport)
|
||||||
|
|
||||||
|
# Register DebugMux frame handlers
|
||||||
|
self.peer.disp.register(CommonFrameHandler(self), 'Common')
|
||||||
|
self.peer.disp.register(PingPongHandler(), 'PingPong')
|
||||||
|
|
||||||
# Modem connection state
|
# Modem connection state
|
||||||
self.set_connected(False)
|
self.set_connected(False)
|
||||||
|
|
||||||
|
@ -88,23 +155,8 @@ class SEDbgMuxApp(cmd2.Cmd):
|
||||||
def do_enquiry(self, opts) -> None:
|
def do_enquiry(self, opts) -> None:
|
||||||
''' Enquiry target identifier and available Data Providers '''
|
''' Enquiry target identifier and available Data Providers '''
|
||||||
self.peer.send(DbgMuxFrame.MsgType.Enquiry)
|
self.peer.send(DbgMuxFrame.MsgType.Enquiry)
|
||||||
while True:
|
# The responce to be handled by CommonFrameHandler
|
||||||
f = self.peer.recv()
|
time.sleep(0.5)
|
||||||
if f['MsgType'] == DbgMuxFrame.MsgType.Ident:
|
|
||||||
log.info("Identified target: '%s', IMEI=%s",
|
|
||||||
f['Msg']['Ident'][:-15],
|
|
||||||
f['Msg']['Ident'][-15:])
|
|
||||||
elif f['MsgType'] == DbgMuxFrame.MsgType.DPAnnounce:
|
|
||||||
log.info("Data Provider available (DPRef=0x%04x): '%s'",
|
|
||||||
f['Msg']['DPRef'], f['Msg']['Name'])
|
|
||||||
|
|
||||||
# No more data in the buffer
|
|
||||||
# FIXME: layer violation!
|
|
||||||
if self.transport._sl.in_waiting == 0:
|
|
||||||
break
|
|
||||||
|
|
||||||
# ACKnowledge reception of the info
|
|
||||||
self.peer.send(DbgMuxFrame.MsgType.Ack)
|
|
||||||
|
|
||||||
ping_parser = cmd2.Cmd2ArgumentParser()
|
ping_parser = cmd2.Cmd2ArgumentParser()
|
||||||
ping_parser.add_argument('-p', '--payload',
|
ping_parser.add_argument('-p', '--payload',
|
||||||
|
@ -115,52 +167,30 @@ class SEDbgMuxApp(cmd2.Cmd):
|
||||||
@cmd2.with_category(CATEGORY_DBGMUX)
|
@cmd2.with_category(CATEGORY_DBGMUX)
|
||||||
def do_ping(self, opts) -> None:
|
def do_ping(self, opts) -> None:
|
||||||
''' Send a Ping to the target, expect Pong '''
|
''' Send a Ping to the target, expect Pong '''
|
||||||
log.info('Tx Ping with payload \'%s\'', opts.payload)
|
hinst = self.peer.disp.find_by_name('PingPong')
|
||||||
self.peer.send(DbgMuxFrame.MsgType.Ping, opts.payload)
|
hinst.ping(opts.payload)
|
||||||
|
|
||||||
f = self.peer.recv()
|
|
||||||
assert f['MsgType'] == DbgMuxFrame.MsgType.Pong
|
|
||||||
log.info('Rx Pong with payload \'%s\'', f['Msg'])
|
|
||||||
self.peer.send(DbgMuxFrame.MsgType.Ack)
|
|
||||||
|
|
||||||
establish_parser = cmd2.Cmd2ArgumentParser()
|
establish_parser = cmd2.Cmd2ArgumentParser()
|
||||||
establish_parser.add_argument('DPRef',
|
establish_parser.add_argument('DPRef',
|
||||||
type=lambda v: int(v, 16),
|
type=lambda v: int(v, 16),
|
||||||
help='DPRef of a Data Provider in hex')
|
help='DPRef of a Data Provider in hex')
|
||||||
|
establish_parser.add_argument('mode',
|
||||||
|
choices=['interactive', 'udp-bridge'],
|
||||||
|
help='Connection mode')
|
||||||
|
|
||||||
@cmd2.with_argparser(establish_parser)
|
@cmd2.with_argparser(establish_parser)
|
||||||
@cmd2.with_category(CATEGORY_DBGMUX)
|
@cmd2.with_category(CATEGORY_DBGMUX)
|
||||||
def do_establish(self, opts) -> None:
|
def do_establish(self, opts) -> None:
|
||||||
''' Establish connection with a Data Provider '''
|
''' Establish connection with a Data Provider '''
|
||||||
log.info("Establishing connection with DPRef=0x%04x", opts.DPRef)
|
if opts.mode == 'interactive':
|
||||||
self.peer.send(DbgMuxFrame.MsgType.ConnEstablish,
|
ch = DbgMuxConnInteractiveTerminal()
|
||||||
dict(DPRef=opts.DPRef))
|
self.peer.disp.register(ch)
|
||||||
|
ch.establish(opts.DPRef)
|
||||||
f = self.peer.recv()
|
ch.attach()
|
||||||
assert f['MsgType'] == DbgMuxFrame.MsgType.ConnEstablished
|
elif opts.mode == 'udp-bridge':
|
||||||
if f['Msg']['ConnRef'] == 0xffff:
|
ch = DbgMuxConnUdpBridge()
|
||||||
log.warning("Connection failed: unknown DPRef=0x%04x?", opts.DPRef)
|
self.peer.disp.register(ch)
|
||||||
self.peer.send(DbgMuxFrame.MsgType.Ack)
|
ch.establish(opts.DPRef)
|
||||||
return
|
|
||||||
|
|
||||||
log.info("Connection established (ConnRef=0x%04x)",
|
|
||||||
f['Msg']['ConnRef'])
|
|
||||||
|
|
||||||
# Read the messages
|
|
||||||
while True:
|
|
||||||
f = self.peer.recv()
|
|
||||||
|
|
||||||
if f['MsgType'] != DbgMuxFrame.MsgType.ConnData:
|
|
||||||
log.warning('Unexpected frame: %s', f)
|
|
||||||
self.peer.send(DbgMuxFrame.MsgType.Ack)
|
|
||||||
continue
|
|
||||||
try: # FIXME: there can be binary data
|
|
||||||
self.stdout.write(f['Msg']['Data'].decode())
|
|
||||||
except: # ... ignore it for now
|
|
||||||
continue
|
|
||||||
|
|
||||||
# ACKnowledge reception of a frame
|
|
||||||
self.peer.send(DbgMuxFrame.MsgType.Ack)
|
|
||||||
|
|
||||||
|
|
||||||
ap = argparse.ArgumentParser(prog='sedbgmux', description=SEDbgMuxApp.DESC,
|
ap = argparse.ArgumentParser(prog='sedbgmux', description=SEDbgMuxApp.DESC,
|
||||||
|
|
Loading…
Reference in New Issue