Skip to content

Commit

Permalink
Merge pull request #90 from hollyhockberry/nativeBuild
Browse files Browse the repository at this point in the history
Support native environment in PlatformIO
  • Loading branch information
mongonta0716 authored Jan 3, 2024
2 parents accdb7b + cdf6ab8 commit e04d072
Show file tree
Hide file tree
Showing 14 changed files with 219 additions and 26 deletions.
51 changes: 51 additions & 0 deletions examples/PlatformIO_SDL/platformio.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html

[platformio]
default_envs = native

[env]
lib_extra_dirs=../../../
lib_deps = m5stack/M5Unified@^0.1.11

[env:native]
platform = native
build_type = debug
build_flags = -O0 -xc++ -std=c++14 -lSDL2
-I"/usr/local/include/SDL2" ; for intel mac homebrew SDL2
-L"/usr/local/lib" ; for intel mac homebrew SDL2
-I"${sysenv.HOMEBREW_PREFIX}/include/SDL2" ; for arm mac homebrew SDL2
-L"${sysenv.HOMEBREW_PREFIX}/lib" ; for arm mac homebrew SDL2

[env:native_m5stack]
extends = native
platform = native
build_flags = ${env:native.build_flags}
-DM5GFX_BOARD=board_M5Stack

[env:native_stickCPlus]
extends = native
platform = native
build_flags = ${env:native.build_flags}
-DM5GFX_SCALE=2
-DM5GFX_ROTATION=0
-DM5GFX_BOARD=board_M5StickCPlus

[esp32_base]
build_type = debug
platform = espressif32
board = esp32dev
upload_speed = 1500000
monitor_speed = 115200
monitor_filters = esp32_exception_decoder

[env:esp32_arduino]
extends = esp32_base
framework = arduino
28 changes: 28 additions & 0 deletions examples/PlatformIO_SDL/src/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include <M5Unified.h>
#include <Avatar.h>

using namespace m5avatar;

Avatar avatar;

void setup()
{
M5.begin();
avatar.init(); // start drawing

// adjust position
const auto r = avatar.getFace()->getBoundingRect();
const auto scale_w = M5.Display.width() / (float)r->getWidth();
const auto scale_h = M5.Display.height() / (float)r->getHeight();
const auto scale = std::min(scale_w, scale_h);
avatar.setScale(scale);
const auto offs_x = (r->getWidth() - M5.Display.width()) / 2;
const auto offs_y = (r->getHeight() - M5.Display.height()) / 2;
avatar.setPosition(-offs_y, -offs_x);
}

void loop()
{
// avatar's face updates in another thread
// so no need to loop-by-loop rendering
}
25 changes: 25 additions & 0 deletions examples/PlatformIO_SDL/src/sdl_main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include <M5GFX.h>
#if defined ( SDL_h_ )

void setup(void);
void loop(void);

__attribute__((weak))
int user_func(bool* running)
{
setup();
do
{
loop();
} while (*running);
return 0;
}

int main(int, char**)
{
// The second argument is effective for step execution with breakpoints.
// You can specify the time in milliseconds to perform slow execution that ensures screen updates.
return lgfx::Panel_sdl::main(user_func, 128);
}

#endif
12 changes: 8 additions & 4 deletions library.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,13 @@
}
],
"license": "MIT",
"dependencies": {
},
"dependencies": [
{
"name": "M5Unified",
"version": ">=0.1.11"
}
],
"version": "0.9.1",
"frameworks": "arduino",
"platforms": "espressif32"
"frameworks": ["arduino", "espidf", "*"],
"platforms": ["espressif32", "native"]
}
1 change: 1 addition & 0 deletions library.properties
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ category=Device Control
url=https://platformio.org/lib/show/4529/M5Stack-Avatar
architectures=esp32
includes=Avatar.h
depends=M5Unified
66 changes: 54 additions & 12 deletions src/Avatar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,54 @@
// license information.

#include "Avatar.h"

#ifndef PI
#define PI 3.1415926535897932384626433832795
#endif

