first commit

This commit is contained in:
stuce-bot 2025-06-30 20:47:33 +02:00
commit 5893b00dd2
1669 changed files with 1982740 additions and 0 deletions

21
libraries/M5HAL/LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 M5Stack Technology CO LTD
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

21
libraries/M5HAL/README.md Normal file
View file

@ -0,0 +1,21 @@
# M5HAL
## Overview
HAL(Hardware Abstraction Layer) for M5 Products.
**UNDER DEVELOPMENT**
Currently, we are in a state of minimal cooperation with M5UnitUnified.
Please wait a little while as it will be modified in the future.
---
## 概要
M5 製品向けの HAL (ハードウェア抽象化レイヤ)です。
**開発中**
現在、M5UnitUnifiedとの連携は最小限の状態です。
今後改修されますので、今しばらくお待ちください。

View file

@ -0,0 +1,25 @@
{
"name": "M5HAL",
"description": "Hardware Abstraction Layer(HAL) for M5 Products",
"keywords": "M5HAL",
"authors": {
"name": "M5Stack",
"url": "http://www.m5stack.com"
},
"repository": {
"type": "git",
"url": "https://github.com/m5stack/M5HAL.git"
},
"dependencies": [],
"version": "0.0.2",
"frameworks": [
"arduino",
"espidf",
"*"
],
"platforms": [
"espressif32"
],
"headers": "M5HAL.hpp",
"license": "MIT"
}

View file

@ -0,0 +1,11 @@
name=M5HAL
version=0.0.2
author=M5Stack
maintainer=M5Stack
sentence=Hardware Abstraction Layer(HAL) for M5 Products
paragraph=M5Stack, M5Stack Core2, M5Stack CoreInk, M5StickC, M5StickC-Plus, M5Paper, M5Tough, M5ATOM, M5STAMP, M5Station, See more on http://M5Stack.com
category=Other
url=https://github.com/m5stack/M5HAL.git
architectures=esp32
includes=M5HAL.hpp
depends=

View file

@ -0,0 +1,16 @@
#include "M5HAL.hpp"
#include "m5_hal/bus/bus.inl"
#include "m5_hal/bus/i2c.inl"
#include "m5_hal/bus/spi.inl"
#define M5HAL_STATIC_MACRO_PATH_IMPL M5HAL_STATIC_MACRO_CONCAT(M5HAL_TARGET_PLATFORM_PATH, impl.inl)
#if M5HAL_TARGET_PLATFORM_NUMBER != 0
#include M5HAL_STATIC_MACRO_PATH_IMPL
#endif
// Arduino環境の場合のみ、Arduino用の実装を用意
#if M5HAL_FRAMEWORK_HAS_ARDUINO
#include "./m5_hal/frameworks/arduino/impl.inl"
#endif

View file

@ -0,0 +1,44 @@
#ifndef M5_HAL_HPP
#define M5_HAL_HPP
#include <M5Utility.hpp>
#include "./m5_hal/platform_checker.hpp"
#include "./m5_hal/framework_checker.hpp"
#include "./m5_hal/bus/i2c.hpp"
#include "./m5_hal/bus/spi.hpp"
#include "./m5_hal/bus/bus.hpp"
#include "./m5_hal/interface/gpio.hpp"
#define M5HAL_STATIC_MACRO_STRING(x) #x
// clang-format off
#define M5HAL_STATIC_MACRO_CONCAT(x, y) M5HAL_STATIC_MACRO_STRING(x/y)
// clang-format on
#define M5HAL_STATIC_MACRO_PATH_HEADER M5HAL_STATIC_MACRO_CONCAT(M5HAL_TARGET_PLATFORM_PATH, header.hpp)
#if M5HAL_TARGET_PLATFORM_NUMBER != 0
#include M5HAL_STATIC_MACRO_PATH_HEADER
#endif
#undef M5HAL_STATIC_MACRO_PATH_HEADER
// Arduinoフレームワークがある場合は準備
#if M5HAL_FRAMEWORK_HAS_ARDUINO
#include "./m5_hal/frameworks/arduino/header.hpp"
// 対象プラットフォームが特定されない場合は Arduino経由の実装を利用
#if 1 // M5HAL_TARGET_PLATFORM_NUMBER == 0
namespace m5 {
namespace hal {
using namespace frameworks::arduino;
}
} // namespace m5
#endif
#endif
#endif

View file

@ -0,0 +1,200 @@
#ifndef M5_HAL_BUS_HPP_
#define M5_HAL_BUS_HPP_
#include "../interface/gpio.hpp"
#include "../interface/io.hpp"
#include "../error.hpp"
#include <memory>
/*!
@namespace m5
@brief Toplevel namespace of M5
*/
namespace m5 {
namespace hal {
namespace bus {
struct Bus;
struct AccessConfig;
struct Accessor;
//-------------------------------------------------------------------------
// 通信バスの初期化に必要な条件を記述するため基底インターフェイス
struct BusConfig {
virtual ~BusConfig() = default;
virtual types::bus_type_t getBusType(void) const = 0;
types::periph_t periph;
};
//-------------------------------------------------------------------------
// 実際の通信に必要な条件を記述するための基底インターフェイス
struct AccessConfig {
virtual ~AccessConfig() = default;
virtual types::bus_type_t getBusType(void) const = 0;
void (*callback_begin)(Accessor*) = nullptr; // 通信開始時時に呼び出すコールバック関数
void (*callback_end)(Accessor*) = nullptr; // 通信終了時に呼び出すコールバック関数
};
//-------------------------------------------------------------------------
// 特定の通信相手との各種通信条件を記述するため基底インターフェイス
struct Accessor : public interface::io::Output, public interface::io::Input {
virtual ~Accessor(void) = default;
virtual types::bus_type_t getBusType(void) const = 0;
virtual const AccessConfig& getAccessConfig(void) const = 0;
Accessor(Bus& bus) : _bus{bus}
{
}
Bus& getBus(void) const
{
return _bus;
};
const BusConfig& getBusConfig(void) const;
virtual m5::stl::expected<void, m5::hal::error::error_t> startWrite(void)
{
return {};
}
virtual m5::stl::expected<void, m5::hal::error::error_t> startRead(void)
{
return {};
}
virtual m5::stl::expected<void, m5::hal::error::error_t> stop(void)
{
return {};
}
virtual m5::stl::expected<size_t, m5::hal::error::error_t> readLastNack(uint8_t* data, size_t len)
{
return readWithLastNackFlag(data, len, true);
}
virtual m5::stl::expected<size_t, m5::hal::error::error_t> readWithLastNackFlag(uint8_t* data, size_t len,
bool last_nack = false)
{
return read(data, len);
}
protected:
Bus& _bus;
};
template <typename TBusAccessInterface>
struct DefaultBusExtension {
DefaultBusExtension(TBusAccessInterface&)
{
}
};
template <typename TBus, typename TBusAccessInterface, typename TExtension = DefaultBusExtension<TBusAccessInterface>>
struct BusAccessor {
BusAccessor() = delete;
BusAccessor(TBus& bus, TBusAccessInterface& access) : _bus(bus), _access(access), _extension(access)
{
}
BusAccessor(const BusAccessor&) = delete;
BusAccessor& operator=(const BusAccessor&) = delete;
BusAccessor(BusAccessor&& other)
: _owner(other.owner), _bus(other.bus), _access(other.access), _extension(other.access)
{
other._owner = false;
}
void release()
{
if (this->_owner) {
this->_bus.release();
}
this->_owner = false;
}
BusAccessor& operator=(BusAccessor&& other)
{
this->release();
this->_owner = other._owner;
this->_bus = other._bus;
this->_access = other._access;
this->_extension = TExtension(this->_access);
other._owner = false;
}
/*
void read() { this->_access.read(this->_bus);}
void write() { this->_access.write(this->_bus); }
void transmit() { this->_access.transmit(this->_bus); }
*/
TExtension& extension()
{
return this->_extension;
}
~BusAccessor()
{
this->release();
}
protected:
bool _owner = true;
TBus& _bus;
TBusAccessInterface& _access;
TExtension _extension;
};
//-------------------------------------------------------------------------
// 通信バスの基底インターフェイス
struct Bus {
public:
virtual ~Bus() = default;
virtual types::bus_type_t getBusType(void) const = 0;
// initとreleaseはユーザーは直接呼ばない。 createBus / releaseBus経由で使用する。
virtual const BusConfig& getConfig(void) const = 0;
// バスの初期化
virtual error::error_t init(const BusConfig& config)
{
return error::error_t::NOT_IMPLEMENTED;
}
// バスの解放
virtual error::error_t release(void)
{
return error::error_t::NOT_IMPLEMENTED;
}
/// @note expectedは参照をサポートしていないのでポインタを含める形とした。
virtual m5::stl::expected<Accessor*, m5::hal::error::error_t> beginAccess(const AccessConfig& access_config) = 0;
virtual error::error_t endAccess(Accessor* Accessor)
{
if (Accessor && _Accessor.get() == Accessor) {
_Accessor.reset(nullptr);
return error::error_t::OK;
}
return error::error_t::INVALID_ARGUMENT;
}
// 無条件でバスをロックしたい場合に使用する
virtual m5::stl::expected<void, error::error_t> lock(void)
{
return m5::stl::make_unexpected(error::error_t::NOT_IMPLEMENTED);
}
virtual m5::stl::expected<void, error::error_t> unlock(void)
{
return m5::stl::make_unexpected(error::error_t::NOT_IMPLEMENTED);
}
protected:
std::unique_ptr<Accessor> _Accessor;
};
//-------------------------------------------------------------------------
// error::error_t Bus::beginAccess(const Accessor* Accessor) { return (Accessor->getBusType() != getBusType()) ?
// error::error_t::INVALID_ARGUMENT : error::error_t::OK; }
} // namespace bus
} // namespace hal
} // namespace m5
#endif

