[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
+5 -3
View File
@@ -68,9 +68,11 @@ When using the extension-provided WebSocket transport layer, the
debugger can be enabled by calling `jerryx_debugger_after_connect
(jerryx_debugger_tcp_create (debug_port) && jerryx_debugger_ws_create ())`
after the `jerry_init ()` function. It initializes the debugger and
blocks until a client connects. (Custom transport layers may be
implemented and initialized similarly. Currently, `jerryx_debugger_rp_create()` for
raw packet transport layer is also available.)
blocks until a client connects.
(Custom transport layers may be implemented and initialized similarly.
Currently, `jerryx_debugger_rp_create ()` for raw packet transport layer and
`jerryx_debugger_serial_create (const char* config)` for serial protocol
are also available.)
The resource name provided to `jerry_parse ()` is used by the client
to identify the resource name of the source code. This resource name
+2
View File
@@ -193,6 +193,8 @@ jerry_cleanup (void)
#ifdef JERRY_DEBUGGER
if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
{
jerry_debugger_send_type (JERRY_DEBUGGER_CLOSE_CONNECTION);
jerry_debugger_transport_close ();
}
#endif /* JERRY_DEBUGGER */
+2 -2
View File
@@ -38,9 +38,9 @@ typedef struct
* The number of message types in the debugger should reflect the
* debugger versioning.
*/
JERRY_STATIC_ASSERT (JERRY_DEBUGGER_MESSAGES_OUT_MAX_COUNT == 32
JERRY_STATIC_ASSERT (JERRY_DEBUGGER_MESSAGES_OUT_MAX_COUNT == 33
&& JERRY_DEBUGGER_MESSAGES_IN_MAX_COUNT == 21
&& JERRY_DEBUGGER_VERSION == 8,
&& JERRY_DEBUGGER_VERSION == 9,
debugger_version_correlates_to_message_type_count);
/**
+1
View File
@@ -156,6 +156,7 @@ typedef enum
JERRY_DEBUGGER_SCOPE_CHAIN_END = 29, /**< last output of scope chain */
JERRY_DEBUGGER_SCOPE_VARIABLES = 30, /**< scope variables */
JERRY_DEBUGGER_SCOPE_VARIABLES_END = 31, /**< last output of scope variables */
JERRY_DEBUGGER_CLOSE_CONNECTION = 32, /**< close connection with the client */
JERRY_DEBUGGER_MESSAGES_OUT_MAX_COUNT, /**< number of different type of output messages by the debugger */
/* Messages sent by the client to server. */
+1 -1
View File
@@ -31,7 +31,7 @@ extern "C"
/**
* JerryScript debugger protocol version.
*/
#define JERRY_DEBUGGER_VERSION (8)
#define JERRY_DEBUGGER_VERSION (9)
/**
* Types for the client source wait and run method.
+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()
+409
View File
@@ -0,0 +1,409 @@
/* 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.
*/
#include "jerryscript-debugger-transport.h"
#include "jerryscript-ext/debugger.h"
#include "jext-common.h"
#if defined JERRY_DEBUGGER && !defined WIN32
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <stdlib.h>
/* Max size of configuration string */
#define CONFIG_SIZE (255)
/**
* Implementation of transport over serial connection.
*/
typedef struct
{
jerry_debugger_transport_header_t header; /**< transport header */
int fd; /**< file descriptor */
} jerryx_debugger_transport_serial_t;
/**
* Configure parameters for a serial port.
*/
typedef struct
{
char *device_id;
uint32_t baud_rate; /**< specify the rate at which bits are transmitted for the serial interface */
uint32_t data_bits; /**< specify the number of data bits to transmit over the serial interface */
char parity; /**< specify how you want to check parity bits in the data bits transmitted via the serial port */
uint32_t stop_bits; /**< specify the number of bits used to indicate the end of a byte. */
} jerryx_debugger_transport_serial_config_t;
/**
* Correctly close a file descriptor.
*/
static inline void
jerryx_debugger_serial_close_fd (int fd) /**< file descriptor to close */
{
if (close (fd) != 0)
{
JERRYX_ERROR_MSG ("Error while closing the file descriptor: %d\n", errno);
}
} /* jerryx_debugger_serial_close_fd */
/**
* Set a file descriptor to blocking or non-blocking mode.
*
* @return true if everything is ok
* false if there was an error
**/
static bool
jerryx_debugger_serial_set_blocking (int fd, bool blocking)
{
/* Save the current flags */
int flags = fcntl (fd, F_GETFL, 0);
if (flags == -1)
{
JERRYX_ERROR_MSG ("Error %d during get flags from file descriptor\n", errno);
return false;
}
if (blocking)
{
flags &= ~O_NONBLOCK;
}
else
{
flags |= O_NONBLOCK;
}
if (fcntl (fd, F_SETFL, flags) == -1)
{
JERRYX_ERROR_MSG ("Error %d during set flags from file descriptor\n", errno);
return false;
}
return true;
} /* jerryx_debugger_serial_set_blocking */
/**
* Configure the file descriptor used by the serial communcation.
*
* @return true if everything is ok
* false if there was an error
*/
static inline bool
jerryx_debugger_serial_configure_attributes (int fd, jerryx_debugger_transport_serial_config_t serial_config)
{
struct termios options;
memset (&options, 0, sizeof (options));
/* Get the parameters associated with the file descriptor */
if (tcgetattr (fd, &options) != 0)
{
JERRYX_ERROR_MSG ("Error %d from tggetattr\n", errno);
return false;
}
/* Set the input and output baud rates */
cfsetispeed (&options, serial_config.baud_rate);
cfsetospeed (&options, serial_config.baud_rate);
/* Set the control modes */
options.c_cflag &= (uint32_t) ~CSIZE; // character size mask
options.c_cflag |= (CLOCAL | CREAD); // ignore modem control lines and enable the receiver
switch (serial_config.data_bits)
{
case 5:
{
options.c_cflag |= CS5; // set character size mask to 5-bit chars
break;
}
case 6:
{
options.c_cflag |= CS6; // set character size mask to 6-bit chars
break;
}
case 7:
{
options.c_cflag |= CS7; // set character size mask to 7-bit chars
break;
}
case 8:
{
options.c_cflag |= CS8; // set character size mask to 8-bit chars
break;
}
default:
{
JERRYX_ERROR_MSG ("Unsupported data bits: %d\n", serial_config.data_bits);
return false;
}
}
switch (serial_config.parity)
{
case 'N':
{
options.c_cflag &= (unsigned int) ~(PARENB | PARODD);
break;
}
case 'O':
{
options.c_cflag |= PARENB;
options.c_cflag |= PARODD;
break;
}
case 'E':
{
options.c_cflag |= PARENB;
options.c_cflag |= PARODD;
break;
}
default:
{
JERRYX_ERROR_MSG ("Unsupported parity: %c\n", serial_config.parity);
return false;
}
}
switch (serial_config.stop_bits)
{
case 1:
{
options.c_cflag &= (uint32_t) ~CSTOPB; // set 1 stop bits
break;
}
case 2:
{
options.c_cflag |= CSTOPB; // set 2 stop bits
break;
}
default:
{
JERRYX_ERROR_MSG ("Unsupported stop bits: %d\n", serial_config.stop_bits);
return false;
}
}
/* Set the input modes */
options.c_iflag &= (uint32_t) ~IGNBRK; // disable break processing
options.c_iflag &= (uint32_t) ~(IXON | IXOFF | IXANY); // disable xon/xoff ctrl
/* Set the output modes: no remapping, no delays */
options.c_oflag = 0;
/* Set the local modes: no signaling chars, no echo, no canoncial processing */
options.c_lflag = 0;
/* Read returns when at least one byte of data is available. */
options.c_cc[VMIN] = 1; // read block
options.c_cc[VTIME] = 5; // 0.5 seconds read timeout
/* Set the parameters associated with the file descriptor */
if (tcsetattr (fd, TCSANOW, &options) != 0)
{
JERRYX_ERROR_MSG ("Error %d from tcsetattr", errno);
return false;
}
/* Flushes both data received but not read, and data written but not transmitted */
if (tcflush (fd, TCIOFLUSH) != 0)
{
JERRYX_ERROR_MSG ("Error %d in tcflush() :%s\n", errno, strerror (errno));
jerryx_debugger_serial_close_fd (fd);
return false;
}
return true;
} /* jerryx_debugger_serial_configure_attributes */
/**
* Close a serial connection.
*/
static void
jerryx_debugger_serial_close (jerry_debugger_transport_header_t *header_p) /**< serial implementation */
{
JERRYX_ASSERT (!jerry_debugger_transport_is_connected ());
jerryx_debugger_transport_serial_t *serial_p = (jerryx_debugger_transport_serial_t *) header_p;
JERRYX_DEBUG_MSG ("Serial connection closed.\n");
jerryx_debugger_serial_close_fd (serial_p->fd);
jerry_heap_free ((void *) header_p, sizeof (jerryx_debugger_transport_serial_t));
} /* jerryx_debugger_serial_close */
/**
* Send data over a serial connection.
*
* @return true - if the data has been sent successfully
* false - otherwise
*/
static bool
jerryx_debugger_serial_send (jerry_debugger_transport_header_t *header_p, /**< serial implementation */
uint8_t *message_p, /**< message to be sent */
size_t message_length) /**< message length in bytes */
{
JERRYX_ASSERT (jerry_debugger_transport_is_connected ());
jerryx_debugger_transport_serial_t *serial_p = (jerryx_debugger_transport_serial_t *) header_p;
do
{
ssize_t sent_bytes = write (serial_p->fd, message_p, message_length);
if (sent_bytes < 0)
{
if (errno == EWOULDBLOCK)
{
continue;
}
JERRYX_ERROR_MSG ("Error: write to file descriptor: %d\n", errno);
jerry_debugger_transport_close ();
return false;
}
message_p += sent_bytes;
message_length -= (size_t) sent_bytes;
}
while (message_length > 0);
return true;
} /* jerryx_debugger_serial_send */
/**
* Receive data from a serial connection.
*/
static bool
jerryx_debugger_serial_receive (jerry_debugger_transport_header_t *header_p, /**< serial implementation */
jerry_debugger_transport_receive_context_t *receive_context_p) /**< receive context */
{
jerryx_debugger_transport_serial_t *serial_p = (jerryx_debugger_transport_serial_t *) header_p;
uint8_t *buffer_p = receive_context_p->buffer_p + receive_context_p->received_length;
size_t buffer_size = JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE - receive_context_p->received_length;
ssize_t length = read (serial_p->fd, buffer_p, buffer_size);
if (length <= 0)
{
if (errno != EWOULDBLOCK || length == 0)
{
jerry_debugger_transport_close ();
return false;
}
length = 0;
}
receive_context_p->received_length += (size_t) length;
if (receive_context_p->received_length > 0)
{
receive_context_p->message_p = receive_context_p->buffer_p;
receive_context_p->message_length = receive_context_p->received_length;
}
return true;
} /* jerryx_debugger_serial_receive */
/**
* Create a serial connection.
*
* @return true if successful,
* false otherwise
*/
bool
jerryx_debugger_serial_create (const char *config) /**< specify the configuration */
{
/* Parse the configuration string */
char tmp_config[CONFIG_SIZE];
strncpy (tmp_config, config, CONFIG_SIZE);
jerryx_debugger_transport_serial_config_t serial_config;
char *token = strtok (tmp_config, ",");
serial_config.device_id = token ? token : "/dev/ttyS0";
serial_config.baud_rate = (token = strtok (NULL, ",")) ? (uint32_t) strtoul (token, NULL, 10) : 115200;
serial_config.data_bits = (token = strtok (NULL, ",")) ? (uint32_t) strtoul (token, NULL, 10) : 8;
serial_config.parity = (token = strtok (NULL, ",")) ? token[0] : 'N';
serial_config.stop_bits = (token = strtok (NULL, ",")) ? (uint32_t) strtoul (token, NULL, 10) : 1;
int fd = open (serial_config.device_id, O_RDWR);
if (fd < 0)
{
JERRYX_ERROR_MSG ("Error %d opening %s: %s", errno, serial_config.device_id, strerror (errno));
return false;
}
if (!jerryx_debugger_serial_configure_attributes (fd, serial_config))
{
jerryx_debugger_serial_close_fd (fd);
return false;
}
JERRYX_DEBUG_MSG ("Waiting for client connection\n");
/* Client will sent a 'c' char to initiate the connection. */
uint8_t conn_char;
ssize_t t = read (fd, &conn_char, 1);
if (t != 1 || conn_char != 'c' || !jerryx_debugger_serial_set_blocking (fd, false))
{
return false;
}
JERRYX_DEBUG_MSG ("Client connected\n");
size_t size = sizeof (jerryx_debugger_transport_serial_t);
jerry_debugger_transport_header_t *header_p;
header_p = (jerry_debugger_transport_header_t *) jerry_heap_alloc (size);
if (!header_p)
{
jerryx_debugger_serial_close_fd (fd);
return false;
}
header_p->close = jerryx_debugger_serial_close;
header_p->send = jerryx_debugger_serial_send;
header_p->receive = jerryx_debugger_serial_receive;
((jerryx_debugger_transport_serial_t *) header_p)->fd = fd;
jerry_debugger_transport_add (header_p,
0,
JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE,
0,
JERRY_DEBUGGER_TRANSPORT_MAX_BUFFER_SIZE);
return true;
} /* jerryx_debugger_serial_create */
#else /* !JERRY_DEBUGGER || WIN32 */
/**
* Dummy function when debugger is disabled.
*
* @return false
*/
bool
jerryx_debugger_serial_create (const char *config)
{
JERRYX_UNUSED (config);
return false;
} /* jerryx_debugger_serial_create */
#endif /* JERRY_DEBUGGER */
@@ -30,6 +30,7 @@ void jerryx_debugger_after_connect (bool success);
* Message transmission interfaces.
*/
bool jerryx_debugger_tcp_create (uint16_t port);
bool jerryx_debugger_serial_create (const char *config);
/*
* Message encoding interfaces.
+45 -7
View File
@@ -318,6 +318,8 @@ typedef enum
OPT_DEBUG_SERVER,
OPT_DEBUG_PORT,
OPT_DEBUG_CHANNEL,
OPT_DEBUG_PROTOCOL,
OPT_DEBUG_SERIAL_CONFIG,
OPT_DEBUGGER_WAIT_SOURCE,
OPT_EXEC_SNAP,
OPT_EXEC_SNAP_FUNC,
@@ -349,6 +351,10 @@ static const cli_opt_t main_opts[] =
.help = "debug server port (default: 5001)"),
CLI_OPT_DEF (.id = OPT_DEBUG_CHANNEL, .longopt = "debug-channel", .meta = "[websocket|rawpacket]",
.help = "Specify the debugger transmission channel (default: websocket)"),
CLI_OPT_DEF (.id = OPT_DEBUG_PROTOCOL, .longopt = "debug-protocol", .meta = "PROTOCOL",
.help = "Specify the transmission protocol over the communication channel (tcp|serial, default: tcp)"),
CLI_OPT_DEF (.id = OPT_DEBUG_SERIAL_CONFIG, .longopt = "serial-config", .meta = "OPTIONS_STRING",
.help = "Configure parameters for serial port (default: /dev/ttyS0,115200,8,N,1)"),
CLI_OPT_DEF (.id = OPT_DEBUGGER_WAIT_SOURCE, .longopt = "debugger-wait-source",
.help = "wait for an executable source from the client"),
CLI_OPT_DEF (.id = OPT_EXEC_SNAP, .longopt = "exec-snapshot", .meta = "FILE",
@@ -422,21 +428,33 @@ context_alloc (size_t size,
static void
init_engine (jerry_init_flag_t flags, /**< initialized flags for the engine */
char *debug_channel, /**< enable the debugger init or not */
uint16_t debug_port) /**< the debugger port */
char *debug_protocol, /**< enable the debugger init or not */
uint16_t debug_port, /**< the debugger port for tcp protocol */
char *debug_serial_config) /**< configuration string for serial protocol */
{
jerry_init (flags);
if (strcmp (debug_channel, ""))
{
bool tcp_created = jerryx_debugger_tcp_create (debug_port);
bool protocol = false;
if (!strcmp (debug_protocol, "tcp"))
{
protocol = jerryx_debugger_tcp_create (debug_port);
}
else
{
assert (!strcmp (debug_protocol, "serial"));
protocol = jerryx_debugger_serial_create (debug_serial_config);
}
if (!strcmp (debug_channel, "rawpacket"))
{
jerryx_debugger_after_connect (tcp_created && jerryx_debugger_rp_create ());
jerryx_debugger_after_connect (protocol && jerryx_debugger_rp_create ());
}
else
{
assert (!strcmp (debug_channel, "websocket"));
jerryx_debugger_after_connect (tcp_created && jerryx_debugger_ws_create ());
jerryx_debugger_after_connect (protocol && jerryx_debugger_ws_create ());
}
}
@@ -464,6 +482,8 @@ main (int argc,
bool start_debug_server = false;
uint16_t debug_port = 5001;
char *debug_channel = "websocket";
char *debug_protocol = "tcp";
char *debug_serial_config = "/dev/ttyS0,115200,8,N,1";
bool is_repl_mode = false;
bool is_wait_mode = false;
@@ -542,6 +562,24 @@ main (int argc,
}
break;
}
case OPT_DEBUG_PROTOCOL:
{
if (check_feature (JERRY_FEATURE_DEBUGGER, cli_state.arg))
{
debug_protocol = (char *) cli_consume_string (&cli_state);
check_usage (!strcmp (debug_protocol, "tcp") || !strcmp (debug_protocol, "serial"),
argv[0], "Error: invalid value for --debug-protocol: ", cli_state.arg);
}
break;
}
case OPT_DEBUG_SERIAL_CONFIG:
{
if (check_feature (JERRY_FEATURE_DEBUGGER, cli_state.arg))
{
debug_serial_config = (char *) cli_consume_string (&cli_state);
}
break;
}
case OPT_DEBUGGER_WAIT_SOURCE:
{
if (check_feature (JERRY_FEATURE_DEBUGGER, cli_state.arg))
@@ -640,7 +678,7 @@ main (int argc,
debug_channel = "";
}
init_engine (flags, debug_channel, debug_port);
init_engine (flags, debug_channel, debug_protocol, debug_port, debug_serial_config);
jerry_value_t ret_value = jerry_create_undefined ();
@@ -758,7 +796,7 @@ main (int argc,
break;
}
init_engine (flags, debug_channel, debug_port);
init_engine (flags, debug_channel, debug_protocol, debug_port, debug_serial_config);
ret_value = jerry_create_undefined ();
}
@@ -802,7 +840,7 @@ main (int argc,
jerry_cleanup ();
init_engine (flags, debug_channel, debug_port);
init_engine (flags, debug_channel, debug_protocol, debug_port, debug_serial_config);
ret_value = jerry_create_undefined ();
}