You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Kaleidoscope/bin/kaleidoscope-builder

388 lines
8.6 KiB

#! /bin/sh
set -e
######
###### Build and output configuration
######
build_version () {
GIT_VERSION="$(cd $(find_sketch); git describe --abbrev=4 --dirty --always)"
LIB_VERSION="$(cd $(find_sketch); (grep version= ../../library.properties 2>/dev/null || echo version=0.0.0) | cut -d= -f2)-g${GIT_VERSION}"
BUILD_PATH="${BUILD_PATH:-$(mktemp -d 2>/dev/null || mktemp -d -t 'build')}"
OUTPUT_DIR="${OUTPUT_DIR:-output/${LIBRARY}}"
OUTPUT_PATH="${OUTPUT_PATH:-${SOURCEDIR}/${OUTPUT_DIR}}"
}
build_filenames () {
OUTPUT_FILE_PREFIX="${SKETCH}-${LIB_VERSION}"
HEX_FILE_PATH="${OUTPUT_PATH}/${OUTPUT_FILE_PREFIX}.hex"
HEX_FILE_WITH_BOOTLOADER_PATH="${OUTPUT_PATH}/${OUTPUT_FILE_PREFIX}-with-bootloader.hex"
ELF_FILE_PATH="${OUTPUT_PATH}/${OUTPUT_FILE_PREFIX}.elf"
}
firmware_size () {
if [ "${BOARD}" = "virtual" ]; then
echo "[Size not computed for virtual build]"
return
fi
## This is a terrible hack, please don't hurt me. - algernon
MAX_PROG_SIZE=28672
output="$($@ | grep "\\(Program\\|Data\\):" | sed -e 's,^, - ,' && echo)"
PROGSIZE="$(echo "${output}" | grep Program: | cut -d: -f2 | awk '{print $1}')"
PERCENT="$(echo ${PROGSIZE} ${MAX_PROG_SIZE} | awk "{ printf \"%02.01f\", \$1 / \$2 * 100 }")"
echo "${output}" | sed -e "s/\(Program:.*\)(\([0-9\.]*%\) Full)/\1(${PERCENT}% Full)/"
}
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
for path in "examples/${LIBRARY}" \
"src" \
"."; do
if [ -f "${path}/${SKETCH}.ino" ]; then
echo "${path}"
return
fi
done
echo "Couldn't find sketch (.ino file)" >&2
exit 1
}
prepare_to_flash () {
if [ ! -e "${HEX_FILE_PATH}" ]; then
compile
fi
echo "Press ENTER when ready..."
read a
}
flash () {
prepare_to_flash
reset_device
sleep 3s
find_bootloader_ports
flash_over_usb || flash_over_usb
}
flash_over_usb () {
if [ -z "${DEVICE_PORT_BOOTLOADER}" ]; then
echo 'DEVICE_PORT_BOOTLOADER is empty (did you hold "Prog" to enable bootloader mode?)' >&2
return 1
fi
sleep 1s
${AVRDUDE} -q -q -C ${AVRDUDE_CONF} -p${MCU} -cavr109 -D -P ${DEVICE_PORT_BOOTLOADER} -b57600 "-Uflash:w:${HEX_FILE_PATH}:i"
}
flash_from_bootloader() {
prepare_to_flash
find_bootloader_ports
flash_over_usb || flash_over_usb
}
program() {
prepare_to_flash
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
cat ${HEX_FILE_PATH} | awk '/^:00000001FF/ == 0' > ${HEX_FILE_WITH_BOOTLOADER_PATH}
echo "Using ${BOOTLOADER_PATH}"
${MD5} ${BOOTLOADER_PATH}
cat ${BOOTLOADER_PATH} >> ${HEX_FILE_WITH_BOOTLOADER_PATH}
ln -sf "${HEX_FILE_WITH_BOOTLOADER_PATH}" "${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
}
build () {
compile $@
size $@
}
compile () {
build_version
build_filenames
install -d "${OUTPUT_PATH}"
echo "Building ${OUTPUT_DIR}/${SKETCH} (${LIB_VERSION}) ..."
${compile_HOOKS}
if [ -d "${ARDUINO_LOCAL_LIB_PATH}/libraries" ]; then
local_LIBS="-libraries \"${ARDUINO_LOCAL_LIB_PATH}/libraries\""
fi
ARDUINO_PACKAGES=""
if [ -d ${ARDUINO_PACKAGE_PATH} ]; then
ARDUINO_PACKAGES="-hardware \"${ARDUINO_PACKAGE_PATH}\""
fi
${ARDUINO_BUILDER} \
-compile \
${ARDUINO_PACKAGES} \
-hardware "${ARDUINO_PATH}/hardware" \
-hardware "${BOARD_HARDWARE_PATH}" \
${ARDUINO_TOOLS_PARAM} \
-tools "${ARDUINO_PATH}/tools-builder" \
-fqbn "${FQBN}" \
-libraries "." \
-libraries "${ROOT}" \
-libraries "${BOARD_HARDWARE_PATH}/.." \
${local_LIBS} \
${EXTRA_BUILDER_ARGS} \
-build-path "${BUILD_PATH}" \
-ide-version "${ARDUINO_IDE_VERSION}" \
-prefs "compiler.cpp.extra_flags=-std=c++11 -Woverloaded-virtual -Wno-unused-parameter -Wno-unused-variable -Wno-ignored-qualifiers ${ARDUINO_CFLAGS} ${LOCAL_CFLAGS}" \
-warnings all \
${ARDUINO_VERBOSE} \
${ARDUINO_AVR_GCC_PREFIX_PARAM} \
"$(find_sketch)/${SKETCH}.ino"
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"
if [ "${ARDUINO_VERBOSE}" = "-verbose" ]; then
echo "Build artifacts can be found in ${BUILD_PATH}";
else
rm -rf "${BUILD_PATH}"
fi
}
_find_all () {
for plugin in ./*.ino \
examples/* \
src/*.ino; do
if [ -d "$(dirname ${plugin})" ] || [ -f "${plugin}" ]; then
p="$(basename "${plugin}" .ino)"
if [ "${p}" != '*' ]; then
echo "${p}"
fi
fi
done | sort
}
build_all () {
plugins="$(_find_all)"
for plugin in ${plugins}; do
export SKETCH="${plugin}"
export LIBRARY="${plugin}"
$0 ${plugin} build
done
}
size () {
if [ ! -e "${HEX_FILE_PATH}" ]; then
compile
fi
echo "- Size: firmware/${LIBRARY}/${OUTPUT_FILE_PREFIX}.elf"
firmware_size "${AVR_SIZE}" -C --mcu="${MCU}" "${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}"
}
reset_device() {
find_device_port
check_device_port
reset_device_cmd
}
check_device_port () {
if [ -z $DEVICE_PORT ]; then
echo "Couldn't autodetect the keyboard's serial port."
echo "If you see this message and your keyboard is connected to your computer,"
echo "it probably means that our serial port detection logic is buggy or incomplete."
echo
echo "Please report this issue at https://github.com/keyboardio/Kaleidoscope";
exit 0;
fi
}
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.
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
export SOURCEDIR="$(pwd)"
if [ -e "${HOME}/.kaleidoscope-builder.conf" ]; then
. "${HOME}/.kaleidoscope-builder.conf"
fi
if [ -e "${SOURCEDIR}/.kaleidoscope-builder.conf" ]; then
. "${SOURCEDIR}/.kaleidoscope-builder.conf"
fi
if [ -e "${SOURCEDIR}/kaleidoscope-builder.conf" ]; then
. "${SOURCEDIR}/kaleidoscope-builder.conf"
fi
. ${ROOT}/etc/kaleidoscope-builder.conf
if [ ! -z "${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
*=*)
export ${v}
;;
*)
cmds="${cmds} ${v}"
;;
esac
done
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=""
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