View file

@ -0,0 +1,15 @@
#include "bus.hpp"
namespace m5 {
namespace hal {
namespace bus {
const BusConfig& Accessor::getBusConfig(void) const
{
return _bus.getConfig();
}
} // namespace bus
} // namespace hal
} // namespace m5

View file

@ -0,0 +1,108 @@
#ifndef M5_HAL_BUS_I2C_HPP_
#define M5_HAL_BUS_I2C_HPP_
#include "./bus.hpp"
namespace m5 {
namespace hal {
namespace bus {
struct I2CBusConfig : public BusConfig {
types::bus_type_t getBusType(void) const override
{
return types::bus_type_t::I2C;
};
interface::gpio::Pin* pin_scl;
interface::gpio::Pin* pin_sda;
};
struct I2CMasterAccessConfig : public AccessConfig {
types::bus_type_t getBusType(void) const override
{
return types::bus_type_t::I2C;
};
uint32_t freq = 100000;
uint32_t timeout_msec = 1000;
uint16_t i2c_addr;
bool address_is_10bit = false;
};
namespace i2c {
struct I2CMasterAccessor : public Accessor {
I2CMasterAccessor(Bus& bus, const I2CMasterAccessConfig& access_config)
: Accessor{bus}, _access_config{access_config}
{
}
types::bus_type_t getBusType(void) const override
{
return types::bus_type_t::I2C;
};
const AccessConfig& getAccessConfig(void) const override
{
return _access_config;
}
m5::stl::expected<void, m5::hal::error::error_t> startWrite(void) override;
m5::stl::expected<void, m5::hal::error::error_t> startRead(void) override;
m5::stl::expected<void, m5::hal::error::error_t> stop(void) override;
// read with ack
m5::stl::expected<size_t, m5::hal::error::error_t> read(uint8_t* data, size_t len) override
{
return readWithLastNackFlag(data, len, false);
};
// virtual m5::stl::expected<size_t, m5::hal::error::error_t> readLastNack(uint8_t* data, size_t len) { return
// readWithLastNackFlag(data, len, true); } virtual m5::stl::expected<size_t, m5::hal::error::error_t>
// readWithLastNackFlag(uint8_t* data, size_t len, bool last_nack = false) = 0;
protected:
I2CMasterAccessConfig _access_config;
virtual m5::stl::expected<void, m5::hal::error::error_t> sendStartCondition(void);
virtual m5::stl::expected<void, m5::hal::error::error_t> sendStopCondition(void);
virtual m5::stl::expected<void, m5::hal::error::error_t> sendDummyClockWhileSdaLow(size_t count = 9);
virtual m5::stl::expected<void, m5::hal::error::error_t> waitClockStretch(uint_fast16_t msec);
};
class SoftwareI2CMasterAccessor : public I2CMasterAccessor {
public:
SoftwareI2CMasterAccessor(Bus& bus, const I2CMasterAccessConfig& access_config)
: I2CMasterAccessor{bus, access_config}
{
}
m5::stl::expected<size_t, m5::hal::error::error_t> write(const uint8_t* data, size_t len) override;
m5::stl::expected<size_t, m5::hal::error::error_t> readWithLastNackFlag(uint8_t* data, size_t len,
bool last_nack = false) override;
};
//-------------------------------------------------------------------------
struct I2CBus : public Bus {
types::bus_type_t getBusType(void) const override
{
return types::bus_type_t::I2C;
};
const BusConfig& getConfig(void) const override
{
return _config;
}
protected:
I2CBusConfig _config;
};
class SoftwareI2CBus : public I2CBus {
public:
error::error_t init(const BusConfig& config) override;
m5::stl::expected<Accessor*, m5::hal::error::error_t> beginAccess(const AccessConfig& access_config) override;
};
m5::stl::expected<I2CBus*, m5::hal::error::error_t> getBus(const I2CBusConfig& config);
} // namespace i2c
// static inline bus::I2CBus* createI2CBus(const bus::I2CBusConfig& config) { return i2c::createBus(config); }
} // namespace bus
} // namespace hal
} // namespace m5
#endif

View file

