Skip to content

Commit

Permalink
First version of UI.
Browse files Browse the repository at this point in the history
  • Loading branch information
dragomda committed Apr 20, 2024
1 parent 96b9f2a commit f4e005c
Show file tree
Hide file tree
Showing 16 changed files with 787 additions and 0 deletions.
87 changes: 87 additions & 0 deletions src/clinostat-ui/ClinostatControl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#ifndef CLINOSTAT_COTROL_H
#define CLINOSTAT_COTROL_H

#import "Motors.h"
#import "motor_settings.h"

// works with motor controls and provides a higher level interface
class ClinostatControl {
// these are the speeds of the frames in RPM unlike the speeds of the motors. The motor speeds will need to be adjusted taking
// into account the pulleys sizes.
float xSpeed = 9;

float ySpeed = 20;

IMotorControl* xMotor;

IMotorControl* yMotor;

public:

ClinostatControl(Motors* motors) {
this->xMotor = motors->get(X_MOTOR);
this->yMotor = motors->get(Y_MOTOR);
}

// set speeds and compensates for Y
void setSpeed(float xSpeed, float ySpeed) {
float adjustedXSpeed = xSpeed*xRatio;
float adjustedYSpeed = ySpeed*yRatio;
xMotor->setSpeed(adjustedXSpeed);
yMotor->setSpeed(adjustedYSpeed-adjustedXSpeed);
this->xSpeed = xSpeed;
this->ySpeed = ySpeed;
}

void setXSpeed(float targetSpeed) {
xMotor->setSpeed(targetSpeed*xRatio);
xSpeed = targetSpeed;
}

void startX() {
xMotor->enable();
}

void stopX() {
xMotor->disable();
}

float getXSpeed() {
return xSpeed;
}

void setYSpeed(float targetSpeed) {
yMotor->setSpeed(targetSpeed*yRatio);
ySpeed = targetSpeed;
}

void startY() {
yMotor->enable();
}

void stopY() {
yMotor->disable();
}

float getYSpeed() {
return ySpeed;
}

void start() {
if (xSpeed != 0.0 || ySpeed != 0.0) {
startX();
startY();
}
}

void stop() {
stopX();
stopY();
}

boolean canRun() {
return xSpeed != 0.0 || ySpeed != 0.0;
}
};

#endif
137 changes: 137 additions & 0 deletions src/clinostat-ui/ClinostatControlWidget.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
#include "extra/widgets/spinbox/lv_spinbox.h"

#ifndef CLINOSTAT_CONTROL_WIDGET_H
#define CLINOSTAT_CONTROL_WIDGET_H
#include "LVGLWidget.h"
#include "ClinostatControl.h"
#include "core/lv_obj_style.h"
#include "font/lv_font.h"
#include "misc/lv_style.h"

