1
0
Fork 0
mirror of https://github.com/iNavFlight/inav.git synced 2025-07-13 11:29:56 +03:00

[BUILD] Add support for openocd helpers with cmake

- Add openocd_<target>: runs openocd for the target
- Add openocd_flash_<target>: flashes the target using openocd.
 It works with both an already running openocd instance as well
 as launching its own one. Uses a helper tool that requires python.
- Add openocd_cfg_<target>: generates openocd config for target. Used
 for generating an openocd config automatically when launching
 a debug session from an IDE.
This commit is contained in:
Alberto García Hierro 2020-07-13 21:25:23 +01:00
parent fb9f61a583
commit d6177e6933
10 changed files with 211 additions and 11 deletions

1
.gitignore vendored
View file

@ -8,6 +8,7 @@
.project
.settings
.cproject
__pycache__
startup_stm32f10x_md_gcc.s
.vagrant/
.vscode/

View file

@ -47,6 +47,7 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
set(FIRMWARE_VERSION ${PROJECT_VERSION})
include(settings)
include(openocd)
include(main)
include(stm32)

View file

@ -53,6 +53,14 @@ function(setup_firmware_target name)
)
get_property(targets GLOBAL PROPERTY VALID_TARGETS)
set_property(GLOBAL PROPERTY VALID_TARGETS "${targets} ${name}")
setup_openocd(${name})
endfunction()
function(exclude_from_all target)
set_property(TARGET ${target} PROPERTY
TARGET_MESSAGES OFF
EXCLUDE_FROM_ALL 1
EXCLUDE_FROM_DEFAULT_BUILD 1)
endfunction()
function(collect_targets)
@ -61,8 +69,5 @@ function(collect_targets)
set(list_target_name "targets")
add_custom_target(${list_target_name}
COMMAND cmake -E echo "Valid targets: ${targets}")
set_property(TARGET ${list_target_name} PROPERTY
TARGET_MESSAGES OFF
EXCLUDE_FROM_ALL 1
EXCLUDE_FROM_DEFAULT_BUILD 1)
exclude_from_all(${list_target_name})
endfunction()

84
cmake/openocd.cmake Normal file
View file