@ -0,0 +1,335 @@
#include "i2c.hpp"
#include "../error.hpp"
namespace m5 {
namespace hal {
namespace bus {
namespace i2c {
// constexpr uint32_t DELAY_CYCLE{400};
constexpr uint32_t DELAY_CYCLE{200};
void delayCycle(uint32_t count)
{
for (uint32_t i = count; i > 0; --i) {
__asm__ __volatile__("nop");
}
}
m5::stl::expected<I2CBus*, m5::hal::error::error_t> getBus(const I2CBusConfig& config)
{
// @TODO ソフトウェアSPIの複数のインスタンスを管理できるようにすること。
static SoftwareI2CBus bus;
bus.init(config);
return &bus;
}
error::error_t SoftwareI2CBus::init(const BusConfig& config)
{
if (config.getBusType() != types::bus_type_t::I2C) {
M5_LIB_LOGE("SoftwareI2C::init: error %s", __PRETTY_FUNCTION__);
return error::error_t::INVALID_ARGUMENT;
}
_config = static_cast<const I2CBusConfig&>(config);
if (_config.pin_scl == nullptr || _config.pin_sda == nullptr) {
M5_LIB_LOGE("SoftwareI2C::init: error %s", __PRETTY_FUNCTION__);
return error::error_t::INVALID_ARGUMENT;
}
M5_LIB_LOGV("SoftwareI2C::init: ok %s", __PRETTY_FUNCTION__);
_config.pin_scl->setMode(m5::hal::types::gpio_mode_t::Output_OpenDrain);
_config.pin_scl->writeLow();
_config.pin_sda->setMode(m5::hal::types::gpio_mode_t::Output_OpenDrain);
_config.pin_sda->writeLow();
_config.pin_scl->writeHigh();
delayCycle(128);
_config.pin_sda->writeHigh();
return error::error_t::OK;
}
m5::stl::expected<m5::hal::bus::Accessor*, m5::hal::error::error_t> SoftwareI2CBus::beginAccess(
const m5::hal::bus::AccessConfig& access_config)
{
/// @TODO ここで排他制御&ロック処理を行うこと。
if (_Accessor.get() != nullptr) {
M5_LIB_LOGE("SoftwareI2C::beginAccess: error %s", __PRETTY_FUNCTION__);
return m5::stl::make_unexpected(m5::hal::error::error_t::INVALID_ARGUMENT);
}
if (access_config.getBusType() != getBusType()) {
M5_LIB_LOGE("SoftwareI2C::beginAccess: error %s", __PRETTY_FUNCTION__);
return m5::stl::make_unexpected(m5::hal::error::error_t::INVALID_ARGUMENT);
}
auto result = new SoftwareI2CMasterAccessor(*this, (I2CMasterAccessConfig&)access_config);
_Accessor.reset(result);
M5_LIB_LOGV("SoftwareI2C::beginAccess: ok %s", __PRETTY_FUNCTION__);
return result;
}
m5::stl::expected<void, m5::hal::error::error_t> I2CMasterAccessor::sendDummyClockWhileSdaLow(size_t count)
{
auto bc = static_cast<const I2CBusConfig&>(getBusConfig());
auto sda = bc.pin_sda;
auto scl = bc.pin_scl;
/// SDAがLOWになっている場合は処理
if (!sda->read()) {
/// @TODO:ディレイサイクル数を求める仕組みを作っておくこと。
int delay_cycle = DELAY_CYCLE; //_nop_wait_w >> 1;
scl->writeLow();
sda->writeHigh();
delayCycle(delay_cycle);
// SDAがHIGHになるまでクロック送出しながら待機する。;
while (!(sda->read()) && (--count)) {
scl->writeHigh();
delayCycle(delay_cycle);
scl->writeLow();
delayCycle(delay_cycle);
}
}
if (count == 0) {
return m5::stl::make_unexpected(error::error_t::I2C_BUS_ERROR);
}
return {};
}
m5::stl::expected<void, m5::hal::error::error_t> I2CMasterAccessor::sendStartCondition(void)
{
auto bc = static_cast<const I2CBusConfig&>(getBusConfig());
auto sda = bc.pin_sda;
auto scl = bc.pin_scl;
/// @TODO:ディレイサイクル数を求める仕組みを作っておくこと。
int delay_cycle = DELAY_CYCLE; //_nop_wait_w >> 1;
// start condition
scl->writeHigh();
delayCycle(delay_cycle);
sda->writeLow();
delayCycle(delay_cycle);
scl->writeLow();
return {};
}
m5::stl::expected<void, m5::hal::error::error_t> I2CMasterAccessor::sendStopCondition(void)
{
auto bc = static_cast<const I2CBusConfig&>(getBusConfig());
auto sda = bc.pin_sda;
auto scl = bc.pin_scl;
/// @TODO:ディレイサイクル数を求める仕組みを作っておくこと。
int delay_cycle = DELAY_CYCLE; //_nop_wait_w >> 1;
auto res = sendDummyClockWhileSdaLow();
if (res.has_value()) {
// stop condition
sda->writeLow();
scl->writeHigh();
delayCycle(delay_cycle);
sda->writeHigh();
}
return res;
}
m5::stl::expected<void, m5::hal::error::error_t> I2CMasterAccessor::waitClockStretch(uint_fast16_t msec)
{
auto bc = static_cast<const I2CBusConfig&>(getBusConfig());
auto scl = bc.pin_scl;
auto ms = m5::utility::millis();
do {
std::this_thread::yield();
if (scl->read()) {
return {};
}
} while ((m5::utility::millis() - ms) < msec);
return m5::stl::make_unexpected(error::error_t::I2C_BUS_ERROR);
}
m5::stl::expected<void, m5::hal::error::error_t> I2CMasterAccessor::startWrite(void)
{
auto ac = static_cast<const I2CMasterAccessConfig&>(getAccessConfig());
sendStartCondition();
uint8_t data[] = {(uint8_t)(ac.i2c_addr << 1)};
auto result = write(data, sizeof(data));
if (result.has_value()) return {};
return m5::stl::make_unexpected(result.error());
}
m5::stl::expected<void, m5::hal::error::error_t> I2CMasterAccessor::startRead(void)
{
auto ac = static_cast<const I2CMasterAccessConfig&>(getAccessConfig());
sendStartCondition();
uint8_t data[] = {(uint8_t)(ac.i2c_addr << 1 | 1)};
auto result = write(data, sizeof(data));
if (result.has_value()) return {};
return m5::stl::make_unexpected(result.error());
}
m5::stl::expected<void, m5::hal::error::error_t> I2CMasterAccessor::stop(void)
{
return sendStopCondition();
}
m5::stl::expected<size_t, m5::hal::error::error_t> SoftwareI2CMasterAccessor::write(const uint8_t* data, size_t len)
{
auto bc = static_cast<const I2CBusConfig&>(getBusConfig());
auto ac = static_cast<const I2CMasterAccessConfig&>(getAccessConfig());
auto scl = bc.pin_scl;
auto sda = bc.pin_sda;
/// @TODO:ディレイサイクル数を求める仕組みを作っておくこと。
int delay_cycle = DELAY_CYCLE; //_nop_wait_w >> 1;
int_fast16_t dc0 = (delay_cycle) >> 2;
int_fast16_t dc1 = delay_cycle - dc0;
size_t result = 0;
do {
uint_fast8_t mask = 0x80;
uint_fast8_t d = *data++;
// 最初の1bitの送信
sda->write((bool)(d & mask));
delayCycle(dc0);
scl->writeHigh();
delayCycle(dc1);
// クロックストレッチの判定と待機;
if (!scl->read()) { // タイムアウト時間までクロックストレッチが解除されるのを待つ;
auto result = waitClockStretch(ac.timeout_msec);
if (!result) {
M5_LIB_LOGE("TIMEOUT");
sda->writeHigh();
return m5::stl::make_unexpected(error::error_t::TIMEOUT_ERROR);
}
}
mask >>= 1;
do { // 2bit~8bit目の送信;
scl->writeLow();
sda->write((bool)(d & mask));
delayCycle(dc0);
scl->writeHigh();
delayCycle(dc1);
mask >>= 1;
} while (mask);
// ACK応答チェック;
scl->writeLow(); // SCL lo
sda->writeHigh(); // SDA hi
delayCycle(dc1);
scl->writeHigh(); // hi
delayCycle(dc0);
// クロックストレッチの判定と待機;
if (!scl->read()) { // タイムアウト時間までクロックストレッチが解除されるのを待つ;
auto result = waitClockStretch(ac.timeout_msec);
if (!result) {
M5_LIB_LOGE("TIMEOUT2");
return m5::stl::make_unexpected(error::error_t::TIMEOUT_ERROR);
}
}
if (sda->read()) { // ToDo:ACK応答がない場合の処理;
M5_LIB_LOGE("NO_ACK");
{
// re-init?
scl->writeLow();
sda->writeLow();
scl->writeHigh();
delayCycle(128);
sda->writeHigh();
}
return m5::stl::make_unexpected(error::error_t::I2C_NO_ACK);
}
scl->writeLow();
} while (++result < len);
return result;
}
m5::stl::expected<size_t, m5::hal::error::error_t> SoftwareI2CMasterAccessor::readWithLastNackFlag(uint8_t* data,
size_t len,
bool last_nack)
{
auto bc = static_cast<const I2CBusConfig&>(getBusConfig());
auto ac = static_cast<const I2CMasterAccessConfig&>(getAccessConfig());
auto scl = bc.pin_scl;
auto sda = bc.pin_sda;
/// @TODO:ディレイサイクル数を求める仕組みを作っておくこと。
int delay_cycle = DELAY_CYCLE; //_nop_wait_w;
int_fast16_t dc0 = (delay_cycle) >> 1;
int_fast16_t dc1 = delay_cycle - dc0;
size_t result = 0;
do {
// 最初の1bitの受信
sda->writeHigh();
delayCycle(dc0);
scl->writeHigh();
delayCycle(dc1);
// クロックストレッチの判定と待機;
if (!scl->read()) { // タイムアウト時間までクロックストレッチが解除されるのを待つ;
if (!waitClockStretch(ac.timeout_msec)) {
return m5::stl::make_unexpected(error::error_t::TIMEOUT_ERROR);
}
}
uint_fast8_t mask = 0x80;
uint_fast8_t byte = sda->read() ? mask : 0;
mask >>= 1;
do {
scl->writeLow();
delayCycle(dc0);
scl->writeHigh();
delayCycle(dc1);
if (sda->read()) {
byte |= mask;
}
mask >>= 1;
} while (mask);
scl->writeLow();
/// ACKを返す (ただし、データ末尾かつNACK指定がある場合はACKを返さない);
if ((++result < len) || !last_nack) {
sda->writeLow();
}
delayCycle(dc0);
scl->writeHigh();
delayCycle(dc1);
scl->writeLow();
*data++ = byte;
} while (result < len);
return result;
}
// I2CBus* createBus(const I2CBusConfig& config)
// {
// static SoftwareI2CBus i2c_bus;
// return &i2c_bus;
// }
// error::error_t SoftwareI2CMasterAccessor::init(const interface::bus::BusConfig& config) { return
// error::error_t::NOT_IMPLEMENTED; } error::error_t SoftwareI2CMasterAccessor::release(void) { return
// error::error_t::NOT_IMPLEMENTED; } error::error_t SoftwareI2CMasterAccessor::start(void) { return
// error::error_t::NOT_IMPLEMENTED; } error::error_t SoftwareI2CMasterAccessor::stop(void) { return
// error::error_t::NOT_IMPLEMENTED; } error::error_t SoftwareI2CMasterAccessor::lock(void) { return
// error::error_t::NOT_IMPLEMENTED; } error::error_t SoftwareI2CMasterAccessor::unlock(void) { return
// error::error_t::NOT_IMPLEMENTED; } error::error_t SoftwareI2CMasterAccessor::beginAccess(interface::bus::Accessor*
// Accessor) { return error::error_t::NOT_IMPLEMENTED; } error::error_t SoftwareI2CMasterAccessor::endAccess(void) {
// return error::error_t::NOT_IMPLEMENTED; } error::error_t SoftwareI2CMasterAccessor::setFrequency(uint32_t freq) {
// return error::error_t::NOT_IMPLEMENTED; } error::error_t SoftwareI2CMasterAccessor::read(uint8_t* data, size_t len,
// interface::io::AsyncResult* async) { return error::error_t::NOT_IMPLEMENTED; } error::error_t
// SoftwareI2CMasterAccessor::write(const uint8_t* data, size_t len, interface::io::AsyncResult* async) { return
// error::error_t::NOT_IMPLEMENTED; }
} // namespace i2c
} // namespace bus
} // namespace hal
} // namespace m5

