diff --git a/docs/07.DEBUGGER.md b/docs/07.DEBUGGER.md index 86df1450e..832233469 100644 --- a/docs/07.DEBUGGER.md +++ b/docs/07.DEBUGGER.md @@ -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 diff --git a/jerry-core/api/jerry.c b/jerry-core/api/jerry.c index 7b646ece9..ff7f11d5d 100644 --- a/jerry-core/api/jerry.c +++ b/jerry-core/api/jerry.c @@ -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 */ diff --git a/jerry-core/debugger/debugger.c b/jerry-core/debugger/debugger.c index 02ba15209..58dc80566 100644 --- a/jerry-core/debugger/debugger.c +++ b/jerry-core/debugger/debugger.c @@ -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); /** diff --git a/jerry-core/debugger/debugger.h b/jerry-core/debugger/debugger.h index 731314df7..61ce0e35e 100644 --- a/jerry-core/debugger/debugger.h +++ b/jerry-core/debugger/debugger.h @@ -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. */ diff --git a/jerry-core/include/jerryscript-debugger.h b/jerry-core/include/jerryscript-debugger.h index 735d61e16..759bd4e8f 100644 --- a/jerry-core/include/jerryscript-debugger.h +++ b/jerry-core/include/jerryscript-debugger.h @@ -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. diff --git a/jerry-debugger/jerry_client.py b/jerry-debugger/jerry_client.py index 831382be3..8c704a229 100755 --- a/jerry-debugger/jerry_client.py +++ b/jerry-debugger/jerry_client.py @@ -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) " diff --git a/jerry-debugger/jerry_client_main.py b/jerry-debugger/jerry_client_main.py index dc16f364f..82ae47a7a 100644 --- a/jerry-debugger/jerry_client_main.py +++ b/jerry-debugger/jerry_client_main.py @@ -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") diff --git a/jerry-debugger/jerry_client_rawpacket.py b/jerry-debugger/jerry_client_rawpacket.py index b90fa8a63..5c3304edd 100644 --- a/jerry-debugger/jerry_client_rawpacket.py +++ b/jerry-debugger/jerry_client_rawpacket.py @@ -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: diff --git a/jerry-debugger/jerry_client_serial.py b/jerry-debugger/jerry_client_serial.py new file mode 100644 index 000000000..9e77e0da0 --- /dev/null +++ b/jerry-debugger/jerry_client_serial.py @@ -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 diff --git a/jerry-debugger/jerry_client_tcp.py b/jerry-debugger/jerry_client_tcp.py index 11d8a6197..c241bfe92 100644 --- a/jerry-debugger/jerry_client_tcp.py +++ b/jerry-debugger/jerry_client_tcp.py @@ -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. """ diff --git a/jerry-debugger/jerry_client_websocket.py b/jerry-debugger/jerry_client_websocket.py index 1e84e55e3..fe2c761a9 100644 --- a/jerry-debugger/jerry_client_websocket.py +++ b/jerry-debugger/jerry_client_websocket.py @@ -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() diff --git a/jerry-ext/debugger/debugger-serial.c b/jerry-ext/debugger/debugger-serial.c new file mode 100644 index 000000000..c7ec716b7 --- /dev/null +++ b/jerry-ext/debugger/debugger-serial.c @@ -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 +#include +#include +#include +#include + +/* 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 */ diff --git a/jerry-ext/include/jerryscript-ext/debugger.h b/jerry-ext/include/jerryscript-ext/debugger.h index c9fbc7e89..e229e25ec 100644 --- a/jerry-ext/include/jerryscript-ext/debugger.h +++ b/jerry-ext/include/jerryscript-ext/debugger.h @@ -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. diff --git a/jerry-main/main-unix.c b/jerry-main/main-unix.c index 8c0b5156d..9b4cacc8e 100644 --- a/jerry-main/main-unix.c +++ b/jerry-main/main-unix.c @@ -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 (); }