// allows controlling speed of clinostat axes
class ClinostatControlWidget : public LVGLWidget {
private:
ClinostatControl* control;

lv_obj_t* xSpeedSlider;

lv_obj_t* ySpeedSlider;

lv_obj_t* startStopButton;

volatile boolean running = false;

char* buttonLabel() {
if (running) {
return LV_SYMBOL_PAUSE;
} else if (control->canRun()) {
return LV_SYMBOL_PLAY;
} else {
return "Set speed please";
}
}

void updateStartStopButtonLabel() {
lv_obj_t* label = lv_obj_get_child(startStopButton, 0);
lv_label_set_text_fmt(label, buttonLabel());
}

public:
ClinostatControlWidget(ClinostatControl* control, LVGLWidget* parent)
: LVGLWidget(parent->getWidget(), parent->getWidget()) {
this->control = control;

// set style so we can reda the values
static lv_style_t style;
lv_style_init(&style);
lv_style_set_text_font(&style, &lv_font_montserrat_28);
lv_obj_add_style(widget, &style, 0);


// create x/y spins
xSpeedSlider = createSpinner(30, 5, (int)((double)control->getXSpeed() * 10.0));
ySpeedSlider = createSpinner(30, 80, (int)((double)control->getYSpeed() * 10.0));


// start/stop button
startStopButton = lv_btn_create(widget);
lv_obj_set_pos(startStopButton, 400, 80);
lv_obj_add_event_cb(startStopButton, startStopEventHandler, LV_EVENT_CLICKED, this);
lv_obj_t* label = lv_label_create(startStopButton);
lv_label_set_text(label, buttonLabel());
lv_obj_center(label);
}

lv_obj_t* createSpinner(int startX, int startY, int initialSpeed) {
lv_obj_t* xSpeedSlider = lv_spinbox_create(widget);

lv_obj_set_pos(xSpeedSlider, startX + 60, startY);
lv_spinbox_set_range(xSpeedSlider, -300, 300);
lv_spinbox_set_digit_format(xSpeedSlider, 3, 2);
lv_spinbox_step_prev(xSpeedSlider);
lv_spinbox_set_value(xSpeedSlider, initialSpeed);
lv_obj_add_event_cb(xSpeedSlider, xSpeedSliderEventCb, LV_EVENT_VALUE_CHANGED, this);
lv_coord_t h = lv_obj_get_height(xSpeedSlider);

lv_obj_t* btn = lv_btn_create(widget);
lv_obj_set_size(btn, h, h);
lv_obj_set_pos(btn, startX + 200, startY);
lv_obj_set_style_bg_img_src(btn, LV_SYMBOL_PLUS, 0);
lv_obj_add_event_cb(btn, lv_spinbox_increment_event_cb, LV_EVENT_ALL, xSpeedSlider);

btn = lv_btn_create(widget);
lv_obj_set_size(btn, h, h);
lv_obj_set_pos(btn, startX, startY);
lv_obj_set_style_bg_img_src(btn, LV_SYMBOL_MINUS, 0);
lv_obj_add_event_cb(btn, lv_spinbox_decrement_event_cb, LV_EVENT_ALL, xSpeedSlider);

return xSpeedSlider;
}

void updateSpeed() {
control->setSpeed(((float)lv_spinbox_get_value(xSpeedSlider))/10.0, ((float)lv_spinbox_get_value(ySpeedSlider))/10.0);
updateStartStopButtonLabel();
}

void toggleRunning() {
if (control->canRun()) {
running = !running;
updateStartStopButtonLabel();
if (running) {
control->start();
} else {
control->stop();
}
}
}


static void lv_spinbox_increment_event_cb(lv_event_t* e) {
lv_obj_t* spinbox = (lv_obj_t*)lv_event_get_user_data(e);
lv_event_code_t code = lv_event_get_code(e);
if (code == LV_EVENT_SHORT_CLICKED || code == LV_EVENT_LONG_PRESSED_REPEAT) {
lv_spinbox_increment(spinbox);
}
}

static void lv_spinbox_decrement_event_cb(lv_event_t* e) {
lv_obj_t* spinbox = (lv_obj_t*)lv_event_get_user_data(e);
lv_event_code_t code = lv_event_get_code(e);
if (code == LV_EVENT_SHORT_CLICKED || code == LV_EVENT_LONG_PRESSED_REPEAT) {
lv_spinbox_decrement(spinbox);
}
}

static void startStopEventHandler(lv_event_t* e) {
ClinostatControlWidget* ctrl = (ClinostatControlWidget*)lv_event_get_user_data(e);
ctrl->toggleRunning();
}


static void xSpeedSliderEventCb(lv_event_t* e) {
ClinostatControlWidget* ctrl = (ClinostatControlWidget*)lv_event_get_user_data(e);
ctrl->updateSpeed();
}
};