View file

@ -0,0 +1,137 @@
#ifndef M5_HAL_BUS_SPI_HPP_
#define M5_HAL_BUS_SPI_HPP_
#include "./bus.hpp"
namespace m5 {
namespace hal {
namespace bus {
/// @brief SPIバスの設定
/// @details 標準的なSPIだけでなく、QSPI,OSPIの設定も可能となっている
struct SPIBusConfig : public BusConfig {
virtual ~SPIBusConfig() = default;
types::bus_type_t getBusType(void) const override
{
return types::bus_type_t::SPI;
};
union {
interface::gpio::Pin* pins[9];
struct {
interface::gpio::Pin* pin_clk;
interface::gpio::Pin* pin_dc;
interface::gpio::Pin* pin_mosi; // data0
interface::gpio::Pin* pin_miso; // data1
interface::gpio::Pin* pin_d2; // data2
interface::gpio::Pin* pin_d3; // data3
interface::gpio::Pin* pin_d4; // data4
interface::gpio::Pin* pin_d5; // data5
interface::gpio::Pin* pin_d6; // data6
interface::gpio::Pin* pin_d7; // data7
};
};
};
enum class SpiDataMode {
spi_halfduplex, // 半二重通信
spi_fullduplex,
spi_halfduplex_with_dc_pin, // 半二重通信+DCピン
spi_fullduplex_with_dc_pin, // 全二重通信+DCピン
spi_halfduplex_with_dc_bit, // 半二重通信+DCビット(9ビットSPI)
spi_fullduplex_with_dc_bit, // 全二重通信+DCビット(9ビットSPI)
spi_dual_output,
spi_dual_io,
spi_quad_output,
spi_quad_io,
spi_octal_output,
spi_octal_io,
};
typedef SpiDataMode spi_data_mode_t;
struct SPIMasterAccessConfig : public AccessConfig {
virtual ~SPIMasterAccessConfig() = default;
types::bus_type_t getBusType(void) const override
{
return types::bus_type_t::SPI;
};
interface::gpio::Pin* pin_cs;
uint32_t freq;
spi_data_mode_t spi_data_mode;
struct {
uint8_t spi_mode : 2;
uint8_t spi_order : 1;
};
uint8_t spi_command_length = 0; // コマンド部のビット長
uint8_t spi_address_length = 0; // アドレス部のビット長
uint8_t spi_dummy_cycle = 0; // アドレスからデータへ移る際のダミーサイクル数
};
namespace spi {
struct SPIMasterAccessor : public Accessor {
SPIMasterAccessor(Bus& bus, const SPIMasterAccessConfig& access_config)
: Accessor{bus}, _access_config{access_config}
{
}
types::bus_type_t getBusType(void) const override
{
return types::bus_type_t::SPI;
};
const AccessConfig& getAccessConfig(void) const override
{
return _access_config;
}
virtual m5::stl::expected<size_t, m5::hal::error::error_t> writeCommand(const uint8_t* data, size_t len);
virtual m5::stl::expected<size_t, m5::hal::error::error_t> writeCommandData(const uint8_t* data, size_t len);
virtual m5::stl::expected<void, m5::hal::error::error_t> sendDummyClock(size_t count);
virtual m5::stl::expected<void, m5::hal::error::error_t> cs_control(bool cs_level);
protected:
SPIMasterAccessConfig _access_config;
};
class SoftwareSPIMasterAccessor : public SPIMasterAccessor {
public:
SoftwareSPIMasterAccessor(Bus& bus, const SPIMasterAccessConfig& access_config)
: SPIMasterAccessor{bus, access_config}
{
}
m5::stl::expected<size_t, m5::hal::error::error_t> read(uint8_t* data, size_t len) override;
m5::stl::expected<size_t, m5::hal::error::error_t> write(const uint8_t* data, size_t len) override;
};
//-------------------------------------------------------------------------
struct SPIBus : public Bus {
types::bus_type_t getBusType(void) const override
{
return types::bus_type_t::SPI;
};
const BusConfig& getConfig(void) const override
{
return _config;
}
// virtual SPIMasterAccessor* beginAccess(const SPIMasterAccessConfig& access_config) = 0;
// Accessor* beginAccess(const AccessConfig& access_config) override { return beginAccess((const
// SPIMasterAccessConfig&)access_config); }
protected:
SPIBusConfig _config;
};
class SoftwareSPIBus : public SPIBus {
public:
error::error_t init(const BusConfig& config) override;
m5::stl::expected<Accessor*, m5::hal::error::error_t> beginAccess(const AccessConfig& access_config) override;
// SPIMasterAccessor* beginAccess(const SPIMasterAccessConfig& access_config) override;
};
m5::stl::expected<SPIBus*, m5::hal::error::error_t> getBus(const SPIBusConfig& config);
// SPIBus* createBus(const SPIBusConfig& config); // { return spi::createBus(config); }
} // namespace spi
} // namespace bus
} // namespace hal
} // namespace m5
#endif

