Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions docs/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ Controls whether all 256 ADIv5 AP addresses will be probed.
<td>bool</td>
<td>True</td>
<td>
When this option is True, the GDB server, probe server, semihosting telnet, and raw SWV server are only served
When this option is True, the GDB server, probe server, stdio server, rtt server, and raw SWV server are only served
on localhost, making them inaccessible across the network. Set to False to enable connecting to these ports
from any machine on the network.
</td></tr>
Expand Down Expand Up @@ -472,7 +472,7 @@ Examples:
</ul>
</td></tr>

<tr><td>telnet_mode</td>
<tr><td>stdio_mode</td>
<td>str, list of str</td>
<td>'server'</td>
<td>Controls connection to standard I/O. Must be one of 'off', 'console', 'server', or 'file'. For multicore devices
Expand All @@ -487,10 +487,10 @@ console and the standard I/O for <tt>core1</tt> is routed to the Telnet Server.<
</ul>
</td></tr>

<tr><td>telnet_port</td>
<tr><td>stdio_port</td>
<td>int, list of int</td>
<td>4444</td>
<td>The option applies only when <tt>telnet_mode</tt> is set to 'server'. Base TCP port for the Telnet Server.
<td>The option applies only when <tt>stdio_mode</tt> is set to 'server'. Base TCP port for the Telnet Server.
For multicore targets the zero-based core number will be added to the value unless a list is specified.

Examples:
Expand All @@ -502,10 +502,10 @@ Examples:
</ul>
</td></tr>

<tr><td>telnet_file_in</td>
<tr><td>stdio_file_in</td>
<td>str, list of str</td>
<td><i>&lt;target&gt;.in</i></td>
<td>The option applies only when <tt>telnet_mode</tt> is set to 'file'. Input filename to use as <i>stdin</i>.
<td>The option applies only when <tt>stdio_mode</tt> is set to 'file'. Input filename to use as <i>stdin</i>.
When a single string is used, the core number (_&lt;core&gt;) will be appended to the filename
in case of multicore targets.

Expand All @@ -519,10 +519,10 @@ assigned to <tt>core0</tt> and <tt>mytarget_cm0.in</tt> is assigned to <tt>core1
</ul>
</td></tr>

<tr><td>telnet_file_out</td>
<tr><td>stdio_file_out</td>
<td>str, list of str</td>
<td><i>&lt;target&gt;.out</i></td>
<td>The option applies only when <tt>telnet_mode</tt> is set to 'file'. Output filename to use as <i>stdout</i>.
<td>The option applies only when <tt>stdio_mode</tt> is set to 'file'. Output filename to use as <i>stdout</i>.
When a single string is used, the core number (_&lt;core&gt;) will be appended to the filename
in case of multicore targets.

Expand Down
28 changes: 18 additions & 10 deletions pyocd/core/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ class OptionInfo(NamedTuple):
OptionInfo('scan_all_aps', bool, False,
"Controls whether all 256 ADIv5 AP addresses will be probed. Default is False."),
OptionInfo('serve_local_only', bool, True,
"When this option is True, the GDB server, probe server, and semihosting telnet, and raw SWV "
"When this option is True, the GDB server, probe server, stdio server, rtt server, and raw SWV "
"server are only served on localhost. Set to False to enable remote connections."),
OptionInfo('smart_flash', bool, True,
"If set to True, the flash loader will attempt to not program pages whose contents are not "
Expand Down Expand Up @@ -196,8 +196,6 @@ class OptionInfo(NamedTuple):
"TCP port number for the raw SWV stream server."),
OptionInfo('swv_raw_file', str, None,
"File path for the raw SWV stream output."),
OptionInfo('telnet_port', (int, tuple), 4444,
"Base TCP port number for the semihosting telnet server."),
OptionInfo('vector_catch', str, 'h',
"Enable vector catch sources."),
OptionInfo('register_fields', bool, True,
Expand All @@ -206,13 +204,15 @@ class OptionInfo(NamedTuple):
OptionInfo('soft_bkpt_as_hard', bool, False,
"Replace software breakpoints with hardware breakpoints."),

# Internal cbuild-run session options
OptionInfo('telnet_mode', (str, tuple), None,
"List of telnet modes for each core."),
OptionInfo('telnet_file_in', (str, tuple), None,
"List of telnet input file paths for each core."),
OptionInfo('telnet_file_out', (str, tuple), None,
"List of telnet output file paths for each core."),
# Extended options with multicore support
OptionInfo('stdio_mode', (str, tuple), None,
"List of STDIO modes for each core."),
OptionInfo('stdio_port', (int, tuple), 4444,
"Base TCP port number for the STDIO server."),
OptionInfo('stdio_file_in', (str, tuple), None,
"List of STDIO input file paths for each core."),
OptionInfo('stdio_file_out', (str, tuple), None,
"List of STDIO output file paths for each core."),
OptionInfo('rtt', tuple, None,
"List of RTT configurations for each core."),
OptionInfo('systemview_file', str, None,
Expand All @@ -223,6 +223,14 @@ class OptionInfo(NamedTuple):
"Enable automatic stop of SystemView."),
]

