mirror of
https://github.com/google/pebble.git
synced 2025-03-15 08:41:21 +00:00
210 lines
7 KiB
Python
210 lines
7 KiB
Python
# Copyright 2024 Google LLC
|
|
#
|
|
# 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 contextlib
|
|
import pexpect
|
|
import re
|
|
import string
|
|
import subprocess
|
|
import sys
|
|
import waflib
|
|
|
|
from waflib import Logs
|
|
|
|
|
|
JTAG_OPTIONS = {'olimex': 'source [find interface/ftdi/olimex-arm-usb-ocd-h.cfg]',
|
|
'fixture': 'source [find interface/flossjtag-noeeprom.cfg]',
|
|
'bb2': 'source waftools/openocd_bb2_ftdi.cfg',
|
|
'bb2-legacy': 'source waftools/openocd_bb2_ft2232.cfg',
|
|
'jtag_ftdi': 'source waftools/openocd_jtag_ftdi.cfg',
|
|
'swd_ftdi': 'source waftools/openocd_swd_ftdi.cfg',
|
|
'swd_jlink': 'source waftools/openocd_swd_jlink.cfg',
|
|
'swd_stlink': 'source [find interface/stlink-v2.cfg]',
|
|
}
|
|
|
|
OPENOCD_TELNET_PORT = 4444
|
|
|
|
|
|
@contextlib.contextmanager
|
|
def daemon(ctx, cfg_file, use_swd=False):
|
|
if _is_openocd_running():
|
|
yield
|
|
else:
|
|
if use_swd:
|
|
expect_str = "SWD IDCODE"
|
|
else:
|
|
expect_str = "device found"
|
|
|
|
proc = pexpect.spawn('openocd', ['-f', cfg_file], logfile=sys.stdout)
|
|
# Wait for OpenOCD to connect to the board:
|
|
result = proc.expect([expect_str, pexpect.TIMEOUT], timeout=10)
|
|
if result == 0:
|
|
yield
|
|
else:
|
|
raise Exception("Timed out connecting OpenOCD to development board...")
|
|
proc.close()
|
|
|
|
|
|
def _has_openocd(ctx):
|
|
try:
|
|
ctx.cmd_and_log(['which', 'openocd'], quiet=waflib.Context.BOTH)
|
|
return True
|
|
except:
|
|
return False
|
|
|
|
|
|
def _is_openocd_running():
|
|
import socket
|
|
import errno
|
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
try:
|
|
s.bind(('', OPENOCD_TELNET_PORT))
|
|
s.close()
|
|
except socket.error as e:
|
|
s.close()
|
|
return e[0] == errno.EADDRINUSE
|
|
return False
|
|
|
|
|
|
def run_command(ctx, cmd, ignore_fail=False, expect=[], timeout=40,
|
|
shutdown=True, enforce_expect=False, cfg_file="openocd.cfg"):
|
|
if _is_openocd_running():
|
|
import telnetlib
|
|
t = telnetlib.Telnet('', OPENOCD_TELNET_PORT)
|
|
Logs.info("Sending commands to OpenOCD daemon:\n%s\n..." % cmd)
|
|
t.write("%s\n" % cmd)
|
|
for regex in expect:
|
|
idx, match, text = t.expect([regex], timeout)
|
|
if enforce_expect and idx == -1:
|
|
# They'll see the full story in another window
|
|
ctx.fatal("OpenOCD expectation '%s' unfulfilled" % regex)
|
|
t.close()
|
|
else:
|
|
fail_handling = ' || true ' if ignore_fail else ''
|
|
if shutdown:
|
|
# append 'shutdown' to make openocd exit:
|
|
cmd = "%s ; shutdown" % cmd
|
|
ctx.exec_command('openocd -f %s -c "%s" 2>&1 | tee .waf.openocd.log %s' %
|
|
(cfg_file, cmd, fail_handling), stdout=None, stderr=None)
|
|
if enforce_expect:
|
|
# Read the result
|
|
with open(".waf.openocd.log", "r") as result_file:
|
|
result = result_file.read()
|
|
match_start = 0
|
|
for regex in expect:
|
|
expect_match = re.search(regex, result[match_start:])
|
|
if not expect_match:
|
|
ctx.fatal("OpenOCD expectation '%s' unfulfilled" % regex)
|
|
match_start = expect_match.end()
|
|
|
|
|
|
|
|
def _get_supported_interfaces(ctx):
|
|
if not _has_openocd(ctx):
|
|
return []
|
|
# Ugh, openocd exits with status 1 when not specifying an interface...
|
|
try:
|
|
ctx.cmd_and_log(['openocd', '-c', '"interface_list"'],
|
|
quiet=waflib.Context.BOTH,
|
|
output=waflib.Context.STDERR)
|
|
except Exception as e:
|
|
# Ugh, openocd prints the output to stderr...
|
|
out = e.stderr
|
|
out_lines = out.splitlines()
|
|
interfaces = []
|
|
for line in out_lines:
|
|
matches = re.search("\d+: (\w+)", line)
|
|
if matches:
|
|
interfaces.append(matches.groups()[0])
|
|
return interfaces
|
|
|
|
|
|
def get_flavor(conf):
|
|
""" Returns a 2-tuple (is_newer_than_0_7_0, is_pebble_flavor) """
|
|
|
|
try:
|
|
version_string = conf.cmd_and_log(['openocd', '--version'],
|
|
quiet=waflib.Context.BOTH,
|
|
output=waflib.Context.STDERR)
|
|
version_string = version_string.splitlines()[0]
|
|
matches = re.search("(\d+)\.(\d+)\.(\d+)", version_string)
|
|
version = map(int, matches.groups())
|
|
return (version[0] >= 0 and version[1] >= 7,
|
|
'pebble' in version_string)
|
|
except Exception:
|
|
Logs.error("Couldn't parse openocd version")
|
|
return (False, False)
|
|
|
|
|
|
def _get_reset_conf(conf, is_newer_than_0_7_0, should_connect_assert_srst):
|
|
if is_newer_than_0_7_0:
|
|
options = ['trst_and_srst', 'srst_nogate']
|
|
if should_connect_assert_srst:
|
|
options.append('connect_assert_srst')
|
|
return ' '.join(options)
|
|
else:
|
|
return 'trst_and_srst'
|
|
|
|
|
|
def write_cfg(conf):
|
|
jtag = conf.env.JTAG
|
|
if jtag == 'bb2':
|
|
if 'ftdi' not in _get_supported_interfaces(conf):
|
|
jtag = 'bb2-legacy'
|
|
Logs.warn('OpenOCD is not compiled with --enable-ftdi, falling'
|
|
' back to legacy ft2232 driver.')
|
|
|
|
if conf.env.MICRO_FAMILY == 'STM32F2':
|
|
target = 'stm32f2x.cfg'
|
|
elif conf.env.MICRO_FAMILY == 'STM32F4':
|
|
target = 'stm32f4x.cfg'
|
|
elif conf.env.MICRO_FAMILY == 'STM32F7':
|
|
target = 'stm32f7x.cfg'
|
|
|
|
(is_newer_than_0_7_0, is_pebble_flavor) = get_flavor(conf)
|
|
|
|
reset_config = _get_reset_conf(conf, is_newer_than_0_7_0, False)
|
|
Logs.info("reset_config: %s" % reset_config)
|
|
|
|
if is_pebble_flavor:
|
|
Logs.info("openocd is Pebble flavored!")
|
|
os_name = 'Pebble_FreeRTOS'
|
|
else:
|
|
os_name = 'FreeRTOS'
|
|
|
|
openocd_cfg = OPENOCD_CFG_TEMPLATE.substitute(jtag=JTAG_OPTIONS[jtag],
|
|
target=target,
|
|
reset_config=reset_config,
|
|
os_name=os_name)
|
|
waflib.Utils.writef('./openocd.cfg', openocd_cfg)
|
|
|
|
|
|
OPENOCD_CFG_TEMPLATE = string.Template("""
|
|
# THIS IS A GENERATED FILE: See waftools/openocd.py for details
|
|
|
|
${jtag}
|
|
source [find target/${target}]
|
|
|
|
reset_config ${reset_config}
|
|
|
|
$$_TARGETNAME configure -rtos ${os_name}
|
|
$$_TARGETNAME configure -event gdb-attach {
|
|
echo "Halting target because GDB is attaching..."
|
|
halt
|
|
}
|
|
$$_TARGETNAME configure -event gdb-detach {
|
|
echo "Resuming target because GDB is detaching..."
|
|
resume
|
|
}
|
|
""")
|