View file

@ -0,0 +1,145 @@
#include "spi.hpp"
namespace m5 {
namespace hal {
namespace bus {
namespace spi {
m5::stl::expected<SPIBus*, m5::hal::error::error_t> getBus(const SPIBusConfig& config)
{
// @TODO ソフトウェアSPIの複数のインスタンスを管理できるようにすること。
static SoftwareSPIBus spi_bus;
spi_bus.init(config);
return &spi_bus;
}
error::error_t SoftwareSPIBus::init(const BusConfig& config)
{
if (config.getBusType() != types::bus_type_t::SPI) {
M5_LIB_LOGE("SoftwareSPI::init: error %s", __PRETTY_FUNCTION__);
return error::error_t::INVALID_ARGUMENT;
}
_config = static_cast<const SPIBusConfig&>(config);
M5_LIB_LOGV("SoftwareSPI::init: ok %s", __PRETTY_FUNCTION__);
if (_config.pin_clk) {
_config.pin_clk->setMode(m5::hal::types::gpio_mode_t::Output);
}
if (_config.pin_dc) {
_config.pin_dc->setMode(m5::hal::types::gpio_mode_t::Output);
}
if (_config.pin_mosi) {
_config.pin_mosi->setMode(m5::hal::types::gpio_mode_t::Output);
}
if (_config.pin_miso) {
_config.pin_miso->setMode(m5::hal::types::gpio_mode_t::Input);
}
return error::error_t::OK;
}
m5::stl::expected<Accessor*, m5::hal::error::error_t> SoftwareSPIBus::beginAccess(const AccessConfig& access_config)
{
/// @TODO ここで排他制御&ロック処理を行うこと。
if (_Accessor.get() != nullptr) {
M5_LIB_LOGE("SoftwareSPI::beginAccess: error %s", __PRETTY_FUNCTION__);
return nullptr;
}
if (access_config.getBusType() != getBusType()) {
M5_LIB_LOGE("SoftwareSPI::beginAccess: error %s", __PRETTY_FUNCTION__);
return nullptr;
}
auto result = new SoftwareSPIMasterAccessor(*this, (const SPIMasterAccessConfig&)access_config);
_Accessor.reset(result);
M5_LIB_LOGV("SoftwareSPI::beginAccess: ok %s", __PRETTY_FUNCTION__);
return result;
}
m5::stl::expected<void, m5::hal::error::error_t> SPIMasterAccessor::sendDummyClock(size_t count)
{
if (count) {
auto bc = static_cast<const SPIBusConfig&>(getBusConfig());
auto ac = static_cast<const SPIMasterAccessConfig&>(getAccessConfig());
auto cpol = (ac.spi_mode & 2);
auto sclk = bc.pin_clk;
do {
sclk->write(!cpol);
sclk->write(cpol);
} while (--count);
}
return {};
}
m5::stl::expected<size_t, m5::hal::error::error_t> SPIMasterAccessor::writeCommand(const uint8_t* data, size_t len)
{
auto bc = static_cast<const SPIBusConfig&>(getBusConfig());
auto pin_dc = bc.pin_dc;
if (pin_dc) pin_dc->write(false);
auto res = write(data, len);
if (pin_dc) pin_dc->write(true);
return res;
}
m5::stl::expected<size_t, m5::hal::error::error_t> SPIMasterAccessor::writeCommandData(const uint8_t* data, size_t len)
{
auto bc = static_cast<const SPIBusConfig&>(getBusConfig());
auto pin_dc = bc.pin_dc;
auto ac = static_cast<const SPIMasterAccessConfig&>(getAccessConfig());
auto cmd_len = (ac.spi_command_length >> 3);
if (cmd_len) {
if (pin_dc) pin_dc->write(false);
auto res = write(data, cmd_len);
data += cmd_len;
auto datalen = len - cmd_len;
if (pin_dc) pin_dc->write(true);
if (!res || datalen == 0) return res;
res = write(data, datalen);
if (!res) {
return res;
}
return len;
}
return write(data, len);
}
m5::stl::expected<void, m5::hal::error::error_t> SPIMasterAccessor::cs_control(bool cs_level)
{
auto pin_cs = static_cast<const SPIMasterAccessConfig&>(getAccessConfig()).pin_cs;
if (pin_cs) pin_cs->write(cs_level);
return {};
}
m5::stl::expected<size_t, m5::hal::error::error_t> SoftwareSPIMasterAccessor::read(uint8_t* data, size_t len)
{
return m5::stl::make_unexpected(error::error_t::NOT_IMPLEMENTED);
}
m5::stl::expected<size_t, m5::hal::error::error_t> SoftwareSPIMasterAccessor::write(const uint8_t* data, size_t len)
{
auto bc = static_cast<const SPIBusConfig&>(getBusConfig());
auto ac = static_cast<const SPIMasterAccessConfig&>(getAccessConfig());
bool cpol = (ac.spi_mode & 2);
bool cpha = (ac.spi_mode & 1);
bool flip = cpol ^ cpha;
auto sclk = bc.pin_clk;
auto mosi = bc.pin_mosi;
size_t result = 0;
do {
uint_fast8_t mask = 0x80;
uint_fast8_t d = *data++;
do {
mosi->write(d & mask);
sclk->write(flip);
sclk->write(!flip);
} while (mask >>= 1);
} while (++result < len);
sclk->write(cpol);
return result;
}
} // namespace spi
} // namespace bus
} // namespace hal
} // namespace m5

View file

@ -0,0 +1,37 @@
#ifndef M5_HAL_ERROR_HPP
#define M5_HAL_ERROR_HPP
#include <stdint.h>
namespace m5 {
namespace hal {
namespace error {
enum class ErrorType : int8_t {
ASYNC_RUNNING = 1,
OK = 0,
UNKNOWN_ERROR = -1,
TIMEOUT_ERROR = -2,
INVALID_ARGUMENT = -3,
NOT_IMPLEMENTED = -4,
I2C_BUS_ERROR = -5,
I2C_NO_ACK = -6,
// @ TODO エラーコード細分化する
};
using error_t = ErrorType;
constexpr bool isError(const error_t e)
{
return e < error_t::OK;
}
constexpr bool isOk(const error_t e)
{
return e == error_t::OK;
}
} // namespace error
} // namespace hal
} // namespace m5
#endif

View file

@ -0,0 +1,22 @@
#ifndef M5_HAL_FRAMEWORK_CHECKER_HPP
#define M5_HAL_FRAMEWORK_CHECKER_HPP
#if defined(ARDUINO)
#define M5HAL_FRAMEWORK_HAS_ARDUINO 1
#else
#define M5HAL_FRAMEWORK_HAS_ARDUINO 0
#endif
#if __has_include(<FreeRTOS.h>) || __has_include(<freertos/FreeRTOS.h>)
#define M5HAL_FRAMEWORK_HAS_FREERTOS 1
#else
#define M5HAL_FRAMEWORK_HAS_FREERTOS 0
#endif
#if __has_include(<SDL2/SDL.h>) || __has_include(<SDL.h>)
#define M5HAL_FRAMEWORK_HAS_SDL 1
#else
#define M5HAL_FRAMEWORK_HAS_SDL 0
#endif
#endif

View file

@ -0,0 +1,79 @@
#ifndef M5_HAL_FRAMEWORKS_ARDUINO_HEADER_HPP
#define M5_HAL_FRAMEWORKS_ARDUINO_HEADER_HPP
#include "../../interface/gpio.hpp"
#include "../../bus/bus.hpp"
#if __has_include(<Arduino.h>)
#include <Arduino.h>
#include <Wire.h>
#endif
#if defined(ARDUINO)
namespace m5 {
namespace hal {
namespace frameworks {
namespace arduino {
namespace gpio {
// 単一のデジタルピンを表すインターフェイス
class Pin : public interface::gpio::Pin {
public:
void write(bool value) override;
void writeHigh(void) override;
void writeLow(void) override;
bool read(void) override;
void setMode(types::gpio_mode_t mode) override;
types::gpio_number_t getGpioNumber(void) const override
{
return _gpio_number;
}
Pin(void) = default;
Pin(types::gpio_number_t gpio_number) : _gpio_number{gpio_number}
{
}
protected:
types::gpio_number_t _gpio_number; // = (int16_t)-1;
};
// 複数のPinを束ねた概念を表すインターフェイス
class Port : public interface::gpio::Port {
public:
interface::gpio::Pin* getPin(uint8_t pinNumber) override;
// uint8_t getPortNumber(void) const override { return 0; }
// void setDirection(uint8_t mask, bool isOutput);
protected:
};
// ポートを含めてGPIO全体を表すインターフェイス
class GPIO : public interface::gpio::GPIO {
public:
interface::gpio::Port* getPort(uint8_t portNumber) override;
interface::gpio::Pin* getPin(types::gpio_number_t pinNumber) override;
private:
};
interface::gpio::GPIO* getGPIO(void);
interface::gpio::Pin* getPin(types::gpio_number_t pinNumber);
} // namespace gpio
namespace bus {
namespace i2c {
// bus::I2CBus* createBus(TwoWire& _wire);
} // namespace i2c
} // namespace bus
} // namespace arduino
} // namespace frameworks
} // namespace hal
} // namespace m5
#endif
#endif

View file

@ -0,0 +1,119 @@
#ifndef M5_HAL_PLATFORMS_ARDUINO_IMPL_INL
#define M5_HAL_PLATFORMS_ARDUINO_IMPL_INL
#include "../src/m5_hal/bus/bus.hpp"
#include <M5Utility.hpp>
#if __has_include(<Arduino.h>)
#include <Arduino.h>
#include <Wire.h>
#endif
#include <vector>
#include <list>
#if defined(ARDUINO)
namespace m5 {
namespace hal {
namespace frameworks {
namespace arduino {
namespace gpio {
interface::gpio::GPIO* getGPIO(void)
{
M5_LIB_LOGV("getGPIO\n");
static GPIO s_gpio_instance;
return &s_gpio_instance;
}
interface::gpio::Pin* getPin(types::gpio_number_t pinNumber)
{
M5_LIB_LOGV("getPin %d", pinNumber);
return getGPIO()->getPin(pinNumber);
}
interface::gpio::Port* GPIO::getPort(uint8_t portNumber)
{
static Port s_port_instance;
return &s_port_instance;
}
interface::gpio::Pin* GPIO::getPin(types::gpio_number_t pinNumber)
{
M5_LIB_LOGV("GPIO::getPin %d", pinNumber);
return getPort(0)->getPin(pinNumber);
}
interface::gpio::Pin* Port::getPin(uint8_t pinNumber)
{
static std::vector<Pin*> s_pins_pointer;
static std::list<Pin> s_pins_instance;
if (s_pins_pointer.size() <= pinNumber) {
s_pins_pointer.resize(pinNumber + 1);
}
if (s_pins_pointer[pinNumber] == nullptr) {
s_pins_instance.push_back(Pin(pinNumber));
s_pins_pointer[pinNumber] = &s_pins_instance.back();
}
return s_pins_pointer[pinNumber];
}
void Pin::write(bool value)
{
// M5_LIB_LOGV("Pin::write %d [pin %d]", value, _gpio_number);
digitalWrite(_gpio_number, value);
}
bool Pin::read(void)
{
return digitalRead(_gpio_number);
}
void Pin::writeHigh(void)
{
// M5_LIB_LOGV("Pin::setHigh [pin %d]", _gpio_number);
digitalWrite(_gpio_number, true);
}
void Pin::writeLow(void)
{
// M5_LIB_LOGV("Pin::setLow [pin %d]", _gpio_number);
digitalWrite(_gpio_number, false);
}
void Pin::setMode(types::gpio_mode_t mode)
{
switch (mode) {
case types::gpio_mode_t::Input:
pinMode(_gpio_number, INPUT);
break;
case types::gpio_mode_t::Output:
pinMode(_gpio_number, OUTPUT);
break;
case types::gpio_mode_t::Output_OpenDrain:
pinMode(_gpio_number, OUTPUT_OPEN_DRAIN);
break;
default:
break;
}
}
} // namespace gpio
namespace bus {
namespace i2c {
// interface::bus::I2C* createBus(TwoWire& _wire)
// {
// return nullptr;
// }
} // namespace i2c
} // namespace bus
//
} // namespace arduino
} // namespace frameworks
} // namespace hal
} // namespace m5
#endif
#endif

