|
|
|
#!/usr/bin/env bash
|
|
|
|
# kaleidoscope-builder - Kaleidoscope helper tool
|
|
|
|
# Copyright (C) 2017-2018 Keyboard.io, Inc.
|
|
|
|
#
|
|
|
|
# This program is free software: you can redistribute it and/or modify it under
|
|
|
|
# the terms of the GNU General Public License as published by the Free Software
|
|
|
|
# Foundation, version 3.
|
|
|
|
#
|
|
|
|
# This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
|
|
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU General Public License along with
|
|
|
|
# this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
set -e
|
|
|
|
|
|
|
|
######
|
|
|
|
###### Build and output configuration
|
|
|
|
######
|
|
|
|
|
|
|
|
absolute_filename() {
|
|
|
|
echo "$(cd "$(dirname "$1")" && pwd)/$(basename "$1")"
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
build_version () {
|
|
|
|
GIT_VERSION="$(cd "${SKETCH_DIR}"; if [ -d .git ]; then echo -n '-g' && git describe --abbrev=4 --dirty --always; fi)"
|
|
|
|
LIB_PROPERTIES_PATH="${LIB_PROPERTIES_PATH:-"../.."}"
|
|
|
|
LIB_VERSION="$(cd "${SKETCH_DIR}"; (grep version= "${LIB_PROPERTIES_PATH}/library.properties" 2>/dev/null || echo version=0.0.0) | cut -d= -f2)${GIT_VERSION}"
|
|
|
|
}
|
|
|
|
|
|
|
|
build_paths() {
|
|
|
|
# We need that echo because we\re piping to cksum
|
|
|
|
# shellcheck disable=SC2005
|
|
|
|
SKETCH_IDENTIFIER="$(echo "$(absolute_filename "${SKETCH_DIR}/${SKETCH}.ino")" | cksum | cut -d ' ' -f 1)-${SKETCH}.ino"
|
|
|
|
KALEIDOSCOPE_TEMP_PATH="${KALEIDOSCOPE_TEMP_PATH:-${TMPDIR:-/tmp}/kaleidoscope-${USER}}"
|
|
|
|
|
|
|
|
|
|
|
|
KALEIDOSCOPE_BUILD_PATH="${KALEIDOSCOPE_BUILD_PATH:-${KALEIDOSCOPE_TEMP_PATH}/sketch}"
|
|
|
|
KALEIDOSCOPE_OUTPUT_PATH="${KALEIDOSCOPE_OUTPUT_PATH:-${KALEIDOSCOPE_TEMP_PATH}/sketch}"
|
|
|
|
|
|
|
|
SKETCH_OUTPUT_DIR="${SKETCH_OUTPUT_DIR:-${SKETCH_IDENTIFIER}/output}"
|
|
|
|
SKETCH_BUILD_DIR="${SKETCH_BUILD_DIR:-${SKETCH_IDENTIFIER}/build}"
|
|
|
|
|
|
|
|
BUILD_PATH="${BUILD_PATH:-${KALEIDOSCOPE_BUILD_PATH}/${SKETCH_BUILD_DIR}}"
|
|
|
|
OUTPUT_PATH="${OUTPUT_PATH:-${KALEIDOSCOPE_OUTPUT_PATH}/${SKETCH_OUTPUT_DIR}}"
|
|
|
|
|
|
|
|
CCACHE_WRAPPER_PATH="${CCACHE_WRAPPER_PATH:-${KALEIDOSCOPE_TEMP_PATH}/ccache/bin}"
|
|
|
|
CORE_CACHE_PATH="${CORE_CACHE_PATH:-${KALEIDOSCOPE_TEMP_PATH}/arduino-cores}"
|
|
|
|
|
|
|
|
mkdir -p "$CORE_CACHE_PATH"
|
|
|
|
mkdir -p "$BUILD_PATH"
|
|
|
|
}
|
|
|
|
|
|
|
|
build_filenames () {
|
|
|
|
OUTPUT_FILE_PREFIX="${OUTPUT_FILE_PREFIX:-${SKETCH}-${LIB_VERSION}}"
|
|
|
|
HEX_FILE_PATH="${HEX_FILE_PATH:-${OUTPUT_PATH}/${OUTPUT_FILE_PREFIX}.hex}"
|
|
|
|
HEX_FILE_WITH_BOOTLOADER_PATH="${HEX_FILE_WITH_BOOTLOADER_PATH:-${OUTPUT_PATH}/${OUTPUT_FILE_PREFIX}-with-bootloader.hex}"
|
|
|
|
ELF_FILE_PATH="${ELF_FILE_PATH:-${OUTPUT_PATH}/${OUTPUT_FILE_PREFIX}.elf}"
|
|
|
|
LIB_FILE_PATH="${LIB_FILE_PATH:-${OUTPUT_PATH}/${OUTPUT_FILE_PREFIX}.a}"
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
enable_ccache () {
|
|
|
|
if [ -z "${CCACHE_NOT_SUPPORTED}" ] && [ "$(command -v ccache)" ]; then
|
|
|
|
if ! [ -d "$CCACHE_WRAPPER_PATH" ]; then
|
|
|
|
mkdir -p "$CCACHE_WRAPPER_PATH"
|
|
|
|
|
|
|
|
if ! [ -h "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}${C_COMPILER_BASENAME}" ]; then
|
|
|
|
ln -s "$(command -v ccache)" "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}${C_COMPILER_BASENAME}"
|
|
|
|
fi
|
|
|
|
|
|
|
|
if ! [ -h "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}${CXX_COMPILER_BASENAME}" ]; then
|
|
|
|
ln -s "$(command -v ccache)" "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}${CXX_COMPILER_BASENAME}"
|
|
|
|
fi
|
|
|
|
|
|
|
|
if ! [ -h "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}nm" ]; then
|
|
|
|
ln -s "${AVR_NM}" "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}nm"
|
|
|
|
fi
|
|
|
|
|
|
|
|
if ! [ -h "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}objcopy" ]; then
|
|
|
|
ln -s "${AVR_OBJCOPY}" "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}objcopy"
|
|
|
|
fi
|
|
|
|
|
|
|
|
if ! [ -h "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}ar" ]; then
|
|
|
|
ln -s "${AVR_AR}" "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}ar"
|
|
|
|
fi
|
|
|
|
|
|
|
|
if ! [ -h "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}size" ]; then
|
|
|
|
ln -s "${AVR_SIZE}" "${CCACHE_WRAPPER_PATH}/${COMPILER_PREFIX}size"
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
|
|
|
export CCACHE_PATH=${COMPILER_PATH}/
|
|
|
|
CCACHE_ENABLE="-prefs compiler.path=${CCACHE_WRAPPER_PATH}/"
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
firmware_size () {
|
|
|
|
if [ "${ARCH}" = "virtual" ]; then
|
|
|
|
echo "[Size not computed for virtual build]"
|
|
|
|
return
|
|
|
|
fi
|
|
|
|
|
|
|
|
## This is a terrible hack, please don't hurt me. - algernon
|
|
|
|
|
|
|
|
find_max_prog_size
|
Add rules and scripts for building on FreeBSD.
* Uses usbconfig to determine the Model 01's USB modem port.
* Works around incompatibe avrsize flags.
You need to be able to run usbconfig to flash the firmware from the
buildtools. This can be accomplished with appropriate groups and devfs
rules.
Requires gmake, perl, avrdude, and (probably) arduino18 from ports.
The version of avrdude in ports uses an avr-size command that doesn't
understand the -C or --mcu flags. From what I can tell, these flags
are uneccessary, as the size computed with them is the same as what
you get from adding up the appropriate segments from the standard
output of avr-size without any flags. However, since the size is only
informative, I've opted to simply check to see if the command
succeeded, and if not, output a string saying it could not be.
It would probably be better to:
* Determine appropriate flags based on build tools, or,
* Just not use the flags at all, and grab the .text, etc., segment
sizes from the standard output and add them up via `dc` for
display.
I've been using this toolchain to build successfully on FreeBSD 12 for
the Model 01 without issue. It should work with earlier versions of
FreeBSD as well.
Signed-off-by: Brian Cully <bjc@kublai.com>
6 years ago
|
|
|
set +e
|
|
|
|
raw_output=$("$@" 2> /dev/null)
|
|
|
|
rc=$?
|
|
|
|
set -e
|
|
|
|
|
Add rules and scripts for building on FreeBSD.
* Uses usbconfig to determine the Model 01's USB modem port.
* Works around incompatibe avrsize flags.
You need to be able to run usbconfig to flash the firmware from the
buildtools. This can be accomplished with appropriate groups and devfs
rules.
Requires gmake, perl, avrdude, and (probably) arduino18 from ports.
The version of avrdude in ports uses an avr-size command that doesn't
understand the -C or --mcu flags. From what I can tell, these flags
are uneccessary, as the size computed with them is the same as what
you get from adding up the appropriate segments from the standard
output of avr-size without any flags. However, since the size is only
informative, I've opted to simply check to see if the command
succeeded, and if not, output a string saying it could not be.
It would probably be better to:
* Determine appropriate flags based on build tools, or,
* Just not use the flags at all, and grab the .text, etc., segment
sizes from the standard output and add them up via `dc` for
display.
I've been using this toolchain to build successfully on FreeBSD 12 for
the Model 01 without issue. It should work with earlier versions of
FreeBSD as well.
Signed-off-by: Brian Cully <bjc@kublai.com>
6 years ago
|
|
|
if [ $rc -eq 0 ]; then
|
|
|
|
output="$(echo "${raw_output}"| grep "\\(Program\\|Data\\):" | sed -e 's,^, - ,' && echo)"
|
|
|
|
|
Add rules and scripts for building on FreeBSD.
* Uses usbconfig to determine the Model 01's USB modem port.
* Works around incompatibe avrsize flags.
You need to be able to run usbconfig to flash the firmware from the
buildtools. This can be accomplished with appropriate groups and devfs
rules.
Requires gmake, perl, avrdude, and (probably) arduino18 from ports.
The version of avrdude in ports uses an avr-size command that doesn't
understand the -C or --mcu flags. From what I can tell, these flags
are uneccessary, as the size computed with them is the same as what
you get from adding up the appropriate segments from the standard
output of avr-size without any flags. However, since the size is only
informative, I've opted to simply check to see if the command
succeeded, and if not, output a string saying it could not be.
It would probably be better to:
* Determine appropriate flags based on build tools, or,
* Just not use the flags at all, and grab the .text, etc., segment
sizes from the standard output and add them up via `dc` for
display.
I've been using this toolchain to build successfully on FreeBSD 12 for
the Model 01 without issue. It should work with earlier versions of
FreeBSD as well.
Signed-off-by: Brian Cully <bjc@kublai.com>
6 years ago
|
|
|
PROGSIZE="$(echo "${output}" | grep "Program:" | cut -d: -f2 | awk '{print $1}')"
|
|
|
|
|
Add rules and scripts for building on FreeBSD.
* Uses usbconfig to determine the Model 01's USB modem port.
* Works around incompatibe avrsize flags.
You need to be able to run usbconfig to flash the firmware from the
buildtools. This can be accomplished with appropriate groups and devfs
rules.
Requires gmake, perl, avrdude, and (probably) arduino18 from ports.
The version of avrdude in ports uses an avr-size command that doesn't
understand the -C or --mcu flags. From what I can tell, these flags
are uneccessary, as the size computed with them is the same as what
you get from adding up the appropriate segments from the standard
output of avr-size without any flags. However, since the size is only
informative, I've opted to simply check to see if the command
succeeded, and if not, output a string saying it could not be.
It would probably be better to:
* Determine appropriate flags based on build tools, or,
* Just not use the flags at all, and grab the .text, etc., segment
sizes from the standard output and add them up via `dc` for
display.
I've been using this toolchain to build successfully on FreeBSD 12 for
the Model 01 without issue. It should work with earlier versions of
FreeBSD as well.
Signed-off-by: Brian Cully <bjc@kublai.com>
6 years ago
|
|
|
PERCENT="$(echo "${PROGSIZE}" "${MAX_PROG_SIZE}" | awk "{ printf \"%02.01f\", \$1 / \$2 * 100 }")"
|
|
|
|
|
|
|
|
# we want the sed there, doing with shell builtins would be worse.
|
|
|
|
# shellcheck disable=SC2001 disable=SC1117
|
|
|
|
echo "${output}" | sed -e "s/\(Program:.*\)(\([0-9\.]*%\) Full)/\1(${PERCENT}% Full)/"
|
|
|
|
else
|
|
|
|
echo "Unable to determine image size."
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
find_sketch () {
|
|
|
|
SKETCH="${SKETCH:-${DEFAULT_SKETCH}}"
|
|
|
|
LIBRARY="${LIBRARY:-${SKETCH}}"
|
|
|
|
if [ -z "${SKETCH}" ] || [ -z "${LIBRARY}" ] || [ -z "${ROOT}" ] || [ -z "${SOURCEDIR}" ]; then
|
|
|
|
echo "SKETCH, LIBRARY, SOURCEDIR, and ROOT need to be set before including this file!" >&2
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
SKETCH_DIR="$SKETCH"
|
|
|
|
SKETCH_FILE=$(basename "$SKETCH")
|
|
|
|
|
|
|
|
for path in "${SKETCH_DIR}" \
|
|
|
|
"examples/${LIBRARY}" \
|
|
|
|
"src" \
|
|
|
|
"."; do
|
|
|
|
if [ -f "${path}/${SKETCH_FILE}.ino" ]; then
|
|
|
|
SKETCH_DIR="${path}"
|
|
|
|
SKETCH="${SKETCH_FILE}"
|
|
|
|
return
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
echo "I couldn't find your sketch (.ino file)" >&2
|
|
|
|
exit 1
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
prompt_before_flashing () {
|
|
|
|
flashing_instructions=$(get_arduino_pref 'build.flashing_instructions')
|
|
|
|
|
|
|
|
if [ "x${flashing_instructions}x" = "xx" ]; then
|
|
|
|
flashing_instructions="If your keyboard needs you to do something to put it in flashing mode, do that now."
|
|
|
|
fi
|
|
|
|
|
|
|
|
printf '%b\n\n' "${flashing_instructions}"
|
|
|
|
echo ""
|
|
|
|
echo "When you're ready to proceed, press 'Enter'."
|
|
|
|
|
|
|
|
# We do not want to permit line continuations here. We just want a newline.
|
|
|
|
# shellcheck disable=SC2162
|
|
|
|
read
|
|
|
|
}
|
|
|
|
|
|
|
|
flash () {
|
|
|
|
maybe_build "$@"
|
|
|
|
|
|
|
|
# Check to see if we can see a keyboard bootloader port.
|
|
|
|
# If we -can-, then we should skip over the "reset to bootloader" thing
|
|
|
|
find_bootloader_ports
|
|
|
|
if [ -z "${DEVICE_PORT_BOOTLOADER}" ]; then
|
|
|
|
prompt_before_flashing
|
|
|
|
|
|
|
|
# This is defined in the (optional) user config.
|
|
|
|
# shellcheck disable=SC2154
|
|
|
|
${preFlash_HOOKS}
|
|
|
|
|
|
|
|
# If we're -not- doing a manual reset, then try to do it automatically
|
|
|
|
if [ -z "${MANUAL_RESET}" ]; then
|
|
|
|
reset_device
|
|
|
|
sleep 2
|
|
|
|
find_bootloader_ports
|
|
|
|
# Otherwise, poll for a bootloader port.
|
|
|
|
else
|
|
|
|
wait_for_bootloader_port
|
|
|
|
fi
|
|
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
check_bootloader_port_and_flash
|
|
|
|
|
|
|
|
# This is defined in the (optional) user config.
|
|
|
|
# shellcheck disable=SC2154
|
|
|
|
${postFlash_HOOKS}
|
|
|
|
}
|
|
|
|
|
|
|
|
wait_for_bootloader_port() {
|
|
|
|
declare -i tries
|
|
|
|
tries=15
|
|
|
|
|
|
|
|
while [ "$tries" -gt 0 ] && [ -z "${DEVICE_PORT_BOOTLOADER}" ]; do
|
|
|
|
sleep 1
|
|
|
|
printf "."
|
|
|
|
find_bootloader_ports
|
|
|
|
# the variable annotations do appear to be necessary
|
|
|
|
# shellcheck disable=SC2004
|
|
|
|
tries=$(($tries-1))
|
|
|
|
done
|
|
|
|
|
|
|
|
if [ "$tries" -gt 0 ]; then
|
|
|
|
echo "Found."
|
|
|
|
else
|
|
|
|
echo "Timed out."
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
check_bootloader_port () {
|
|
|
|
if [ -z "${DEVICE_PORT_BOOTLOADER}" ]; then
|
|
|
|
echo "Unable to detect a keyboard in bootloader mode."
|
|
|
|
echo "You may need to hold a key or hit a reset button."
|
|
|
|
echo "Please check your keyboard's documentation"
|
|
|
|
return 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
check_bootloader_port_and_flash () {
|
|
|
|
|
|
|
|
if ! check_bootloader_port; then
|
|
|
|
return 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
echo "Flashing your keyboard:"
|
|
|
|
|
|
|
|
# If the flash fails, try a second time
|
|
|
|
if ! flash_over_usb; then
|
|
|
|
sleep 2
|
|
|
|
if ! flash_over_usb; then
|
|
|
|
if [ "${ARDUINO_VERBOSE}" != "-verbose" ]; then
|
|
|
|
echo "Something went wrong."
|
|
|
|
echo "You might want to try flashing again with the VERBOSE environment variable set"
|
|
|
|
fi
|
|
|
|
|
|
|
|
return 1
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
echo "Keyboard flashed successfully!"
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
flash_over_usb () {
|
|
|
|
if [ "${ARDUINO_VERBOSE}" != "-verbose" ]; then
|
|
|
|
${AVRDUDE} \
|
|
|
|
-C "${AVRDUDE_CONF}" \
|
|
|
|
-p"${MCU}" \
|
|
|
|
-cavr109 \
|
|
|
|
-D \
|
|
|
|
-P "${DEVICE_PORT_BOOTLOADER}" \
|
|
|
|
-b57600 \
|
|
|
|
"-Uflash:w:${HEX_FILE_PATH}:i" \
|
|
|
|
2>&1 |grep -v ^avrdude | grep -v '^$' |grep -v '^ ' | grep -vi programmer
|
|
|
|
return "${PIPESTATUS[0]}"
|
|
|
|
else
|
|
|
|
${AVRDUDE} \
|
|
|
|
-C "${AVRDUDE_CONF}" \
|
|
|
|
-p"${MCU}" \
|
|
|
|
-cavr109 \
|
|
|
|
-D \
|
|
|
|
-P "${DEVICE_PORT_BOOTLOADER}" \
|
|
|
|
-b57600 \
|
|
|
|
"-Uflash:w:${HEX_FILE_PATH}:i"
|
|
|
|
return $?
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
flash_from_bootloader() {
|
|
|
|
maybe_build "$@"
|
|
|
|
prompt_before_flashing
|
|
|
|
find_bootloader_ports
|
|
|
|
check_bootloader_port_and_flash
|
|
|
|
}
|
|
|
|
|
|
|
|
program() {
|
|
|
|
maybe_build "$@"
|
|
|
|
prompt_before_flashing
|
|
|
|
flash_with_programmer
|
|
|
|
}
|
|
|
|
|
|
|
|
flash_with_programmer() {
|
|
|
|
${AVRDUDE} -v \
|
|
|
|
-C "${AVRDUDE_CONF}" \
|
|
|
|
-p"${MCU}" \
|
|
|
|
-cusbtiny \
|
|
|
|
-D \
|
|
|
|
-B 1 \
|
|
|
|
"-Uflash:w:${HEX_FILE_PATH}:i"
|
|
|
|
}
|
|
|
|
|
|
|
|
hex_with_bootloader () {
|
|
|
|
if [ ! -e "${HEX_FILE_PATH}" ]; then
|
|
|
|
compile
|
|
|
|
fi
|
|
|
|
|
|
|
|
find_bootloader_path
|
|
|
|
|
|
|
|
awk '/^:00000001FF/ == 0' "${HEX_FILE_PATH}" > "${HEX_FILE_WITH_BOOTLOADER_PATH}"
|
|
|
|
echo "Using ${BOOTLOADER_PATH}"
|
|
|
|
${MD5} "${BOOTLOADER_PATH}"
|
|
|
|
cat "${BOOTLOADER_PATH}" >> "${HEX_FILE_WITH_BOOTLOADER_PATH}"
|
|
|
|
ln -sf -- "${OUTPUT_FILE_PREFIX}-with-bootloader.hex" "${OUTPUT_PATH}/${SKETCH}-latest-with-bootloader.hex"
|
|
|
|
cat <<- EOF
|
|
|
|
|
|
|
|
Combined firmware and bootloader are now at ${HEX_FILE_WITH_BOOTLOADER_PATH}
|
|
|
|
Make sure you have the bootloader version you expect.
|
|
|
|
|
|
|
|
And TEST THIS ON REAL HARDWARE BEFORE YOU GIVE IT TO ANYONE
|
|
|
|
|
|
|
|
EOF
|
|
|
|
}
|
|
|
|
|
|
|
|
maybe_build () {
|
|
|
|
find_sketch
|
|
|
|
build_version
|
|
|
|
build_paths
|
|
|
|
build_filenames
|
|
|
|
# If the hex file is older than the sketch file, or the hex file does not exist
|
|
|
|
# then rebuild. This is not as correct as letting make check our dependencies
|
|
|
|
# But it's less broken for most user use cases
|
|
|
|
# TODO(anyone): Make this suck less
|
|
|
|
SKETCH_FILE_PATH=$(absolute_filename "${SKETCH_DIR}/${SKETCH}.ino")
|
|
|
|
if [ "${HEX_FILE_PATH}" -ot "${SKETCH_FILE_PATH}" ]; then
|
|
|
|
build "$@"
|
|
|
|
fi
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
build () {
|
|
|
|
compile "$@"
|
|
|
|
size "$@"
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
prepare_ccache () {
|
|
|
|
build_paths
|
|
|
|
enable_ccache
|
|
|
|
}
|
|
|
|
|
|
|
|
compile () {
|
|
|
|
find_sketch
|
|
|
|
build_version
|
|
|
|
build_paths
|
|
|
|
build_filenames
|
|
|
|
enable_ccache
|
|
|
|
|
|
|
|
install -d "${OUTPUT_PATH}"
|
|
|
|
|
|
|
|
echo "Building ${SKETCH_DIR}/${SKETCH}"
|
|
|
|
|
|
|
|
# This is defined in the (optional) user config.
|
|
|
|
# shellcheck disable=SC2154
|
|
|
|
${compile_HOOKS}
|
|
|
|
|
|
|
|
if [ -d "${ARDUINO_LOCAL_LIB_PATH}/libraries" ]; then
|
|
|
|
# shellcheck disable=SC2089
|
|
|
|
# We want literal backslashes here, not arrays.
|
|
|
|
local_LIBS="-libraries \"${ARDUINO_LOCAL_LIB_PATH}/libraries\""
|
|
|
|
fi
|
|
|
|
|
|
|
|
ARDUINO_PACKAGES=""
|
|
|
|
if [ -d "${ARDUINO_PACKAGE_PATH}" ]; then
|
|
|
|
# shellcheck disable=SC2089
|
|
|
|
# We want literal backslashes here, not arrays.
|
|
|
|
ARDUINO_PACKAGES="-hardware \"${ARDUINO_PACKAGE_PATH}\""
|
|
|
|
fi
|
|
|
|
|
|
|
|
SAVED_BOARD="${BOARD}"
|
|
|
|
SAVED_FQBN="${FQBN}"
|
|
|
|
if [ -e "${SKETCH_DIR}/.kaleidoscope-builder.conf" ]; then
|
|
|
|
# shellcheck disable=SC1090
|
|
|
|
BOARD="$(. "${SKETCH_DIR}"/.kaleidoscope-builder.conf && echo "${BOARD}")"
|
|
|
|
# shellcheck disable=SC1090
|
|
|
|
FQBN="$(. "${SKETCH_DIR}"/.kaleidoscope-builder.conf && echo "${FQBN}")"
|
|
|
|
if [ -n "${BOARD}" ]; then
|
|
|
|
if [ -z "${ARCH}" ]; then
|
|
|
|
FQBN="keyboardio:avr:${BOARD}"
|
|
|
|
else
|
|
|
|
FQBN="keyboardio:${ARCH}:${BOARD}"
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
|
|
|
_CMD_CXX="${CXX:-${COMPILER_PREFIX}${CXX_COMPILER_BASENAME}${COMPILER_SUFFIX}}"
|
|
|
|
_CMD_CC="${CC:-${COMPILER_PREFIX}${C_COMPILER_BASENAME}${COMPILER_SUFFIX}}"
|
|
|
|
_CMD_AR="${AR:-${COMPILER_PREFIX}${AR_BASENAME}${COMPILER_SUFFIX}}"
|
|
|
|
|
|
|
|
# SC2091: We do not care if quotes or backslashes are not respected.
|
|
|
|
# SC2086: We want word splitting.
|
|
|
|
# shellcheck disable=SC2086,SC2090
|
|
|
|
"${ARDUINO_BUILDER}" \
|
|
|
|
-compile \
|
|
|
|
${ARDUINO_PACKAGES} \
|
|
|
|
-hardware "${ARDUINO_PATH}/hardware" \
|
|
|
|
-hardware "${BOARD_HARDWARE_PATH}" \
|
|
|
|
${ARDUINO_TOOLS_FLAG:+"${ARDUINO_TOOLS_FLAG}"} ${ARDUINO_TOOLS_PARAM:+"${ARDUINO_TOOLS_PARAM}"} \
|
|
|
|
-tools "${ARDUINO_PATH}/tools-builder" \
|
|
|
|
-fqbn "${FQBN}" \
|
|
|
|
-libraries "." \
|
|
|
|
-libraries "${ROOT}" \
|
|
|
|
-libraries "${BOARD_HARDWARE_PATH}/.." \
|
|
|
|
${local_LIBS} \
|
|
|
|
${EXTRA_BUILDER_ARGS} \
|
|
|
|
-build-cache "${CORE_CACHE_PATH}" \
|
|
|
|
-build-path "${BUILD_PATH}" \
|
|
|
|
-ide-version "${ARDUINO_IDE_VERSION}" \
|
|
|
|
-built-in-libraries "${ARDUINO_PATH}/libraries" \
|
|
|
|
-prefs "compiler.cpp.extra_flags=${ARDUINO_CFLAGS} ${LOCAL_CFLAGS}" \
|
|
|
|
-prefs "compiler.path=${COMPILER_PATH}" \
|
|
|
|
-prefs "compiler.c.cmd=${_CMD_CC}" \
|
|
|
|
-prefs "compiler.cpp.cmd=${_CMD_CXX}" \
|
|
|
|
-prefs "compiler.ar.cmd=${_CMD_AR}" \
|
|
|
|
-prefs "compiler.c.elf.cmd=${_CMD_CXX}" \
|
|
|
|
$CCACHE_ENABLE \
|
|
|
|
-warnings all \
|
|
|
|
${ARDUINO_VERBOSE} \
|
|
|
|
${ARDUINO_AVR_GCC_PREFIX_PARAM} \
|
|
|
|
"${SKETCH_DIR}/${SKETCH}.ino"
|
|
|
|
|
|
|
|
if [ -z "${LIBONLY}" ]; then
|
|
|
|
cp "${BUILD_PATH}/${SKETCH}.ino.hex" "${HEX_FILE_PATH}"
|
|
|
|
cp "${BUILD_PATH}/${SKETCH}.ino.elf" "${ELF_FILE_PATH}"
|
|
|
|
ln -sf "${OUTPUT_FILE_PREFIX}.hex" "${OUTPUT_PATH}/${SKETCH}-latest.hex"
|
|
|
|
ln -sf "${OUTPUT_FILE_PREFIX}.elf" "${OUTPUT_PATH}/${SKETCH}-latest.elf"
|
|
|
|
else
|
|
|
|
cp "${BUILD_PATH}/${SKETCH}.ino.a" "${LIB_FILE_PATH}"
|
|
|
|
ln -sf "${OUTPUT_FILE_PREFIX}.a" "${OUTPUT_PATH}/${SKETCH}-latest.a"
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [ "${ARDUINO_VERBOSE}" = "-verbose" ]; then
|
|
|
|
echo "Build artifacts can be found in ${BUILD_PATH}";
|
|
|
|
fi
|
|
|
|
|
|
|
|
BOARD="${SAVED_BOARD}"
|
|
|
|
FQBN="${SAVED_FQBN}"
|
|
|
|
}
|
|
|
|
|
|
|
|
find_all_sketches () {
|
|
|
|
for plugin in ./*.ino \
|
|
|
|
$([ -d examples ] && find examples -name '*.ino') \
|
|
|
|
src/*.ino; do
|
|
|
|
if [ -d "$(dirname "${plugin}")" ] || [ -f "${plugin}" ]; then
|
|
|
|
p="$(basename "${plugin}" .ino)"
|
|
|
|
if [ "${p}" != '*' ]; then
|
|
|
|
case "${plugin}" in
|
|
|
|
examples/*/${p}/${p}.ino)
|
|
|
|
echo "${plugin}" | sed -e "s,examples/,," | sed -e "s,/${p}\\.ino,,"
|
|
|
|
;;
|
|
|
|
*)
|
|
|
|
echo "${p}"
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
done | sort
|
|
|
|
}
|
|
|
|
|
|
|
|
build_all () {
|
|
|
|
plugins="$(find_all_sketches)"
|
|
|
|
|
|
|
|
for plugin in ${plugins}; do
|
|
|
|
export SKETCH="${plugin}"
|
|
|
|
export LIBRARY="${plugin}"
|
|
|
|
$0 "${plugin}" build
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
compile_all () {
|
|
|
|
plugins="$(find_all_sketches)"
|
|
|
|
|
|
|
|
for plugin in ${plugins}; do
|
|
|
|
export SKETCH="${plugin}"
|
|
|
|
export LIBRARY="${plugin}"
|
|
|
|
$0 "${plugin}" compile
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
size () {
|
|
|
|
if [ ! -e "${HEX_FILE_PATH}" ]; then
|
|
|
|
compile
|
|
|
|
fi
|
|
|
|
|
|
|
|
echo "- Size: firmware/${LIBRARY}/${OUTPUT_FILE_PREFIX}.elf"
|
|
|
|
# shellcheck disable=SC2086
|
|
|
|
firmware_size "${AVR_SIZE}" ${AVR_SIZE_FLAGS} "${ELF_FILE_PATH}"
|
|
|
|
echo
|
|
|
|
}
|
|
|
|
|
|
|
|
size_map () {
|
|
|
|
if [ ! -e "${HEX_FILE_PATH}" ]; then
|
|
|
|
compile
|
|
|
|
fi
|
|
|
|
|
|
|
|
"${AVR_NM}" --size-sort -C -r -l -t decimal "${ELF_FILE_PATH}"
|
|
|
|
}
|
|
|
|
|
|
|
|
disassemble () {
|
|
|
|
|
|
|
|
if [ ! -e "${HEX_FILE_PATH}" ]; then
|
|
|
|
compile
|
|
|
|
fi
|
|
|
|
|
|
|
|
"${AVR_OBJDUMP}" -C -d "${ELF_FILE_PATH}"
|
|
|
|
}
|
|
|
|
|
|
|
|
decompile () {
|
|
|
|
disassemble
|
|
|
|
}
|
|
|
|
|
|
|
|
clean () {
|
|
|
|
rm -rf -- "${OUTPUT_PATH}"
|
|
|
|
kaleidoscope_dir="$(dirname "$0")/.."
|
|
|
|
(install -d "${kaleidoscope_dir}/testing/googletest/build" &&
|
|
|
|
cd "${kaleidoscope_dir}/testing/googletest/build" &&
|
|
|
|
cmake .. &&
|
|
|
|
make clean)
|
|
|
|
}
|
|
|
|
|
|
|
|
reset_device() {
|
|
|
|
find_device_port
|
|
|
|
check_device_port
|
|
|
|
reset_device_cmd
|
|
|
|
}
|
|
|
|
|
|
|
|
check_device_port () {
|
|
|
|
if [ -z "$DEVICE_PORT" ]; then
|
|
|
|
cat <<EOF >&2
|
|
|
|
|
|
|
|
I couldn't autodetect the keyboard's serial port.
|
|
|
|
|
|
|
|
If you see this message and your keyboard is connected to your computer,
|
|
|
|
it may mean that our serial port detection logic is buggy or incomplete.
|
|
|
|
In that case, please report this issue at:
|
|
|
|
https://github.com/keyboardio/Kaleidoscope
|
|
|
|
EOF
|
|
|
|
exit 1
|
|
|
|
elif echo "$DEVICE_PORT" | grep -q '[[:space:]]'; then
|
|
|
|
cat <<EOF >&2
|
|
|
|
Unexpected whitespace found in detected serial port:
|
|
|
|
|
|
|
|
$DEVICE_PORT
|
|
|
|
|
|
|
|
If you see this message, it means that our serial port
|
|
|
|
detection logic is buggy or incomplete.
|
|
|
|
|
|
|
|
Please report this issue at:
|
|
|
|
https://github.com/keyboardio/Kaleidoscope
|
|
|
|
EOF
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
if ! [ -w "$DEVICE_PORT" ]; then
|
|
|
|
cat <<EOF >&2
|
|
|
|
|
|
|
|
In order to update your keyboard's firmware you need to have permission
|
|
|
|
to write to its serial port $DEVICE_PORT.
|
|
|
|
|
|
|
|
It appears that you do not have this permission:
|
|
|
|
|
|
|
|
$(ls -l "$DEVICE_PORT")
|
|
|
|
|
|
|
|
This may be because you're not in the correct unix group:
|
|
|
|
|
|
|
|
$(stat -c %G "$DEVICE_PORT").
|
|
|
|
|
|
|
|
You are currently in the following groups:
|
|
|
|
|
|
|
|
$(id -Gn)
|
|
|
|
|
|
|
|
Please ensure you have followed the instructions on setting up your
|
|
|
|
account to be in the right group:
|
|
|
|
|
|
|
|
https://github.com/keyboardio/Kaleidoscope/wiki/Install-Arduino-support-on-Linux
|
|
|
|
|
|
|
|
EOF
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
build_gtest_gmock() {
|
|
|
|
kaleidoscope_dir="$(dirname "$0")/.."
|
|
|
|
(cd "${kaleidoscope_dir}/testing/googletest" && cmake . && make)
|
|
|
|
}
|
|
|
|
|
|
|
|
run_tests() {
|
|
|
|
(cd "${BOARD_HARDWARE_PATH}/keyboardio" && make prepare-virtual)
|
|
|
|
build_gtest_gmock
|
|
|
|
kaleidoscope_dir="$(dirname "$0")/.."
|
|
|
|
cd "${kaleidoscope_dir}/tests"
|
|
|
|
${MAKE:-make}
|
|
|
|
}
|
|
|
|
|
|
|
|
docker_tests() {
|
|
|
|
kaleidoscope_dir="$(dirname "$0")/.."
|
|
|
|
cd "${kaleidoscope_dir}"
|
|
|
|
bin/run-docker make -C tests all
|
|
|
|
}
|
|
|
|
|
|
|
|
usage () {
|
|
|
|
cat <<- EOF
|
|
|
|
Usage: $0 SKETCH commands...
|
|
|
|
|
|
|
|
Runs all of the commands in the context of the Sketch.
|
|
|
|
|
|
|
|
Available commands:
|
|
|
|
|
|
|
|
help
|
|
|
|
This help screen.
|
|
|
|
|
|
|
|
compile
|
|
|
|
Compiles the sketch.
|
|
|
|
|
|
|
|
size
|
|
|
|
Reports the size of the compiled sketch.
|
|
|
|
|
|
|
|
build
|
|
|
|
Runs compile and report-size.
|
|
|
|
|
|
|
|
clean
|
|
|
|
Cleans up the output directory.
|
|
|
|
|
|
|
|
size-map
|
|
|
|
Displays the size map for the sketch.
|
|
|
|
|
|
|
|
disassemble
|
|
|
|
Decompile the sketch.
|
|
|
|
|
|
|
|
reset-device
|
|
|
|
Reset the device.
|
|
|
|
|
|
|
|
flash
|
|
|
|
Flashes the firmware using avrdude.
|
|
|
|
|
|
|
|
build-all
|
|
|
|
Build all Sketches we can find.
|
|
|
|
|
|
|
|
run-tests | docker-tests
|
|
|
|
Builds and runs the test suite, on the host, and in docker, respectively.
|
|
|
|
EOF
|
|
|
|
}
|
|
|
|
|
|
|
|
help () {
|
|
|
|
usage
|
|
|
|
}
|
|
|
|
|
|
|
|
if [ $# -lt 1 ]; then
|
|
|
|
usage
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
## Parse the command-line
|
|
|
|
## - anything that has a =, is an env var
|
|
|
|
## - from the remaining stuff, the first one is the Library/Sketch
|
|
|
|
## - everything else are commands
|
|
|
|
##
|
|
|
|
## - if there is only one argument, that's a command
|
|
|
|
|
|
|
|
ROOT="$(cd "$(dirname "$0")"/..; pwd)"
|
|
|
|
export ROOT
|
|
|
|
# shellcheck disable=SC2155
|
|
|
|
export SOURCEDIR="$(pwd)"
|
|
|
|
|
|
|
|
if [ -e "${HOME}/.kaleidoscope-builder.conf" ]; then
|
|
|
|
# shellcheck disable=SC1090
|
|
|
|
. "${HOME}/.kaleidoscope-builder.conf"
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [ -e "${SOURCEDIR}/.kaleidoscope-builder.conf" ]; then
|
|
|
|
# shellcheck disable=SC1090
|
|
|
|
. "${SOURCEDIR}/.kaleidoscope-builder.conf"
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [ -e "${SOURCEDIR}/kaleidoscope-builder.conf" ]; then
|
|
|
|
# shellcheck disable=SC1090
|
|
|
|
. "${SOURCEDIR}/kaleidoscope-builder.conf"
|
|
|
|
fi
|
|
|
|
|
|
|
|
# shellcheck disable=SC1090
|
|
|
|
. "${ROOT}/etc/kaleidoscope-builder.conf"
|
|
|
|
|
|
|
|
if [ -n "${VERBOSE}" ] && [[ "${VERBOSE}" -gt 0 ]]; then
|
|
|
|
ARDUINO_VERBOSE="-verbose"
|
|
|
|
else
|
|
|
|
ARDUINO_VERBOSE="-quiet"
|
|
|
|
fi
|
|
|
|
|
|
|
|
cmds=""
|
|
|
|
|
|
|
|
## Export vars
|
|
|
|
for i in $(seq 1 $#); do
|
|
|
|
v="$1"
|
|
|
|
shift
|
|
|
|
|
|
|
|
case "${v}" in
|
|
|
|
*=*)
|
|
|
|
# Exporting an expansion is *precisely* what we want here.
|
|
|
|
# shellcheck disable=SC2086,SC2163
|
|
|
|
export ${v}
|
|
|
|
;;
|
|
|
|
*)
|
|
|
|
cmds="${cmds} ${v}"
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
done
|
|
|
|
|
|
|
|
# Word splitting is desired here.
|
|
|
|
# shellcheck disable=SC2086
|
|
|
|
set -- ${cmds}
|
|
|
|
|
|
|
|
if [ $# -eq 1 ]; then
|
|
|
|
cmd="$(echo "$1" | tr '-' '_')"
|
|
|
|
${cmd}
|
|
|
|
exit $?
|
|
|
|
fi
|
|
|
|
|
|
|
|
SKETCH="$1"
|
|
|
|
shift
|
|
|
|
|
|
|
|
if [ "${SKETCH}" = "default" ]; then
|
|
|
|
SKETCH="${DEFAULT_SKETCH}"
|
|
|
|
fi
|
|
|
|
|
|
|
|
cmds=""
|
|
|
|
|
|
|
|
# shellcheck disable=2034
|
|
|
|
for i in $(seq 1 $#); do
|
|
|
|
cmds="${cmds} $(echo "$1" | tr '-' '_')"
|
|
|
|
shift
|
|
|
|
done
|
|
|
|
|
|
|
|
LIBRARY="${SKETCH}"
|
|
|
|
|
|
|
|
export SKETCH
|
|
|
|
export LIBRARY
|
|
|
|
|
|
|
|
for cmd in ${cmds}; do
|
|
|
|
${cmd}
|
|
|
|
done
|