Skip to content

Commit 3d656cd

Browse files
authored
[Debugger] Implementation of transport over serial connection (#2800)
JerryScript-DCO-1.0-Signed-off-by: Robert Sipka [email protected]
1 parent 0981985 commit 3d656cd

File tree

14 files changed

+577
-51
lines changed

14 files changed

+577
-51
lines changed

docs/07.DEBUGGER.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,11 @@ When using the extension-provided WebSocket transport layer, the
6868
debugger can be enabled by calling `jerryx_debugger_after_connect
6969
(jerryx_debugger_tcp_create (debug_port) && jerryx_debugger_ws_create ())`
7070
after the `jerry_init ()` function. It initializes the debugger and
71-
blocks until a client connects. (Custom transport layers may be
72-
implemented and initialized similarly. Currently, `jerryx_debugger_rp_create()` for
73-
raw packet transport layer is also available.)
71+
blocks until a client connects.
72+
(Custom transport layers may be implemented and initialized similarly.
73+
Currently, `jerryx_debugger_rp_create ()` for raw packet transport layer and
74+
`jerryx_debugger_serial_create (const char* config)` for serial protocol
75+
are also available.)
7476

7577
The resource name provided to `jerry_parse ()` is used by the client
7678
to identify the resource name of the source code. This resource name

jerry-core/api/jerry.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,8 @@ jerry_cleanup (void)
193193
#ifdef JERRY_DEBUGGER
194194
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
195195
{
196+
jerry_debugger_send_type (JERRY_DEBUGGER_CLOSE_CONNECTION);
197+
196198
jerry_debugger_transport_close ();
197199
}
198200
#endif /* JERRY_DEBUGGER */

jerry-core/debugger/debugger.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ typedef struct
3838
* The number of message types in the debugger should reflect the
3939
* debugger versioning.
4040
*/
41-
JERRY_STATIC_ASSERT (JERRY_DEBUGGER_MESSAGES_OUT_MAX_COUNT == 32
41+
JERRY_STATIC_ASSERT (JERRY_DEBUGGER_MESSAGES_OUT_MAX_COUNT == 33
4242
&& JERRY_DEBUGGER_MESSAGES_IN_MAX_COUNT == 21
43-
&& JERRY_DEBUGGER_VERSION == 8,
43+
&& JERRY_DEBUGGER_VERSION == 9,
4444
debugger_version_correlates_to_message_type_count);
4545

4646
/**

jerry-core/debugger/debugger.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ typedef enum
156156
JERRY_DEBUGGER_SCOPE_CHAIN_END = 29, /**< last output of scope chain */
157157
JERRY_DEBUGGER_SCOPE_VARIABLES = 30, /**< scope variables */
158158
JERRY_DEBUGGER_SCOPE_VARIABLES_END = 31, /**< last output of scope variables */
159+
JERRY_DEBUGGER_CLOSE_CONNECTION = 32, /**< close connection with the client */
159160
JERRY_DEBUGGER_MESSAGES_OUT_MAX_COUNT, /**< number of different type of output messages by the debugger */
160161

161162
/* Messages sent by the client to server. */

jerry-core/include/jerryscript-debugger.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ extern "C"
3131
/**
3232
* JerryScript debugger protocol version.
3333
*/
34-
#define JERRY_DEBUGGER_VERSION (8)
34+
#define JERRY_DEBUGGER_VERSION (9)
3535

3636
/**
3737
* Types for the client source wait and run method.

jerry-debugger/jerry_client.py

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@
2424
import time
2525
import jerry_client_main
2626

27+
from jerry_client_websocket import WebSocket
28+
from jerry_client_rawpacket import RawPacket
29+
from jerry_client_tcp import Socket
30+
from jerry_client_serial import Serial
31+
2732
def write(string):
2833
print(string, end='')
2934

@@ -246,14 +251,40 @@ def src_check_args(args):
246251
print("Error: Non-negative integer number expected: %s" % (val_errno))
247252
return -1
248253

249-
# pylint: disable=too-many-branches,too-many-locals,too-many-statements
254+
# pylint: disable=too-many-branches,too-many-locals,too-many-statements,redefined-variable-type
250255
def main():
251256
args = jerry_client_main.arguments_parse()
252257

253-
debugger = jerry_client_main.JerryDebugger(args.address, args.channel)
258+
channel = None
259+
protocol = None
260+
261+
if args.protocol == "tcp":
262+
address = None
263+
if ":" not in args.address:
264+
address = (args.address, 5001) # use default port
265+
else:
266+
host, port = args.address.split(":")
267+
address = (host, int(port))
268+
269+
protocol = Socket(address)
270+
elif args.protocol == "serial":
271+
protocol = Serial(args.serial_config)
272+
else:
273+
print("Unsupported transmission protocol")
274+
return -1
275+
276+
if args.channel == "websocket":
277+
channel = WebSocket(protocol=protocol)
278+
elif args.channel == "rawpacket":
279+
channel = RawPacket(protocol=protocol)
280+
else:
281+
print("Unsupported communication channel")
282+
return -1
283+
284+
debugger = jerry_client_main.JerryDebugger(channel)
254285
debugger.non_interactive = args.non_interactive
255286

256-
logging.debug("Connected to JerryScript on %d port", debugger.port)
287+
logging.debug("Connected to JerryScript")
257288

258289
prompt = DebuggerPrompt(debugger)
259290
prompt.prompt = "(jerry-debugger) "

jerry-debugger/jerry_client_main.py

Lines changed: 12 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,9 @@
2121
import select
2222
import struct
2323
import sys
24-
from jerry_client_websocket import WebSocket
25-
from jerry_client_rawpacket import RawPacket
26-
from jerry_client_tcp import Socket
2724

2825
# Expected debugger protocol version.
29-
JERRY_DEBUGGER_VERSION = 8
26+
JERRY_DEBUGGER_VERSION = 9
3027

3128
# Messages sent by the server to client.
3229
JERRY_DEBUGGER_CONFIGURATION = 1
@@ -60,6 +57,7 @@
6057
JERRY_DEBUGGER_SCOPE_CHAIN_END = 29
6158
JERRY_DEBUGGER_SCOPE_VARIABLES = 30
6259
JERRY_DEBUGGER_SCOPE_VARIABLES_END = 31
60+
JERRY_DEBUGGER_CLOSE_CONNECTION = 32
6361

6462
# Debugger option flags
6563
JERRY_DEBUGGER_LITTLE_ENDIAN = 0x1
@@ -123,7 +121,7 @@ def arguments_parse():
123121
parser = argparse.ArgumentParser(description="JerryScript debugger client")
124122

125123
parser.add_argument("address", action="store", nargs="?", default="localhost:5001",
126-
help="specify a unique network address for connection (default: %(default)s)")
124+
help="specify a unique network address for tcp connection (default: %(default)s)")
127125
parser.add_argument("-v", "--verbose", action="store_true", default=False,
128126
help="increase verbosity (default: %(default)s)")
129127
parser.add_argument("--non-interactive", action="store_true", default=False,
@@ -138,6 +136,10 @@ def arguments_parse():
138136
help="specify a javascript source file to execute")
139137
parser.add_argument("--channel", choices=["websocket", "rawpacket"], default="websocket",
140138
help="specify the communication channel (default: %(default)s)")
139+
parser.add_argument("--protocol", choices=["tcp", "serial"], default="tcp",
140+
help="specify the transmission protocol over the communication channel (default: %(default)s)")
141+
parser.add_argument("--serial-config", metavar="CONFIG_STRING", default="/dev/ttyUSB0,115200,8,N,1",
142+
help="Configure parameters for serial port (default: %(default)s)")
141143
args = parser.parse_args()
142144

143145
if args.verbose:
@@ -266,17 +268,7 @@ def get_text(self):
266268

267269
class JerryDebugger(object):
268270
# pylint: disable=too-many-instance-attributes,too-many-statements,too-many-public-methods,no-self-use,redefined-variable-type
269-
def __init__(self, address, channel):
270-
271-
if ":" not in address:
272-
self.host = address
273-
self.port = 5001 # use default port
274-
else:
275-
self.host, self.port = address.split(":")
276-
self.port = int(self.port)
277-
278-
print("Connecting to: %s:%s" % (self.host, self.port))
279-
271+
def __init__(self, channel):
280272
self.prompt = False
281273
self.function_list = {}
282274
self.source = ''
@@ -304,15 +296,7 @@ def __init__(self, address, channel):
304296
self.non_interactive = False
305297
self.current_out = b""
306298
self.current_log = b""
307-
self.channel = None
308-
309-
protocol = Socket()
310-
if channel == "websocket":
311-
self.channel = WebSocket(address=(self.host, self.port), protocol=protocol)
312-
elif channel == "rawpacket":
313-
self.channel = RawPacket(address=(self.host, self.port), protocol=protocol)
314-
else:
315-
raise Exception("Unsupported communication channel")
299+
self.channel = channel
316300

317301
config_size = 8
318302
# The server will send the configuration message after connection established
@@ -697,7 +681,6 @@ def send_no_more_source(self):
697681
# pylint: disable=too-many-branches,too-many-locals,too-many-statements,too-many-return-statements
698682
def process_messages(self):
699683
result = ""
700-
701684
while True:
702685
data = self.channel.get_message(False)
703686
if not self.non_interactive:
@@ -846,6 +829,9 @@ def process_messages(self):
846829

847830
return DebuggerAction(DebuggerAction.TEXT, result)
848831

832+
elif JERRY_DEBUGGER_CLOSE_CONNECTION:
833+
return DebuggerAction(DebuggerAction.END, "")
834+
849835
else:
850836
raise Exception("Unknown message")
851837

jerry-debugger/jerry_client_rawpacket.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,13 @@
2020

2121
class RawPacket(object):
2222
""" Simplified transmission layer. """
23-
def __init__(self, address, protocol):
23+
def __init__(self, protocol):
2424
self.protocol = protocol
2525
self.data_buffer = b""
26-
self.address = address
2726

2827
def connect(self, config_size):
2928
""" Create connection. """
30-
self.protocol.connect(self.address)
29+
self.protocol.connect()
3130
self.data_buffer = b""
3231

3332
# It will return with the Network configurations, which has the following struct:

jerry-debugger/jerry_client_serial.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright JS Foundation and other contributors, http://js.foundation
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
import select
18+
import serial
19+
20+
class Serial(object):
21+
""" Create a new socket using the given address family, socket type and protocol number. """
22+
def __init__(self, serial_config):
23+
config = serial_config.split(',')
24+
config_size = len(config)
25+
26+
port = config[0] if config_size > 0 else "/dev/ttyUSB0"
27+
baudrate = config[1] if config_size > 1 else 115200
28+
bytesize = int(config[2]) if config_size > 2 else 8
29+
parity = config[3] if config_size > 3 else 'N'
30+
stopbits = int(config[4]) if config_size > 4 else 1
31+
32+
self.ser = serial.Serial(port=port, baudrate=baudrate, parity=parity,
33+
stopbits=stopbits, bytesize=bytesize, timeout=1)
34+
35+
def connect(self):
36+
""" Connect to the server, write a 'c' to the serial port """
37+
self.send_data('c')
38+
39+
def close(self):
40+
"""" close the serial port. """
41+
self.ser.close()
42+
43+
def receive_data(self, max_size=1024):
44+
""" The maximum amount of data to be received at once is specified by max_size. """
45+
return self.ser.read(max_size)
46+
47+
def send_data(self, data):
48+
""" Write data to the serial port. """
49+
return self.ser.write(data)
50+
51+
def ready(self):
52+
""" Monitor the file descriptor. """
53+
result = select.select([self.ser.fileno()], [], [], 0)[0]
54+
55+
return self.ser.fileno() in result

jerry-debugger/jerry_client_tcp.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,20 @@
1717
import socket
1818
import select
1919

20+
# pylint: disable=too-many-arguments,superfluous-parens
2021
class Socket(object):
2122
""" Create a new socket using the given address family, socket type and protocol number. """
22-
def __init__(self, socket_family=socket.AF_INET, socket_type=socket.SOCK_STREAM, proto=0, fileno=None):
23+
def __init__(self, address, socket_family=socket.AF_INET, socket_type=socket.SOCK_STREAM, proto=0, fileno=None):
24+
self.address = address
2325
self.socket = socket.socket(socket_family, socket_type, proto, fileno)
2426

25-
def connect(self, address):
27+
def connect(self):
2628
"""
2729
Connect to a remote socket at address (host, port).
2830
The format of address depends on the address family.
2931
"""
30-
self.socket.connect(address)
32+
print("Connecting to: %s:%s" % (self.address[0], self.address[1]))
33+
self.socket.connect(self.address)
3134

3235
def close(self):
3336
"""" Mark the socket closed. """

0 commit comments

Comments
 (0)