View file

@ -0,0 +1,18 @@
#ifndef M5_HAL_GPIO_GPIO_HPP_
#define M5_HAL_GPIO_GPIO_HPP_
#include "../interface/gpio.hpp"
#include <stdint.h>
#include <stddef.h>
namespace m5 {
namespace hal {
namespace gpio {
class GPIO { /* Empty*/
};
}; // namespace gpio
} // namespace hal
} // namespace m5
#endif

View file

@ -0,0 +1,93 @@
#ifndef M5_HAL_INTERFACE_GPIO_HPP
#define M5_HAL_INTERFACE_GPIO_HPP
#include "../types.hpp"
#include <vector>
/*!
@namespace m5
@brief Toplevel namespace of M5
*/
namespace m5 {
namespace hal {
namespace interface {
// 抽象化されたGPIOインターフェースを置く。これは LowLayerではなく汎用的なもの。
// このGPIOインターフェースを継承してGPIOエキスパンダの実装を作ることもできる。
namespace gpio {
// 単一のデジタルピンを表すインターフェイス
struct Pin {
virtual ~Pin() = default;
virtual void write(bool value) = 0;
virtual bool read(void) = 0;
virtual void writeHigh(void)
{
write(true);
}
virtual void writeLow(void)
{
write(false);
}
virtual types::gpio_number_t getGpioNumber(void) const = 0;
virtual void setMode(types::gpio_mode_t mode) = 0;
};
// 複数のPinを保持する概念を表すインターフェイス
struct Port {
virtual ~Port() = default;
virtual Pin* getPin(uint8_t pinNumber) = 0;
// virtual uint8_t getPortNumber(void) const = 0;
};
// Portを複数含むGPIO全体を表すインターフェイス
struct GPIO {
virtual ~GPIO() = default;
virtual Port* getPort(uint8_t portNumber) = 0;
virtual Pin* getPin(types::gpio_number_t gpioNumber) = 0;
virtual void digitalWrite(types::gpio_number_t gpioNumber, bool value)
{
getPin(gpioNumber)->write(value);
}
virtual bool digitalRead(types::gpio_number_t gpioNumber)
{
return getPin(gpioNumber)->read();
}
virtual int analogRead(types::gpio_number_t gpioNumber)
{
return -1;
}
};
// n個のピンを内包するポート (例: 2個ならGROVEコネクタ、等)
// コンストラクタにてピンの数を指定する。生成後のサイズ変更は不可とする。
// 暫定的に std::vector でポインタを保持するが、将来的にはメモリ効率を考慮して変更する可能性あり。
class MultiPinPort : public Port {
public:
MultiPinPort(size_t size) : _pins{size, nullptr}
{
}
Pin* getPin(uint8_t pinNumber) override
{
return _pins.size() > pinNumber ? _pins[pinNumber] : nullptr;
}
void setPin(uint8_t pinNumber, Pin* pin)
{
if (_pins.size() > pinNumber) _pins[pinNumber] = pin;
}
size_t getPinCount(void) const
{
return _pins.size();
}
protected:
std::vector<Pin*> _pins;
};
} // namespace gpio
} // namespace interface
} // namespace hal
} // namespace m5
#endif

View file

@ -0,0 +1,88 @@
#ifndef M5_HAL_INTERFACE_IO_HPP_
#define M5_HAL_INTERFACE_IO_HPP_
#include "../error.hpp"
#include "../types.hpp"
#include <M5Utility.hpp>
#include <future>
/*!
@namespace m5
@brief Toplevel namespace of M5
*/
namespace m5 {
namespace hal {
namespace interface {
namespace io {
// struct AsyncParam {
// public:
// // タイムアウト時間を設定する変数 (呼び出し側が設定しておく。0なら処理を終えるかエラーになるまで無限待ち)
// uint32_t timeout_ms;
// // read/writeの結果得られた長さを格納する変数
// size_t length;
// // 処理の結果を格納する変数 (ASYNC_RUNNINGの場合はまだ処理中)
// error::error_t error;
// };
struct Input {
public:
virtual ~Input() = default;
// @param data 読み込んだデータを格納するバッファ
// @param len 読み込むデータの長さ
// @return 読み込んだデータの長さ / エラー
virtual m5::stl::expected<size_t, m5::hal::error::error_t> read(uint8_t* data, size_t len) = 0;
// virtual std::future<m5::stl::expected<size_t, m5::hal::error::error_t> > asyncRead(uint8_t* data, size_t len,
// AsyncParam* async = nullptr) = 0;
virtual m5::stl::expected<size_t, m5::hal::error::error_t> availableRead(void) const
{
return m5::stl::make_unexpected(error::error_t::NOT_IMPLEMENTED);
};
};
struct Output {
public:
virtual ~Output() = default;
virtual m5::stl::expected<size_t, m5::hal::error::error_t> write(const uint8_t* data, size_t len) = 0;
// virtual std::future<m5::stl::expected<size_t, m5::hal::error::error_t> > asyncWrite(const uint8_t* data, size_t
// len, AsyncParam* async = nullptr) = 0;
virtual m5::stl::expected<size_t, m5::hal::error::error_t> availableWrite(void) const
{
return m5::stl::make_unexpected(error::error_t::NOT_IMPLEMENTED);
};
};
// Push型の入力はデータが一定量たまったらコールバックが呼ばれ、readで取得する
struct PushInput : public Input {
public:
virtual ~PushInput() = default;
virtual m5::stl::expected<void, m5::hal::error::error_t> setCallbackRead(void (*cb)(PushInput* bus,
size_t available_len,
void* cb_obj)) = 0;
};
// Push型の出力は新しいデータが必要になったらコールバックが呼ばれ、writeで書き込む
struct PushOutput : public Output {
public:
virtual ~PushOutput() = default;
virtual m5::stl::expected<void, m5::hal::error::error_t> setCallbackWrite(void (*cb)(PushOutput* bus,
size_t request_len,
void* cb_obj)) = 0;
};
} // namespace io
} // namespace interface
} // namespace hal
} // namespace m5
#endif

View file

