[Debugger] Implementation of transport over serial connection (#2800)

JerryScript-DCO-1.0-Signed-off-by: Robert Sipka rsipka.uszeged@partner.samsung.com
This commit is contained in:
Robert Sipka
2019-03-26 09:39:51 +01:00
committed by GitHub
parent 0981985134
commit 3d656cdf57
14 changed files with 577 additions and 51 deletions
+34 -3
View File
@@ -24,6 +24,11 @@ import logging
import time
import jerry_client_main
from jerry_client_websocket import WebSocket
from jerry_client_rawpacket import RawPacket
from jerry_client_tcp import Socket
from jerry_client_serial import Serial
def write(string):
print(string, end='')
@@ -246,14 +251,40 @@ def src_check_args(args):
print("Error: Non-negative integer number expected: %s" % (val_errno))
return -1
# pylint: disable=too-many-branches,too-many-locals,too-many-statements
# pylint: disable=too-many-branches,too-many-locals,too-many-statements,redefined-variable-type
def main():
args = jerry_client_main.arguments_parse()
debugger = jerry_client_main.JerryDebugger(args.address, args.channel)
channel = None
protocol = None
if args.protocol == "tcp":
address = None
if ":" not in args.address:
address = (args.address, 5001) # use default port
else:
host, port = args.address.split(":")
address = (host, int(port))
protocol = Socket(address)
elif args.protocol == "serial":
protocol = Serial(args.serial_config)
else:
print("Unsupported transmission protocol")
return -1
if args.channel == "websocket":
channel = WebSocket(protocol=protocol)
elif args.channel == "rawpacket":
channel = RawPacket(protocol=protocol)
else:
print("Unsupported communication channel")
return -1
debugger = jerry_client_main.JerryDebugger(channel)
debugger.non_interactive = args.non_interactive
logging.debug("Connected to JerryScript on %d port", debugger.port)
logging.debug("Connected to JerryScript")
prompt = DebuggerPrompt(debugger)
prompt.prompt = "(jerry-debugger) "
+12 -26
View File
@@ -21,12 +21,9 @@ import re
import select
import struct
import sys
from jerry_client_websocket import WebSocket
from jerry_client_rawpacket import RawPacket
from jerry_client_tcp import Socket
# Expected debugger protocol version.
JERRY_DEBUGGER_VERSION = 8
JERRY_DEBUGGER_VERSION = 9
# Messages sent by the server to client.
JERRY_DEBUGGER_CONFIGURATION = 1
@@ -60,6 +57,7 @@ JERRY_DEBUGGER_SCOPE_CHAIN = 28
JERRY_DEBUGGER_SCOPE_CHAIN_END = 29
JERRY_DEBUGGER_SCOPE_VARIABLES = 30
JERRY_DEBUGGER_SCOPE_VARIABLES_END = 31
JERRY_DEBUGGER_CLOSE_CONNECTION = 32
# Debugger option flags
JERRY_DEBUGGER_LITTLE_ENDIAN = 0x1
@@ -123,7 +121,7 @@ def arguments_parse():
parser = argparse.ArgumentParser(description="JerryScript debugger client")
parser.add_argument("address", action="store", nargs="?", default="localhost:5001",
help="specify a unique network address for connection (default: %(default)s)")
help="specify a unique network address for tcp connection (default: %(default)s)")
parser.add_argument("-v", "--verbose", action="store_true", default=False,
help="increase verbosity (default: %(default)s)")
parser.add_argument("--non-interactive", action="store_true", default=False,
@@ -138,6 +136,10 @@ def arguments_parse():
help="specify a javascript source file to execute")
parser.add_argument("--channel", choices=["websocket", "rawpacket"], default="websocket",
help="specify the communication channel (default: %(default)s)")
parser.add_argument("--protocol", choices=["tcp", "serial"], default="tcp",
help="specify the transmission protocol over the communication channel (default: %(default)s)")
parser.add_argument("--serial-config", metavar="CONFIG_STRING", default="/dev/ttyUSB0,115200,8,N,1",
help="Configure parameters for serial port (default: %(default)s)")
args = parser.parse_args()
if args.verbose:
@@ -266,17 +268,7 @@ class DebuggerAction(object):
class JerryDebugger(object):
# pylint: disable=too-many-instance-attributes,too-many-statements,too-many-public-methods,no-self-use,redefined-variable-type
def __init__(self, address, channel):
if ":" not in address:
self.host = address
self.port = 5001 # use default port
else:
self.host, self.port = address.split(":")
self.port = int(self.port)
print("Connecting to: %s:%s" % (self.host, self.port))
def __init__(self, channel):
self.prompt = False
self.function_list = {}
self.source = ''
@@ -304,15 +296,7 @@ class JerryDebugger(object):
self.non_interactive = False
self.current_out = b""
self.current_log = b""
self.channel = None
protocol = Socket()
if channel == "websocket":
self.channel = WebSocket(address=(self.host, self.port), protocol=protocol)
elif channel == "rawpacket":
self.channel = RawPacket(address=(self.host, self.port), protocol=protocol)
else:
raise Exception("Unsupported communication channel")
self.channel = channel
config_size = 8
# The server will send the configuration message after connection established
@@ -697,7 +681,6 @@ class JerryDebugger(object):
# pylint: disable=too-many-branches,too-many-locals,too-many-statements,too-many-return-statements
def process_messages(self):
result = ""
while True:
data = self.channel.get_message(False)
if not self.non_interactive:
@@ -846,6 +829,9 @@ class JerryDebugger(object):
return DebuggerAction(DebuggerAction.TEXT, result)
elif JERRY_DEBUGGER_CLOSE_CONNECTION:
return DebuggerAction(DebuggerAction.END, "")
else:
raise Exception("Unknown message")
+2 -3
View File
@@ -20,14 +20,13 @@ MAX_BUFFER_SIZE = 256
class RawPacket(object):
""" Simplified transmission layer. """
def __init__(self, address, protocol):
def __init__(self, protocol):
self.protocol = protocol
self.data_buffer = b""
self.address = address
def connect(self, config_size):
""" Create connection. """
self.protocol.connect(self.address)
self.protocol.connect()
self.data_buffer = b""
# It will return with the Network configurations, which has the following struct:
+55
View File
@@ -0,0 +1,55 @@
#!/usr/bin/env python
# Copyright JS Foundation and other contributors, http://js.foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import select
import serial
class Serial(object):
""" Create a new socket using the given address family, socket type and protocol number. """
def __init__(self, serial_config):
config = serial_config.split(',')
config_size = len(config)
port = config[0] if config_size > 0 else "/dev/ttyUSB0"
baudrate = config[1] if config_size > 1 else 115200
bytesize = int(config[2]) if config_size > 2 else 8
parity = config[3] if config_size > 3 else 'N'
stopbits = int(config[4]) if config_size > 4 else 1
self.ser = serial.Serial(port=port, baudrate=baudrate, parity=parity,
stopbits=stopbits, bytesize=bytesize, timeout=1)
def connect(self):
""" Connect to the server, write a 'c' to the serial port """
self.send_data('c')
def close(self):
"""" close the serial port. """
self.ser.close()
def receive_data(self, max_size=1024):
""" The maximum amount of data to be received at once is specified by max_size. """
return self.ser.read(max_size)
def send_data(self, data):
""" Write data to the serial port. """
return self.ser.write(data)
def ready(self):
""" Monitor the file descriptor. """
result = select.select([self.ser.fileno()], [], [], 0)[0]
return self.ser.fileno() in result
+6 -3
View File
@@ -17,17 +17,20 @@
import socket
import select
# pylint: disable=too-many-arguments,superfluous-parens
class Socket(object):
""" Create a new socket using the given address family, socket type and protocol number. """
def __init__(self, socket_family=socket.AF_INET, socket_type=socket.SOCK_STREAM, proto=0, fileno=None):
def __init__(self, address, socket_family=socket.AF_INET, socket_type=socket.SOCK_STREAM, proto=0, fileno=None):
self.address = address
self.socket = socket.socket(socket_family, socket_type, proto, fileno)
def connect(self, address):
def connect(self):
"""
Connect to a remote socket at address (host, port).
The format of address depends on the address family.
"""
self.socket.connect(address)
print("Connecting to: %s:%s" % (self.address[0], self.address[1]))
self.socket.connect(self.address)
def close(self):
"""" Mark the socket closed. """
+2 -3
View File
@@ -21,11 +21,10 @@ WEBSOCKET_BINARY_FRAME = 2
WEBSOCKET_FIN_BIT = 0x80
class WebSocket(object):
def __init__(self, address, protocol):
def __init__(self, protocol):
self.data_buffer = b""
self.protocol = protocol
self.address = address
def __handshake(self):
""" Client Handshake Request. """
@@ -55,7 +54,7 @@ class WebSocket(object):
def connect(self, config_size):
""" WebSockets connection. """
self.protocol.connect(self.address)
self.protocol.connect()
self.data_buffer = b""
self.__handshake()