Skip to content

Commit

Permalink
Merge pull request #33 from roleroz/master
Browse files Browse the repository at this point in the history
Allow for multiple platformio_project() entries in a single BUILD file
  • Loading branch information
mum4k authored Dec 27, 2022
2 parents 2d2808f + ea627e7 commit 0a76510
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 39 deletions.
99 changes: 73 additions & 26 deletions platformio/platformio.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,14 @@ _COPY_COMMAND="cp {source} {destination}"


# Command that zips files recursively. It enters the output directory first so
# that the zipped path starts at lib/.
_ZIP_COMMAND="cd {output_dir} && zip -qq -r -u {zip_filename} lib/"
# that the zipped path starts at lib/. It will return to the original directory
# when finishing the command.
_ZIP_COMMAND="cd {output_dir} && zip -qq -r -u {zip_filename} lib/; cd -"


# Command that unzips a zip archive into the specified directory.
_UNZIP_COMMAND="unzip -qq -o -d {project_dir} {zip_filename}"
# Command that unzips a zip archive into the specified directory. It will create
# the destination directory if it doesn't exist.
_UNZIP_COMMAND="mkdir -p {project_dir} && unzip -qq -o -d {project_dir} {zip_filename}"


# Command that executes the PlatformIO build system and builds the project in
Expand Down Expand Up @@ -130,11 +132,31 @@ def _platformio_library_impl(ctx):
)


def _emit_ini_file_action(ctx):
def _declare_outputs(ctx):
"""Declares the output files needed by the platformio_project rule.
Args:
ctx: The Starlark context.
Returns:
List of output files declared by ctx.actions.declare_file().
"""
dirname = "%s_workdir" % ctx.attr.name
platformio_ini = ctx.actions.declare_file("%s/platformio.ini" % dirname)
main_cpp = ctx.actions.declare_file("%s/src/main.cpp" % dirname)
firmware_elf = ctx.actions.declare_file("%s/.pio/build/%s/firmware.elf" % (dirname, ctx.attr.board))
return struct(
main_cpp=main_cpp,
platformio_ini=platformio_ini,
firmware_elf=firmware_elf)


def _emit_ini_file_action(ctx, output_files):
"""Emits a Bazel action that generates the PlatformIO configuration file.
Args:
ctx: The Starlark context.
output_files: List of output files declared by ctx.actions.declare_file().
"""
environment_kwargs = []
if ctx.attr.environment_kwargs:
Expand All @@ -158,38 +180,40 @@ def _emit_ini_file_action(ctx):
build_flags=build_flags,
).to_json()
ctx.actions.run(
outputs=[ctx.outputs.platformio_ini],
outputs=[output_files.platformio_ini],
inputs=[ctx.file._platformio_ini_tmpl],
executable=ctx.executable._template_renderer,
arguments=[
ctx.file._platformio_ini_tmpl.path,
ctx.outputs.platformio_ini.path,
output_files.platformio_ini.path,
substitutions
],
)


def _emit_main_file_action(ctx):
def _emit_main_file_action(ctx, output_files):
"""Emits a Bazel action that outputs the project main C++ file.
Args:
ctx: The Starlark context.
output_files: List of output files declared by ctx.actions.declare_file().
"""
ctx.actions.run_shell(
inputs=[ctx.file.src],
outputs=[ctx.outputs.main_cpp],
outputs=[output_files.main_cpp],
command=_COPY_COMMAND.format(
source=ctx.file.src.path, destination=ctx.outputs.main_cpp.path),
source=ctx.file.src.path, destination=output_files.main_cpp.path),
)


