|
| 1 | +if which nproc > /dev/null; then |
| 2 | + MAKEOPTS="-j$(nproc)" |
| 3 | +else |
| 4 | + MAKEOPTS="-j$(sysctl -n hw.ncpu)" |
| 5 | +fi |
| 6 | + |
| 7 | +# TODO: Could also make these opts into the build_micropython_opencv function if we care... |
| 8 | +FROZEN_MODULES_DIR="$(dirname "$0")/frozen_modules" |
| 9 | +FROZEN_EXAMPLES_ARCHIVE_SCRIPT="frozen_examples.py" |
| 10 | +FROZEN_EXAMPLES_UNPACKED_DIR="opencv-examples" |
| 11 | +PERSISTENT_FILE_FOR_UNPACK="/${FROZEN_EXAMPLES_UNPACKED_DIR}/reset_examples.txt" |
| 12 | + |
| 13 | +# Uses freezefs to create a frozen filesystem archive for the provided directory. |
| 14 | +# See https://github.com/bixb922/freezefs for more details on freezefs |
| 15 | +# Options: |
| 16 | + # $1: The directory to freeze |
| 17 | + # $2: The name that you want the frozen directory to have once unpacked on the board |
| 18 | + # $3: The output file name for the frozen archive .py file |
| 19 | +function create_frozen_fs { |
| 20 | + local DIR_TO_FREEZE=$1 |
| 21 | + local DIR_NAME_ON_BOARD=$2 |
| 22 | + local OUTPUT_FILE=$3 |
| 23 | + |
| 24 | + echo "Creating frozen filesystem for directory: $DIR_TO_FREEZE" |
| 25 | + echo "The frozen directory will be named: $DIR_NAME_ON_BOARD" |
| 26 | + echo "The output file will be: $OUTPUT_FILE" |
| 27 | + |
| 28 | + if [ $DIR_TO_FREEZE != $DIR_NAME_ON_BOARD ]; then |
| 29 | + cp -r $DIR_TO_FREEZE $DIR_NAME_ON_BOARD |
| 30 | + fi |
| 31 | + |
| 32 | + # Use on-import=extract so our frozen filesystem is unpacked to '/' in flash on import |
| 33 | + # Use --compress to compress the frozen filesystem archive |
| 34 | + # Use --overwrite always to ensure that the frozen filesystem is returned to factory state if the persistent file is deleted |
| 35 | + |
| 36 | + python -m freezefs $DIR_NAME_ON_BOARD $OUTPUT_FILE --on-import=extract --compress --overwrite always |
| 37 | +} |
| 38 | + |
| 39 | +# Adds the provided directory to the manifest file for the specified port and board. |
| 40 | +# Options: |
| 41 | +# $1: The directory to add to the manifest |
| 42 | +# $2: The port (e.g. rp2) |
| 43 | +# $3: The board (e.g. SPARKFUN_XRP_CONTROLLER) |
| 44 | +# $4: The mpconfigboard file name (e.g. mpconfigboard.cmake or mpconfigboard.m) Default: mpconfigboard.cmake |
| 45 | +function add_to_manifest { |
| 46 | + local DIR=$1 |
| 47 | + local PORT=$2 |
| 48 | + local BOARD=$3 |
| 49 | + local MPCONFIG_FILE="${4:-mpconfigboard.cmake}" |
| 50 | + |
| 51 | + # Add the directory to the manifest file |
| 52 | + echo "Adding $DIR to the manifest for $PORT on $BOARD using $MPCONFIG_FILE" |
| 53 | + local BOARD_DIR="micropython/ports/${PORT}/boards/${BOARD}" |
| 54 | + |
| 55 | + # Create manifest.py if it doesn't exist |
| 56 | + if [ ! -f ${BOARD_DIR}/manifest.py ]; then |
| 57 | + echo "include(\"\$(PORT_DIR)/boards/manifest.py\")" > ${BOARD_DIR}/manifest.py |
| 58 | + |
| 59 | + # also add the necessary frozen manifest line to mpconfigboard.cmake: set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py) |
| 60 | + # We will use the optional MPCONFIG_FILE argument to determine if we should add this line |
| 61 | + |
| 62 | + if [ -n "$MPCONFIG_FILE" ]; then |
| 63 | + echo "Attempting to add frozen manifest line to $MPCONFIG_FILE for $BOARD" |
| 64 | + |
| 65 | + if [[ $MPCONFIG_FILE == *.mk ]]; then |
| 66 | + # e.g. for TEENSY which uses mpconfigboard.mk instead of mpconfigboard.cmake |
| 67 | + printf "\nFROZEN_MANIFEST ?= \$(BOARD_DIR)/manifest.py" >> ${BOARD_DIR}/$MPCONFIG_FILE |
| 68 | + elif [[ $MPCONFIG_FILE == *.cmake ]]; then |
| 69 | + printf "\nset(MICROPY_FROZEN_MANIFEST \"\${MICROPY_BOARD_DIR}/manifest.py\")" >> ${BOARD_DIR}/$MPCONFIG_FILE |
| 70 | + fi |
| 71 | + fi |
| 72 | + fi |
| 73 | + |
| 74 | + # Add the freeze line to the manifest.py for the board |
| 75 | + echo "Adding freeze line to manifest.py for $BOARD" |
| 76 | + printf "\nfreeze(\"${DIR}\")" >> ${BOARD_DIR}/manifest.py |
| 77 | + |
| 78 | + # Helpful for debugging during the build process, but can be removed if we'd rather not see this output... |
| 79 | + echo "Manifest.py for $BOARD:" |
| 80 | + cat ${BOARD_DIR}/manifest.py |
| 81 | +} |
| 82 | + |
| 83 | +# Adds the frozen data filesystem to the _boot.py file for the given port |
| 84 | +# Options: |
| 85 | + # $1: Port name |
| 86 | + # $2: Frozen data file path |
| 87 | + # $3: Unpacked directory name on the board (optional). If provided, the modules in this directory will be made importable |
| 88 | +function add_frozen_data_to_boot_for_port { |
| 89 | + local TARGET_PORT_NAME=$1 |
| 90 | + local FROZEN_DATA_FILE=$2 |
| 91 | + local UNPACKED_DIR=$3 |
| 92 | + |
| 93 | + # Remove the ".py" extension from the frozen data file |
| 94 | + local FROZEN_DATA_BASENAME=$(basename $FROZEN_DATA_FILE .py) |
| 95 | + |
| 96 | + # Check if the _boot.py file exists in the port's modules directory and error out if it does not |
| 97 | + if [ ! -f micropython/ports/${TARGET_PORT_NAME}/modules/_boot.py ]; then |
| 98 | + echo "Error: _boot.py file not found in ports/${TARGET_PORT_NAME}/modules/" |
| 99 | + exit 1 |
| 100 | + fi |
| 101 | + |
| 102 | + # Add the frozen data filesystem to the _boot.py file |
| 103 | + local BOOT_FILE="micropython/ports/${TARGET_PORT_NAME}/modules/_boot.py" |
| 104 | + |
| 105 | + # Create our "persistent file for unpack" that will be used to check if the frozen data filesystem has already been unpacked |
| 106 | + # If it has not been unpacked, we will import the frozen data filesystem |
| 107 | + echo "Adding frozen data filesystem to ${BOOT_FILE}" |
| 108 | + echo "import os" >> ${BOOT_FILE} |
| 109 | + echo "try:" >> ${BOOT_FILE} |
| 110 | + echo " os.stat('${PERSISTENT_FILE_FOR_UNPACK}')" >> ${BOOT_FILE} |
| 111 | + echo "except OSError:" >> ${BOOT_FILE} |
| 112 | + echo " import ${FROZEN_DATA_BASENAME}" >> ${BOOT_FILE} |
| 113 | + echo " with open('${PERSISTENT_FILE_FOR_UNPACK}', 'w') as f:" >> ${BOOT_FILE} |
| 114 | + echo " f.write('Hi! The firmware has this directory frozen into the firmware, and the _boot.py\\n')" >> ${BOOT_FILE} |
| 115 | + echo " f.write('file has been modified to automatically unpack this directory if needed. As long\\n')" >> ${BOOT_FILE} |
| 116 | + echo " f.write('as this file exists, it will not unpack the directory, meaning you can safely\\n')" >> ${BOOT_FILE} |
| 117 | + echo " f.write('edit the files here or delete all other files to free up storage space. If you\\n')" >> ${BOOT_FILE} |
| 118 | + echo " f.write('want to restore this directory to its default state, delete this file and the\\n')" >> ${BOOT_FILE} |
| 119 | + echo " f.write('directory will be unpacked again on the next boot.\\n')" >> ${BOOT_FILE} |
| 120 | + echo " f.write('\\n')" >> ${BOOT_FILE} |
| 121 | + echo " f.write('WARNING: Deleting this file will override ALL changes to this directory!')" >> ${BOOT_FILE} |
| 122 | + |
| 123 | + # If a destination directory is provided, we will add it to the sys.path so that the modules in the unpacked directory can be imported |
| 124 | + if [ -n "$UNPACKED_DIR" ]; then |
| 125 | + echo "Adding ${UNPACKED_DIR} to sys.path in _boot.py" |
| 126 | + echo "import sys" >> ${BOOT_FILE} |
| 127 | + echo "sys.path.append('/${UNPACKED_DIR}')" >> ${BOOT_FILE} |
| 128 | + fi |
| 129 | + |
| 130 | + # Helpful for debugging during the build process, but can be removed if we'd rather not see this output... |
| 131 | + echo "Content of _boot.py after adding frozen data filesystem:" |
| 132 | + cat micropython/ports/${TARGET_PORT_NAME}/modules/_boot.py |
| 133 | +} |
| 134 | + |
| 135 | +# Installs necessary dependencies and builds OpenCV and the firmware |
| 136 | +# Also freezes the examples directory in a filesystem archive on the board |
| 137 | +function build_micropython_opencv { |
| 138 | + # Install necessary packages (Could move into an install_dependencies.sh if we want this to be more explicit/modular) |
| 139 | + sudo apt update |
| 140 | + sudo apt install cmake python3 build-essential gcc-arm-none-eabi libnewlib-arm-none-eabi libstdc++-arm-none-eabi-newlib |
| 141 | + # Install necessary python packages (could also move this to a requirements.txt file) |
| 142 | + pip install freezefs |
| 143 | + |
| 144 | + # Create a directory for frozen modules, we can add arbitrary .py files to this directory in the future. |
| 145 | + # For now it will just contain the archived examples script. |
| 146 | + mkdir "$FROZEN_MODULES_DIR" |
| 147 | + |
| 148 | + # Create our frozen filesystem archive for the examples directory |
| 149 | + create_frozen_fs "opencv-examples" "$FROZEN_EXAMPLES_UNPACKED_DIR" "$FROZEN_MODULES_DIR/$FROZEN_EXAMPLES_ARCHIVE_SCRIPT" |
| 150 | + |
| 151 | + # Add necessary content to the manifest file to freeze the modules in the provided directory |
| 152 | + add_to_manifest "$FROZEN_MODULES_DIR" "rp2" "SPARKFUN_XRP_CONTROLLER" "mpconfigvariant_LARGE_BINARY.cmake" |
| 153 | + |
| 154 | + # Add necessary content to the boot.py file to unpack the frozen data filesystem on boot |
| 155 | + # Provide the source and destination directories to copy the frozen data filesystem to a mutable (and non-hidden) location |
| 156 | + # Provide "true" as the last argument to add the destination directory to sys.path (since our examples directory contains modules that we want to be importable...) |
| 157 | + # add_frozen_data_to_boot_for_port "rp2" "$FROZEN_EXAMPLES_ARCHIVE_SCRIPT" ".$FROZEN_EXAMPLES_UNPACKED_DIR" "$FROZEN_EXAMPLES_UNPACKED_DIR" true |
| 158 | + add_frozen_data_to_boot_for_port "rp2" "$FROZEN_EXAMPLES_ARCHIVE_SCRIPT" "$FROZEN_EXAMPLES_UNPACKED_DIR" true |
| 159 | + |
| 160 | + # Set Pico SDK path to $GITHUB_WORKSPACE/micropython/lib/pico-sdk if $GITHUB_WORKSPACE is set, otherwise use the current directory |
| 161 | + if [ -n "$GITHUB_WORKSPACE" ]; then |
| 162 | + export PICO_SDK_PATH="$GITHUB_WORKSPACE/micropython/lib/pico-sdk" |
| 163 | + else |
| 164 | + export PICO_SDK_PATH=$(dirname "$0")/micropython/lib/pico-sdk |
| 165 | + fi |
| 166 | + |
| 167 | + # Build MPY Cross compiler |
| 168 | + make -C micropython/mpy-cross |
| 169 | + |
| 170 | + # Update necessary MicroPython submodules |
| 171 | + make -C micropython/ports/rp2 BOARD=SPARKFUN_XRP_CONTROLLER submodules |
| 172 | + |
| 173 | + # Build OpenCV |
| 174 | + make -C src/opencv PLATFORM=rp2350 --no-print-directory ${MAKEOPTS} |
| 175 | + |
| 176 | + # Build firmware |
| 177 | + make BOARD=SPARKFUN_XRP_CONTROLLER ${MAKEOPTS} |
| 178 | + |
| 179 | + # Rename firmware file to identify it as the OpenCV build and which board it's for |
| 180 | + mv micropython/ports/rp2/build-SPARKFUN_XRP_CONTROLLER-LARGE_BINARY/firmware.uf2 micropython/ports/rp2/build-SPARKFUN_XRP_CONTROLLER-LARGE_BINARY/MICROPYTHON_OPENCV_SPARKFUN_XRP_CONTROLLER.uf2 |
| 181 | +} |
0 commit comments