## @brief Aliases for backwards-compatible option names.
OPTIONS_ALIASES: Dict[str, str] = {
'telnet_port': 'stdio_port',
'telnet_mode': 'stdio_mode',
'telnet_file_in': 'stdio_file_in',
'telnet_file_out': 'stdio_file_out',
}

## @brief The runtime dictionary of options.
OPTIONS_INFO: Dict[str, OptionInfo] = {}

Expand Down
11 changes: 6 additions & 5 deletions pyocd/core/options_manager.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# pyOCD debugger
# Copyright (c) 2019-2020 Arm Limited
# Copyright (c) 2019-2020,2026 Arm Limited
# Copyright (c) 2021 Chris Reed
# SPDX-License-Identifier: Apache-2.0
#
Expand All @@ -19,7 +19,7 @@
from functools import partial
from typing import (Any, Callable, Dict, List, Mapping, NamedTuple, Optional)

from .options import OPTIONS_INFO
from .options import (OPTIONS_ALIASES, OPTIONS_INFO)
from ..utility.notification import Notifier

LOG = logging.getLogger(__name__)
Expand Down Expand Up @@ -101,14 +101,15 @@ def _convert_options(self, new_options: LayerType) -> LayerType:
1. Strip dictionary entries with a value of None.
2. Replace double-underscores ("__") with a dot (".").
3. Convert option names to all-lowercase.
4. Resolve option aliases.
"""
output = {}
for name, value in new_options.items():
if value is None:
continue
else:
name = name.replace("__", ".").lower()
output[name] = value
name = name.replace("__", ".").lower()
name = OPTIONS_ALIASES.get(name, name)
output[name] = value
return output

def is_set(self, key: str) -> bool:
Expand Down
10 changes: 5 additions & 5 deletions pyocd/core/session.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,11 +295,11 @@ def _get_cbuild_run_config(self, command: Optional[str]) -> Dict[str, Any]:
debugger_options['connect_mode'] = connect_mode

debugger_options['gdbserver_port'] = self.cbuild_run.gdbserver_port
debugger_options['telnet_port'] = self.cbuild_run.telnet_port
debugger_options['telnet_mode'] = self.cbuild_run.telnet_mode
telnet_file = self.cbuild_run.telnet_file
debugger_options['telnet_file_in'] = telnet_file.get('in')
debugger_options['telnet_file_out'] = telnet_file.get('out')
debugger_options['stdio_port'] = self.cbuild_run.stdio_port
debugger_options['stdio_mode'] = self.cbuild_run.stdio_mode
stdio_file = self.cbuild_run.stdio_file
debugger_options['stdio_file_in'] = stdio_file.get('in')
debugger_options['stdio_file_out'] = stdio_file.get('out')

debugger_options['rtt'] = self.cbuild_run.rtt
debugger_options['systemview_file'] = self.cbuild_run.systemview_file
Expand Down
70 changes: 40 additions & 30 deletions pyocd/target/pack/cbuild_run.py
Original file line number Diff line number Diff line change
Expand Up @@ -518,8 +518,12 @@ def flashinfo(self) -> List[dict]:
def debugger(self) -> Dict[str, Any]:
"""@brief Debugger section of cbuild-run."""
if self._debugger is None:
self._debugger = self._data.get('debugger', {})
LOG.debug("Read debugger configuration: %s", self._debugger)
_debugger = self._data.get('debugger') or {}
LOG.debug("Read debugger configuration: %s", _debugger)
if 'stdio' in _debugger and 'telnet' in _debugger:
LOG.warning("Both 'stdio' and 'telnet' sections found in debugger configuration. "
"Using 'stdio' section and ignoring 'telnet'.")
self._debugger = _debugger
return self._debugger

@property
Expand Down Expand Up @@ -627,52 +631,53 @@ def gdbserver_port(self) -> Optional[Tuple]:
return self._get_server_port('gdbserver')

@property
def telnet_port(self) -> Optional[Tuple]:
"""@brief Telnet server port assignments from debugger section.
def stdio_port(self) -> Optional[Tuple]:
"""@brief STDIO server port assignments from debugger section.
The method will not be called frequently, so performance is not critical.
"""
return self._get_server_port('telnet')
server_type = 'stdio' if 'stdio' in self.debugger else 'telnet'
return self._get_server_port(server_type)