#endif
13 changes: 13 additions & 0 deletions src/clinostat-ui/IMotorControl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#ifndef I_MOTOR_CONTROL_H
#define I_MOTOR_CONTROL_H
// a motor control interface
class IMotorControl {
public:
virtual bool run() = 0;
virtual void updateSpeed(float delta) = 0;
virtual void setSpeed(float speed) = 0;
virtual void enable() = 0;
virtual void disable() = 0;
virtual void setEnablePin(uint8_t pin = 0xff);
};
#endif
19 changes: 19 additions & 0 deletions src/clinostat-ui/LVGLFlexView.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#ifndef LVGL_FLEX_VIEW_H
#define LVGL_FLEX_VIEW_H

#include "LVGLWidget.h"

class LVGLFlexView : public LVGLWidget {
public:
LVGLFlexView(LVGLWidget* parent)
: LVGLWidget(parent->getWidget(), parent->getWidget()) {

static lv_style_t style;
lv_style_init(&style);
lv_style_set_flex_flow(&style, LV_FLEX_FLOW_COLUMN);
lv_style_set_flex_main_place(&style, LV_FLEX_ALIGN_SPACE_EVENLY);
lv_style_set_layout(&style, LV_LAYOUT_FLEX);
lv_obj_add_style(parentWidget, &style, 0);
}
};
#endif
16 changes: 16 additions & 0 deletions src/clinostat-ui/LVGLScreen.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#ifndef LVGL_SCREEN_H
#define LVGL_SCREEN_H

#include "LVGLWidget.h"
#include "Arduino_H7_Video.h"
#include "Arduino_GigaDisplayTouch.h"

// the whole screen
class LVGLScreen : public LVGLWidget {
public:
LVGLScreen(Arduino_H7_Video* display)
: LVGLWidget(lv_scr_act()) {
lv_obj_set_size(widget, display->width(), display->height());
}
};
#endif
28 changes: 28 additions & 0 deletions src/clinostat-ui/LVGLTabView.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#ifndef LVGL_TAB_VIEW_H
#define LVGL_TAB_VIEW_H

#include "LVGLWidget.h"

// a tab view
class LVGLTabView : public LVGLWidget {
public:
LVGLTabView(LVGLWidget* parent)
: LVGLWidget(parent->getWidget()) {

widget = lv_tabview_create(lv_scr_act(), LV_DIR_LEFT, 80);

lv_obj_set_style_bg_color(widget, lv_palette_lighten(LV_PALETTE_RED, 2), 0);

lv_obj_t* tab_btns = lv_tabview_get_tab_btns(widget);
lv_obj_set_style_bg_color(tab_btns, lv_palette_darken(LV_PALETTE_GREY, 3), 0);
lv_obj_set_style_text_color(tab_btns, lv_palette_lighten(LV_PALETTE_GREY, 5), 0);
lv_obj_set_style_border_side(tab_btns, LV_BORDER_SIDE_RIGHT, LV_PART_ITEMS | LV_STATE_CHECKED);
lv_obj_clear_flag(lv_tabview_get_content(widget), LV_OBJ_FLAG_SCROLLABLE);
}

LVGLWidget* addTab(const char* name) {
return new LVGLWidget(this->getWidget(), lv_tabview_add_tab(widget, name));
}
};

#endif
30 changes: 30 additions & 0 deletions src/clinostat-ui/LVGLWidget.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#ifndef LVGL_WIDGET_H
#define LVGL_WIDGET_H

#include "lvgl.h"

// a generic widget
class LVGLWidget {

protected:
lv_obj_t* widget;
lv_obj_t* parentWidget;

public:
LVGLWidget(lv_obj_t* parentWidget) {
this->parentWidget = parentWidget;
this->widget = lv_obj_create(parentWidget);
}

LVGLWidget(lv_obj_t* parentWidget, lv_obj_t* widget) {
this->parentWidget = parentWidget;
this->widget = widget;
}


lv_obj_t* getWidget() {
return this->widget;
}
};

#endif
Loading

0 comments on commit f4e005c

Please sign in to comment.