build.sh 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. #!/usr/bin/env bash
  2. require_uv() {
  3. if ! command -v uv >/dev/null 2>&1; then
  4. echo "uv is required. Install it from https://docs.astral.sh/uv/" >&2
  5. exit 1
  6. fi
  7. }
  8. sync_python_tooling() {
  9. uv sync --locked --no-group docs >/dev/null
  10. uv pip install --python .venv/bin/python pip setuptools wheel >/dev/null
  11. }
  12. run_python() {
  13. .venv/bin/python "$@"
  14. }
  15. run_pio() {
  16. .venv/bin/pio "$@"
  17. }
  18. global_usage() {
  19. cat - <<EOF
  20. Usage:
  21. sh build.sh <command> [target]
  22. Commands:
  23. help|usage|-h|--help: Shows this message.
  24. list|-l: List firmwares available to build.
  25. build-firmware <target>: Build the firmware for the given build target.
  26. build-firmwares: Build all firmwares for all targets.
  27. build-matching-firmwares <build-match-spec>: Build all firmwares for build targets containing the string given for <build-match-spec>.
  28. build-companion-firmwares: Build all companion firmwares for all build targets.
  29. build-repeater-firmwares: Build all repeater firmwares for all build targets.
  30. build-room-server-firmwares: Build all chat room server firmwares for all build targets.
  31. Examples:
  32. Build firmware for the "RAK_4631_repeater" device target
  33. $ sh build.sh build-firmware RAK_4631_repeater
  34. Build all firmwares for device targets containing the string "RAK_4631"
  35. $ sh build.sh build-matching-firmwares <build-match-spec>
  36. Build all companion firmwares
  37. $ sh build.sh build-companion-firmwares
  38. Build all repeater firmwares
  39. $ sh build.sh build-repeater-firmwares
  40. Build all chat room server firmwares
  41. $ sh build.sh build-room-server-firmwares
  42. Environment Variables:
  43. DISABLE_DEBUG=1: Disables all debug logging flags (MESH_DEBUG, MESH_PACKET_LOGGING, etc.)
  44. If not set, debug flags from variant platformio.ini files are used.
  45. Examples:
  46. Build without debug logging:
  47. $ export FIRMWARE_VERSION=v1.0.0
  48. $ export DISABLE_DEBUG=1
  49. $ sh build.sh build-firmware RAK_4631_repeater
  50. Build with debug logging (default, uses flags from variant files):
  51. $ export FIRMWARE_VERSION=v1.0.0
  52. $ sh build.sh build-firmware RAK_4631_repeater
  53. EOF
  54. }
  55. # get a list of pio env names that start with "env:"
  56. get_pio_envs() {
  57. run_pio project config | grep 'env:' | sed 's/env://'
  58. }
  59. # Catch cries for help before doing anything else.
  60. case $1 in
  61. help|usage|-h|--help)
  62. global_usage
  63. exit 1
  64. ;;
  65. list|-l)
  66. get_pio_envs
  67. exit 0
  68. ;;
  69. esac
  70. # cache project config json for use in get_platform_for_env()
  71. require_uv
  72. sync_python_tooling
  73. PIO_CONFIG_JSON=$(run_pio project config --json-output)
  74. # $1 should be the string to find (case insensitive)
  75. get_pio_envs_containing_string() {
  76. shopt -s nocasematch
  77. envs=($(get_pio_envs))
  78. for env in "${envs[@]}"; do
  79. if [[ "$env" == *${1}* ]]; then
  80. echo $env
  81. fi
  82. done
  83. }
  84. # $1 should be the string to find (case insensitive)
  85. get_pio_envs_ending_with_string() {
  86. shopt -s nocasematch
  87. envs=($(get_pio_envs))
  88. for env in "${envs[@]}"; do
  89. if [[ "$env" == *${1} ]]; then
  90. echo $env
  91. fi
  92. done
  93. }
  94. # get platform flag for a given environment
  95. # $1 should be the environment name
  96. get_platform_for_env() {
  97. local env_name=$1
  98. echo "$PIO_CONFIG_JSON" | run_python -c "
  99. import sys, json, re
  100. data = json.load(sys.stdin)
  101. for section, options in data:
  102. if section == 'env:$env_name':
  103. for key, value in options:
  104. if key == 'build_flags':
  105. for flag in value:
  106. match = re.search(r'(ESP32_PLATFORM|NRF52_PLATFORM|STM32_PLATFORM|RP2040_PLATFORM)', flag)
  107. if match:
  108. print(match.group(1))
  109. sys.exit(0)
  110. "
  111. }
  112. # disable all debug logging flags if DISABLE_DEBUG=1 is set
  113. disable_debug_flags() {
  114. if [ "$DISABLE_DEBUG" == "1" ]; then
  115. export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -UMESH_DEBUG -UBLE_DEBUG_LOGGING -UWIFI_DEBUG_LOGGING -UBRIDGE_DEBUG -UGPS_NMEA_DEBUG -UCORE_DEBUG_LEVEL -UESPNOW_DEBUG_LOGGING -UDEBUG_RP2040_WIRE -UDEBUG_RP2040_SPI -UDEBUG_RP2040_CORE -UDEBUG_RP2040_PORT -URADIOLIB_DEBUG_SPI -UCFG_DEBUG -URADIOLIB_DEBUG_BASIC -URADIOLIB_DEBUG_PROTOCOL"
  116. fi
  117. }
  118. # build firmware for the provided pio env in $1
  119. build_firmware() {
  120. # get env platform for post build actions
  121. ENV_PLATFORM=($(get_platform_for_env $1))
  122. # get git commit sha
  123. COMMIT_HASH=$(git rev-parse --short HEAD)
  124. # set firmware build date
  125. FIRMWARE_BUILD_DATE=$(date '+%d-%b-%Y')
  126. # get FIRMWARE_VERSION, which should be provided by the environment
  127. if [ -z "$FIRMWARE_VERSION" ]; then
  128. echo "FIRMWARE_VERSION must be set in environment"
  129. exit 1
  130. fi
  131. # set firmware version string
  132. # e.g: v1.2.3-eastmesh-v1.0.1-abcdef
  133. FIRMWARE_VERSION_BASE="${FIRMWARE_VERSION}"
  134. if [ -n "$EASTMESH_VERSION" ]; then
  135. FIRMWARE_VERSION_BASE="${FIRMWARE_VERSION_BASE}-eastmesh-${EASTMESH_VERSION}"
  136. fi
  137. FIRMWARE_VERSION_STRING="${FIRMWARE_VERSION_BASE}-${COMMIT_HASH}"
  138. # craft filename
  139. # e.g: RAK_4631_Repeater-v1.0.0-SHA
  140. FIRMWARE_FILENAME="$1-${FIRMWARE_VERSION_STRING}"
  141. # add firmware version info to end of existing platformio build flags in environment vars
  142. export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DFIRMWARE_BUILD_DATE='\"${FIRMWARE_BUILD_DATE}\"' -DFIRMWARE_VERSION='\"${FIRMWARE_VERSION_STRING}\"'"
  143. # disable debug flags if requested
  144. disable_debug_flags
  145. # build firmware target
  146. run_pio run -e $1
  147. # build merge-bin for esp32 fresh install, copy .bins to out folder (e.g: Heltec_v3_room_server-v1.0.0-SHA.bin)
  148. if [ "$ENV_PLATFORM" == "ESP32_PLATFORM" ]; then
  149. run_pio run -t mergebin -e $1
  150. cp .pio/build/$1/firmware.bin out/${FIRMWARE_FILENAME}.bin 2>/dev/null || true
  151. cp .pio/build/$1/firmware-merged.bin out/${FIRMWARE_FILENAME}-merged.bin 2>/dev/null || true
  152. fi
  153. # build .uf2 for nrf52 boards, copy .uf2 and .zip to out folder (e.g: RAK_4631_Repeater-v1.0.0-SHA.uf2)
  154. if [ "$ENV_PLATFORM" == "NRF52_PLATFORM" ]; then
  155. run_python bin/uf2conv/uf2conv.py .pio/build/$1/firmware.hex -c -o .pio/build/$1/firmware.uf2 -f 0xADA52840
  156. cp .pio/build/$1/firmware.uf2 out/${FIRMWARE_FILENAME}.uf2 2>/dev/null || true
  157. cp .pio/build/$1/firmware.zip out/${FIRMWARE_FILENAME}.zip 2>/dev/null || true
  158. fi
  159. # for stm32, copy .bin and .hex to out folder
  160. if [ "$ENV_PLATFORM" == "STM32_PLATFORM" ]; then
  161. cp .pio/build/$1/firmware.bin out/${FIRMWARE_FILENAME}.bin 2>/dev/null || true
  162. cp .pio/build/$1/firmware.hex out/${FIRMWARE_FILENAME}.hex 2>/dev/null || true
  163. fi
  164. # for rp2040, copy .bin and .uf2 to out folder
  165. if [ "$ENV_PLATFORM" == "RP2040_PLATFORM" ]; then
  166. cp .pio/build/$1/firmware.bin out/${FIRMWARE_FILENAME}.bin 2>/dev/null || true
  167. cp .pio/build/$1/firmware.uf2 out/${FIRMWARE_FILENAME}.uf2 2>/dev/null || true
  168. fi
  169. }
  170. # firmwares containing $1 will be built
  171. build_all_firmwares_matching() {
  172. envs=($(get_pio_envs_containing_string "$1"))
  173. for env in "${envs[@]}"; do
  174. build_firmware $env
  175. done
  176. }
  177. # firmwares ending with $1 will be built
  178. build_all_firmwares_by_suffix() {
  179. envs=($(get_pio_envs_ending_with_string "$1"))
  180. for env in "${envs[@]}"; do
  181. build_firmware $env
  182. done
  183. }
  184. build_repeater_firmwares() {
  185. # # build specific repeater firmwares
  186. # build_firmware "Heltec_v2_repeater"
  187. # build_firmware "Heltec_v3_repeater"
  188. # build_firmware "Xiao_C3_Repeater_sx1262"
  189. # build_firmware "Xiao_S3_WIO_Repeater"
  190. # build_firmware "LilyGo_T3S3_sx1262_Repeater"
  191. # build_firmware "RAK_4631_Repeater"
  192. # build all repeater firmwares
  193. build_all_firmwares_by_suffix "_repeater"
  194. }
  195. build_companion_firmwares() {
  196. # # build specific companion firmwares
  197. # build_firmware "Heltec_v2_companion_radio_usb"
  198. # build_firmware "Heltec_v2_companion_radio_ble"
  199. # build_firmware "Heltec_v3_companion_radio_usb"
  200. # build_firmware "Heltec_v3_companion_radio_ble"
  201. # build_firmware "Xiao_S3_WIO_companion_radio_ble"
  202. # build_firmware "LilyGo_T3S3_sx1262_companion_radio_usb"
  203. # build_firmware "LilyGo_T3S3_sx1262_companion_radio_ble"
  204. # build_firmware "RAK_4631_companion_radio_usb"
  205. # build_firmware "RAK_4631_companion_radio_ble"
  206. # build_firmware "t1000e_companion_radio_ble"
  207. # build all companion firmwares
  208. build_all_firmwares_by_suffix "_companion_radio_usb"
  209. build_all_firmwares_by_suffix "_companion_radio_ble"
  210. }
  211. build_room_server_firmwares() {
  212. # # build specific room server firmwares
  213. # build_firmware "Heltec_v3_room_server"
  214. # build_firmware "RAK_4631_room_server"
  215. # build all room server firmwares
  216. build_all_firmwares_by_suffix "_room_server"
  217. }
  218. build_firmwares() {
  219. build_companion_firmwares
  220. build_repeater_firmwares
  221. build_room_server_firmwares
  222. }
  223. # clean build dir
  224. rm -rf out
  225. mkdir -p out
  226. # handle script args
  227. if [[ $1 == "build-firmware" ]]; then
  228. TARGETS=${@:2}
  229. if [ "$TARGETS" ]; then
  230. for env in $TARGETS; do
  231. build_firmware $env
  232. done
  233. else
  234. echo "usage: $0 build-firmware <target>"
  235. exit 1
  236. fi
  237. elif [[ $1 == "build-matching-firmwares" ]]; then
  238. if [ "$2" ]; then
  239. build_all_firmwares_matching $2
  240. else
  241. echo "usage: $0 build-matching-firmwares <build-match-spec>"
  242. exit 1
  243. fi
  244. elif [[ $1 == "build-firmwares" ]]; then
  245. build_firmwares
  246. elif [[ $1 == "build-companion-firmwares" ]]; then
  247. build_companion_firmwares
  248. elif [[ $1 == "build-repeater-firmwares" ]]; then
  249. build_repeater_firmwares
  250. elif [[ $1 == "build-room-server-firmwares" ]]; then
  251. build_room_server_firmwares
  252. fi