namespace m5avatar {

unsigned int seed = 0;

#ifndef rand_r
#define init_rand() srand(seed)
#define _rand() rand()
#else
#define init_rand() ;
#define _rand() rand_r(&seed)
#endif

#ifdef SDL_h_
#define TaskResult() return 0
#define TaskDelay(ms) lgfx::delay(ms)
long random(long howbig) {
return std::rand() % howbig;
}
#else
#define TaskResult() vTaskDelete(NULL)
#define TaskDelay(ms) vTaskDelay(ms/portTICK_PERIOD_MS)
#endif

// TODO(meganetaaan): make read-only
DriveContext::DriveContext(Avatar *avatar) : avatar{avatar} {}

Avatar *DriveContext::getAvatar() { return avatar; }

TaskHandle_t drawTaskHandle;

void drawLoop(void *args) {
TaskResult_t drawLoop(void *args) {
DriveContext *ctx = reinterpret_cast<DriveContext *>(args);
Avatar *avatar = ctx->getAvatar();
while (avatar->isDrawing()) {
if (avatar->isDrawing()) {
avatar->draw();
}
vTaskDelay(10/portTICK_PERIOD_MS);
TaskDelay(10);
}
vTaskDelete(NULL);
TaskResult();
}

void facialLoop(void *args) {
TaskResult_t facialLoop(void *args) {
int c = 0;
DriveContext *ctx = reinterpret_cast<DriveContext *>(args);
Avatar *avatar = ctx->getAvatar();
Expand All @@ -38,17 +62,18 @@ void facialLoop(void *args) {
float vertical = 0.0f;
float horizontal = 0.0f;
float breath = 0.0f;
init_rand();
while (avatar->isDrawing()) {

if ((millis() - last_saccade_millis) > saccade_interval) {
vertical = rand_r(&seed) / (RAND_MAX / 2.0) - 1;
horizontal = rand_r(&seed) / (RAND_MAX / 2.0) - 1;
if ((lgfx::millis() - last_saccade_millis) > saccade_interval) {
vertical = _rand() / (RAND_MAX / 2.0) - 1;
horizontal = _rand() / (RAND_MAX / 2.0) - 1;
avatar->setGaze(vertical, horizontal);
saccade_interval = 500 + 100 * random(20);
last_saccade_millis = millis();
last_saccade_millis = lgfx::millis();
}

if ((millis()- last_blink_millis) > blink_interval) {
if ((lgfx::millis()- last_blink_millis) > blink_interval) {
if (eye_open) {
avatar->setEyeOpenRatio(1);
blink_interval = 2500 + 100 * random(20);
Expand All @@ -57,14 +82,14 @@ void facialLoop(void *args) {
blink_interval = 300 + 10 * random(20);
}
eye_open = !eye_open;
last_blink_millis = millis();
last_blink_millis = lgfx::millis();
}
c = (c + 1) % 100;
breath = sin(c * 2 * PI / 100.0);
avatar->setBreath(breath);
vTaskDelay(33/portTICK_PERIOD_MS);
TaskDelay(33);
}
vTaskDelete(NULL);
TaskResult();
}

Avatar::Avatar() : Avatar(new Face()) {}
Expand Down Expand Up @@ -100,6 +125,13 @@ void Avatar::addTask(TaskFunction_t f
, TaskHandle_t* const task_handle
, const BaseType_t core_id) {
DriveContext *ctx = new DriveContext(this);
#ifdef SDL_h_
if (task_handle == NULL) {
SDL_CreateThreadWithStackSize(f, name, stack_size, ctx);
} else {
*task_handle = SDL_CreateThreadWithStackSize(f, name, stack_size, ctx);
}
#else
// TODO(meganetaaan): set a task handler
xTaskCreateUniversal(f, /* Function to implement the task */
name, /* Name of the task */
Expand All @@ -108,6 +140,7 @@ void Avatar::addTask(TaskFunction_t f
priority, /* Priority of the task */
task_handle, /* Task handle. */
core_id); /* Core No*/
#endif
}

void Avatar::init(int colorDepth) {
Expand All @@ -118,11 +151,15 @@ void Avatar::init(int colorDepth) {
void Avatar::stop() { _isDrawing = false; }

void Avatar::suspend() {
#ifndef SDL_h_
vTaskSuspend(drawTaskHandle);
#endif
}

void Avatar::resume() {
#ifndef SDL_h_
vTaskResume(drawTaskHandle);
#endif
}

void Avatar::start(int colorDepth) {
Expand All @@ -132,6 +169,10 @@ void Avatar::start(int colorDepth) {

this->colorDepth = colorDepth;
DriveContext *ctx = new DriveContext(this);
#ifdef SDL_h_
drawTaskHandle = SDL_CreateThreadWithStackSize(drawLoop, "drawLoop", 2048, ctx);
SDL_CreateThreadWithStackSize(facialLoop, "facialLoop", 1024, ctx);
#else
// TODO(meganetaaan): keep handle of these tasks
xTaskCreateUniversal(drawLoop, /* Function to implement the task */
"drawLoop", /* Name of the task */
Expand All @@ -148,6 +189,7 @@ void Avatar::start(int colorDepth) {
2, /* Priority of the task */
NULL, /* Task handle. */
APP_CPU_NUM);
#endif
}

void Avatar::draw() {
Expand Down
16 changes: 16 additions & 0 deletions src/Avatar.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,26 @@
#include "Face.h"
#include <M5GFX.h>

#ifdef SDL_h_
typedef SDL_ThreadFunction TaskFunction_t;
typedef int BaseType_t;
typedef unsigned int UBaseType_t;
typedef SDL_Thread* TaskHandle_t;
typedef int TaskResult_t;
#define APP_CPU_NUM (1)
#else
typedef void TaskResult_t;
#endif

#ifndef APP_CPU_NUM
#define APP_CPU_NUM PRO_CPU_NUM
#endif

#ifndef ARDUINO
#include <string>
typedef std::string String;
#endif // ARDUINO

namespace m5avatar {
class Avatar {
private:
Expand Down
9 changes: 7 additions & 2 deletions src/Balloon.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
#include "DrawContext.h"
#include "Drawable.h"

#ifndef ARDUINO
#include <string>
typedef std::string String;
#endif // ARDUINO

const int16_t TEXT_HEIGHT = 8;
const int16_t TEXT_SIZE = 2;
const int16_t MIN_WIDTH = 40;
Expand Down Expand Up @@ -39,7 +44,7 @@ class Balloon final : public Drawable {
spi->setTextColor(primaryColor, backgroundColor);
spi->setTextDatum(MC_DATUM);
M5.Lcd.setFont(font);
int textWidth = M5.Lcd.textWidth(text);
int textWidth = M5.Lcd.textWidth(text.c_str());
int textHeight = TEXT_HEIGHT * TEXT_SIZE;
spi->fillEllipse(cx - 20, cy,textWidth + 2, textHeight * 2 + 2,
primaryColor);
Expand All @@ -49,7 +54,7 @@ class Balloon final : public Drawable {
backgroundColor);
spi->fillTriangle(cx - 60, cy - 40, cx - 10, cy - 10, cx - 40, cy - 10,
backgroundColor);
spi->drawString(text, cx - textWidth / 6 - 15, cy, font); // Continue printing from new x position
spi->drawString(text.c_str(), cx - textWidth / 6 - 15, cy, font); // Continue printing from new x position
}
};

Expand Down
1 change: 0 additions & 1 deletion src/BoundingRect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
// license information.

#include "BoundingRect.h"
#include <Arduino.h>

namespace m5avatar {
BoundingRect::BoundingRect(int16_t top, int16_t left)
Expand Down
2 changes: 1 addition & 1 deletion src/BoundingRect.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

#ifndef BOUNDINGRECT_H_
#define BOUNDINGRECT_H_
#include <Arduino.h>
#include <stdint.h>

namespace m5avatar {
class BoundingRect {
Expand Down
4 changes: 2 additions & 2 deletions src/ColorPalette.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,15 @@ uint16_t ColorPalette::get(const char* key) const {
} else {
// NOTE: if no value it returns BLACK(0x00) as the default value of the
// type(int)
Serial.printf("no color with the key %s\n", key);
M5_LOGI("no color with the key %s", key);
return TFT_BLACK;
}
}

void ColorPalette::set(const char* key, uint16_t value) {
auto itr = colors.find(key);
if (itr != colors.end()) {
Serial.println("Overwriting");
M5_LOGI("Overwriting");
}
itr->second = value;
}
Expand Down
4 changes: 4 additions & 0 deletions src/DrawContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
#include "Expression.h"
#include "Gaze.h"

#ifndef ARDUINO
#include <string>
typedef std::string String;
#endif // ARDUINO

namespace m5avatar {
enum BatteryIconStatus { discharging, charging, invisible, unknown };
Expand Down
Loading

0 comments on commit e04d072

Please sign in to comment.