Skip to content

Instantly share code, notes, and snippets.

@smittytone
Created September 2, 2021 19:03
Show Gist options
  • Save smittytone/02d2d644a855644c9f00f29fd3c91a50 to your computer and use it in GitHub Desktop.
Save smittytone/02d2d644a855644c9f00f29fd3c91a50 to your computer and use it in GitHub Desktop.
Makepico, a Raspberry Pi Pico project-creation script
#!/bin/zsh
#
# makepico.zsh
#
# Create a baseline Raspberry Pi Pico C-language project
#
# @author Tony Smith
# @copyright 2021, Tony Smith
# @version 2.1.0
# @license MIT
#
# FROM 1.0.2
# Check that PICO_SDK_PATH is defined
# and the SDK is installed
if [[ -z "${PICO_SDK_PATH}" ]]; then
echo "Error — environment variable PICO_SDK_PATH not set"
exit 1
else
ls "${PICO_SDK_PATH}" >/dev/null 2>&1
if [[ $? -ne 0 ]]; then
echo "Error — Pico SDK not installed at ${PICO_SDK_PATH}"
exit 1
fi
fi
show_help() {
echo -e "\nmakepico 2.1.0\n\nInitialise a Pi Pico Project\n"
echo -e "Usage:\n makepico [path/name] [-c] [-d] [-n your name] [-h]\n"
echo "Options:"
echo " -c / --cpp Set up the project for C++. Default: false"
echo " -d / --debug Set up the project for SWD. Default: false"
echo " -n / --name Your name for the comments. Default: <YOU>"
echo " -h / --help This help screen"
echo
}
make_project() {
# Create and copy the project files
# Args: 1 -- the project path
# Check the path and, if necessary
# create intermediate directories
# NOTE The check will exit on error
check_path "${1}"
# Get project name in lower case
project_name=${1:t:l}
project_path=${1}
# Create initial C files
make_source_files "${1}"
# Copy over the .make file from the SDK
file="pico_sdk_import.cmake"
if cp "${PICO_SDK_PATH}/external/${file}" "${project_path}/${file}"; then
# NOP
else
echo "Error - could not copy the ${file} file"
exit 1
fi
# Make the CMakeLists.txt file for this project
make_cmake_file "${1}"
# FROM 1.0.2
make_vscode "${1}"
# And done...
project_name=${1:t}
echo "Project ${project_name} created at ${project_path}"
}
make_source_files() {
# Output lines to the file
# Args: 1 -- project path
# FROM 1.3.0
file_ext="c"
project_type="C"
if [[ $do_cpp -eq 1 ]]; then
file_ext="cpp"
project_type="C++"
fi
echo "Creating ${project_type} project files..."
project_name=${1:t}
source_file=${1:t:l}
write_header "$project_name" "${1}/main.${file_ext}"
write_header "$project_name" "${1}/main.h"
# FROM 2.0.0
# Write main() function
{
echo "#include \"main.h\""
echo
echo 'int main() {'
echo ' // Use for debugging'
echo ' stdio_init_all();'
echo
echo ' return 0;'
echo '}'
} >> "${1}/main.${file_ext}"
# FROM 1.3.0
# Break into sections for C/C++ usage
# Add header guard
{
echo "#ifndef _${project_name:u}_MAIN_HEADER_"
echo "#define _${project_name:u}_MAIN_HEADER_"
echo
} >> "${1}/main.h"
# C++ standard libraries or C standard libraries
if [[ $do_cpp -eq 1 ]]; then
{
echo '#include <iostream>'
echo '#include <string>'
echo '#include <vector>'
echo '#include <cstdlib>'
echo '#include <cstdint>'
echo '#include <cstring>'
echo
} >> "${1}/main.h"
else
{
echo '#include <stdbool.h>'
echo '#include <stdio.h>'
echo '#include <stdlib.h>'
echo '#include <string.h>'
echo '#include <time.h>'
} >> "${1}/main.h"
fi
# Standard Pico libraries
{
echo '#include "pico/stdlib.h"'
echo '#include "pico/binary_info.h"'
echo '#include "hardware/gpio.h"'
echo '#include "hardware/i2c.h"'
echo '#include "hardware/adc.h"'
echo '#include "hardware/uart.h"'
echo
} >> "${1}/main.h"
if [[ $do_cpp -eq 1 ]]; then
{
echo '#ifdef __cplusplus'
echo 'extern "C" {'
echo '#endif'
echo
echo '/*'
echo ' * Usual header code here'
echo ' */'
echo
echo '#ifdef __cplusplus'
echo '}'
echo '#endif'
echo
} >> "${1}/main.h"
fi
{
echo "#endif // _${project_name:u}_MAIN_HEADER_"
} >> "${1}/main.h"
}
write_header() {
# Write header info
{
echo "/*"
echo " * ${1} for Raspberry Pi Pico"
echo " *"
echo " * @version 1.0.0"
echo " * @author ${users_name}"
echo " * @copyright $(date +'%Y')"
echo " * @licence MIT"
echo " *"
echo " */"
} > "$2"
}
make_cmake_file() {
# Output lines to the file, interpolating the project name
# Args: 1 -- project path
echo "Creating CMakeLists.txt..."
project_name=${1:t}
source_file=${project_name:l}
# FROM 1.3.0
file_ext="c"
if [[ $do_cpp -eq 1 ]]; then
file_ext="cpp"
fi
{
echo 'cmake_minimum_required(VERSION 3.14)'
echo 'include(pico_sdk_import.cmake)'
echo "project(${project_name} VERSION 1.0.0)"
echo "add_executable(${project_name}"
echo " main.${file_ext})"
echo
echo 'pico_sdk_init()'
echo
echo "pico_enable_stdio_usb(${project_name} 1)"
echo "pico_enable_stdio_uart(${project_name} 1)"
echo "pico_add_extra_outputs(${project_name})"
echo
echo "target_link_libraries(${project_name}"
echo ' pico_stdlib'
echo ' hardware_gpio'
echo ' hardware_i2c'
echo ' hardware_adc'
echo ' hardware_uart)'
} >> "${1}/CMakeLists.txt"
}
make_vscode() {
# FROM 1.0.2
# Make the vscode settings
echo "Configuring VSCode..."
mkdir "${1}/.vscode"
{
echo '{'
echo ' "cmake.environment": {'
echo " \"PICO_SDK_PATH\": \"${PICO_SDK_PATH}\""
echo ' },'
echo ' "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools"'
echo '}'
} >> "${1}/.vscode/settings.json"
# Debug flag set? write out an SWD launch config
if [[ $do_swd -eq 1 ]]; then
{
echo '{'
echo ' "version": "0.2.0",'
echo ' "configurations": ['
echo ' { "name": "Pico Debug",'
echo ' "device": "RP2040",'
echo ' "gdbPath": "arm-none-eabi-gdb",'
echo ' "cwd": "${workspaceRoot}",'
echo ' "executable": "${command:cmake.launchTargetPath}",'
echo ' "request": "launch",'
echo ' "type": "cortex-debug",'
echo ' "servertype": "openocd",'
echo ' "configFiles": ['
echo ' "/interface/picoprobe.cfg",'
echo ' "/target/rp2040.cfg"'
echo ' ],'
echo ' "svdFile": "${env:PICO_SDK_PATH}/src/rp2040/hardware_regs/rp2040.svd",'
echo ' "runToMain": true,'
echo ' "postRestartCommands": ['
echo ' "break main",'
echo ' "continue"'
echo ' ]'
echo ' }'
echo ' ]'
echo '}'
} >> "${1}/.vscode/launch.json"
fi
}
check_path() {
# Check the path is valid
# Args: 1 -- the project path as specified by the user
project_name={$1:t}
if [[ ! -d "${1}" ]]; then
if mkdir -p "${1}" >> /dev/null; then
echo "Creating project directory..."
else
echo "Error — could not create path for project ${project_name}"
exit 1
fi
fi
}
# Runtime start
# Get the arguments, which should be project path(s)
projects=()
do_swd=0
do_cpp=0
users_name="<YOU>"
next_is_arg=0
last_arg=""
for arg in "$@"; do
upper_arg=${arg:u}
if [[ $next_is_arg -gt 0 ]]; then
# The argument should be a value (previous argument was an option)
if [[ ${arg:0:1} = "-" ]]; then
# Next value is an option: ie. missing value
echo "Error -- Missing value for ${last_arg}"
exit 1
fi
# Set the appropriate internal value
case "$next_is_arg" in
1) users_name=$arg ;;
*) echo "Error -- Unknown argument" exit 1 ;;
esac
# Reset
next_is_arg=0
else
if [[ "$upper_arg" == "-N" || "$upper_arg" == "--NAME" ]]; then
next_is_arg=1
elif [[ "$upper_arg" == "-C" || "$upper_arg" == "--CPP" ]]; then
do_cpp=1
elif [[ "$upper_arg" == "-D" || "$upper_arg" == "--DEBUG" ]]; then
do_swd=1
elif [[ "$upper_arg" == "-H" || "$upper_arg" == "--HELP" ]]; then
show_help
exit 0
else
projects+=("$arg")
fi
last_arg=$uarg
fi
done
if [[ ${#projects[@]} -gt 0 ]]; then
for project in "${projects[@]}"; do
make_project "$project"
done
else
show_help
exit 0
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment