Skip to content

Commit

Permalink
Migrate to FreeRTOS for UI and camera control. (#126)
Browse files Browse the repository at this point in the history
Still using the Arduino framework, however we now use the underlying
FreeRTOS for better control over tasks.

Initially, split the UI and control to separate tasks, furthermore, use
a queue to manage camera control.
This almost allows the UI to operate without constraints on camera traffic.
  • Loading branch information
gkoh authored Sep 10, 2024
1 parent bbcd140 commit 8afb0e1
Show file tree
Hide file tree
Showing 12 changed files with 186 additions and 46 deletions.
19 changes: 19 additions & 0 deletions include/furble_control.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#ifndef FURBLE_CONTROL_H
#define FURBLE_CONTROL_H

#include <Camera.h>

#define CONTROL_CMD_QUEUE_LEN (32)

typedef enum {
CONTROL_CMD_SHUTTER_PRESS,
CONTROL_CMD_SHUTTER_RELEASE,
CONTROL_CMD_FOCUS_PRESS,
CONTROL_CMD_FOCUS_RELEASE,
CONTROL_CMD_GPS_UPDATE
} control_cmd_t;

void control_update_gps(Furble::Camera::gps_t &gps, Furble::Camera::timesync_t &timesync);
void control_task(void *param);

#endif
2 changes: 1 addition & 1 deletion include/furble_gps.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ extern TinyGPSPlus furble_gps;
extern bool furble_gps_enable;

void furble_gps_init(void);
void furble_gps_update_geodata(Furble::Camera *camera);
void furble_gps_update(Furble::Camera *camera);

#endif
2 changes: 2 additions & 0 deletions include/furble_ui.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ struct FurbleCtx {
bool reconnected;
};

void vUITask(void *param);

#endif
6 changes: 0 additions & 6 deletions lib/M5ez/src/M5ez.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -743,9 +743,6 @@ void ezSettings::begin() {
#ifdef M5EZ_BATTERY
ez.battery.begin();
#endif
#ifdef M5EZ_CLOCK
ez.clock.begin();
#endif
#ifdef M5EZ_BACKLIGHT
ez.backlight.begin();
#endif
Expand Down Expand Up @@ -1075,9 +1072,6 @@ void M5ez::yield() {
}
}
}
#ifdef M5EZ_CLOCK
events(); // TMP
#endif
}

