Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
pguyot committed Nov 7, 2022
1 parent 00ab81d commit 6ce067b
Show file tree
Hide file tree
Showing 13 changed files with 534 additions and 3 deletions.
39 changes: 39 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# SPDX-License-Identifier: MIT
name: Build
on:
push:
pull_request:
workflow_dispatch:

jobs:
build:
runs-on: ubuntu-latest
container: espressif/idf:release-v4.4
steps:
- name: Checkout AtomVM
uses: actions/checkout@v3
with:
repository: pguyot/AtomVM
ref: w41/smp-support
path: AtomVM
- name: Checkout M5Unified
uses: actions/checkout@v3
with:
repository: m5stack/M5Unified
path: AtomVM/src/platform/esp32/components/
- name: Checkout M5GFX
uses: actions/checkout@v3
with:
repository: m5stack/M5GFX
path: AtomVM/src/platform/esp32/components/
- name: Checkout atomvm_m5
uses: actions/checkout@v3
with:
path: AtomVM/src/platform/esp32/components/
- name: Build with idf.py
shell: bash
working-directory: AtomVM/src/platforms/esp32/
run: |
. $IDF_PATH/export.sh
idf.py reconfigure
idf.py build
16 changes: 16 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# SPDX-License-Identifier: MIT

set(ATOMVM_M5_COMPONENT_SRCS
"nifs/atomvm_m5.cc"
)

idf_component_register(
SRCS ${ATOMVM_M5_COMPONENT_SRCS}
INCLUDE_DIRS "nifs/include"
PRIV_REQUIRES "libatomvm" "avm_sys" "main" "M5Unified"
)

idf_build_set_property(
LINK_OPTIONS "-Wl,--whole-archive ${CMAKE_CURRENT_BINARY_DIR}/lib${COMPONENT_NAME}.a -Wl,--no-whole-archive"
APPEND
)
9 changes: 9 additions & 0 deletions Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
menu "ATOMVM_M5 Configuration"

config AVM_M5_ENABLE
bool "Enable AtomVM M5 driver"
default y
help
Use this parameter to enable or disable the AtomVM M5 driver.

endmenu
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2022 Paul Guyot
Copyright (c) 2022 Paul Guyot <pguyot@kallisys.net>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
17 changes: 15 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,15 @@
# atomvm_m5
AtomVM support for M5
# AtomVM support for M5

This project is a port of M5Unified for the AtomVM platform.

## Installation

