Skip to content

Commit

Permalink
Merge pull request #2737 from particle-iot/lfs_gcc/sc-125175
Browse files Browse the repository at this point in the history
Enable Ledger and filesystem APIs on GCC platform
  • Loading branch information
sergeuz authored Feb 19, 2024
2 parents ab3ef74 + 290a8ec commit 60838a7
Show file tree
Hide file tree
Showing 36 changed files with 1,352 additions and 36 deletions.
2 changes: 0 additions & 2 deletions build/platform-id.mk
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,6 @@ PLATFORM_MCU=gcc
PLATFORM_NET=gcc
ARCH=gcc
PRODUCT_DESC=GCC xcompile
# explicitly exclude platform headers
SPARK_NO_PLATFORM=1
DEFAULT_PRODUCT_ID=3
endif

Expand Down
4 changes: 2 additions & 2 deletions crypto/inc/mbedtls_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@
#include "platforms.h"

/* For new platforms the configuration file resides in hal */
#if PLATFORM_ID == PLATFORM_GCC || PLATFORM_ID == PLATFORM_NEWHAL
#if PLATFORM_ID == PLATFORM_NEWHAL
#include "mbedtls_config_default.h"
#else
#include "mbedtls_config_platform.h"
#endif /* PLATFORM_ID == PLATFORM_GCC || PLATFORM_ID == PLATFORM_NEWHAL */
#endif /* PLATFORM_ID == PLATFORM_NEWHAL */

#if defined(MODULAR_FIRMWARE) && MODULAR_FIRMWARE
#endif /* defined(MODULAR_FIRMWARE) && MODULAR_FIRMWARE */
Expand Down
9 changes: 5 additions & 4 deletions hal/shared/filesystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@

#include "filesystem_impl.h"

#include <lfs_util.h>
#include <lfs.h>

#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */

#include <lfs_util.h>
#include <lfs.h>

typedef enum filesystem_instance_t {
FILESYSTEM_INSTANCE_DEFAULT = 0,
FILESYSTEM_INSTANCE_ASSET_STORAGE = 1
Expand Down Expand Up @@ -67,7 +67,7 @@ int filesystem_unlock(filesystem_t* fs);
int filesystem_to_system_error(int error);

#ifdef __cplusplus
}
} // extern "C"

#define CHECK_FS(expr) \
({ \
Expand Down Expand Up @@ -98,6 +98,7 @@ struct FsLock {
filesystem_unlock(fs_);
}

// TODO: Rename this method to avoid confusion with filesystem_get_instance()
lfs_t* instance() const {
return &fs_->instance;
}
Expand Down
267 changes: 267 additions & 0 deletions hal/src/gcc/concurrent_hal.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
/*
* Copyright (c) 2024 Particle Industries, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/

#include <chrono>
#include <thread>
#include <mutex>
#include <cassert>

#include <boost/asio.hpp>

#include "concurrent_hal.h"

#include "system_error.h"
#include "logging.h"

namespace {

class IoService {
public:
void stop() {
work_.reset(); // Break the event loop
if (thread_.joinable()) {
thread_.join();
}
}

boost::asio::io_context& context() {
return ctx_;
}

static IoService* instance() {
static IoService s;
return &s;
}

private:
boost::asio::io_context ctx_;
boost::asio::executor_work_guard<boost::asio::io_context::executor_type> work_;
std::thread thread_;

IoService() :
work_(ctx_.get_executor()),
thread_([this]() { this->ctx_.run(); }) {
}

~IoService() {
stop();
}
};

class Timer {
public:
typedef void (*Callback)(os_timer_t timer);

Timer(unsigned period, Callback callback, bool oneShot = true, void* id = nullptr) :
d_(std::make_shared<Data>(this, period, callback, oneShot, id)) {
// Requirement for the period to be greater than 0 mimics the behavior of FreeRTOS' xTimerCreate():
// https://www.freertos.org/FreeRTOS-timers-xTimerCreate.html
if (!period || !callback) {
throw std::runtime_error("Invalid argument");
}
}

Timer(const Timer&) = delete;

~Timer() {
stop();
}

void start() {
std::lock_guard lock(d_->mutex);
cancel();
startTimer(d_);
d_->started = true;
}

void stop() {
std::lock_guard lock(d_->mutex);
cancel();
}

void setPeriod(unsigned period) {
// Requirement for the period to be greater than 0 mimics the behavior of FreeRTOS' xTimerChangePeriod():
// https://www.freertos.org/FreeRTOS-timers-xTimerChangePeriod.html
if (!period) {
throw std::runtime_error("Invalid argument");
}
std::lock_guard lock(d_->mutex);
cancel();
d_->period = period;
// xTimerChangePeriod() also starts the timer
startTimer(d_);
}

void setId(void* id) {
std::lock_guard lock(d_->mutex);
d_->timerId = id;
}

void* id() const {
std::lock_guard lock(d_->mutex);
return d_->timerId;
}

bool isStarted() {
std::lock_guard lock(d_->mutex);
return d_->started;
}

Timer& operator=(const Timer&) = delete;

private:
struct Data {
boost::asio::steady_timer timer;
std::recursive_mutex mutex;
Callback callback;
os_timer_t halInstance;
void* timerId;
unsigned period;
int stateId;
bool oneShot;
bool started;

Data(os_timer_t halInstance, unsigned period, Callback callback, bool oneShot, void* id) :
timer(IoService::instance()->context()),
callback(callback),
halInstance(halInstance),
timerId(id),
period(period),
stateId(0),
oneShot(oneShot),
started(false) {
}
};

std::shared_ptr<Data> d_;

void cancel() {
d_->timer.cancel();
d_->started = false;
// "Invalidate" any references to the timer's internal state
d_->stateId += 1;
}

static void startTimer(std::shared_ptr<Data> d) {
auto t = std::chrono::steady_clock::now() + std::chrono::milliseconds(d->period);
d->timer.expires_at(t);
d->timer.async_wait([d, stateId = d->stateId](const boost::system::error_code& err) {
std::lock_guard lock(d->mutex);
if (err || d->stateId != stateId) {
return;
}
if (d->oneShot) {
d->started = false;
}
assert(d->callback);
d->callback(d->halInstance);
if (d->stateId != stateId) {
return;
}
if (!d->oneShot) {
startTimer(d);
}
});
}
};

} // namespace

int os_timer_create(os_timer_t* timer, unsigned period, void (*callback)(os_timer_t timer), void* timer_id, bool one_shot,
void* /* reserved */) {
try {
assert(timer);
*timer = new Timer(period, callback, one_shot, timer_id);
return 0;
} catch (const std::exception& e) {
LOG(ERROR, "os_timer_create() failed: %s", e.what());
return SYSTEM_ERROR_UNKNOWN;
}
}

int os_timer_destroy(os_timer_t timer, void* /* reserved */) {
auto t = static_cast<Timer*>(timer);
delete t;
return 0;
}

int os_timer_change(os_timer_t timer, os_timer_change_t change, bool /* fromISR */, unsigned period, unsigned /* block */,
void* /* reserved */) {
try {
auto t = static_cast<Timer*>(timer);
assert(t);
switch (change) {
// xTimerStart() and xTimerReset() seem to behave exactly the same :thinking_face:
// https://www.freertos.org/FreeRTOS-timers-xTimerStart.html
// https://www.freertos.org/FreeRTOS-timers-xTimerReset.html
case OS_TIMER_CHANGE_START:
case OS_TIMER_CHANGE_RESET: {
t->start();
break;
}
case OS_TIMER_CHANGE_STOP: {
t->stop();
break;
}
case OS_TIMER_CHANGE_PERIOD: {
t->setPeriod(period);
break;
}
default:
return SYSTEM_ERROR_INVALID_ARGUMENT;
}
return 0;
} catch (const std::exception& e) {
LOG(ERROR, "os_timer_change() failed: %s", e.what());
return SYSTEM_ERROR_UNKNOWN;
}
}

int os_timer_set_id(os_timer_t timer, void* timer_id) {
try {
auto t = static_cast<Timer*>(timer);
assert(t);
t->setId(timer_id);
return 0;
} catch (const std::exception& e) {
LOG(ERROR, "os_timer_set_id() failed: %s", e.what());
return SYSTEM_ERROR_UNKNOWN;
}
}

int os_timer_get_id(os_timer_t timer, void** timer_id) {
try {
auto t = static_cast<Timer*>(timer);
assert(t && timer_id);
*timer_id = t->id();
return 0;
} catch (const std::exception& e) {
LOG(ERROR, "os_timer_get_id() failed: %s", e.what());
return SYSTEM_ERROR_UNKNOWN;
}
}

int os_timer_is_active(os_timer_t timer, void* /* reserved */) {
try {
auto t = static_cast<Timer*>(timer);
assert(t);
return t->isStarted();
} catch (const std::exception& e) {
LOG(ERROR, "os_timer_is_active() failed: %s", e.what());
return SYSTEM_ERROR_UNKNOWN;
}
}
2 changes: 1 addition & 1 deletion hal/src/gcc/core_hal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
#include <cstdarg>
#include <cstdint>
#include <iostream>
#include "filesystem.h"
#include "filesystem_util.h"
#include "service_debug.h"
#include "device_config.h"
#include "hal_platform.h"
Expand Down
9 changes: 8 additions & 1 deletion hal/src/gcc/device_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@

#include "device_config.h"
#include "core_msg.h"
#include "filesystem.h"
#include "filesystem_util.h"
#include "ota_flash_hal.h"
#include "../../../system/inc/system_info.h" // FIXME

#include <filesystem>
#include <cstdlib>
#include <fstream>
#include <istream>
Expand All @@ -36,6 +37,7 @@ using namespace particle;
using namespace particle::config;

namespace po = boost::program_options;
namespace fs = std::filesystem;

DeviceConfig deviceConfig;

Expand Down Expand Up @@ -108,6 +110,7 @@ class ConfigParser
("product_version", po::value<uint16_t>(&config.product_version)->default_value(0xffff), "the product version")
("describe", po::value<std::string>(&config.describe), "the filename containing the device description")
("protocol,p", po::value<ProtocolFactory>(&config.protocol)->default_value(PROTOCOL_NONE), "the cloud communication protocol to use")
("flash_file", po::value<std::string>(&config.flash_file), "the filename to use to store the contents of the external flash")
;

command_line_options.add(program_options).add(device_options);
Expand Down Expand Up @@ -369,5 +372,9 @@ void DeviceConfig::read(Configuration& config)
}
}

if (!config.flash_file.empty()) {
this->flash_file = fs::absolute(config.flash_file);
}

setLoggerLevel((LoggerOutputLevel)(NO_LOG_LEVEL - config.log_level));
}
3 changes: 2 additions & 1 deletion hal/src/gcc/device_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
#include <cstring>
#include <cstdint>

#include "filesystem.h"
#include "spark_protocol_functions.h"
#include "module_info.h"

Expand Down Expand Up @@ -256,6 +255,7 @@ struct Configuration
std::string device_key;
std::string server_key;
std::string describe;
std::string flash_file;
uint16_t log_level;
ProtocolFactory protocol;
uint16_t platform_id;
Expand All @@ -269,6 +269,7 @@ struct DeviceConfig
{
std::vector<std::string> argv;
particle::config::Describe describe;
std::string flash_file;
uint8_t device_id[12];
uint8_t device_key[1024];
uint8_t server_key[1024];
Expand Down
Loading

0 comments on commit 60838a7

Please sign in to comment.