@ -0,0 +1,84 @@
set(OPENOCD "" CACHE STRING "path to openocd (default: search for it)")
set(OPENOCD_CFG "" CACHE STRING "path to openocd configuration (default: generate automatically)")
set(OPENOCD_INTERFACE "" CACHE STRING "openocd interface name (default: automatic depending on target)")
if (OPENOCD)
set(OPENOCD_PATH ${OPENOCD})
else()
find_program(OPENOCD_FOUND_PATH NAMES openocd openocd.exe)
if (NOT OPENOCD_FOUND_PATH)
message(STATUS "Could not find openocd, debugging won't be available")
else()
set(OPENOCD_PATH ${OPENOCD_FOUND_PATH})
endif()
endif()
if(OPENOCD_PATH)
# Retrieve version number as a sanity check
execute_process(COMMAND ${OPENOCD_PATH} -v
OUTPUT_QUIET
ERROR_VARIABLE OPENOCD_HELP
RESULT_VARIABLE OPENOCD_RESULT)
string(REPLACE "\n" ";" OPENOCD_HELP_LINES ${OPENOCD_HELP})
list(GET OPENOCD_HELP_LINES 0 OPENOCD_FIRST_HELP_LINE)
string(REPLACE "\r" "" OPENOCD_HELP_LINE ${OPENOCD_FIRST_HELP_LINE})
if (NOT OPENOCD_RESULT EQUAL 0)
# User provided an incorrect path
message(FATAL_ERROR "error executing ${OPENOCD_PATH} (${OPENOCD_RESULT})")
endif()
message(STATUS "using openocd: ${OPENOCD_HELP_LINE}")
add_custom_target(openocd ${OPENOCD_PATH} -f ${OPENOCD_CFG}
COMMENT "Run openocd using OPENOCD_CFG=(${OPENOCD_CFG}) as configuration"
USES_TERMINAL
)
endif()
function(setup_openocd target_name)
if(OPENOCD_INTERFACE)
set(openocd_interface ${OPENOCD_INTERFACE})
else()
get_property(openocd_interface TARGET ${target_name} PROPERTY OPENOCD_DEFAULT_INTERFACE)
endif()
get_property(openocd_target TARGET ${target_name} PROPERTY OPENOCD_TARGET)
if(OPENOCD_CFG OR (openocd_target AND openocd_interface))
set(openocd_run_target "openocd_${target_name}")
if (OPENOCD_CFG AND NOT OPENOCD_CFG STREQUAL "")
get_filename_component(openocd_cfg_path ${OPENOCD_CFG}
ABSOLUTE
BASE_DIR ${CMAKE_BINARY_DIR})
else()
set(openocd_cfg_path ${CMAKE_BINARY_DIR}/openocd/${target_name}.cfg)
add_custom_command(
OUTPUT ${openocd_cfg_path}
COMMENT "Generating openocd configuration for ${openocd_target} via ${openocd_interface}"
COMMAND ${CMAKE_COMMAND} -P ${MAIN_DIR}/cmake/openocd_cfg.cmake
${openocd_target} ${openocd_interface} ${openocd_cfg_path}
)
endif()
# Target for openocd configuration
set(openocd_cfg_target "openocd_cfg_${target_name}")
add_custom_target(${openocd_cfg_target} DEPENDS ${openocd_cfg_path})
exclude_from_all(${openocd_cfg_target})
# Target for running openocd
add_custom_target(${openocd_run_target} ${OPENOCD_PATH} -f ${openocd_cfg_path}
COMMENT "Running openocd for target ${target_name} via ${openocd_interface}"
DEPENDS ${openocd_cfg_path}
USES_TERMINAL
)
exclude_from_all(${openocd_run_target})
# Target for flashing via openocd
set(openocd_flash_target "openocd_flash_${target_name}")
add_custom_target(${openocd_flash_target} ${CMAKE_COMMAND} -E env
OPENOCD_CMD=${OPENOCD_PATH}
${MAIN_UTILS_DIR}/openocd_flash.py -f
${openocd_cfg_path} $<TARGET_FILE:${target_name}>
COMMENT "Flashing ${target_name} with openocd"
DEPENDS ${openocd_cfg_path} ${target_name}
)
exclude_from_all(${openocd_flash_target})
endif()
endfunction()

20
cmake/openocd_cfg.cmake Normal file
View file

@ -0,0 +1,20 @@
# This is called from the targets that build the
# openocd.cfg file
if(NOT CMAKE_ARGC EQUAL 6)
message(FATAL_ERROR "usage: cmake -P openocd_cfg.cmake <target> <interface> <output>")
endif()
set(OPENOCD_TARGET ${CMAKE_ARGV3})
set(OPENOCD_INTERFACE ${CMAKE_ARGV4})
set(OUTPUT ${CMAKE_ARGV5})
set(opencd_cfg)
list(APPEND openocd_cfg "source [find interface/${OPENOCD_INTERFACE}.cfg]")
list(APPEND openocd_cfg "source [find target/${OPENOCD_TARGET}.cfg]")
list(APPEND openocd_cfg "init")
list(APPEND openocd_cfg "arm semihosting enable")
list(APPEND openocd_cfg "reset halt")
list(JOIN openocd_cfg "\n" contents)
set(contents "${contents}\n")
file(WRITE ${OUTPUT} ${contents})

View file

@ -158,10 +158,11 @@ function(target_stm32 name startup ldscript)
cmake_parse_arguments(
PARSED_ARGS
"DISABLE_MSC" # Boolean arguments
"HSE_MHZ" # Single value arguments
"HSE_MHZ;OPENOCD_TARGET" # Single value arguments
"DEFINITIONS" # Multi-value arguments
${ARGN} # Start parsing after the known arguments
)
if (PARSED_ARGS_HSE_MHZ)
set(hse_mhz ${PARSED_ARGS_HSE_MHZ})
else()
@ -210,6 +211,8 @@ function(target_stm32 name startup ldscript)
endif()
endif()
endif()
set_property(TARGET ${name} PROPERTY OPENOCD_TARGET ${PARSED_ARGS_OPENOCD_TARGET})
set_property(TARGET ${name} PROPERTY OPENOCD_DEFAULT_INTERFACE stlink)
# Generate .hex
# XXX: Generator expressions are not supported for add_custom_command()
# OUTPUT nor BYPRODUCTS, so we can't rely of them. Instead, build the filename