@property
def telnet_mode(self) -> Tuple:
"""@brief Telnet server mode assignments from debugger section.
def stdio_mode(self) -> Tuple:
"""@brief STDIO mode assignments from debugger section.
The method will not be called frequently, so performance is not critical.
"""
SUPPORTED_MODES = { 'off', 'server', 'file', 'console' }
MODE_ALIASES = { False: 'off',
'monitor': 'server'
}
# Get telnet configuration from debugger section
telnet_config = self.debugger.get('telnet') or []
valid_config = any('mode' in t for t in telnet_config)
# Get STDIO configuration from debugger section
stdio_config = self._get_stdio_config()
valid_config = any('mode' in s for s in stdio_config)
# Determine global mode if specified, default to 'off' otherwise
global_mode = next((t.get('mode') for t in telnet_config if 'pname' not in t), 'off')
global_mode = next((s.get('mode') for s in stdio_config if 'pname' not in s), 'off')
global_mode = MODE_ALIASES.get(global_mode, global_mode)
# Build list of telnet modes for each core
telnet_mode = []
# Build list of STDIO modes for each core
stdio_mode = []
for core in self.sorted_processors:
mode = next((t.get('mode') for t in telnet_config if t.get('pname') == core.name), global_mode)
mode = next((s.get('mode') for s in stdio_config if s.get('pname') == core.name), global_mode)
mode = MODE_ALIASES.get(mode, mode)
if mode not in SUPPORTED_MODES:
if valid_config:
LOG.warning("Invalid telnet mode '%s' for core '%s' in cbuild-run, defaulting to '%s'",
LOG.warning("Invalid STDIO mode '%s' for core '%s' in cbuild-run, defaulting to '%s'",
mode, core.name, global_mode)
mode = global_mode
telnet_mode.append(mode)
stdio_mode.append(mode)

return tuple(telnet_mode)
return tuple(stdio_mode)

@property
def telnet_file(self) -> Dict[str, Optional[Tuple]]:
"""@brief Telnet file path assignments from debugger section.
def stdio_file(self) -> Dict[str, Optional[Tuple]]:
"""@brief STDIO file path assignments from debugger section.
The method will not be called frequently, so performance is not critical.
"""
# Get telnet configuration from debugger section
telnet_config = self.debugger.get('telnet') or []
telnet_mode = self.telnet_mode
# Get STDIO configuration from debugger section
stdio_config = self._get_stdio_config()
stdio_mode = self.stdio_mode

if not any(mode == 'file' for mode in telnet_mode):
# No telnet file paths needed
if not any(mode == 'file' for mode in stdio_mode):
# No STDIO file paths needed
return {'in': None, 'out': None}

def _resolve_path(file_path: Optional[str], strict: bool = False) -> Optional[str]:
Expand All @@ -685,19 +690,19 @@ def _resolve_path(file_path: Optional[str], strict: bool = False) -> Optional[st
resolved_path = file_path_obj.resolve()
# In strict mode check if the file exists
if strict and not resolved_path.is_file():
LOG.warning("Telnet file '%s' not found", resolved_path)
LOG.warning("STDIO file '%s' not found", resolved_path)

return str(resolved_path)

in_files = []
out_files = []

# Per pname configuration
config_by_pname = {t['pname']: t for t in telnet_config if 'pname' in t}
config_by_pname = {s['pname']: s for s in stdio_config if 'pname' in s}

if config_by_pname:
# Build config per pname
for proc_info, mode in zip(self.sorted_processors, telnet_mode):
for proc_info, mode in zip(self.sorted_processors, stdio_mode):
if mode != 'file':
in_files.append(None)
out_files.append(None)
Expand All @@ -714,11 +719,11 @@ def _resolve_path(file_path: Optional[str], strict: bool = False) -> Optional[st
out_file = str((self._base_path / f"{self._cbuild_name}.{proc_info.name}.out").resolve())
out_files.append(out_file)
else:
config = next((t for t in telnet_config if t.get('mode') == 'file'), None)
config = next((s for s in stdio_config if s.get('mode') == 'file'), None)
if config is not None:
if len(self.sorted_processors) > 1:
LOG.warning("Ignoring invalid telnet file configuration for multicore target in cbuild-run")
for proc_info, mode in zip(self.sorted_processors, telnet_mode):
LOG.warning("Ignoring invalid STDIO file configuration for multicore target in cbuild-run")
for proc_info, mode in zip(self.sorted_processors, stdio_mode):
if mode != 'file':
in_files.append(None)
out_files.append(None)
Expand Down Expand Up @@ -795,6 +800,11 @@ def populate_target(self, target: Optional[str] = None) -> None:
})
TARGET[target] = tgt

def _get_stdio_config(self) -> List[dict]:
"""@brief Returns STDIO configuration from debugger section, with telnet as an alias."""
server_type = 'stdio' if 'stdio' in self.debugger else 'telnet'
return self.debugger.get(server_type) or []

def _get_server_port(self, server_type: str) -> Optional[Tuple]:
"""@brief Generic method to get server port assignments from debugger section."""
server_config = self.debugger.get(server_type, [])
Expand Down
3 changes: 2 additions & 1 deletion pyocd/utility/cmdline.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import yaml

from ..core.target import Target
from ..core.options import OPTIONS_INFO
from ..core.options import (OPTIONS_ALIASES, OPTIONS_INFO)
from ..utility.compatibility import to_str_safe

LOG = logging.getLogger(__name__)
Expand Down Expand Up @@ -165,6 +165,7 @@ def convert_one_session_option(name: str, value: Optional[str]) -> Tuple[str, An
had_no_prefix = True
else:
had_no_prefix = False
name = OPTIONS_ALIASES.get(name, name)

# Look up this option.
try:
Expand Down
Loading
Loading