- Install ESP-IDF SDK 4.4
- Checkout [atomvm](https://github.com/AtomVM/AtomVM)
- Within `src/platform/esp32/components`, checkout [M5Unified](https://github.com/m5stack/M5Unified)
- Within `src/platform/esp32/components`, checkout [M5GFX](https://github.com/m5stack/M5GFX)
- Within `src/platform/esp32/components`, checkout this project
- Activate ESP-IDF environment and within `src/platform/esp32/` run `idf.py build`

## Usage

4 changes: 4 additions & 0 deletions component.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
COMPONENT_ADD_INCLUDEDIRS := nifs/include ../../main
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
COMPONENT_SRCDIRS := nifs
CXXFLAGS += -fno-rtti
276 changes: 276 additions & 0 deletions nifs/atomvm_m5.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
/* SPDX-License-Identifier: MIT */
#include <sdkconfig.h>

#ifdef CONFIG_AVM_M5_ENABLE

#include <stdlib.h>

#include <atomvm_m5.h>
#include <esp_log.h>
#include <esp_attr.h>
#include <context.h>
#include <defaultatoms.h>
#include <interop.h>
#include <nifs.h>
#include <term.h>
#include <memory.h>
#include <esp_system.h>

#include "esp32_sys.h"

//#define ENABLE_TRACE
#include "trace.h"

#include <M5Unified.h>

static term nif_begin(Context *ctx, int argc, term argv[])
{
UNUSED(argc);
auto cfg = M5.config();

#if defined ( ARDUINO )
cfg.serial_baudrate = 115200; // default=115200. if "Serial" is not needed, set it to 0.
#endif
cfg.clear_display = true; // default=true. clear the screen when begin.
cfg.output_power = true; // default=true. use external port 5V output.
cfg.internal_imu = true; // default=true. use internal IMU.
cfg.internal_rtc = true; // default=true. use internal RTC.
cfg.internal_spk = true; // default=true. use internal speaker.
cfg.internal_mic = true; // default=true. use internal microphone.
cfg.external_imu = true; // default=false. use Unit Accel & Gyro.
cfg.external_rtc = true; // default=false. use Unit RTC.
cfg.external_spk = false; // default=false. use SPK_HAT / ATOMIC_SPK
//cfg.external_spk_detail.omit_atomic_spk = true; // omit ATOMIC SPK
//cfg.external_spk_detail.omit_spk_hat = true; // omit SPK HAT
cfg.led_brightness = 64; // default= 0. system LED brightness (0=off / 255=max) (※ not NeoPixel)


M5.begin(cfg);

return OK_ATOM;
}

static term nif_get_board(Context *ctx, int argc, term argv[])
{
UNUSED(argc);

switch (M5.getBoard())
{
#if defined (CONFIG_IDF_TARGET_ESP32C3)
case m5::board_t::board_M5StampC3:
return globalcontext_make_atom(ctx, ATOM_STR("\x8", "stamp_c3"));
case m5::board_t::board_M5StampC3U:
return globalcontext_make_atom(ctx->global, ATOM_STR("\x9", "stamp_c3u"));
#else
case m5::board_t::board_M5Stack:
return globalcontext_make_atom(ctx->global, ATOM_STR("\x5", "stack"));
case m5::board_t::board_M5StackCore2:
return globalcontext_make_atom(ctx->global, ATOM_STR("\xB", "stack_core2"));
case m5::board_t::board_M5StickC:
return globalcontext_make_atom(ctx->global, ATOM_STR("\x7", "stick_c"));
case m5::board_t::board_M5StickCPlus:
return globalcontext_make_atom(ctx->global, ATOM_STR("\xB", "stick_cplus"));
case m5::board_t::board_M5StackCoreInk:
return globalcontext_make_atom(ctx->global, ATOM_STR("\x8", "core_ink"));
case m5::board_t::board_M5Paper:
return globalcontext_make_atom(ctx->global, ATOM_STR("\x5", "paper"));
case m5::board_t::board_M5Tough:
return globalcontext_make_atom(ctx->global, ATOM_STR("\x5", "tough"));
case m5::board_t::board_M5Station:
return globalcontext_make_atom(ctx->global, ATOM_STR("\x7", "station"));
case m5::board_t::board_M5Atom:
return globalcontext_make_atom(ctx->global, ATOM_STR("\x4", "atom"));
case m5::board_t::board_M5AtomPsram:
return globalcontext_make_atom(ctx->global, ATOM_STR("\xA", "atom_psram"));
case m5::board_t::board_M5AtomU:
return globalcontext_make_atom(ctx->global, ATOM_STR("\x6", "atom_u"));
case m5::board_t::board_M5TimerCam:
return globalcontext_make_atom(ctx->global, ATOM_STR("\xC", "timer_camera"));
case m5::board_t::board_M5StampPico:
return globalcontext_make_atom(ctx->global, ATOM_STR("\xA", "stamp_pico"));
#endif
default:
return UNDEFINED_ATOM;
}
}

static term nif_update(Context *ctx, int argc, term argv[])
{
UNUSED(argc);
UNUSED(argv);

M5.update();
return OK_ATOM;
}

static term nif_display_set_epd_mode(Context *ctx, int argc, term argv[])
{
UNUSED(argc);

M5.Display.setEpdMode(epd_mode_t::epd_fastest); // fastest but very-low quality.
return OK_ATOM;
}

static term nif_display_height(Context *ctx, int argc, term argv[])
{
UNUSED(argc);

return term_from_int32(M5.Display.height());
}

static term nif_display_width(Context *ctx, int argc, term argv[])
{
UNUSED(argc);

return term_from_int32(M5.Display.width());
}

static term nif_display_get_rotation(Context *ctx, int argc, term argv[])
{
UNUSED(argc);

return term_from_int32(M5.Display.getRotation());
}

static term nif_display_set_rotation(Context *ctx, int argc, term argv[])
{
UNUSED(argc);
VALIDATE_VALUE(argv[0], term_is_integer);

M5.Display.setRotation(term_to_int32(argv[0]));
return OK_ATOM;
}

static term nif_display_set_text_size(Context *ctx, int argc, term argv[])
{
UNUSED(argc);
VALIDATE_VALUE(argv[0], term_is_integer);

M5.Display.setTextSize(term_to_int32(argv[0]));
return OK_ATOM;
}

static term nif_display_start_write(Context *ctx, int argc, term argv[])
{
UNUSED(argc);
UNUSED(argv);

M5.Display.startWrite();

return OK_ATOM;
}

static term nif_display_end_write(Context *ctx, int argc, term argv[])
{
UNUSED(argc);
UNUSED(argv);

M5.Display.endWrite();

return OK_ATOM;
}

static term nif_display_fill_rect(Context *ctx, int argc, term argv[])
{
UNUSED(argc);
VALIDATE_VALUE(argv[0], term_is_integer);
VALIDATE_VALUE(argv[1], term_is_integer);
VALIDATE_VALUE(argv[2], term_is_integer);
VALIDATE_VALUE(argv[3], term_is_integer);
VALIDATE_VALUE(argv[4], term_is_integer);

M5.Display.fillRect(
term_to_int32(argv[0]),
term_to_int32(argv[1]),
term_to_int32(argv[2]),
term_to_int32(argv[3]),
term_to_int32(argv[4])
);

return OK_ATOM;
}

static term nif_display_print(Context *ctx, int argc, term argv[])
{
UNUSED(argc);
VALIDATE_VALUE(argv[0], term_is_binary);
unsigned long binLen = term_binary_size(argv[0]);
const char* bin = term_binary_data(argv[0]);
size_t r = M5.Display.write(bin, binLen);
return term_from_int(r);
}

static term nif_display_println(Context *ctx, int argc, term argv[])
{
size_t r = 0;
if (argc == 1) {
VALIDATE_VALUE(argv[0], term_is_binary);
unsigned long binLen = term_binary_size(argv[0]);
const char* bin = term_binary_data(argv[0]);
r = M5.Display.write(bin, binLen);
}
r += M5.Display.println();
return term_from_int(r);
}

static term nif_power_timer_sleep(Context *ctx, int argc, term argv[])
{
UNUSED(argc);
VALIDATE_VALUE(argv[0], term_is_integer);
M5.Power.timerSleep(term_to_int32(argv[0]));
return OK_ATOM;
}

static term nif_get_battery_level(Context *ctx, int argc, term argv[])
{
UNUSED(argc);
UNUSED(argv);
int32_t level = M5.Power.getBatteryLevel();
return term_from_int(level);
}

constexpr std::array<std::pair<const char*, const struct Nif>, 17> M5_NIFS = {{
{"m5:begin_/1", { { NIFFunctionType }, nif_begin }},
{"m5:get_board/0", { { NIFFunctionType }, nif_get_board }},
{"m5:update/0", { { NIFFunctionType }, nif_update }},

{"m5_display:set_epd_mode/1", { { NIFFunctionType }, nif_display_set_epd_mode }},
{"m5_display:height/0", { { NIFFunctionType }, nif_display_height }},
{"m5_display:width/0", { { NIFFunctionType }, nif_display_width }},
{"m5_display:set_rotation/1", { { NIFFunctionType }, nif_display_set_rotation }},
{"m5_display:get_rotation/0", { { NIFFunctionType }, nif_display_get_rotation }},
{"m5_display:set_text_size/1", { { NIFFunctionType }, nif_display_set_text_size }},
{"m5_display:start_write/0", { { NIFFunctionType }, nif_display_start_write }},
{"m5_display:end_write/0", { { NIFFunctionType }, nif_display_end_write }},
{"m5_display:fill_rect/5", { { NIFFunctionType }, nif_display_fill_rect }},
{"m5_display:print/1", { { NIFFunctionType }, nif_display_print }},
{"m5_display:println/1", { { NIFFunctionType }, nif_display_println }},
{"m5_display:println/0", { { NIFFunctionType }, nif_display_println }},

{"m5_power:timer_sleep/1", { { NIFFunctionType }, nif_power_timer_sleep }},
{"m5_power:get_battery_level/0", { { NIFFunctionType }, nif_get_battery_level }},
}};

//
// Component Nif Entrypoints
//

void m5_init(GlobalContext *global)
{
// no-op
}

const struct Nif *m5_get_nif(const char *nifname)
{
for (const auto& nif : M5_NIFS)
{
if (strcmp(nif.first, nifname) == 0) {
return &nif.second;
}
}
return NULL;
}

REGISTER_NIF_COLLECTION(m5, m5_init, m5_get_nif)

#endif
11 changes: 11 additions & 0 deletions nifs/include/atomvm_m5.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/* SPDX-License-Identifier: MIT */
#ifndef __ATOMVM_M5_H
#define __ATOMVM_M5_H

#include <globalcontext.h>
#include <nifs.h>

void atomvm_m5_init(GlobalContext *global);
const struct Nif *atomvm_m5_get_nif(const char *nifname);

#endif
6 changes: 6 additions & 0 deletions rebar.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{erl_opts, [debug_info]}.
{deps, [
]}.
{plugins, [
atomvm_rebar3_plugin
]}.
Loading

0 comments on commit 6ce067b

Please sign in to comment.