View file

@ -60,7 +60,7 @@ set(STM32F303_DEFINITIONS
function(target_stm32f3xx name startup ldscript)
# F3 targets don't support MSC
target_stm32(${name} ${startup} ${ldscript} DISABLE_MSC ${ARGN})
target_stm32(${name} ${startup} ${ldscript} DISABLE_MSC OPENOCD_TARGET stm32f3x ${ARGN})
# F3 targets don't use -O2 to save size
if (IS_RELEASE_BUILD)
target_compile_options(${name} PRIVATE "-Os")

View file

@ -76,7 +76,7 @@ set(STM32F4_DEFINITIONS
)
function(target_stm32f4xx name startup ldscript)
target_stm32(${name} ${startup} ${ldscript} ${ARGN})
target_stm32(${name} ${startup} ${ldscript} OPENOCD_TARGET stm32f4x ${ARGN})
if (IS_RELEASE_BUILD)
target_compile_options(${name} PRIVATE "-O2")
target_link_options(${name} PRIVATE "-O2")

View file

@ -83,7 +83,7 @@ set(STM32F7_DEFINITIONS
)
function(target_stm32f7xx name startup ldscript)
target_stm32(${name} ${startup} ${ldscript} ${ARGN})
target_stm32(${name} ${startup} ${ldscript} OPENOCD_TARGET stm32f7x ${ARGN})
if (IS_RELEASE_BUILD)
target_compile_options(${name} PRIVATE "-O2")
target_link_options(${name} PRIVATE "-O2")

86
src/utils/openocd_flash.py Executable file
View file

@ -0,0 +1,86 @@
#!/usr/bin/env python
from __future__ import print_function
import os
import socket
import subprocess
import sys
def openocd_telnet_await_prompt(s):
prev = None
while True:
b = s.recv(1)
if b == '':
# Closed
return False
if prev == '>' and b == ' ':
# Prompt for next command
return True
prev = b
print(b, end='')
def openocd_telnet_command(s, cmd):
s.send(cmd + '\n')
openocd_telnet_await_prompt(s)
def openocd_flash_telnet(port, filename):
try:
s = socket.create_connection(('localhost', port))
except socket.error:
return False
openocd_telnet_await_prompt(s)
openocd_telnet_command(s, 'halt')
openocd_telnet_command(s, 'program {} verify reset\n'.format(filename))
openocd_telnet_command(s, 'exit')
s.close()
return True
def openocd_flash_cmd(openocd, args, filename):
cmd = [openocd]
cmd.extend(args)
cmd.extend(('-c', 'program {} verify reset exit'.format(filename)))
status = subprocess.call(cmd)
return status == 0
def usage():
print('Usage: {} <openocd_args> <elf_file>'.format(sys.argv[0]))
print('Environment variables: OPENOCD_CMD = path to openocd')
sys.exit(1)
def main():
import sys
# Default openocd telnet port
# TODO: Parse arguments and check if we
# should use a non-default port
port = 4444
openocd = os.environ.get('OPENOCD_CMD') or 'openocd'
openocd_args = []
flag = None
elf = None
for arg in sys.argv[1:]:
if flag:
openocd_args.append(arg)
flag = None
else:
if arg.startswith('-'):
openocd_args.append(arg)
flag = arg
elif elf is None:
elf = arg
else:
usage()
if len(openocd_args) == 0 or elf is None:
usage()
if not openocd_flash_telnet(port, elf):
if not openocd_flash_cmd(openocd, openocd_args, elf):
print('could not flash')
sys.exit(1)
if __name__ == '__main__':
main()