@ -0,0 +1,67 @@
#ifndef M5_HAL_PLATFORM_CHECKER_HPP
#define M5_HAL_PLATFORM_CHECKER_HPP
#define M5HAL_PLATFORM_NUMBER_UNKNOWN 0
#define M5HAL_PLATFORM_NUMBER_WINDOWS 10
#define M5HAL_PLATFORM_NUMBER_MACOS 20
#define M5HAL_PLATFORM_NUMBER_LINUX 30
#define M5HAL_PLATFORM_NUMBER_SDL_MAX 99
#define M5HAL_PLATFORM_NUMBER_AVR 200
#define M5HAL_PLATFORM_NUMBER_ESP8266 300
#define M5HAL_PLATFORM_NUMBER_ESP32_UNKNOWN 310
#define M5HAL_PLATFORM_NUMBER_ESP32_1st 311
#define M5HAL_PLATFORM_NUMBER_ESP32_S2 312
#define M5HAL_PLATFORM_NUMBER_ESP32_S3 313
#define M5HAL_PLATFORM_NUMBER_ESP32_C3 314
#define M5HAL_PLATFORM_NUMBER_ESP32_C6 315
#define M5HAL_PLATFORM_NUMBER_ESP32_P4 316
#define M5HAL_PLATFORM_NUMBER_RP2040 400
#define M5HAL_PLATFORM_NUMBER_SAMD21 500
#define M5HAL_PLATFORM_NUMBER_SAMD51 510
#define M5HAL_PLATFORM_NUMBER_SPRESENSE 600
#define M5HAL_PLATFORM_NUMBER_STM32 700
#define XSTR(x) STR(x)
#define STR(x) #x
#if defined(ESP_PLATFORM)
#if __has_include(<sdkconfig.h>)
#include <sdkconfig.h>
#endif
// clang-format off
#if defined(CONFIG_IDF_TARGET)
#if defined(CONFIG_IDF_TARGET_ESP32C3)
#define M5HAL_TARGET_PLATFORM_NUMBER M5HAL_PLATFORM_NUMBER_ESP32C3
#define M5HAL_TARGET_PLATFORM_PATH m5_hal/platforms/espressif/esp32c3
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
#define M5HAL_TARGET_PLATFORM_NUMBER M5HAL_PLATFORM_NUMBER_ESP32S3
#define M5HAL_TARGET_PLATFORM_PATH m5_hal/platforms/espressif/esp32s3
#elif defined(CONFIG_IDF_TARGET_ESP32)
#define M5HAL_TARGET_PLATFORM_NUMBER M5HAL_PLATFORM_NUMBER_ESP32_1st
#define M5HAL_TARGET_PLATFORM_PATH m5_hal/platforms/espressif/esp32
#elif defined(CONFIG_IDF_TARGET_ESP32C6)
#define M5HAL_TARGET_PLATFORM_NUMBER M5HAL_PLATFORM_NUMBER_ESP32_C6
#define M5HAL_TARGET_PLATFORM_PATH m5_hal/platforms/espressif/esp32c6
#elif defined(CONFIG_IDF_TARGET_ESP32P4)
#define M5HAL_TARGET_PLATFORM_NUMBER M5HAL_PLATFORM_NUMBER_ESP32_P4
#define M5HAL_TARGET_PLATFORM_PATH m5_hal/platforms/espressif/esp32p4
#else
#define M5HAL_TARGET_PLATFORM_NUMBER M5HAL_PLATFORM_NUMBER_ESP32_UNKNOWN
#define M5HAL_TARGET_PLATFORM_PATH m5_hal/platforms/espressif/esp32_unknown
#endif
#endif
#else
#endif
// clang-format on
#undef XSTR
#undef STR
#if !defined(M5HAL_TARGET_PLATFORM_NUMBER)
#define M5HAL_TARGET_PLATFORM_NUMBER M5HAL_PLATFORM_NUMBER_UNKNOWN
#endif
#endif

View file

@ -0,0 +1,39 @@
#ifndef M5_HAL_PLATFORMS_ESPRESSIF_ESP32_HEADER_HPP
#define M5_HAL_PLATFORMS_ESPRESSIF_ESP32_HEADER_HPP
#include "../../../interface/gpio.hpp"
#include "../../../bus/bus.hpp"
namespace m5 {
namespace hal {
namespace platforms {
// namespace esp32 {}
// namespace current_platform {
// using namespace esp32;
// }
namespace esp32 {
namespace types {
enum class PeripheralType : uint8_t {
none = 0,
i2c0,
i2c1,
spi2,
spi3,
};
using periph_t = PeripheralType;
} // namespace types
namespace gpio {
interface::gpio::GPIO* getGPIO(void);
} // namespace gpio
} // namespace esp32
} // namespace platforms
} // namespace hal
} // namespace m5
#endif

View file

@ -0,0 +1,23 @@
#ifndef M5_HAL_PLATFORMS_ESPRESSIF_ESP32C6_HEADER_HPP
#define M5_HAL_PLATFORMS_ESPRESSIF_ESP32C6_HEADER_HPP
#include "../../../interface/gpio.hpp"
// #include "../../../interface/bus.hpp"
namespace m5 {
namespace hal {
namespace platforms {
namespace esp32 {
namespace gpio {
interface::gpio::GPIO* getGPIO(void);
} // namespace gpio
namespace bus {
namespace i2c {
} // namespace i2c
} // namespace bus
} // namespace esp32
} // namespace platforms
} // namespace hal
} // namespace m5
#endif

View file

@ -0,0 +1,23 @@
#ifndef M5_HAL_PLATFORMS_ESPRESSIF_ESP32P4_HEADER_HPP
#define M5_HAL_PLATFORMS_ESPRESSIF_ESP32P4_HEADER_HPP
#include "../../../interface/gpio.hpp"
// #include "../../../interface/bus.hpp"
namespace m5 {
namespace hal {
namespace platforms {
namespace esp32 {
namespace gpio {
interface::gpio::GPIO* getGPIO(void);
} // namespace gpio
namespace bus {
namespace i2c {
} // namespace i2c
} // namespace bus
} // namespace esp32
} // namespace platforms
} // namespace hal
} // namespace m5
#endif

View file

@ -0,0 +1,23 @@
#ifndef M5_HAL_PLATFORMS_ESPRESSIF_ESP32S3_HEADER_HPP
#define M5_HAL_PLATFORMS_ESPRESSIF_ESP32S3_HEADER_HPP
#include "../../../interface/gpio.hpp"
#include "../../../interface/bus.hpp"
namespace m5 {
namespace hal {
namespace platforms {
namespace esp32 {
namespace gpio {
interface::gpio::GPIO* getGPIO(void);
} // namespace gpio
namespace bus {
namespace i2c {
} // namespace i2c
} // namespace bus
} // namespace esp32
} // namespace platforms
} // namespace hal
} // namespace m5
#endif

View file

@ -0,0 +1,65 @@
#ifndef M5_HAL_TYPES_HPP
#define M5_HAL_TYPES_HPP
#include <stdint.h>
#include <stddef.h>
// #include <M5Utility.hpp>
namespace m5 {
namespace hal {
namespace types {
enum class PeripheralType : uint8_t;
using periph_t = PeripheralType;
// GPIOピンの通し番号型
typedef int16_t gpio_number_t;
// typedef m5::utility::BitSegment<3, int16_t> gpio_number_t;
// class gpio_number_t : public m5::utility::BitSegment<3, int16_t> {
// public:
// inline constexpr gpio_number_t() = default;
// inline constexpr gpio_number_t(const base_type v) : BitSegment(v) {
// }
// inline constexpr int16_t port(void) const { return upper(); }
// inline constexpr int16_t pin(void) const { return lower(); }
// inline void port(int16_t v) { upper(v); }
// inline void pin(int16_t v) { lower(v); }
// };
/*
: 3bit (8)
gpio_number_t 3bit 12bit
: 5bit (32)
gpio_number_t 5bit 10bit
*/
enum class GpioMode : uint8_t {
Input = 0,
Output,
Output_OpenDrain,
};
using gpio_mode_t = GpioMode;
enum class BusType : uint8_t {
UNKNOWN = 0,
I2C,
SPI,
I2S,
UART,
PWM,
GPIO,
ADC,
DAC,
};
using bus_type_t = BusType;
} // namespace types
} // namespace hal
} // namespace m5
#endif