def _emit_build_action(ctx, project_dir):
def _emit_build_action(ctx, project_dir, output_files):
"""Emits a Bazel action that unzips the libraries and builds the project.
Args:
ctx: The Starlark context.
project_dir: A string, the main directory of the PlatformIO project.
This is where the zip files will be extracted.
output_files: List of output files declared by ctx.actions.declare_file().
"""
transitive_zip_files=depset(
transitive=[
Expand All @@ -204,12 +228,12 @@ def _emit_build_action(ctx, project_dir):

# The PlatformIO build system needs the project configuration file, the main
# file and all the transitive dependancies.
inputs=[ctx.outputs.platformio_ini, ctx.outputs.main_cpp]
inputs=[output_files.platformio_ini, output_files.main_cpp]
for zip_file in transitive_zip_files.to_list():
inputs.append(zip_file)
ctx.actions.run_shell(
inputs=inputs,
outputs=[ctx.outputs.firmware_elf],
outputs=[output_files.firmware_elf],
command="\n".join(commands),
env={
# The PlatformIO binary assumes that the build tools are in the path.
Expand All @@ -227,22 +251,33 @@ def _emit_build_action(ctx, project_dir):
)


def _emit_executable_action(ctx):
def _emit_executable_action(ctx, project_dir):
"""Emits a Bazel action that produces executable script.
When the script is executed, the compiled firmware gets uploaded to the
Arduino device.
Args:
ctx: The Starlark context.
project_dir: A string, the main directory of the PlatformIO project.
This is where the zip files will be extracted.
"""
# TODO(mum4k): Make this script smarter, when executed via Bazel, the current
# directory is project_name.runfiles/__main__ so we need to go two dirs up.
# This however won't work when executed directly.
content=[_SHELL_HEADER, _UPLOAD_COMMAND.format(project_dir="../..")]
transitive_zip_files=depset(
transitive=[
dep[DefaultInfo].default_runfiles.files for dep in ctx.attr.deps
])

commands = [_SHELL_HEADER]
for zip_file in transitive_zip_files.to_list():
commands.append(_UNZIP_COMMAND.format(
project_dir=project_dir, zip_filename=zip_file.short_path))
commands.append(_UPLOAD_COMMAND.format(project_dir=project_dir))
ctx.actions.write(
output=ctx.outputs.executable,
content="\n".join(content),
content="\n".join(commands),
is_executable=True,
)

Expand All @@ -258,14 +293,31 @@ def _platformio_project_impl(ctx):
Args:
ctx: The Starlark context.
"""
_emit_ini_file_action(ctx)
_emit_main_file_action(ctx)
output_files = _declare_outputs(ctx)
_emit_ini_file_action(ctx, output_files)
_emit_main_file_action(ctx, output_files)

# Determine the build directory used by Bazel, that is the directory where
# our output files will be placed.
project_dir = ctx.outputs.platformio_ini.dirname
_emit_build_action(ctx, project_dir)
_emit_executable_action(ctx)
project_build_dir = output_files.platformio_ini.dirname
_emit_build_action(ctx, project_build_dir, output_files)
# Determine the run directory used by Bazel, that is the directory where our
# output files will be placed.
project_run_dir = "./%s" % project_build_dir[len(output_files.platformio_ini.root.path)+1:]
_emit_executable_action(ctx, project_run_dir)

return DefaultInfo(
default_runfiles=ctx.runfiles(files=[
ctx.outputs.executable,
output_files.main_cpp,
output_files.platformio_ini,
output_files.firmware_elf,
] + depset(
transitive=[
dep[DefaultInfo].default_runfiles.files for dep in ctx.attr.deps
]).to_list()
)
)


platformio_library = rule(
Expand Down Expand Up @@ -352,11 +404,6 @@ expected by PlatformIO.
platformio_project = rule(
implementation=_platformio_project_impl,
executable=True,
outputs = {
"main_cpp": "src/main.cpp",
"platformio_ini": "platformio.ini",
"firmware_elf": ".pio/build/%{board}/firmware.elf",
},
attrs={
"_platformio_ini_tmpl": attr.label(
default=Label("//platformio:platformio_ini_tmpl"),
Expand Down
36 changes: 32 additions & 4 deletions tests/binary_counter/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,44 @@

load("//platformio:platformio.bzl", "platformio_project")

platformio_project(
name = "binary_counter",
configs = [
{
"name": "mega",
"board": "megaatmega2560",
"build_flags": [
"-DRED_LED_PIN=44",
"-DORANGE_LED_PIN=46",
"-DGREEN_LED_PIN=48",
"-DBLUE_LED_PIN=50",
"-DYELLOW_LED_PIN=52",
"-DBUTTON_PIN=2",
],
},
{
"name": "nano",
"board": "nanoatmega328",
"build_flags": [
"-DRED_LED_PIN=3",
"-DORANGE_LED_PIN=4",
"-DGREEN_LED_PIN=5",
"-DBLUE_LED_PIN=6",
"-DYELLOW_LED_PIN=7",
"-DBUTTON_PIN=2",
],
},
]

[platformio_project(
name = "binary_counter_%s" % config["name"],
src = "binary_counter.cc",
board = "megaatmega2560",
board = config["board"],
framework = "arduino",
platform = "atmelavr",
build_flags = config["build_flags"],
deps = [
"//tests/arduino:Arduino_impl",
"//tests/arduino:Arduino_interface",
"//tests/binary_counter/button_presses:Button_presses",
"//tests/binary_counter/led_display:Led_display",
],
)
) for config in configs]
11 changes: 8 additions & 3 deletions tests/binary_counter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,14 @@ count will be displayed in binary form using the Leds.

### The breadboard

![The binary counter breadboard](doc/binary_counter_bb.png)
#### On Arduino Mega
![The binary counter breadboard](doc/binary_counter_mega_bb.png)

### Fritzing circuit
The [Fritzing](http://fritzing.org) circuit is stored in file
[binary_counter.fzz](doc/binary_counter_mega.fzz).

#### On Arduino Nano
![The binary counter breadboard](doc/binary_counter_nano_bb.png)

The [Fritzing](http://fritzing.org) circuit is stored in file
[binary_counter.fzz](doc/binary_counter.fzz).
[binary_counter.fzz](doc/binary_counter_nano.fzz).
31 changes: 25 additions & 6 deletions tests/binary_counter/binary_counter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -32,23 +32,42 @@ using binary_counter::kDefaultTimeoutMs;
using binary_counter::LedDisplay;
using binary_counter::LedPins;

#ifndef RED_LED_PIN
#error RED_LED_PIN needs to be defined
#endif
#ifndef ORANGE_LED_PIN
#error ORANGE_LED_PIN needs to be defined
#endif
#ifndef GREEN_LED_PIN
#error GREEN_LED_PIN needs to be defined
#endif
#ifndef BLUE_LED_PIN
#error BLUE_LED_PIN needs to be defined
#endif
#ifndef YELLOW_LED_PIN
#error YELLOW_LED_PIN needs to be defined
#endif
#ifndef BUTTON_PIN
#error BUTTON_PIN needs to be defined
#endif

// Arduino hardware layer.
const ArduinoImpl ino = ArduinoImpl();

// Pin numbers where the Leds are wired.
const int kRedLedPin = 44;
const int kOrangeLedPin = 46;
const int kGreenLedPin = 48;
const int kBlueLedPin = 50;
const int kYellowLedPin = 52;
const int kRedLedPin = RED_LED_PIN;
const int kOrangeLedPin = ORANGE_LED_PIN;
const int kGreenLedPin = GREEN_LED_PIN;
const int kBlueLedPin = BLUE_LED_PIN;
const int kYellowLedPin = YELLOW_LED_PIN;
const LedPins led_pins(kYellowLedPin, kBlueLedPin, kGreenLedPin, kOrangeLedPin,
kRedLedPin);

// Class that can display binary numbers using Leds.
const LedDisplay led = LedDisplay(ino, led_pins);

// Pin where the button is wired.
const int kButtonPin = 2;
const int kButtonPin = BUTTON_PIN;

// Remains in the intro mode until this gets set to false.
volatile bool intro = true;
Expand Down
File renamed without changes.
Binary file added tests/binary_counter/doc/binary_counter_nano.fzz
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 0a76510

Please sign in to comment.