Skip to content

Commit

Permalink
Merge pull request #105 from OpenSourceLightshows/daniel/helios-lib-a…
Browse files Browse the repository at this point in the history
…nd-wasm

Start of helios lib and wasm build
  • Loading branch information
Unreal-Dan authored Dec 12, 2024
2 parents 175f395 + 7ece523 commit 67bd448
Show file tree
Hide file tree
Showing 8 changed files with 425 additions and 10 deletions.
75 changes: 72 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,46 @@ on:
branches: ["master"]

jobs:
setup:
runs-on: ubuntu-latest
outputs:
helios_version_major: ${{ steps.set_version.outputs.helios_version_major }}
helios_version_minor: ${{ steps.set_version.outputs.helios_version_minor }}
helios_build_number: ${{ steps.set_version.outputs.helios_build_number }}
helios_version_number: ${{ steps.set_version.outputs.helios_version_number }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetches all history for all branches and tags
- name: Determine Version and Build Number
id: set_version
run: |
# Fetch all tags
git fetch --depth=1 origin +refs/tags/*:refs/tags/*
# Get the latest tag that matches the branch suffix
LATEST_TAG=$(git tag --list | sort -V | tail -n1)
if [ -z "$LATEST_TAG" ]; then
echo "No matching tags found. Setting default version."
VERSION_MAJOR="0"
VERSION_MINOR="1"
BUILD_NUMBER="0"
else
echo "Found latest tag: $LATEST_TAG"
VERSION_MAJOR=$(echo $LATEST_TAG | cut -d. -f1)
VERSION_MINOR=$(echo $LATEST_TAG | cut -d. -f2)
LAST_HELIOS_BUILD_NUMBER=$(echo $LATEST_TAG | cut -d. -f3)
COMMITS_SINCE_TAG=$(git rev-list --count $LATEST_TAG..HEAD)
BUILD_NUMBER=$(( $LAST_HELIOS_BUILD_NUMBER + $COMMITS_SINCE_TAG ))
fi
FULL_VERSION="$VERSION_MAJOR.$VERSION_MINOR.$BUILD_NUMBER"
echo "helios_version_major=$VERSION_MAJOR" >> $GITHUB_OUTPUT
echo "helios_version_minor=$VERSION_MINOR" >> $GITHUB_OUTPUT
echo "helios_build_number=$BUILD_NUMBER" >> $GITHUB_OUTPUT
echo "helios_version_number=$FULL_VERSION" >> $GITHUB_OUTPUT
echo "Version Number: $FULL_VERSION"
build:
needs: setup
runs-on: ubuntu-latest
steps:
- name: Checkout current repository
Expand All @@ -29,7 +68,7 @@ jobs:
path: HeliosCLI/helioscli.zip

tests:
needs: build
needs: [setup, build]
runs-on: ubuntu-latest
steps:
- name: Checkout current repository
Expand All @@ -47,7 +86,7 @@ jobs:
working-directory: tests

embedded:
needs: tests
needs: [setup, build, tests]
runs-on: ubuntu-latest
steps:
- name: Checkout current repository
Expand All @@ -60,7 +99,12 @@ jobs:
run: make install
working-directory: HeliosEmbedded
- name: Build Binary
run: make build
run: |
export HELIOS_VERSION_MAJOR=${{ needs.setup.outputs.helios_version_major }}
export HELIOS_VERSION_MINOR=${{ needs.setup.outputs.helios_version_minor }}
export HELIOS_BUILD_NUMBER=${{ needs.setup.outputs.helios_build_number }}
export HELIOS_VERSION_NUMBER=${{ needs.setup.outputs.helios_version_number }}
make -j build
working-directory: HeliosEmbedded
- name: Archive HeliosEmbedded artifacts
run: zip -r "embedded-firmware.zip" .
Expand All @@ -71,3 +115,28 @@ jobs:
name: embedded-firmware
path: HeliosEmbedded/embedded-firmware.zip

wasm:
needs: [setup, build, tests, embedded]
runs-on: ubuntu-latest
steps:
- name: Checkout current repository
uses: actions/checkout@v4
- name: Update Package Lists
run: sudo apt-get update
- name: Install Emscripten
run: |
sudo apt install -y cmake python3
git clone https://github.com/emscripten-core/emsdk.git
cd emsdk
./emsdk install latest
./emsdk activate latest
working-directory: HeliosLib
- name: Build Webassembly
run: |
source ./emsdk/emsdk_env.sh
export HELIOS_VERSION_MAJOR=${{ needs.setup.outputs.helios_version_major }}
export HELIOS_VERSION_MINOR=${{ needs.setup.outputs.helios_version_minor }}
export HELIOS_BUILD_NUMBER=${{ needs.setup.outputs.helios_build_number }}
export HELIOS_VERSION_NUMBER=${{ needs.setup.outputs.helios_version_number }}
make -j wasm
working-directory: HeliosLib
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,5 @@

!*.md

!**/Makefile

2 changes: 1 addition & 1 deletion Helios/TimeControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ uint32_t Time::microseconds()
{
#ifdef HELIOS_CLI
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
clock_gettime(CLOCK_MONOTONIC, &ts);
uint64_t us = SEC_TO_US((uint64_t)ts.tv_sec) + NS_TO_US((uint64_t)ts.tv_nsec);
return (unsigned long)us;
#else
Expand Down
20 changes: 18 additions & 2 deletions HeliosCLI/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ CFLAGS=-O2 -g -Wall -std=c++11
# compiler defines
DEFINES=\
-D HELIOS_CLI \
-D HELIOS_VERSION_MAJOR=$(HELIOS_VERSION_MAJOR) \
-D HELIOS_VERSION_MINOR=$(HELIOS_VERSION_MINOR) \
-D HELIOS_BUILD_NUMBER=$(HELIOS_BUILD_NUMBER) \
-D HELIOS_VERSION_NUMBER=$(HELIOS_VERSION_NUMBER)

# compiler include paths
INCLUDES=\
Expand Down Expand Up @@ -84,8 +88,8 @@ all: $(TARGETS)
tests: $(TESTS)

# target for vortex lib
helios: $(DEPS)
$(CC) $(CFLAGS) $^ -o $@ $(LLIBS)
helios: compute_version $(DEPS)
$(CC) $(CFLAGS) $(DEPS) -o $@ $(LLIBS)

# catch-all make target to generate .o and .d files
%.o: %.cpp
Expand All @@ -105,6 +109,18 @@ FORCE:
clean:
@$(RM) $(DFILES) $(OBJS) $(TARGETS) $(TESTS)

compute_version:
$(eval LATEST_TAG ?= $(shell git fetch --depth=1 origin +refs/tags/*:refs/tags/* &> /dev/null && git tag --list | sort -V | tail -n1))
$(eval HELIOS_VERSION_MAJOR ?= $(shell echo $(LATEST_TAG) | cut -d. -f1))
$(eval HELIOS_VERSION_MINOR ?= $(shell echo $(LATEST_TAG) | cut -d. -f2))
$(eval LAST_HELIOS_BUILD_NUMBER ?= $(shell echo $(LATEST_TAG) | cut -d. -f3))
$(eval COMMITS_SINCE_TAG := $(shell git rev-list --count $(LATEST_TAG)..HEAD))
$(eval HELIOS_BUILD_NUMBER := $(shell echo $$(( $(LAST_HELIOS_BUILD_NUMBER) + $(COMMITS_SINCE_TAG) ))))
$(eval HELIOS_VERSION_MAJOR := $(if $(HELIOS_VERSION_MAJOR),$(HELIOS_VERSION_MAJOR),1))
$(eval HELIOS_VERSION_MINOR := $(if $(HELIOS_VERSION_MINOR),$(HELIOS_VERSION_MINOR),0))
$(eval HELIOS_BUILD_NUMBER := $(if $(HELIOS_BUILD_NUMBER),$(HELIOS_BUILD_NUMBER),0))
$(eval HELIOS_VERSION_NUMBER := $(HELIOS_VERSION_MAJOR).$(HELIOS_VERSION_MINOR).$(HELIOS_BUILD_NUMBER))

# generate svg
svgs: bmps
./generate_svgs.sh
Expand Down
10 changes: 6 additions & 4 deletions HeliosEmbedded/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -289,10 +289,12 @@ clean:
compute_version:
$(eval LATEST_TAG ?= $(shell git fetch --depth=1 origin +refs/tags/*:refs/tags/* &> /dev/null && git tag --list | sort -V | tail -n1))
$(eval HELIOS_VERSION_MAJOR ?= $(shell echo $(LATEST_TAG) | cut -d. -f1))
$(eval HELIOS_VERSION_MINOR ?= $(shell echo $(LATEST_TAG) | sed 's/$(BRANCH_SUFFIX)$$//' | cut -d. -f2))
$(eval HELIOS_BUILD_NUMBER ?= $(shell git rev-list --count $(LATEST_TAG)..HEAD))
$(eval HELIOS_VERSION_MAJOR := $(if $(HELIOS_VERSION_MAJOR),$(HELIOS_VERSION_MAJOR),0))
$(eval HELIOS_VERSION_MINOR := $(if $(HELIOS_VERSION_MINOR),$(HELIOS_VERSION_MINOR),1))
$(eval HELIOS_VERSION_MINOR ?= $(shell echo $(LATEST_TAG) | cut -d. -f2))
$(eval LAST_HELIOS_BUILD_NUMBER ?= $(shell echo $(LATEST_TAG) | cut -d. -f3))
$(eval COMMITS_SINCE_TAG := $(shell git rev-list --count $(LATEST_TAG)..HEAD))
$(eval HELIOS_BUILD_NUMBER := $(shell echo $$(( $(LAST_HELIOS_BUILD_NUMBER) + $(COMMITS_SINCE_TAG) ))))
$(eval HELIOS_VERSION_MAJOR := $(if $(HELIOS_VERSION_MAJOR),$(HELIOS_VERSION_MAJOR),1))
$(eval HELIOS_VERSION_MINOR := $(if $(HELIOS_VERSION_MINOR),$(HELIOS_VERSION_MINOR),0))
$(eval HELIOS_BUILD_NUMBER := $(if $(HELIOS_BUILD_NUMBER),$(HELIOS_BUILD_NUMBER),0))
$(eval HELIOS_VERSION_NUMBER := $(HELIOS_VERSION_MAJOR).$(HELIOS_VERSION_MINOR).$(HELIOS_BUILD_NUMBER))

Expand Down
166 changes: 166 additions & 0 deletions HeliosLib/HeliosLib.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
#include "HeliosLib.h"

// Helios includes
#include "Helios.h"
#include "Led.h"

#ifdef WASM
#include <emscripten/bind.h>
#include <emscripten/val.h>

using namespace emscripten;

// just need a non class function to bind to wasm here
static void init_helios() { HeliosLib::init(); }
static void cleanup_helios() { HeliosLib::cleanup(); }

// this is a spcial function that wraps tick then returns the current color of
// the leds as a javascript object 'value'
val tick_helios() {
// first run a tick
HeliosLib::tick();
// fetch led color
val color = val::object();
color.set("red", Led::get().red);
color.set("green", Led::get().green);
color.set("blue", Led::get().blue);
return color;
}

// js is dumb and has issues doing this cast I guess
PatternID intToPatternID(int val)
{
return (PatternID)val;
}

EMSCRIPTEN_BINDINGS(Vortex) {
// basic control functions
function("Init", &init_helios);
function("Cleanup", &cleanup_helios);
function("Tick", &tick_helios);

// Bind the HSVColor class
class_<HSVColor>("HSVColor")
.constructor<>()
.constructor<uint8_t, uint8_t, uint8_t>()
.constructor<uint32_t>()
.function("empty", &HSVColor::empty)
.function("clear", &HSVColor::clear)
.function("raw", &HSVColor::raw)
.property("hue", &HSVColor::hue)
.property("sat", &HSVColor::sat)
.property("val", &HSVColor::val);

// Bind the RGBColor class
class_<RGBColor>("RGBColor")
.constructor<>()
.constructor<uint8_t, uint8_t, uint8_t>()
.constructor<uint32_t>()
.function("empty", &RGBColor::empty)
.function("clear", &RGBColor::clear)
.function("adjustBrightness", &RGBColor::adjustBrightness)
.function("raw", &RGBColor::raw)
.property("red", &RGBColor::red)
.property("green", &RGBColor::green)
.property("blue", &RGBColor::blue);

// pattern id constants
enum_<PatternID>("PatternID")
.value("PATTERN_NONE", PatternID::PATTERN_NONE)
// Strobe
.value("PATTERN_RIBBON", PatternID::PATTERN_RIBBON)
.value("PATTERN_ULTRA_DOPS", PatternID::PATTERN_ULTRA_DOPS)
.value("PATTERN_DOPS", PatternID::PATTERN_DOPS)
.value("PATTERN_STROBE", PatternID::PATTERN_STROBE)
.value("PATTERN_HYPNOSTROBE", PatternID::PATTERN_HYPNOSTROBE)
.value("PATTERN_STROBIE", PatternID::PATTERN_STROBIE)
.value("PATTERN_RAZOR", PatternID::PATTERN_RAZOR)
.value("PATTERN_FLARE", PatternID::PATTERN_FLARE)
.value("PATTERN_BURST", PatternID::PATTERN_BURST)
.value("PATTERN_GLOW", PatternID::PATTERN_GLOW)
.value("PATTERN_FLICKER", PatternID::PATTERN_FLICKER)
.value("PATTERN_FLASH", PatternID::PATTERN_FLASH)
// Morph
.value("PATTERN_MORPH", PatternID::PATTERN_MORPH)
.value("PATTERN_MORPH_STROBE", PatternID::PATTERN_MORPH_STROBE)
.value("PATTERN_MORPH_STROBIE", PatternID::PATTERN_MORPH_STROBIE)
.value("PATTERN_MORPH_GLOW", PatternID::PATTERN_MORPH_GLOW)
// Dash
.value("PATTERN_DASH_DOPS", PatternID::PATTERN_DASH_DOPS)
.value("PATTERN_DASH_DOT", PatternID::PATTERN_DASH_DOT)
.value("PATTERN_WAVE_PARTICLE", PatternID::PATTERN_WAVE_PARTICLE)
.value("PATTERN_LIGHTSPEED", PatternID::PATTERN_LIGHTSPEED);

// colorset class
class_<Colorset>("Colorset")
.constructor<>()
.constructor<RGBColor, RGBColor, RGBColor, RGBColor, RGBColor, RGBColor, RGBColor, RGBColor>()
.constructor<uint8_t, const uint32_t *>()
.function("init", &Colorset::init)
.function("clear", &Colorset::clear)
.function("equals", select_overload<bool(const Colorset & set) const>(&Colorset::equals))
.function("get", &Colorset::get)
.function("set", &Colorset::set)
.function("skip", &Colorset::skip)
.function("cur", &Colorset::cur)
.function("setCurIndex", &Colorset::setCurIndex)
.function("resetIndex", &Colorset::resetIndex)
.function("curIndex", &Colorset::curIndex)
.function("getPrev", &Colorset::getPrev)
.function("getNext", &Colorset::getNext)
.function("peek", &Colorset::peek)
.function("peekNext", &Colorset::peekNext)
.function("numColors", &Colorset::numColors)
.function("onStart", &Colorset::onStart)
.function("onEnd", &Colorset::onEnd)
.function("addColor", select_overload<bool(RGBColor)>(&Colorset::addColor))
.function("addColorHSV", &Colorset::addColorHSV)
.function("adjustBrightness", &Colorset::adjustBrightness)
.function("removeColor", &Colorset::removeColor)
.function("operator[]", &Colorset::operator[]);

// pattern args class
class_<PatternArgs>("PatternArgs")
.property("on_dur", &PatternArgs::on_dur)
.property("off_dur", &PatternArgs::off_dur)
.property("gap_dur", &PatternArgs::gap_dur)
.property("dash_dur", &PatternArgs::dash_dur)
.property("group_size", &PatternArgs::group_size)
.property("blend_speed", &PatternArgs::blend_speed);

// pattern class
class_<Pattern>("Pattern")
.function("init", &Pattern::init)
.function("setArgs", &Pattern::setArgs)
.function("getArgs", select_overload<PatternArgs()>(&Pattern::getArgs))
.function("equals", &Pattern::equals, allow_raw_pointer<const Pattern *>())
.function("getColorset", select_overload<const Colorset() const>(&Pattern::getColorset))
.function("setColorset", &Pattern::setColorset)
.function("clearColorset", &Pattern::clearColorset)
.function("getFlags", &Pattern::getFlags)
.function("hasFlags", &Pattern::hasFlags);

// bind others as necessary
}
#endif

// Helios Lib code

bool HeliosLib::init()
{
if (!Helios::init()) {
return false;
}

return true;
}

void HeliosLib::cleanup()
{

}

void HeliosLib::tick()
{
Helios::tick();
}
15 changes: 15 additions & 0 deletions HeliosLib/HeliosLib.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

// Wrapper class around Helios as a whole, put high level apis that are used on
// desktop or in wasm but not in the core of Helios in this layer. Technically
// HeliosCLI would wrap this library to produce a CLI tool, but we already
// wrapped the Helios core so we should abstract some of that logic to here and
// simplify the CLI tool by just using this library directly
class HeliosLib
{
public:
static bool init();
static void cleanup();

static void tick();
};

Loading

0 comments on commit 67bd448

Please sign in to comment.