void M5ez::addEvent(uint16_t (*function)(void *private_data),
Expand Down
8 changes: 8 additions & 0 deletions lib/furble/Camera.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ bool Camera::connect(esp_power_level_t power, progressFunc pFunc, void *pCtx) {
return connected;
}

bool Camera::isActive(void) {
return m_Active;
}

void Camera::setActive(bool active) {
m_Active = active;
}

const char *Camera::getName(void) {
return m_Name.c_str();
}
Expand Down
12 changes: 12 additions & 0 deletions lib/furble/Camera.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,16 @@ class Camera {
*/
virtual bool isConnected(void);

/**
* Camera is active (ie. connect() has succeeded previously).
*/
bool isActive(void);

/**
* Set camera activity state.
*/
void setActive(bool active);

const char *getName(void);

void fillSaveName(char *name);
Expand Down Expand Up @@ -115,6 +125,8 @@ class Camera {
const uint16_t m_Latency = 1;
// double the disconnect timeout
const uint16_t m_Timeout = (2 * BLE_GAP_INITIAL_SUPERVISION_TIMEOUT);

bool m_Active = false;
};
} // namespace Furble

Expand Down
76 changes: 41 additions & 35 deletions src/furble.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@

#include <M5Unified.h>

#include "furble_control.h"
#include "furble_gps.h"
#include "furble_ui.h"
#include "interval.h"
#include "settings.h"

const uint32_t SCAN_DURATION = (60 * 5);
static QueueHandle_t queue;

/**
* Progress bar update function.
Expand Down Expand Up @@ -75,11 +77,14 @@ static void remote_control(FurbleCtx *fctx) {
auto camera = fctx->camera;
static unsigned long shutter_lock_start_ms = 0;
static bool shutter_lock = false;
control_cmd_t cmd;

ESP_LOGI(LOG_TAG, "Remote Control");

show_shutter_control(false, 0);

ESP_LOGW(LOG_TAG, "queue = %p", queue);

do {
ez.yield();

Expand All @@ -91,7 +96,8 @@ static void remote_control(FurbleCtx *fctx) {
if (M5.BtnPWR.wasClicked() || M5.BtnC.wasPressed()) {
if (shutter_lock) {
// ensure shutter is released on exit
camera->shutterRelease();
cmd = CONTROL_CMD_SHUTTER_RELEASE;
xQueueSend(queue, &cmd, 0);
}
ESP_LOGI(LOG_TAG, "Exit shutter");
break;
Expand All @@ -101,16 +107,16 @@ static void remote_control(FurbleCtx *fctx) {
// release shutter if either shutter or focus is pressed
if (M5.BtnA.wasClicked() || M5.BtnB.wasClicked()) {
shutter_lock = false;
camera->shutterRelease();
cmd = CONTROL_CMD_SHUTTER_RELEASE;
xQueueSend(queue, &cmd, 0);
show_shutter_control(false, 0);
ESP_LOGI(LOG_TAG, "shutterRelease(unlock)");
} else {
show_shutter_control(true, shutter_lock_start_ms);
}
} else {
if (M5.BtnA.wasPressed()) {
camera->shutterPress();
ESP_LOGI(LOG_TAG, "shutterPress()");
cmd = CONTROL_CMD_SHUTTER_PRESS;
xQueueSend(queue, &cmd, 0);
continue;
}

Expand All @@ -122,21 +128,21 @@ static void remote_control(FurbleCtx *fctx) {
show_shutter_control(true, shutter_lock_start_ms);
ESP_LOGI(LOG_TAG, "shutter lock");
} else {
camera->shutterRelease();
ESP_LOGI(LOG_TAG, "shutterRelease()");
cmd = CONTROL_CMD_SHUTTER_RELEASE;
xQueueSend(queue, &cmd, 0);
}
continue;
}

if (M5.BtnB.wasPressed()) {
camera->focusPress();
ESP_LOGI(LOG_TAG, "focusPress()");
cmd = CONTROL_CMD_FOCUS_PRESS;
xQueueSend(queue, &cmd, 0);
continue;
}

if (M5.BtnB.wasReleased()) {
camera->focusRelease();
ESP_LOGI(LOG_TAG, "focusRelease()");
cmd = CONTROL_CMD_FOCUS_RELEASE;
xQueueSend(queue, &cmd, 0);
continue;
}
}
Expand All @@ -153,7 +159,7 @@ static uint16_t statusRefresh(void *private_data) {
auto camera = fctx->camera;

if (camera->isConnected()) {
furble_gps_update_geodata(camera);
furble_gps_update(camera);
return 500;
}

Expand Down Expand Up @@ -204,6 +210,7 @@ static void menu_remote(FurbleCtx *fctx) {
ez.removeEvent(statusRefresh);

fctx->camera->disconnect();
fctx->camera->setActive(false);
ez.backlight.inactivity(USER_SET);
}

Expand Down Expand Up @@ -255,11 +262,13 @@ static void menu_connect(bool scan) {

FurbleCtx fctx = {Furble::CameraList::get(i - 1), false};

ezProgressBar progress_bar(FURBLE_STR, {"Connecting ..."}, {""});
ezProgressBar progress_bar(FURBLE_STR, {std::string("Connecting to ") + fctx.camera->getName()},
{""});
if (fctx.camera->connect(settings_load_esp_tx_power(), &update_progress_bar, &progress_bar)) {
if (scan) {
Furble::CameraList::save(fctx.camera);
}
fctx.camera->setActive(true);
menu_remote(&fctx);
}
}
Expand Down Expand Up @@ -317,37 +326,34 @@ static void mainmenu_poweroff(void) {
M5.Power.powerOff();
}

void setup() {
Serial.begin(115200);
void vUITask(void *param) {
queue = static_cast<QueueHandle_t>(param);

#include <themes/dark.h>
#include <themes/default.h>
#include <themes/mono_furble.h>

ez.begin();
Furble::Device::init();
furble_gps_init();

Furble::Scan::init(settings_load_esp_tx_power());
}
while (true) {
size_t save_count = Furble::CameraList::getSaveCount();

void loop() {
size_t save_count = Furble::CameraList::getSaveCount();
ezMenu mainmenu(FURBLE_STR);
mainmenu.buttons({"OK", "down"});
if (save_count > 0) {
mainmenu.addItem("Connect", "", do_saved);
}
mainmenu.addItem("Scan", "", do_scan);
if (save_count > 0) {
mainmenu.addItem("Delete Saved", "", menu_delete);
}
mainmenu.addItem("Settings", "", menu_settings);
mainmenu.addItem("Power Off", "", mainmenu_poweroff);
mainmenu.downOnLast("first");

ezMenu mainmenu(FURBLE_STR);
mainmenu.buttons({"OK", "down"});
if (save_count > 0) {
mainmenu.addItem("Connect", "", do_saved);
do {
mainmenu.runOnce();
} while (Furble::CameraList::getSaveCount() == save_count);
}
mainmenu.addItem("Scan", "", do_scan);
if (save_count > 0) {
mainmenu.addItem("Delete Saved", "", menu_delete);
}
mainmenu.addItem("Settings", "", menu_settings);
mainmenu.addItem("Power Off", "", mainmenu_poweroff);
mainmenu.downOnLast("first");

do {
mainmenu.runOnce();
} while (Furble::CameraList::getSaveCount() == save_count);
}
58 changes: 58 additions & 0 deletions src/furble_control.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#include <CameraList.h>

#include "furble_control.h"

static QueueHandle_t queue;

static Furble::Camera::gps_t last_gps;
static Furble::Camera::timesync_t last_timesync;

void control_update_gps(Furble::Camera::gps_t &gps, Furble::Camera::timesync_t &timesync) {
last_gps = gps;
last_timesync = timesync;

control_cmd_t cmd = CONTROL_CMD_GPS_UPDATE;
xQueueSend(queue, &cmd, sizeof(control_cmd_t));
}

void control_task(void *param) {
queue = static_cast<QueueHandle_t>(param);

while (true) {
control_cmd_t cmd;
BaseType_t ret = xQueueReceive(queue, &cmd, pdMS_TO_TICKS(50));
if (ret == pdTRUE) {
for (size_t n = 0; n < Furble::CameraList::size(); n++) {
Furble::Camera *camera = Furble::CameraList::get(n);
if (!camera->isActive()) {
continue;
}

switch (cmd) {
case CONTROL_CMD_SHUTTER_PRESS:
camera->shutterPress();
ESP_LOGI(LOG_TAG, "shutterPress()");
break;
case CONTROL_CMD_SHUTTER_RELEASE:
ESP_LOGI(LOG_TAG, "shutterRelease()");
camera->shutterRelease();
break;
case CONTROL_CMD_FOCUS_PRESS:
ESP_LOGI(LOG_TAG, "focusPress()");
camera->focusPress();
break;
case CONTROL_CMD_FOCUS_RELEASE:
ESP_LOGI(LOG_TAG, "focusRelease()");
camera->focusRelease();
break;
case CONTROL_CMD_GPS_UPDATE:
ESP_LOGI(LOG_TAG, "updateGeoData()");
camera->updateGeoData(last_gps, last_timesync);
break;
default:
ESP_LOGE(LOG_TAG, "Invalid control command %d.", cmd);
}
}
}
}
}
5 changes: 3 additions & 2 deletions src/furble_gps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <M5ez.h>
#include <TinyGPS++.h>

#include "furble_control.h"
#include "furble_gps.h"
#include "settings.h"

Expand Down Expand Up @@ -51,7 +52,7 @@ static uint16_t service_grove_gps(void *private_data) {
/**
* Update geotag data.
*/
void furble_gps_update_geodata(Furble::Camera *camera) {
void furble_gps_update(Furble::Camera *camera) {
if (!furble_gps_enable) {
return;
}
Expand All @@ -65,7 +66,7 @@ void furble_gps_update_geodata(Furble::Camera *camera) {
furble_gps.date.day(), furble_gps.time.hour(),
furble_gps.time.minute(), furble_gps.time.second()};

camera->updateGeoData(dgps, timesync);
control_update_gps(dgps, timesync);
ez.header.draw("gps");
}
}
Expand Down
1 change: 0 additions & 1 deletion src/interval.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,6 @@ static void do_interval(FurbleCtx *fctx, interval_t *interval) {

do {
ez.yield();
furble_gps_update_geodata(camera);
now = millis();

if (fctx->reconnected) {
Expand Down
Loading

0 comments on commit 8afb0e1

Please sign in to comment.