mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-04-18 09:25:06 +00:00
New kernel drivers, filesystem API, and more (#513)
* **New Features** * BMI270 6-axis IMU driver added; new unified filesystem abstraction for mounted filesystems. * Public Wi‑Fi API surface (no implementation yet) * SDMMC driver added (kernel drive$) * expanded GPIO interrupt/callback support * **Improvements** * M5Stack Tab5: revamped GPIO/power initialization and IMU integration. * LVGL updates including device fontSize configuration. * Updated all code related to SD card device/fs handling * Rename LilyGO T-HMI S3 to LilyGO T-HMI * **Bug Fixes** * Simplified and consolidated SD card handling and mount discovery.
This commit is contained in:
parent
2de35b2d2d
commit
aa7530e515
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -53,7 +53,7 @@ jobs:
|
|||||||
{ id: guition-jc8048w550c, arch: esp32s3 },
|
{ id: guition-jc8048w550c, arch: esp32s3 },
|
||||||
{ id: heltec-wifi-lora-32-v3, arch: esp32s3 },
|
{ id: heltec-wifi-lora-32-v3, arch: esp32s3 },
|
||||||
{ id: lilygo-tdeck, arch: esp32s3 },
|
{ id: lilygo-tdeck, arch: esp32s3 },
|
||||||
{ id: lilygo-thmi-s3, arch: esp32s3 },
|
{ id: lilygo-thmi, arch: esp32s3 },
|
||||||
{ id: lilygo-tdongle-s3, arch: esp32s3 },
|
{ id: lilygo-tdongle-s3, arch: esp32s3 },
|
||||||
{ id: lilygo-tdisplay-s3, arch: esp32s3 },
|
{ id: lilygo-tdisplay-s3, arch: esp32s3 },
|
||||||
{ id: lilygo-tlora-pager, arch: esp32s3 },
|
{ id: lilygo-tlora-pager, arch: esp32s3 },
|
||||||
|
|||||||
@ -18,6 +18,7 @@ static const auto LOGGER = tt::Logger("JcSdCard");
|
|||||||
// ESP32-P4 Slot 0 uses IO MUX (fixed pins, not manually configurable)
|
// ESP32-P4 Slot 0 uses IO MUX (fixed pins, not manually configurable)
|
||||||
// CLK=43, CMD=44, D0=39, D1=40, D2=41, D3=42 (defined automatically by hardware)
|
// CLK=43, CMD=44, D0=39, D1=40, D2=41, D3=42 (defined automatically by hardware)
|
||||||
|
|
||||||
|
// TODO: Migrate to "espressif,esp32-sdmmc" driver (needs LDO code porting)
|
||||||
class SdCardDeviceImpl final : public SdCardDevice {
|
class SdCardDeviceImpl final : public SdCardDevice {
|
||||||
|
|
||||||
class NoLock final : public tt::Lock {
|
class NoLock final : public tt::Lock {
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
#include "devices/Display.h"
|
#include "devices/Display.h"
|
||||||
#include "devices/Sdcard.h"
|
|
||||||
|
|
||||||
#include <Tactility/hal/Configuration.h>
|
#include <Tactility/hal/Configuration.h>
|
||||||
|
|
||||||
@ -9,8 +8,7 @@ using namespace tt::hal;
|
|||||||
|
|
||||||
static std::vector<std::shared_ptr<tt::hal::Device>> createDevices() {
|
static std::vector<std::shared_ptr<tt::hal::Device>> createDevices() {
|
||||||
return {
|
return {
|
||||||
createDisplay(),
|
createDisplay()
|
||||||
createSdCard()
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,22 +0,0 @@
|
|||||||
#include "Sdcard.h"
|
|
||||||
|
|
||||||
#include <Tactility/hal/sdcard/SdmmcDevice.h>
|
|
||||||
#include <Tactility/lvgl/LvglSync.h>
|
|
||||||
|
|
||||||
using tt::hal::sdcard::SdmmcDevice;
|
|
||||||
|
|
||||||
std::shared_ptr<SdCardDevice> createSdCard() {
|
|
||||||
auto configuration = std::make_unique<SdmmcDevice::Config>(
|
|
||||||
GPIO_NUM_12,
|
|
||||||
GPIO_NUM_16,
|
|
||||||
GPIO_NUM_14,
|
|
||||||
GPIO_NUM_17,
|
|
||||||
GPIO_NUM_21,
|
|
||||||
GPIO_NUM_18,
|
|
||||||
SdCardDevice::MountBehaviour::AtBoot
|
|
||||||
);
|
|
||||||
|
|
||||||
return std::make_shared<SdmmcDevice>(
|
|
||||||
std::move(configuration)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Tactility/hal/sdcard/SdCardDevice.h"
|
|
||||||
|
|
||||||
using tt::hal::sdcard::SdCardDevice;
|
|
||||||
|
|
||||||
std::shared_ptr<SdCardDevice> createSdCard();
|
|
||||||
@ -22,3 +22,4 @@ dpi=186
|
|||||||
[lvgl]
|
[lvgl]
|
||||||
colorDepth=16
|
colorDepth=16
|
||||||
uiDensity=compact
|
uiDensity=compact
|
||||||
|
fontSize=10
|
||||||
|
|||||||
@ -3,6 +3,7 @@
|
|||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
|
#include <tactility/bindings/esp32_sdmmc.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
#include <tactility/bindings/esp32_uart.h>
|
#include <tactility/bindings/esp32_uart.h>
|
||||||
|
|
||||||
@ -30,6 +31,17 @@
|
|||||||
pin-sclk = <&gpio0 5 GPIO_FLAG_NONE>;
|
pin-sclk = <&gpio0 5 GPIO_FLAG_NONE>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
sdmmc0 {
|
||||||
|
compatible = "espressif,esp32-sdmmc";
|
||||||
|
pin-clk = <&gpio0 12 GPIO_FLAG_NONE>;
|
||||||
|
pin-cmd = <&gpio0 16 GPIO_FLAG_NONE>;
|
||||||
|
pin-d0 = <&gpio0 14 GPIO_FLAG_NONE>;
|
||||||
|
pin-d1 = <&gpio0 17 GPIO_FLAG_NONE>;
|
||||||
|
pin-d2 = <&gpio0 21 GPIO_FLAG_NONE>;
|
||||||
|
pin-d3 = <&gpio0 18 GPIO_FLAG_NONE>;
|
||||||
|
bus-width = <4>;
|
||||||
|
};
|
||||||
|
|
||||||
stemma_qt: uart1 {
|
stemma_qt: uart1 {
|
||||||
compatible = "espressif,esp32-uart";
|
compatible = "espressif,esp32-uart";
|
||||||
port = <UART_NUM_1>;
|
port = <UART_NUM_1>;
|
||||||
|
|||||||
@ -1,23 +0,0 @@
|
|||||||
#include "SdCard.h"
|
|
||||||
|
|
||||||
#include <Tactility/lvgl/LvglSync.h>
|
|
||||||
#include <Tactility/hal/sdcard/SdmmcDevice.h>
|
|
||||||
|
|
||||||
using tt::hal::sdcard::SdmmcDevice;
|
|
||||||
|
|
||||||
std::shared_ptr<SdCardDevice> createSdCard() {
|
|
||||||
auto configuration = std::make_unique<SdmmcDevice::Config>(
|
|
||||||
SD_DIO_SCLK, //CLK
|
|
||||||
SD_DIO_CMD, //CMD
|
|
||||||
SD_DIO_DATA0, //D0
|
|
||||||
SD_DIO_NC, //D1
|
|
||||||
SD_DIO_NC, //D2
|
|
||||||
SD_DIO_NC, //D3
|
|
||||||
SdCardDevice::MountBehaviour::AtBoot,
|
|
||||||
SD_DIO_BUS_WIDTH
|
|
||||||
);
|
|
||||||
|
|
||||||
return std::make_shared<SdmmcDevice>(
|
|
||||||
std::move(configuration)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <driver/gpio.h>
|
|
||||||
|
|
||||||
#include "Tactility/hal/sdcard/SdCardDevice.h"
|
|
||||||
|
|
||||||
using tt::hal::sdcard::SdCardDevice;
|
|
||||||
|
|
||||||
constexpr auto SD_DIO_CMD = GPIO_NUM_11;
|
|
||||||
constexpr auto SD_DIO_SCLK = GPIO_NUM_12;
|
|
||||||
constexpr auto SD_DIO_DATA0 = GPIO_NUM_13;
|
|
||||||
constexpr auto SD_DIO_NC = GPIO_NUM_NC;
|
|
||||||
constexpr auto SD_DIO_BUS_WIDTH = 1;
|
|
||||||
|
|
||||||
std::shared_ptr<SdCardDevice> createSdCard();
|
|
||||||
@ -1,5 +1,4 @@
|
|||||||
#include "devices/Power.h"
|
#include "devices/Power.h"
|
||||||
#include "devices/SdCard.h"
|
|
||||||
#include "devices/Display.h"
|
#include "devices/Display.h"
|
||||||
|
|
||||||
#include <ButtonControl.h>
|
#include <ButtonControl.h>
|
||||||
@ -11,7 +10,6 @@ using namespace tt::hal;
|
|||||||
|
|
||||||
static std::vector<std::shared_ptr<tt::hal::Device>> createDevices() {
|
static std::vector<std::shared_ptr<tt::hal::Device>> createDevices() {
|
||||||
return {
|
return {
|
||||||
createSdCard(),
|
|
||||||
createDisplay(),
|
createDisplay(),
|
||||||
std::make_shared<Power>(),
|
std::make_shared<Power>(),
|
||||||
ButtonControl::createOneButtonControl(0)
|
ButtonControl::createOneButtonControl(0)
|
||||||
@ -5,11 +5,11 @@
|
|||||||
#include "Tactility/kernel/SystemEvents.h"
|
#include "Tactility/kernel/SystemEvents.h"
|
||||||
#include <Tactility/TactilityCore.h>
|
#include <Tactility/TactilityCore.h>
|
||||||
|
|
||||||
#define TAG "thmi-s3"
|
#define TAG "thmi"
|
||||||
|
|
||||||
static bool powerOn() {
|
static bool powerOn() {
|
||||||
gpio_config_t power_signal_config = {
|
gpio_config_t power_signal_config = {
|
||||||
.pin_bit_mask = (1ULL << THMI_S3_POWERON_GPIO) | (1ULL << THMI_S3_POWEREN_GPIO),
|
.pin_bit_mask = (1ULL << THMI_POWERON_GPIO) | (1ULL << THMI_POWEREN_GPIO),
|
||||||
.mode = GPIO_MODE_OUTPUT,
|
.mode = GPIO_MODE_OUTPUT,
|
||||||
.pull_up_en = GPIO_PULLUP_DISABLE,
|
.pull_up_en = GPIO_PULLUP_DISABLE,
|
||||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||||
@ -20,11 +20,11 @@ static bool powerOn() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gpio_set_level(THMI_S3_POWERON_GPIO, 1) != ESP_OK) {
|
if (gpio_set_level(THMI_POWERON_GPIO, 1) != ESP_OK) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gpio_set_level(THMI_S3_POWEREN_GPIO, 1) != ESP_OK) {
|
if (gpio_set_level(THMI_POWEREN_GPIO, 1) != ESP_OK) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6,16 +6,16 @@
|
|||||||
#include <ChargeFromVoltage.h>
|
#include <ChargeFromVoltage.h>
|
||||||
#include <Tactility/hal/power/PowerDevice.h>
|
#include <Tactility/hal/power/PowerDevice.h>
|
||||||
|
|
||||||
constexpr auto THMI_S3_POWEREN_GPIO = GPIO_NUM_10;
|
constexpr auto THMI_POWEREN_GPIO = GPIO_NUM_10;
|
||||||
constexpr auto THMI_S3_POWERON_GPIO = GPIO_NUM_14;
|
constexpr auto THMI_POWERON_GPIO = GPIO_NUM_14;
|
||||||
|
|
||||||
using tt::hal::power::PowerDevice;
|
using tt::hal::power::PowerDevice;
|
||||||
|
|
||||||
class Power final : public PowerDevice {
|
class Power final : public PowerDevice {
|
||||||
|
|
||||||
ChargeFromVoltage chargeFromAdcVoltage = ChargeFromVoltage(3.3f, 4.2f);
|
ChargeFromVoltage chargeFromAdcVoltage = ChargeFromVoltage(3.3f, 4.2f);
|
||||||
bool initialized = false;
|
|
||||||
esp_adc_cal_characteristics_t adcCharacteristics;
|
esp_adc_cal_characteristics_t adcCharacteristics;
|
||||||
|
bool initialized = false;
|
||||||
bool calibrated = false;
|
bool calibrated = false;
|
||||||
|
|
||||||
bool adcInitCalibration();
|
bool adcInitCalibration();
|
||||||
@ -25,7 +25,7 @@ class Power final : public PowerDevice {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
std::string getName() const override { return "T-hmi Power"; }
|
std::string getName() const override { return "T-HMI Power"; }
|
||||||
std::string getDescription() const override { return "Power measurement via ADC"; }
|
std::string getDescription() const override { return "Power measurement via ADC"; }
|
||||||
|
|
||||||
bool supportsMetric(MetricType type) const override;
|
bool supportsMetric(MetricType type) const override;
|
||||||
@ -13,7 +13,7 @@ static error_t stop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct Module lilygo_thmi_s3_module = {
|
struct Module lilygo_thmi_s3_module = {
|
||||||
.name = "lilygo-thmi-s3",
|
.name = "lilygo-thmi",
|
||||||
.start = start,
|
.start = start,
|
||||||
.stop = stop,
|
.stop = stop,
|
||||||
.symbols = nullptr,
|
.symbols = nullptr,
|
||||||
@ -1,6 +1,6 @@
|
|||||||
[general]
|
[general]
|
||||||
vendor=LilyGO
|
vendor=LilyGO
|
||||||
name=T-HMI S3
|
name=T-HMI
|
||||||
|
|
||||||
[apps]
|
[apps]
|
||||||
launcherAppId=Launcher
|
launcherAppId=Launcher
|
||||||
@ -1,3 +1,3 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
- Platforms/platform-esp32
|
- Platforms/platform-esp32
|
||||||
dts: lilygo,thmi-s3.dts
|
dts: lilygo,thmi.dts
|
||||||
@ -3,11 +3,12 @@
|
|||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
|
#include <tactility/bindings/esp32_sdmmc.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
|
|
||||||
/ {
|
/ {
|
||||||
compatible = "root";
|
compatible = "root";
|
||||||
model = "LilyGO T-HMI S3";
|
model = "LilyGO T-HMI";
|
||||||
|
|
||||||
gpio0 {
|
gpio0 {
|
||||||
compatible = "espressif,esp32-gpio";
|
compatible = "espressif,esp32-gpio";
|
||||||
@ -21,4 +22,12 @@
|
|||||||
pin-miso = <&gpio0 4 GPIO_FLAG_NONE>;
|
pin-miso = <&gpio0 4 GPIO_FLAG_NONE>;
|
||||||
pin-sclk = <&gpio0 1 GPIO_FLAG_NONE>;
|
pin-sclk = <&gpio0 1 GPIO_FLAG_NONE>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
sdmmc0 {
|
||||||
|
compatible = "espressif,esp32-sdmmc";
|
||||||
|
pin-clk = <&gpio0 12 GPIO_FLAG_NONE>;
|
||||||
|
pin-cmd = <&gpio0 11 GPIO_FLAG_NONE>;
|
||||||
|
pin-d0 = <&gpio0 13 GPIO_FLAG_NONE>;
|
||||||
|
bus-width = <1>;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
@ -3,5 +3,5 @@ file(GLOB_RECURSE SOURCE_FILES Source/*.c*)
|
|||||||
idf_component_register(
|
idf_component_register(
|
||||||
SRCS ${SOURCE_FILES}
|
SRCS ${SOURCE_FILES}
|
||||||
INCLUDE_DIRS "Source"
|
INCLUDE_DIRS "Source"
|
||||||
REQUIRES Tactility esp_lvgl_port esp_lcd EspLcdCompat esp_lcd_ili9881c GT911 PwmBacklight driver vfs fatfs pi4ioe5v6408-module
|
REQUIRES Tactility esp_lvgl_port esp_lcd EspLcdCompat esp_lcd_ili9881c GT911 PwmBacklight driver vfs fatfs
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
#include "devices/Display.h"
|
#include "devices/Display.h"
|
||||||
#include "devices/SdCard.h"
|
#include "devices/SdCard.h"
|
||||||
#include <driver/gpio.h>
|
|
||||||
|
|
||||||
|
#include <tactility/drivers/gpio_controller.h>
|
||||||
#include <tactility/drivers/i2c_controller.h>
|
#include <tactility/drivers/i2c_controller.h>
|
||||||
|
|
||||||
#include <Tactility/hal/Configuration.h>
|
#include <Tactility/hal/Configuration.h>
|
||||||
#include <Tactility/hal/i2c/I2c.h>
|
#include <Tactility/hal/i2c/I2c.h>
|
||||||
#include <drivers/pi4ioe5v6408.h>
|
|
||||||
|
|
||||||
using namespace tt::hal;
|
using namespace tt::hal;
|
||||||
|
|
||||||
@ -19,50 +18,115 @@ static DeviceVector createDevices() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static error_t initPower(::Device* io_expander0, ::Device* io_expander1) {
|
/*
|
||||||
constexpr TickType_t i2c_timeout = pdMS_TO_TICKS(10);
|
PI4IOE5V6408-0 (0x43)
|
||||||
|
- Bit 0: RF internal/external switch
|
||||||
|
- Bit 1: Speaker enable
|
||||||
|
- Bit 2: External 5V bus enable
|
||||||
|
- Bit 3: /
|
||||||
|
- Bit 4: LCD reset
|
||||||
|
- Bit 5: Touch reset
|
||||||
|
- Bit 6: Camera reset
|
||||||
|
- Bit 7: Headphone detect
|
||||||
|
*/
|
||||||
|
constexpr auto GPIO_EXP0_PIN_RF_INTERNAL_EXTERNAL = 0;
|
||||||
|
constexpr auto GPIO_EXP0_PIN_SPEAKER_ENABLE = 1;
|
||||||
|
constexpr auto GPIO_EXP0_PIN_EXTERNAL_5V_BUS_ENABLE = 2;
|
||||||
|
constexpr auto GPIO_EXP0_PIN_LCD_RESET = 4;
|
||||||
|
constexpr auto GPIO_EXP0_PIN_TOUCH_RESET = 5;
|
||||||
|
constexpr auto GPIO_EXP0_PIN_CAMERA_RESET = 6;
|
||||||
|
constexpr auto GPIO_EXP0_PIN_HEADPHONE_DETECT = 7;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
PI4IOE5V6408-0 (0x43)
|
PI4IOE5V6408-1 (0x44)
|
||||||
- Bit 0: RF internal/external switch
|
- Bit 0: C6 WLAN enable
|
||||||
- Bit 1: Speaker enable
|
- Bit 1: /
|
||||||
- Bit 2: External 5V bus enable
|
- Bit 2: /
|
||||||
- Bit 3: /
|
- Bit 3: USB-A 5V enable
|
||||||
- Bit 4: LCD reset
|
- Bit 4: Device power: PWROFF_PLUSE
|
||||||
- Bit 5: Touch reset
|
- Bit 5: IP2326: nCHG_QC_EN
|
||||||
- Bit 6: Camera reset
|
- Bit 6: IP2326: CHG_STAT_LED
|
||||||
- Bit 7: Headphone detect
|
- Bit 7: IP2326: CHG_EN
|
||||||
*/
|
*/
|
||||||
|
constexpr auto GPIO_EXP1_PIN_C6_WLAN_ENABLE = 0;
|
||||||
|
constexpr auto GPIO_EXP1_PIN_USB_A_5V_ENABLE = 3;
|
||||||
|
constexpr auto GPIO_EXP1_PIN_DEVICE_POWER = 4;
|
||||||
|
constexpr auto GPIO_EXP1_PIN_IP2326_NCHG_QC_EN = 5;
|
||||||
|
constexpr auto GPIO_EXP1_PIN_IP2326_CHG_STAT_LED = 6;
|
||||||
|
constexpr auto GPIO_EXP1_PIN_IP2326_CHG_EN = 7;
|
||||||
|
|
||||||
check(pi4ioe5v6408_set_direction(io_expander0, 0b01111111, i2c_timeout) == ERROR_NONE);
|
static void initExpander0(::Device* io_expander0) {
|
||||||
check(pi4ioe5v6408_set_output_level(io_expander0, 0b01000110, i2c_timeout) == ERROR_NONE);
|
auto* rf_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_RF_INTERNAL_EXTERNAL, GPIO_OWNER_GPIO);
|
||||||
check(pi4ioe5v6408_set_output_high_impedance(io_expander0, 0b00000000, i2c_timeout) == ERROR_NONE);
|
check(rf_pin);
|
||||||
check(pi4ioe5v6408_set_pull_select(io_expander0, 0b01111111, i2c_timeout) == ERROR_NONE);
|
auto* speaker_enable_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_SPEAKER_ENABLE, GPIO_OWNER_GPIO);
|
||||||
check(pi4ioe5v6408_set_pull_enable(io_expander0, 0b01111111, i2c_timeout) == ERROR_NONE);
|
check(speaker_enable_pin);
|
||||||
|
auto* external_5v_bus_enable_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_EXTERNAL_5V_BUS_ENABLE, GPIO_OWNER_GPIO);
|
||||||
|
check(external_5v_bus_enable_pin);
|
||||||
|
auto* lcd_reset_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_LCD_RESET, GPIO_OWNER_GPIO);
|
||||||
|
check(lcd_reset_pin);
|
||||||
|
auto* touch_reset_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_TOUCH_RESET, GPIO_OWNER_GPIO);
|
||||||
|
check(touch_reset_pin);
|
||||||
|
auto* camera_reset_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_CAMERA_RESET, GPIO_OWNER_GPIO);
|
||||||
|
check(camera_reset_pin);
|
||||||
|
auto* headphone_detect_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_HEADPHONE_DETECT, GPIO_OWNER_GPIO);
|
||||||
|
check(headphone_detect_pin);
|
||||||
|
|
||||||
|
gpio_descriptor_set_flags(rf_pin, GPIO_FLAG_DIRECTION_OUTPUT);
|
||||||
|
gpio_descriptor_set_flags(speaker_enable_pin, GPIO_FLAG_DIRECTION_OUTPUT);
|
||||||
|
gpio_descriptor_set_flags(external_5v_bus_enable_pin, GPIO_FLAG_DIRECTION_OUTPUT);
|
||||||
|
gpio_descriptor_set_flags(lcd_reset_pin, GPIO_FLAG_DIRECTION_OUTPUT);
|
||||||
|
gpio_descriptor_set_flags(touch_reset_pin, GPIO_FLAG_DIRECTION_OUTPUT);
|
||||||
|
gpio_descriptor_set_flags(camera_reset_pin, GPIO_FLAG_DIRECTION_OUTPUT);
|
||||||
|
gpio_descriptor_set_flags(headphone_detect_pin, GPIO_FLAG_DIRECTION_INPUT);
|
||||||
|
|
||||||
|
gpio_descriptor_set_level(rf_pin, false);
|
||||||
|
gpio_descriptor_set_level(speaker_enable_pin, false);
|
||||||
|
gpio_descriptor_set_level(external_5v_bus_enable_pin, true);
|
||||||
|
gpio_descriptor_set_level(lcd_reset_pin, false);
|
||||||
|
gpio_descriptor_set_level(touch_reset_pin, false);
|
||||||
|
gpio_descriptor_set_level(camera_reset_pin, true);
|
||||||
vTaskDelay(pdMS_TO_TICKS(10));
|
vTaskDelay(pdMS_TO_TICKS(10));
|
||||||
check(pi4ioe5v6408_set_output_level(io_expander0, 0b01110110, i2c_timeout) == ERROR_NONE);
|
// Enable touch and lcd, but not the camera
|
||||||
|
gpio_descriptor_set_level(lcd_reset_pin, true);
|
||||||
|
gpio_descriptor_set_level(touch_reset_pin, true);
|
||||||
|
|
||||||
/*
|
gpio_descriptor_release(rf_pin);
|
||||||
PI4IOE5V6408-1 (0x44)
|
gpio_descriptor_release(speaker_enable_pin);
|
||||||
- Bit 0: C6 WLAN enable
|
gpio_descriptor_release(external_5v_bus_enable_pin);
|
||||||
- Bit 1: /
|
gpio_descriptor_release(lcd_reset_pin);
|
||||||
- Bit 2: /
|
gpio_descriptor_release(touch_reset_pin);
|
||||||
- Bit 3: USB-A 5V enable
|
gpio_descriptor_release(camera_reset_pin);
|
||||||
- Bit 4: Device power: PWROFF_PLUSE
|
gpio_descriptor_release(headphone_detect_pin);
|
||||||
- Bit 5: IP2326: nCHG_QC_EN
|
}
|
||||||
- Bit 6: IP2326: CHG_STAT_LED
|
|
||||||
- Bit 7: IP2326: CHG_EN
|
|
||||||
*/
|
|
||||||
|
|
||||||
check(pi4ioe5v6408_set_direction(io_expander1, 0b10111001, i2c_timeout) == ERROR_NONE);
|
static void initExpander1(::Device* io_expander1) {
|
||||||
check(pi4ioe5v6408_set_output_high_impedance(io_expander1, 0b00000110, i2c_timeout) == ERROR_NONE);
|
|
||||||
check(pi4ioe5v6408_set_pull_select(io_expander1, 0b10111001, i2c_timeout) == ERROR_NONE);
|
|
||||||
check(pi4ioe5v6408_set_pull_enable(io_expander1, 0b11111001, i2c_timeout) == ERROR_NONE);
|
|
||||||
check(pi4ioe5v6408_set_input_default_level(io_expander1, 0b01000000, i2c_timeout) == ERROR_NONE);
|
|
||||||
check(pi4ioe5v6408_set_interrupt_mask(io_expander1, 0b10111111, i2c_timeout) == ERROR_NONE);
|
|
||||||
check(pi4ioe5v6408_set_output_level(io_expander1, 0b10001001, i2c_timeout) == ERROR_NONE);
|
|
||||||
|
|
||||||
return ERROR_NONE;
|
auto* c6_wlan_enable_pin = gpio_descriptor_acquire(io_expander1, GPIO_EXP1_PIN_C6_WLAN_ENABLE, GPIO_OWNER_GPIO);
|
||||||
|
auto* usb_a_5v_enable_pin = gpio_descriptor_acquire(io_expander1, GPIO_EXP1_PIN_USB_A_5V_ENABLE, GPIO_OWNER_GPIO);
|
||||||
|
auto* device_power_pin = gpio_descriptor_acquire(io_expander1, GPIO_EXP1_PIN_DEVICE_POWER, GPIO_OWNER_GPIO);
|
||||||
|
auto* ip2326_ncharge_qc_enable_pin = gpio_descriptor_acquire(io_expander1, GPIO_EXP1_PIN_IP2326_NCHG_QC_EN, GPIO_OWNER_GPIO);
|
||||||
|
auto* ip2326_charge_state_led_pin = gpio_descriptor_acquire(io_expander1, GPIO_EXP1_PIN_IP2326_CHG_STAT_LED, GPIO_OWNER_GPIO);
|
||||||
|
auto* ip2326_charge_enable_pin = gpio_descriptor_acquire(io_expander1, GPIO_EXP1_PIN_IP2326_CHG_EN, GPIO_OWNER_GPIO);
|
||||||
|
|
||||||
|
gpio_descriptor_set_flags(c6_wlan_enable_pin, GPIO_FLAG_DIRECTION_OUTPUT);
|
||||||
|
gpio_descriptor_set_flags(usb_a_5v_enable_pin, GPIO_FLAG_DIRECTION_OUTPUT);
|
||||||
|
gpio_descriptor_set_flags(device_power_pin, GPIO_FLAG_DIRECTION_OUTPUT);
|
||||||
|
gpio_descriptor_set_flags(ip2326_ncharge_qc_enable_pin, GPIO_FLAG_DIRECTION_OUTPUT);
|
||||||
|
gpio_descriptor_set_flags(ip2326_charge_state_led_pin, GPIO_FLAG_DIRECTION_OUTPUT);
|
||||||
|
gpio_descriptor_set_flags(ip2326_charge_enable_pin, GPIO_FLAG_DIRECTION_INPUT | GPIO_FLAG_PULL_UP);
|
||||||
|
|
||||||
|
gpio_descriptor_set_level(c6_wlan_enable_pin, true);
|
||||||
|
gpio_descriptor_set_level(usb_a_5v_enable_pin, true);
|
||||||
|
gpio_descriptor_set_level(device_power_pin, false);
|
||||||
|
gpio_descriptor_set_level(ip2326_ncharge_qc_enable_pin, false);
|
||||||
|
gpio_descriptor_set_level(ip2326_charge_state_led_pin, false);
|
||||||
|
|
||||||
|
gpio_descriptor_release(c6_wlan_enable_pin);
|
||||||
|
gpio_descriptor_release(usb_a_5v_enable_pin);
|
||||||
|
gpio_descriptor_release(device_power_pin);
|
||||||
|
gpio_descriptor_release(ip2326_ncharge_qc_enable_pin);
|
||||||
|
gpio_descriptor_release(ip2326_charge_state_led_pin);
|
||||||
|
gpio_descriptor_release(ip2326_charge_enable_pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
static error_t initSound(::Device* i2c_controller, ::Device* io_expander0 = nullptr) {
|
static error_t initSound(::Device* i2c_controller, ::Device* io_expander0 = nullptr) {
|
||||||
@ -113,13 +177,11 @@ static error_t initSound(::Device* i2c_controller, ::Device* io_expander0 = null
|
|||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t output_level = 0;
|
auto* speaker_enable_pin = gpio_descriptor_acquire(io_expander0, GPIO_EXP0_PIN_SPEAKER_ENABLE, GPIO_OWNER_GPIO);
|
||||||
if (pi4ioe5v6408_get_output_level(io_expander0, &output_level, pdMS_TO_TICKS(100)) != ERROR_NONE) {
|
check(speaker_enable_pin, "Failed to acquire speaker enable pin");
|
||||||
LOG_E(TAG, "Failed to read power level: %s", error_to_string(error));
|
error = gpio_descriptor_set_level(speaker_enable_pin, true);
|
||||||
return ERROR_RESOURCE;
|
gpio_descriptor_release(speaker_enable_pin);
|
||||||
}
|
if (error != ERROR_NONE) {
|
||||||
|
|
||||||
if (pi4ioe5v6408_set_output_level(io_expander0, output_level | 0b00000010, pdMS_TO_TICKS(100)) != ERROR_NONE) {
|
|
||||||
LOG_E(TAG, "Failed to enable amplifier: %s", error_to_string(error));
|
LOG_E(TAG, "Failed to enable amplifier: %s", error_to_string(error));
|
||||||
return ERROR_RESOURCE;
|
return ERROR_RESOURCE;
|
||||||
}
|
}
|
||||||
@ -132,10 +194,12 @@ static bool initBoot() {
|
|||||||
check(i2c0, "i2c0 not found");
|
check(i2c0, "i2c0 not found");
|
||||||
|
|
||||||
auto* io_expander0 = device_find_by_name("io_expander0");
|
auto* io_expander0 = device_find_by_name("io_expander0");
|
||||||
|
check(io_expander0, "io_expander0 not found");
|
||||||
auto* io_expander1 = device_find_by_name("io_expander1");
|
auto* io_expander1 = device_find_by_name("io_expander1");
|
||||||
check(i2c0, "i2c0 not found");
|
check(io_expander1, "io_expander1 not found");
|
||||||
|
|
||||||
initPower(io_expander0, io_expander1);
|
initExpander0(io_expander0);
|
||||||
|
initExpander1(io_expander1);
|
||||||
|
|
||||||
error_t error = initSound(i2c0, io_expander0);
|
error_t error = initSound(i2c0, io_expander0);
|
||||||
if (error != ERROR_NONE) {
|
if (error != ERROR_NONE) {
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
- Platforms/platform-esp32
|
- Platforms/platform-esp32
|
||||||
- Drivers/pi4ioe5v6408-module
|
- Drivers/pi4ioe5v6408-module
|
||||||
|
- Drivers/bmi270-module
|
||||||
dts: m5stack,tab5.dts
|
dts: m5stack,tab5.dts
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
#include <tactility/bindings/esp32_i2s.h>
|
#include <tactility/bindings/esp32_i2s.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
|
#include <bindings/bmi270.h>
|
||||||
#include <bindings/pi4ioe5v6408.h>
|
#include <bindings/pi4ioe5v6408.h>
|
||||||
|
|
||||||
/ {
|
/ {
|
||||||
@ -23,35 +24,20 @@
|
|||||||
pin-sda = <&gpio0 31 GPIO_FLAG_NONE>;
|
pin-sda = <&gpio0 31 GPIO_FLAG_NONE>;
|
||||||
pin-scl = <&gpio0 32 GPIO_FLAG_NONE>;
|
pin-scl = <&gpio0 32 GPIO_FLAG_NONE>;
|
||||||
|
|
||||||
/*
|
|
||||||
- Bit 0: RF internal/external switch
|
|
||||||
- Bit 1: Speaker enable
|
|
||||||
- Bit 2: External 5V bus enable
|
|
||||||
- Bit 3: /
|
|
||||||
- Bit 4: LCD reset
|
|
||||||
- Bit 5: Touch reset
|
|
||||||
- Bit 6: Camera reset
|
|
||||||
- Bit 7: Headphone detect
|
|
||||||
*/
|
|
||||||
io_expander0 {
|
io_expander0 {
|
||||||
compatible = "diodes,pi4ioe5v6408";
|
compatible = "diodes,pi4ioe5v6408";
|
||||||
reg = <0x43>;
|
reg = <0x43>;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
|
||||||
- Bit 0: C6 WLAN enable
|
|
||||||
- Bit 1: /
|
|
||||||
- Bit 2: /
|
|
||||||
- Bit 3: USB-A 5V enable
|
|
||||||
- Bit 4: Device power: PWROFF_PLUSE
|
|
||||||
- Bit 5: IP2326: nCHG_QC_EN
|
|
||||||
- Bit 6: IP2326: CHG_STAT_LED
|
|
||||||
- Bit 7: IP2326: CHG_EN
|
|
||||||
*/
|
|
||||||
io_expander1 {
|
io_expander1 {
|
||||||
compatible = "diodes,pi4ioe5v6408";
|
compatible = "diodes,pi4ioe5v6408";
|
||||||
reg = <0x44>;
|
reg = <0x44>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bmi270 {
|
||||||
|
compatible = "bosch,bmi270";
|
||||||
|
reg = <0x68>;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
i2c_port_a: i2c1 {
|
i2c_port_a: i2c1 {
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
#include "devices/Display.h"
|
#include "devices/Display.h"
|
||||||
#include "devices/SdCard.h"
|
|
||||||
|
|
||||||
#include <Tactility/hal/Configuration.h>
|
#include <Tactility/hal/Configuration.h>
|
||||||
#include <PwmBacklight.h>
|
#include <PwmBacklight.h>
|
||||||
@ -10,7 +9,6 @@ using namespace tt::hal;
|
|||||||
static DeviceVector createDevices() {
|
static DeviceVector createDevices() {
|
||||||
return {
|
return {
|
||||||
createDisplay(),
|
createDisplay(),
|
||||||
createSdCard(),
|
|
||||||
ButtonControl::createOneButtonControl(0)
|
ButtonControl::createOneButtonControl(0)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,22 +0,0 @@
|
|||||||
#include "SdCard.h"
|
|
||||||
|
|
||||||
#include <Tactility/lvgl/LvglSync.h>
|
|
||||||
#include <Tactility/hal/sdcard/SdmmcDevice.h>
|
|
||||||
|
|
||||||
using tt::hal::sdcard::SdmmcDevice;
|
|
||||||
|
|
||||||
std::shared_ptr<SdCardDevice> createSdCard() {
|
|
||||||
auto configuration = std::make_unique<SdmmcDevice::Config>(
|
|
||||||
GPIO_NUM_36, //CLK
|
|
||||||
GPIO_NUM_35, //CMD
|
|
||||||
GPIO_NUM_37, //D0
|
|
||||||
GPIO_NUM_33, //D1
|
|
||||||
GPIO_NUM_38, //D2
|
|
||||||
GPIO_NUM_34, //D3
|
|
||||||
SdCardDevice::MountBehaviour::AtBoot
|
|
||||||
);
|
|
||||||
|
|
||||||
return std::make_shared<SdmmcDevice>(
|
|
||||||
std::move(configuration)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -1,7 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "Tactility/hal/sdcard/SdCardDevice.h"
|
|
||||||
|
|
||||||
using tt::hal::sdcard::SdCardDevice;
|
|
||||||
|
|
||||||
std::shared_ptr<SdCardDevice> createSdCard();
|
|
||||||
@ -3,6 +3,7 @@
|
|||||||
#include <tactility/bindings/root.h>
|
#include <tactility/bindings/root.h>
|
||||||
#include <tactility/bindings/esp32_gpio.h>
|
#include <tactility/bindings/esp32_gpio.h>
|
||||||
#include <tactility/bindings/esp32_i2c.h>
|
#include <tactility/bindings/esp32_i2c.h>
|
||||||
|
#include <tactility/bindings/esp32_sdmmc.h>
|
||||||
#include <tactility/bindings/esp32_spi.h>
|
#include <tactility/bindings/esp32_spi.h>
|
||||||
#include <tactility/bindings/esp32_uart.h>
|
#include <tactility/bindings/esp32_uart.h>
|
||||||
|
|
||||||
@ -30,6 +31,17 @@
|
|||||||
pin-sclk = <&gpio0 12 GPIO_FLAG_NONE>;
|
pin-sclk = <&gpio0 12 GPIO_FLAG_NONE>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
sdmmc0 {
|
||||||
|
compatible = "espressif,esp32-sdmmc";
|
||||||
|
pin-clk = <&gpio0 36 GPIO_FLAG_NONE>;
|
||||||
|
pin-cmd = <&gpio0 35 GPIO_FLAG_NONE>;
|
||||||
|
pin-d0 = <&gpio0 37 GPIO_FLAG_NONE>;
|
||||||
|
pin-d1 = <&gpio0 33 GPIO_FLAG_NONE>;
|
||||||
|
pin-d2 = <&gpio0 38 GPIO_FLAG_NONE>;
|
||||||
|
pin-d3 = <&gpio0 34 GPIO_FLAG_NONE>;
|
||||||
|
bus-width = <4>;
|
||||||
|
};
|
||||||
|
|
||||||
uart0 {
|
uart0 {
|
||||||
compatible = "espressif,esp32-uart";
|
compatible = "espressif,esp32-uart";
|
||||||
port = <UART_NUM_0>;
|
port = <UART_NUM_0>;
|
||||||
|
|||||||
12
Drivers/bmi270-module/CMakeLists.txt
Normal file
12
Drivers/bmi270-module/CMakeLists.txt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
|
||||||
|
include("${CMAKE_CURRENT_LIST_DIR}/../../Buildscripts/module.cmake")
|
||||||
|
|
||||||
|
file(GLOB_RECURSE SOURCE_FILES "source/*.c*")
|
||||||
|
|
||||||
|
tactility_add_module(bmi270-module
|
||||||
|
SRCS ${SOURCE_FILES}
|
||||||
|
INCLUDE_DIRS include/
|
||||||
|
PRIV_INCLUDE_DIRS private/
|
||||||
|
REQUIRES TactilityKernel
|
||||||
|
)
|
||||||
195
Drivers/bmi270-module/LICENSE-Apache-2.0.md
Normal file
195
Drivers/bmi270-module/LICENSE-Apache-2.0.md
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
Apache License
|
||||||
|
==============
|
||||||
|
|
||||||
|
_Version 2.0, January 2004_
|
||||||
|
_<<http://www.apache.org/licenses/>>_
|
||||||
|
|
||||||
|
### Terms and Conditions for use, reproduction, and distribution
|
||||||
|
|
||||||
|
#### 1. Definitions
|
||||||
|
|
||||||
|
“License” shall mean the terms and conditions for use, reproduction, and
|
||||||
|
distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
“Licensor” shall mean the copyright owner or entity authorized by the copyright
|
||||||
|
owner that is granting the License.
|
||||||
|
|
||||||
|
“Legal Entity” shall mean the union of the acting entity and all other entities
|
||||||
|
that control, are controlled by, or are under common control with that entity.
|
||||||
|
For the purposes of this definition, “control” means **(i)** the power, direct or
|
||||||
|
indirect, to cause the direction or management of such entity, whether by
|
||||||
|
contract or otherwise, or **(ii)** ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or **(iii)** beneficial ownership of such entity.
|
||||||
|
|
||||||
|
“You” (or “Your”) shall mean an individual or Legal Entity exercising
|
||||||
|
permissions granted by this License.
|
||||||
|
|
||||||
|
“Source” form shall mean the preferred form for making modifications, including
|
||||||
|
but not limited to software source code, documentation source, and configuration
|
||||||
|
files.
|
||||||
|
|
||||||
|
“Object” form shall mean any form resulting from mechanical transformation or
|
||||||
|
translation of a Source form, including but not limited to compiled object code,
|
||||||
|
generated documentation, and conversions to other media types.
|
||||||
|
|
||||||
|
“Work” shall mean the work of authorship, whether in Source or Object form, made
|
||||||
|
available under the License, as indicated by a copyright notice that is included
|
||||||
|
in or attached to the work (an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
“Derivative Works” shall mean any work, whether in Source or Object form, that
|
||||||
|
is based on (or derived from) the Work and for which the editorial revisions,
|
||||||
|
annotations, elaborations, or other modifications represent, as a whole, an
|
||||||
|
original work of authorship. For the purposes of this License, Derivative Works
|
||||||
|
shall not include works that remain separable from, or merely link (or bind by
|
||||||
|
name) to the interfaces of, the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
“Contribution” shall mean any work of authorship, including the original version
|
||||||
|
of the Work and any modifications or additions to that Work or Derivative Works
|
||||||
|
thereof, that is intentionally submitted to Licensor for inclusion in the Work
|
||||||
|
by the copyright owner or by an individual or Legal Entity authorized to submit
|
||||||
|
on behalf of the copyright owner. For the purposes of this definition,
|
||||||
|
“submitted” means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems, and
|
||||||
|
issue tracking systems that are managed by, or on behalf of, the Licensor for
|
||||||
|
the purpose of discussing and improving the Work, but excluding communication
|
||||||
|
that is conspicuously marked or otherwise designated in writing by the copyright
|
||||||
|
owner as “Not a Contribution.”
|
||||||
|
|
||||||
|
“Contributor” shall mean Licensor and any individual or Legal Entity on behalf
|
||||||
|
of whom a Contribution has been received by Licensor and subsequently
|
||||||
|
incorporated within the Work.
|
||||||
|
|
||||||
|
#### 2. Grant of Copyright License
|
||||||
|
|
||||||
|
Subject to the terms and conditions of this License, each Contributor hereby
|
||||||
|
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||||
|
irrevocable copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the Work and such
|
||||||
|
Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
#### 3. Grant of Patent License
|
||||||
|
|
||||||
|
Subject to the terms and conditions of this License, each Contributor hereby
|
||||||
|
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||||
|
irrevocable (except as stated in this section) patent license to make, have
|
||||||
|
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
|
||||||
|
such license applies only to those patent claims licensable by such Contributor
|
||||||
|
that are necessarily infringed by their Contribution(s) alone or by combination
|
||||||
|
of their Contribution(s) with the Work to which such Contribution(s) was
|
||||||
|
submitted. If You institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
|
||||||
|
Contribution incorporated within the Work constitutes direct or contributory
|
||||||
|
patent infringement, then any patent licenses granted to You under this License
|
||||||
|
for that Work shall terminate as of the date such litigation is filed.
|
||||||
|
|
||||||
|
#### 4. Redistribution
|
||||||
|
|
||||||
|
You may reproduce and distribute copies of the Work or Derivative Works thereof
|
||||||
|
in any medium, with or without modifications, and in Source or Object form,
|
||||||
|
provided that You meet the following conditions:
|
||||||
|
|
||||||
|
* **(a)** You must give any other recipients of the Work or Derivative Works a copy of
|
||||||
|
this License; and
|
||||||
|
* **(b)** You must cause any modified files to carry prominent notices stating that You
|
||||||
|
changed the files; and
|
||||||
|
* **(c)** You must retain, in the Source form of any Derivative Works that You distribute,
|
||||||
|
all copyright, patent, trademark, and attribution notices from the Source form
|
||||||
|
of the Work, excluding those notices that do not pertain to any part of the
|
||||||
|
Derivative Works; and
|
||||||
|
* **(d)** If the Work includes a “NOTICE” text file as part of its distribution, then any
|
||||||
|
Derivative Works that You distribute must include a readable copy of the
|
||||||
|
attribution notices contained within such NOTICE file, excluding those notices
|
||||||
|
that do not pertain to any part of the Derivative Works, in at least one of the
|
||||||
|
following places: within a NOTICE text file distributed as part of the
|
||||||
|
Derivative Works; within the Source form or documentation, if provided along
|
||||||
|
with the Derivative Works; or, within a display generated by the Derivative
|
||||||
|
Works, if and wherever such third-party notices normally appear. The contents of
|
||||||
|
the NOTICE file are for informational purposes only and do not modify the
|
||||||
|
License. You may add Your own attribution notices within Derivative Works that
|
||||||
|
You distribute, alongside or as an addendum to the NOTICE text from the Work,
|
||||||
|
provided that such additional attribution notices cannot be construed as
|
||||||
|
modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and may provide
|
||||||
|
additional or different license terms and conditions for use, reproduction, or
|
||||||
|
distribution of Your modifications, or for any such Derivative Works as a whole,
|
||||||
|
provided Your use, reproduction, and distribution of the Work otherwise complies
|
||||||
|
with the conditions stated in this License.
|
||||||
|
|
||||||
|
#### 5. Submission of Contributions
|
||||||
|
|
||||||
|
Unless You explicitly state otherwise, any Contribution intentionally submitted
|
||||||
|
for inclusion in the Work by You to the Licensor shall be under the terms and
|
||||||
|
conditions of this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify the terms of
|
||||||
|
any separate license agreement you may have executed with Licensor regarding
|
||||||
|
such Contributions.
|
||||||
|
|
||||||
|
#### 6. Trademarks
|
||||||
|
|
||||||
|
This License does not grant permission to use the trade names, trademarks,
|
||||||
|
service marks, or product names of the Licensor, except as required for
|
||||||
|
reasonable and customary use in describing the origin of the Work and
|
||||||
|
reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
#### 7. Disclaimer of Warranty
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, Licensor provides the
|
||||||
|
Work (and each Contributor provides its Contributions) on an “AS IS” BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
|
||||||
|
including, without limitation, any warranties or conditions of TITLE,
|
||||||
|
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
|
||||||
|
solely responsible for determining the appropriateness of using or
|
||||||
|
redistributing the Work and assume any risks associated with Your exercise of
|
||||||
|
permissions under this License.
|
||||||
|
|
||||||
|
#### 8. Limitation of Liability
|
||||||
|
|
||||||
|
In no event and under no legal theory, whether in tort (including negligence),
|
||||||
|
contract, or otherwise, unless required by applicable law (such as deliberate
|
||||||
|
and grossly negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special, incidental,
|
||||||
|
or consequential damages of any character arising as a result of this License or
|
||||||
|
out of the use or inability to use the Work (including but not limited to
|
||||||
|
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
|
||||||
|
any and all other commercial damages or losses), even if such Contributor has
|
||||||
|
been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
#### 9. Accepting Warranty or Additional Liability
|
||||||
|
|
||||||
|
While redistributing the Work or Derivative Works thereof, You may choose to
|
||||||
|
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
|
||||||
|
other liability obligations and/or rights consistent with this License. However,
|
||||||
|
in accepting such obligations, You may act only on Your own behalf and on Your
|
||||||
|
sole responsibility, not on behalf of any other Contributor, and only if You
|
||||||
|
agree to indemnify, defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason of your
|
||||||
|
accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
_END OF TERMS AND CONDITIONS_
|
||||||
|
|
||||||
|
### APPENDIX: How to apply the Apache License to your work
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following boilerplate
|
||||||
|
notice, with the fields enclosed by brackets `[]` replaced with your own
|
||||||
|
identifying information. (Don't include the brackets!) The text should be
|
||||||
|
enclosed in the appropriate comment syntax for the file format. We also
|
||||||
|
recommend that a file or class name and description of purpose be included on
|
||||||
|
the same “printed page” as the copyright notice for easier identification within
|
||||||
|
third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
7
Drivers/bmi270-module/README.md
Normal file
7
Drivers/bmi270-module/README.md
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# BMI270 I2C Driver
|
||||||
|
|
||||||
|
A driver for the `BMI270` 6-axis IMU.
|
||||||
|
|
||||||
|
See https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmi270-ds000.pdf
|
||||||
|
|
||||||
|
License: [Apache v2.0](LICENSE-Apache-2.0.md)
|
||||||
5
Drivers/bmi270-module/bindings/bosch,bmi270.yaml
Normal file
5
Drivers/bmi270-module/bindings/bosch,bmi270.yaml
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
description: Bosch BMI270 6-axis IMU
|
||||||
|
|
||||||
|
include: ["i2c-device.yaml"]
|
||||||
|
|
||||||
|
compatible: "bosch,bmi270"
|
||||||
3
Drivers/bmi270-module/devicetree.yaml
Normal file
3
Drivers/bmi270-module/devicetree.yaml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
dependencies:
|
||||||
|
- TactilityKernel
|
||||||
|
bindings: bindings
|
||||||
15
Drivers/bmi270-module/include/bindings/bmi270.h
Normal file
15
Drivers/bmi270-module/include/bindings/bmi270.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <tactility/bindings/bindings.h>
|
||||||
|
#include <drivers/bmi270.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DEFINE_DEVICETREE(bmi270, struct Bmi270Config)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
14
Drivers/bmi270-module/include/bmi270_module.h
Normal file
14
Drivers/bmi270-module/include/bmi270_module.h
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <tactility/module.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern struct Module bmi270_module;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
33
Drivers/bmi270-module/include/drivers/bmi270.h
Normal file
33
Drivers/bmi270-module/include/drivers/bmi270.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <tactility/error.h>
|
||||||
|
|
||||||
|
struct Device;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct Bmi270Config {
|
||||||
|
/** Address on bus */
|
||||||
|
uint8_t address;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Bmi270Data {
|
||||||
|
float ax, ay, az; // acceleration in g (±8g range)
|
||||||
|
float gx, gy, gz; // angular rate in °/s (±2000°/s range)
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read accelerometer and gyroscope data.
|
||||||
|
* @param[in] device bmi270 device
|
||||||
|
* @param[out] data Pointer to Bmi270Data structure to store the data
|
||||||
|
* @return ERROR_NONE on success
|
||||||
|
*/
|
||||||
|
error_t bmi270_read(struct Device* device, struct Bmi270Data* data);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
442
Drivers/bmi270-module/private/drivers/bmi270_config_data.h
Normal file
442
Drivers/bmi270-module/private/drivers/bmi270_config_data.h
Normal file
@ -0,0 +1,442 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// BMI270 configuration file
|
||||||
|
// Copyright (c) 2023 Bosch Sensortec GmbH
|
||||||
|
// SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
// Source: https://github.com/boschsensortec/BMI270_SensorAPI
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
static const uint8_t bmi270_config_data[] = {
|
||||||
|
0xc8, 0x2e, 0x00, 0x2e, 0x80, 0x2e, 0x3d, 0xb1, 0xc8, 0x2e, 0x00, 0x2e, 0x80, 0x2e, 0x91, 0x03, 0x80, 0x2e, 0xbc,
|
||||||
|
0xb0, 0x80, 0x2e, 0xa3, 0x03, 0xc8, 0x2e, 0x00, 0x2e, 0x80, 0x2e, 0x00, 0xb0, 0x50, 0x30, 0x21, 0x2e, 0x59, 0xf5,
|
||||||
|
0x10, 0x30, 0x21, 0x2e, 0x6a, 0xf5, 0x80, 0x2e, 0x3b, 0x03, 0x00, 0x00, 0x00, 0x00, 0x08, 0x19, 0x01, 0x00, 0x22,
|
||||||
|
0x00, 0x75, 0x00, 0x00, 0x10, 0x00, 0x10, 0xd1, 0x00, 0xb3, 0x43, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1,
|
||||||
|
0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00,
|
||||||
|
0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e,
|
||||||
|
0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80,
|
||||||
|
0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1,
|
||||||
|
0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00,
|
||||||
|
0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e,
|
||||||
|
0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80,
|
||||||
|
0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1,
|
||||||
|
0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0xe0, 0x5f, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x19, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05,
|
||||||
|
0xe0, 0xaa, 0x38, 0x05, 0xe0, 0x90, 0x30, 0xfa, 0x00, 0x96, 0x00, 0x4b, 0x09, 0x11, 0x00, 0x11, 0x00, 0x02, 0x00,
|
||||||
|
0x2d, 0x01, 0xd4, 0x7b, 0x3b, 0x01, 0xdb, 0x7a, 0x04, 0x00, 0x3f, 0x7b, 0xcd, 0x6c, 0xc3, 0x04, 0x85, 0x09, 0xc3,
|
||||||
|
0x04, 0xec, 0xe6, 0x0c, 0x46, 0x01, 0x00, 0x27, 0x00, 0x19, 0x00, 0x96, 0x00, 0xa0, 0x00, 0x01, 0x00, 0x0c, 0x00,
|
||||||
|
0xf0, 0x3c, 0x00, 0x01, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x32, 0x00, 0x05, 0x00, 0xee,
|
||||||
|
0x06, 0x04, 0x00, 0xc8, 0x00, 0x00, 0x00, 0x04, 0x00, 0xa8, 0x05, 0xee, 0x06, 0x00, 0x04, 0xbc, 0x02, 0xb3, 0x00,
|
||||||
|
0x85, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0xb4, 0x00, 0x01, 0x00, 0xb9, 0x00, 0x01, 0x00, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x01, 0x00, 0x80, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x2e, 0x00, 0xc1, 0xfd, 0x2d, 0xde,
|
||||||
|
0x00, 0xeb, 0x00, 0xda, 0x00, 0x00, 0x0c, 0xff, 0x0f, 0x00, 0x04, 0xc0, 0x00, 0x5b, 0xf5, 0xc9, 0x01, 0x1e, 0xf2,
|
||||||
|
0x80, 0x00, 0x3f, 0xff, 0x19, 0xf4, 0x58, 0xf5, 0x66, 0xf5, 0x64, 0xf5, 0xc0, 0xf1, 0xf0, 0x00, 0xe0, 0x00, 0xcd,
|
||||||
|
0x01, 0xd3, 0x01, 0xdb, 0x01, 0xff, 0x7f, 0xff, 0x01, 0xe4, 0x00, 0x74, 0xf7, 0xf3, 0x00, 0xfa, 0x00, 0xff, 0x3f,
|
||||||
|
0xca, 0x03, 0x6c, 0x38, 0x56, 0xfe, 0x44, 0xfd, 0xbc, 0x02, 0xf9, 0x06, 0x00, 0xfc, 0x12, 0x02, 0xae, 0x01, 0x58,
|
||||||
|
0xfa, 0x9a, 0xfd, 0x77, 0x05, 0xbb, 0x02, 0x96, 0x01, 0x95, 0x01, 0x7f, 0x01, 0x82, 0x01, 0x89, 0x01, 0x87, 0x01,
|
||||||
|
0x88, 0x01, 0x8a, 0x01, 0x8c, 0x01, 0x8f, 0x01, 0x8d, 0x01, 0x92, 0x01, 0x91, 0x01, 0xdd, 0x00, 0x9f, 0x01, 0x7e,
|
||||||
|
0x01, 0xdb, 0x00, 0xb6, 0x01, 0x70, 0x69, 0x26, 0xd3, 0x9c, 0x07, 0x1f, 0x05, 0x9d, 0x00, 0x00, 0x08, 0xbc, 0x05,
|
||||||
|
0x37, 0xfa, 0xa2, 0x01, 0xaa, 0x01, 0xa1, 0x01, 0xa8, 0x01, 0xa0, 0x01, 0xa8, 0x05, 0xb4, 0x01, 0xb4, 0x01, 0xce,
|
||||||
|
0x00, 0xd0, 0x00, 0xfc, 0x00, 0xc5, 0x01, 0xff, 0xfb, 0xb1, 0x00, 0x00, 0x38, 0x00, 0x30, 0xfd, 0xf5, 0xfc, 0xf5,
|
||||||
|
0xcd, 0x01, 0xa0, 0x00, 0x5f, 0xff, 0x00, 0x40, 0xff, 0x00, 0x00, 0x80, 0x6d, 0x0f, 0xeb, 0x00, 0x7f, 0xff, 0xc2,
|
||||||
|
0xf5, 0x68, 0xf7, 0xb3, 0xf1, 0x67, 0x0f, 0x5b, 0x0f, 0x61, 0x0f, 0x80, 0x0f, 0x58, 0xf7, 0x5b, 0xf7, 0x83, 0x0f,
|
||||||
|
0x86, 0x00, 0x72, 0x0f, 0x85, 0x0f, 0xc6, 0xf1, 0x7f, 0x0f, 0x6c, 0xf7, 0x00, 0xe0, 0x00, 0xff, 0xd1, 0xf5, 0x87,
|
||||||
|
0x0f, 0x8a, 0x0f, 0xff, 0x03, 0xf0, 0x3f, 0x8b, 0x00, 0x8e, 0x00, 0x90, 0x00, 0xb9, 0x00, 0x2d, 0xf5, 0xca, 0xf5,
|
||||||
|
0xcb, 0x01, 0x20, 0xf2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x50, 0x98, 0x2e,
|
||||||
|
0xd7, 0x0e, 0x50, 0x32, 0x98, 0x2e, 0xfa, 0x03, 0x00, 0x30, 0xf0, 0x7f, 0x00, 0x2e, 0x00, 0x2e, 0xd0, 0x2e, 0x00,
|
||||||
|
0x2e, 0x01, 0x80, 0x08, 0xa2, 0xfb, 0x2f, 0x98, 0x2e, 0xba, 0x03, 0x21, 0x2e, 0x19, 0x00, 0x01, 0x2e, 0xee, 0x00,
|
||||||
|
0x00, 0xb2, 0x07, 0x2f, 0x01, 0x2e, 0x19, 0x00, 0x00, 0xb2, 0x03, 0x2f, 0x01, 0x50, 0x03, 0x52, 0x98, 0x2e, 0x07,
|
||||||
|
0xcc, 0x01, 0x2e, 0xdd, 0x00, 0x00, 0xb2, 0x27, 0x2f, 0x05, 0x2e, 0x8a, 0x00, 0x05, 0x52, 0x98, 0x2e, 0xc7, 0xc1,
|
||||||
|
0x03, 0x2e, 0xe9, 0x00, 0x40, 0xb2, 0xf0, 0x7f, 0x08, 0x2f, 0x01, 0x2e, 0x19, 0x00, 0x00, 0xb2, 0x04, 0x2f, 0x00,
|
||||||
|
0x30, 0x21, 0x2e, 0xe9, 0x00, 0x98, 0x2e, 0xb4, 0xb1, 0x01, 0x2e, 0x18, 0x00, 0x00, 0xb2, 0x10, 0x2f, 0x05, 0x50,
|
||||||
|
0x98, 0x2e, 0x4d, 0xc3, 0x05, 0x50, 0x98, 0x2e, 0x5a, 0xc7, 0x98, 0x2e, 0xf9, 0xb4, 0x98, 0x2e, 0x54, 0xb2, 0x98,
|
||||||
|
0x2e, 0x67, 0xb6, 0x98, 0x2e, 0x17, 0xb2, 0x10, 0x30, 0x21, 0x2e, 0x77, 0x00, 0x01, 0x2e, 0xef, 0x00, 0x00, 0xb2,
|
||||||
|
0x04, 0x2f, 0x98, 0x2e, 0x7a, 0xb7, 0x00, 0x30, 0x21, 0x2e, 0xef, 0x00, 0x01, 0x2e, 0xd4, 0x00, 0x04, 0xae, 0x0b,
|
||||||
|
0x2f, 0x01, 0x2e, 0xdd, 0x00, 0x00, 0xb2, 0x07, 0x2f, 0x05, 0x52, 0x98, 0x2e, 0x8e, 0x0e, 0x00, 0xb2, 0x02, 0x2f,
|
||||||
|
0x10, 0x30, 0x21, 0x2e, 0x7d, 0x00, 0x01, 0x2e, 0x7d, 0x00, 0x00, 0x90, 0x90, 0x2e, 0xf1, 0x02, 0x01, 0x2e, 0xd7,
|
||||||
|
0x00, 0x00, 0xb2, 0x04, 0x2f, 0x98, 0x2e, 0x2f, 0x0e, 0x00, 0x30, 0x21, 0x2e, 0x7b, 0x00, 0x01, 0x2e, 0x7b, 0x00,
|
||||||
|
0x00, 0xb2, 0x12, 0x2f, 0x01, 0x2e, 0xd4, 0x00, 0x00, 0x90, 0x02, 0x2f, 0x98, 0x2e, 0x1f, 0x0e, 0x09, 0x2d, 0x98,
|
||||||
|
0x2e, 0x81, 0x0d, 0x01, 0x2e, 0xd4, 0x00, 0x04, 0x90, 0x02, 0x2f, 0x50, 0x32, 0x98, 0x2e, 0xfa, 0x03, 0x00, 0x30,
|
||||||
|
0x21, 0x2e, 0x7b, 0x00, 0x01, 0x2e, 0x7c, 0x00, 0x00, 0xb2, 0x90, 0x2e, 0x09, 0x03, 0x01, 0x2e, 0x7c, 0x00, 0x01,
|
||||||
|
0x31, 0x01, 0x08, 0x00, 0xb2, 0x04, 0x2f, 0x98, 0x2e, 0x47, 0xcb, 0x10, 0x30, 0x21, 0x2e, 0x77, 0x00, 0x81, 0x30,
|
||||||
|
0x01, 0x2e, 0x7c, 0x00, 0x01, 0x08, 0x00, 0xb2, 0x61, 0x2f, 0x03, 0x2e, 0x89, 0x00, 0x01, 0x2e, 0xd4, 0x00, 0x98,
|
||||||
|
0xbc, 0x98, 0xb8, 0x05, 0xb2, 0x0f, 0x58, 0x23, 0x2f, 0x07, 0x90, 0x09, 0x54, 0x00, 0x30, 0x37, 0x2f, 0x15, 0x41,
|
||||||
|
0x04, 0x41, 0xdc, 0xbe, 0x44, 0xbe, 0xdc, 0xba, 0x2c, 0x01, 0x61, 0x00, 0x0f, 0x56, 0x4a, 0x0f, 0x0c, 0x2f, 0xd1,
|
||||||
|
0x42, 0x94, 0xb8, 0xc1, 0x42, 0x11, 0x30, 0x05, 0x2e, 0x6a, 0xf7, 0x2c, 0xbd, 0x2f, 0xb9, 0x80, 0xb2, 0x08, 0x22,
|
||||||
|
0x98, 0x2e, 0xc3, 0xb7, 0x21, 0x2d, 0x61, 0x30, 0x23, 0x2e, 0xd4, 0x00, 0x98, 0x2e, 0xc3, 0xb7, 0x00, 0x30, 0x21,
|
||||||
|
0x2e, 0x5a, 0xf5, 0x18, 0x2d, 0xe1, 0x7f, 0x50, 0x30, 0x98, 0x2e, 0xfa, 0x03, 0x0f, 0x52, 0x07, 0x50, 0x50, 0x42,
|
||||||
|
0x70, 0x30, 0x0d, 0x54, 0x42, 0x42, 0x7e, 0x82, 0xe2, 0x6f, 0x80, 0xb2, 0x42, 0x42, 0x05, 0x2f, 0x21, 0x2e, 0xd4,
|
||||||
|
0x00, 0x10, 0x30, 0x98, 0x2e, 0xc3, 0xb7, 0x03, 0x2d, 0x60, 0x30, 0x21, 0x2e, 0xd4, 0x00, 0x01, 0x2e, 0xd4, 0x00,
|
||||||
|
0x06, 0x90, 0x18, 0x2f, 0x01, 0x2e, 0x76, 0x00, 0x0b, 0x54, 0x07, 0x52, 0xe0, 0x7f, 0x98, 0x2e, 0x7a, 0xc1, 0xe1,
|
||||||
|
0x6f, 0x08, 0x1a, 0x40, 0x30, 0x08, 0x2f, 0x21, 0x2e, 0xd4, 0x00, 0x20, 0x30, 0x98, 0x2e, 0xaf, 0xb7, 0x50, 0x32,
|
||||||
|
0x98, 0x2e, 0xfa, 0x03, 0x05, 0x2d, 0x98, 0x2e, 0x38, 0x0e, 0x00, 0x30, 0x21, 0x2e, 0xd4, 0x00, 0x00, 0x30, 0x21,
|
||||||
|
0x2e, 0x7c, 0x00, 0x18, 0x2d, 0x01, 0x2e, 0xd4, 0x00, 0x03, 0xaa, 0x01, 0x2f, 0x98, 0x2e, 0x45, 0x0e, 0x01, 0x2e,
|
||||||
|
0xd4, 0x00, 0x3f, 0x80, 0x03, 0xa2, 0x01, 0x2f, 0x00, 0x2e, 0x02, 0x2d, 0x98, 0x2e, 0x5b, 0x0e, 0x30, 0x30, 0x98,
|
||||||
|
0x2e, 0xce, 0xb7, 0x00, 0x30, 0x21, 0x2e, 0x7d, 0x00, 0x50, 0x32, 0x98, 0x2e, 0xfa, 0x03, 0x01, 0x2e, 0x77, 0x00,
|
||||||
|
0x00, 0xb2, 0x24, 0x2f, 0x98, 0x2e, 0xf5, 0xcb, 0x03, 0x2e, 0xd5, 0x00, 0x11, 0x54, 0x01, 0x0a, 0xbc, 0x84, 0x83,
|
||||||
|
0x86, 0x21, 0x2e, 0xc9, 0x01, 0xe0, 0x40, 0x13, 0x52, 0xc4, 0x40, 0x82, 0x40, 0xa8, 0xb9, 0x52, 0x42, 0x43, 0xbe,
|
||||||
|
0x53, 0x42, 0x04, 0x0a, 0x50, 0x42, 0xe1, 0x7f, 0xf0, 0x31, 0x41, 0x40, 0xf2, 0x6f, 0x25, 0xbd, 0x08, 0x08, 0x02,
|
||||||
|
0x0a, 0xd0, 0x7f, 0x98, 0x2e, 0xa8, 0xcf, 0x06, 0xbc, 0xd1, 0x6f, 0xe2, 0x6f, 0x08, 0x0a, 0x80, 0x42, 0x98, 0x2e,
|
||||||
|
0x58, 0xb7, 0x00, 0x30, 0x21, 0x2e, 0xee, 0x00, 0x21, 0x2e, 0x77, 0x00, 0x21, 0x2e, 0xdd, 0x00, 0x80, 0x2e, 0xf4,
|
||||||
|
0x01, 0x1a, 0x24, 0x22, 0x00, 0x80, 0x2e, 0xec, 0x01, 0x10, 0x50, 0xfb, 0x7f, 0x98, 0x2e, 0xf3, 0x03, 0x57, 0x50,
|
||||||
|
0xfb, 0x6f, 0x01, 0x30, 0x71, 0x54, 0x11, 0x42, 0x42, 0x0e, 0xfc, 0x2f, 0xc0, 0x2e, 0x01, 0x42, 0xf0, 0x5f, 0x80,
|
||||||
|
0x2e, 0x00, 0xc1, 0xfd, 0x2d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x01,
|
||||||
|
0x34, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x20, 0x50, 0xe7, 0x7f, 0xf6, 0x7f, 0x06, 0x32, 0x0f, 0x2e, 0x61, 0xf5, 0xfe, 0x09, 0xc0, 0xb3, 0x04,
|
||||||
|
0x2f, 0x17, 0x30, 0x2f, 0x2e, 0xef, 0x00, 0x2d, 0x2e, 0x61, 0xf5, 0xf6, 0x6f, 0xe7, 0x6f, 0xe0, 0x5f, 0xc8, 0x2e,
|
||||||
|
0x20, 0x50, 0xe7, 0x7f, 0xf6, 0x7f, 0x46, 0x30, 0x0f, 0x2e, 0xa4, 0xf1, 0xbe, 0x09, 0x80, 0xb3, 0x06, 0x2f, 0x0d,
|
||||||
|
0x2e, 0xd4, 0x00, 0x84, 0xaf, 0x02, 0x2f, 0x16, 0x30, 0x2d, 0x2e, 0x7b, 0x00, 0x86, 0x30, 0x2d, 0x2e, 0x60, 0xf5,
|
||||||
|
0xf6, 0x6f, 0xe7, 0x6f, 0xe0, 0x5f, 0xc8, 0x2e, 0x01, 0x2e, 0x77, 0xf7, 0x09, 0xbc, 0x0f, 0xb8, 0x00, 0xb2, 0x10,
|
||||||
|
0x50, 0xfb, 0x7f, 0x10, 0x30, 0x0b, 0x2f, 0x03, 0x2e, 0x8a, 0x00, 0x96, 0xbc, 0x9f, 0xb8, 0x40, 0xb2, 0x05, 0x2f,
|
||||||
|
0x03, 0x2e, 0x68, 0xf7, 0x9e, 0xbc, 0x9f, 0xb8, 0x40, 0xb2, 0x07, 0x2f, 0x03, 0x2e, 0x7e, 0x00, 0x41, 0x90, 0x01,
|
||||||
|
0x2f, 0x98, 0x2e, 0xdc, 0x03, 0x03, 0x2c, 0x00, 0x30, 0x21, 0x2e, 0x7e, 0x00, 0xfb, 0x6f, 0xf0, 0x5f, 0xb8, 0x2e,
|
||||||
|
0x20, 0x50, 0xe0, 0x7f, 0xfb, 0x7f, 0x00, 0x2e, 0x27, 0x50, 0x98, 0x2e, 0x3b, 0xc8, 0x29, 0x50, 0x98, 0x2e, 0xa7,
|
||||||
|
0xc8, 0x01, 0x50, 0x98, 0x2e, 0x55, 0xcc, 0xe1, 0x6f, 0x2b, 0x50, 0x98, 0x2e, 0xe0, 0xc9, 0xfb, 0x6f, 0x00, 0x30,
|
||||||
|
0xe0, 0x5f, 0x21, 0x2e, 0x7e, 0x00, 0xb8, 0x2e, 0x73, 0x50, 0x01, 0x30, 0x57, 0x54, 0x11, 0x42, 0x42, 0x0e, 0xfc,
|
||||||
|
0x2f, 0xb8, 0x2e, 0x21, 0x2e, 0x59, 0xf5, 0x10, 0x30, 0xc0, 0x2e, 0x21, 0x2e, 0x4a, 0xf1, 0x90, 0x50, 0xf7, 0x7f,
|
||||||
|
0xe6, 0x7f, 0xd5, 0x7f, 0xc4, 0x7f, 0xb3, 0x7f, 0xa1, 0x7f, 0x90, 0x7f, 0x82, 0x7f, 0x7b, 0x7f, 0x98, 0x2e, 0x35,
|
||||||
|
0xb7, 0x00, 0xb2, 0x90, 0x2e, 0x97, 0xb0, 0x03, 0x2e, 0x8f, 0x00, 0x07, 0x2e, 0x91, 0x00, 0x05, 0x2e, 0xb1, 0x00,
|
||||||
|
0x3f, 0xba, 0x9f, 0xb8, 0x01, 0x2e, 0xb1, 0x00, 0xa3, 0xbd, 0x4c, 0x0a, 0x05, 0x2e, 0xb1, 0x00, 0x04, 0xbe, 0xbf,
|
||||||
|
0xb9, 0xcb, 0x0a, 0x4f, 0xba, 0x22, 0xbd, 0x01, 0x2e, 0xb3, 0x00, 0xdc, 0x0a, 0x2f, 0xb9, 0x03, 0x2e, 0xb8, 0x00,
|
||||||
|
0x0a, 0xbe, 0x9a, 0x0a, 0xcf, 0xb9, 0x9b, 0xbc, 0x01, 0x2e, 0x97, 0x00, 0x9f, 0xb8, 0x93, 0x0a, 0x0f, 0xbc, 0x91,
|
||||||
|
0x0a, 0x0f, 0xb8, 0x90, 0x0a, 0x25, 0x2e, 0x18, 0x00, 0x05, 0x2e, 0xc1, 0xf5, 0x2e, 0xbd, 0x2e, 0xb9, 0x01, 0x2e,
|
||||||
|
0x19, 0x00, 0x31, 0x30, 0x8a, 0x04, 0x00, 0x90, 0x07, 0x2f, 0x01, 0x2e, 0xd4, 0x00, 0x04, 0xa2, 0x03, 0x2f, 0x01,
|
||||||
|
0x2e, 0x18, 0x00, 0x00, 0xb2, 0x0c, 0x2f, 0x19, 0x50, 0x05, 0x52, 0x98, 0x2e, 0x4d, 0xb7, 0x05, 0x2e, 0x78, 0x00,
|
||||||
|
0x80, 0x90, 0x10, 0x30, 0x01, 0x2f, 0x21, 0x2e, 0x78, 0x00, 0x25, 0x2e, 0xdd, 0x00, 0x98, 0x2e, 0x3e, 0xb7, 0x00,
|
||||||
|
0xb2, 0x02, 0x30, 0x01, 0x30, 0x04, 0x2f, 0x01, 0x2e, 0x19, 0x00, 0x00, 0xb2, 0x00, 0x2f, 0x21, 0x30, 0x01, 0x2e,
|
||||||
|
0xea, 0x00, 0x08, 0x1a, 0x0e, 0x2f, 0x23, 0x2e, 0xea, 0x00, 0x33, 0x30, 0x1b, 0x50, 0x0b, 0x09, 0x01, 0x40, 0x17,
|
||||||
|
0x56, 0x46, 0xbe, 0x4b, 0x08, 0x4c, 0x0a, 0x01, 0x42, 0x0a, 0x80, 0x15, 0x52, 0x01, 0x42, 0x00, 0x2e, 0x01, 0x2e,
|
||||||
|
0x18, 0x00, 0x00, 0xb2, 0x1f, 0x2f, 0x03, 0x2e, 0xc0, 0xf5, 0xf0, 0x30, 0x48, 0x08, 0x47, 0xaa, 0x74, 0x30, 0x07,
|
||||||
|
0x2e, 0x7a, 0x00, 0x61, 0x22, 0x4b, 0x1a, 0x05, 0x2f, 0x07, 0x2e, 0x66, 0xf5, 0xbf, 0xbd, 0xbf, 0xb9, 0xc0, 0x90,
|
||||||
|
0x0b, 0x2f, 0x1d, 0x56, 0x2b, 0x30, 0xd2, 0x42, 0xdb, 0x42, 0x01, 0x04, 0xc2, 0x42, 0x04, 0xbd, 0xfe, 0x80, 0x81,
|
||||||
|
0x84, 0x23, 0x2e, 0x7a, 0x00, 0x02, 0x42, 0x02, 0x32, 0x25, 0x2e, 0x62, 0xf5, 0x05, 0x2e, 0xd6, 0x00, 0x81, 0x84,
|
||||||
|
0x25, 0x2e, 0xd6, 0x00, 0x02, 0x31, 0x25, 0x2e, 0x60, 0xf5, 0x05, 0x2e, 0x8a, 0x00, 0x0b, 0x50, 0x90, 0x08, 0x80,
|
||||||
|
0xb2, 0x0b, 0x2f, 0x05, 0x2e, 0xca, 0xf5, 0xf0, 0x3e, 0x90, 0x08, 0x25, 0x2e, 0xca, 0xf5, 0x05, 0x2e, 0x59, 0xf5,
|
||||||
|
0xe0, 0x3f, 0x90, 0x08, 0x25, 0x2e, 0x59, 0xf5, 0x90, 0x6f, 0xa1, 0x6f, 0xb3, 0x6f, 0xc4, 0x6f, 0xd5, 0x6f, 0xe6,
|
||||||
|
0x6f, 0xf7, 0x6f, 0x7b, 0x6f, 0x82, 0x6f, 0x70, 0x5f, 0xc8, 0x2e, 0xc0, 0x50, 0x90, 0x7f, 0xe5, 0x7f, 0xd4, 0x7f,
|
||||||
|
0xc3, 0x7f, 0xb1, 0x7f, 0xa2, 0x7f, 0x87, 0x7f, 0xf6, 0x7f, 0x7b, 0x7f, 0x00, 0x2e, 0x01, 0x2e, 0x60, 0xf5, 0x60,
|
||||||
|
0x7f, 0x98, 0x2e, 0x35, 0xb7, 0x02, 0x30, 0x63, 0x6f, 0x15, 0x52, 0x50, 0x7f, 0x62, 0x7f, 0x5a, 0x2c, 0x02, 0x32,
|
||||||
|
0x1a, 0x09, 0x00, 0xb3, 0x14, 0x2f, 0x00, 0xb2, 0x03, 0x2f, 0x09, 0x2e, 0x18, 0x00, 0x00, 0x91, 0x0c, 0x2f, 0x43,
|
||||||
|
0x7f, 0x98, 0x2e, 0x97, 0xb7, 0x1f, 0x50, 0x02, 0x8a, 0x02, 0x32, 0x04, 0x30, 0x25, 0x2e, 0x64, 0xf5, 0x15, 0x52,
|
||||||
|
0x50, 0x6f, 0x43, 0x6f, 0x44, 0x43, 0x25, 0x2e, 0x60, 0xf5, 0xd9, 0x08, 0xc0, 0xb2, 0x36, 0x2f, 0x98, 0x2e, 0x3e,
|
||||||
|
0xb7, 0x00, 0xb2, 0x06, 0x2f, 0x01, 0x2e, 0x19, 0x00, 0x00, 0xb2, 0x02, 0x2f, 0x50, 0x6f, 0x00, 0x90, 0x0a, 0x2f,
|
||||||
|
0x01, 0x2e, 0x79, 0x00, 0x00, 0x90, 0x19, 0x2f, 0x10, 0x30, 0x21, 0x2e, 0x79, 0x00, 0x00, 0x30, 0x98, 0x2e, 0xdc,
|
||||||
|
0x03, 0x13, 0x2d, 0x01, 0x2e, 0xc3, 0xf5, 0x0c, 0xbc, 0x0f, 0xb8, 0x12, 0x30, 0x10, 0x04, 0x03, 0xb0, 0x26, 0x25,
|
||||||
|
0x21, 0x50, 0x03, 0x52, 0x98, 0x2e, 0x4d, 0xb7, 0x10, 0x30, 0x21, 0x2e, 0xee, 0x00, 0x02, 0x30, 0x60, 0x7f, 0x25,
|
||||||
|
0x2e, 0x79, 0x00, 0x60, 0x6f, 0x00, 0x90, 0x05, 0x2f, 0x00, 0x30, 0x21, 0x2e, 0xea, 0x00, 0x15, 0x50, 0x21, 0x2e,
|
||||||
|
0x64, 0xf5, 0x15, 0x52, 0x23, 0x2e, 0x60, 0xf5, 0x02, 0x32, 0x50, 0x6f, 0x00, 0x90, 0x02, 0x2f, 0x03, 0x30, 0x27,
|
||||||
|
0x2e, 0x78, 0x00, 0x07, 0x2e, 0x60, 0xf5, 0x1a, 0x09, 0x00, 0x91, 0xa3, 0x2f, 0x19, 0x09, 0x00, 0x91, 0xa0, 0x2f,
|
||||||
|
0x90, 0x6f, 0xa2, 0x6f, 0xb1, 0x6f, 0xc3, 0x6f, 0xd4, 0x6f, 0xe5, 0x6f, 0x7b, 0x6f, 0xf6, 0x6f, 0x87, 0x6f, 0x40,
|
||||||
|
0x5f, 0xc8, 0x2e, 0xc0, 0x50, 0xe7, 0x7f, 0xf6, 0x7f, 0x26, 0x30, 0x0f, 0x2e, 0x61, 0xf5, 0x2f, 0x2e, 0x7c, 0x00,
|
||||||
|
0x0f, 0x2e, 0x7c, 0x00, 0xbe, 0x09, 0xa2, 0x7f, 0x80, 0x7f, 0x80, 0xb3, 0xd5, 0x7f, 0xc4, 0x7f, 0xb3, 0x7f, 0x91,
|
||||||
|
0x7f, 0x7b, 0x7f, 0x0b, 0x2f, 0x23, 0x50, 0x1a, 0x25, 0x12, 0x40, 0x42, 0x7f, 0x74, 0x82, 0x12, 0x40, 0x52, 0x7f,
|
||||||
|
0x00, 0x2e, 0x00, 0x40, 0x60, 0x7f, 0x98, 0x2e, 0x6a, 0xd6, 0x81, 0x30, 0x01, 0x2e, 0x7c, 0x00, 0x01, 0x08, 0x00,
|
||||||
|
0xb2, 0x42, 0x2f, 0x03, 0x2e, 0x89, 0x00, 0x01, 0x2e, 0x89, 0x00, 0x97, 0xbc, 0x06, 0xbc, 0x9f, 0xb8, 0x0f, 0xb8,
|
||||||
|
0x00, 0x90, 0x23, 0x2e, 0xd8, 0x00, 0x10, 0x30, 0x01, 0x30, 0x2a, 0x2f, 0x03, 0x2e, 0xd4, 0x00, 0x44, 0xb2, 0x05,
|
||||||
|
0x2f, 0x47, 0xb2, 0x00, 0x30, 0x2d, 0x2f, 0x21, 0x2e, 0x7c, 0x00, 0x2b, 0x2d, 0x03, 0x2e, 0xfd, 0xf5, 0x9e, 0xbc,
|
||||||
|
0x9f, 0xb8, 0x40, 0x90, 0x14, 0x2f, 0x03, 0x2e, 0xfc, 0xf5, 0x99, 0xbc, 0x9f, 0xb8, 0x40, 0x90, 0x0e, 0x2f, 0x03,
|
||||||
|
0x2e, 0x49, 0xf1, 0x25, 0x54, 0x4a, 0x08, 0x40, 0x90, 0x08, 0x2f, 0x98, 0x2e, 0x35, 0xb7, 0x00, 0xb2, 0x10, 0x30,
|
||||||
|
0x03, 0x2f, 0x50, 0x30, 0x21, 0x2e, 0xd4, 0x00, 0x10, 0x2d, 0x98, 0x2e, 0xaf, 0xb7, 0x00, 0x30, 0x21, 0x2e, 0x7c,
|
||||||
|
0x00, 0x0a, 0x2d, 0x05, 0x2e, 0x69, 0xf7, 0x2d, 0xbd, 0x2f, 0xb9, 0x80, 0xb2, 0x01, 0x2f, 0x21, 0x2e, 0x7d, 0x00,
|
||||||
|
0x23, 0x2e, 0x7c, 0x00, 0xe0, 0x31, 0x21, 0x2e, 0x61, 0xf5, 0xf6, 0x6f, 0xe7, 0x6f, 0x80, 0x6f, 0xa2, 0x6f, 0xb3,
|
||||||
|
0x6f, 0xc4, 0x6f, 0xd5, 0x6f, 0x7b, 0x6f, 0x91, 0x6f, 0x40, 0x5f, 0xc8, 0x2e, 0x60, 0x51, 0x0a, 0x25, 0x36, 0x88,
|
||||||
|
0xf4, 0x7f, 0xeb, 0x7f, 0x00, 0x32, 0x31, 0x52, 0x32, 0x30, 0x13, 0x30, 0x98, 0x2e, 0x15, 0xcb, 0x0a, 0x25, 0x33,
|
||||||
|
0x84, 0xd2, 0x7f, 0x43, 0x30, 0x05, 0x50, 0x2d, 0x52, 0x98, 0x2e, 0x95, 0xc1, 0xd2, 0x6f, 0x27, 0x52, 0x98, 0x2e,
|
||||||
|
0xd7, 0xc7, 0x2a, 0x25, 0xb0, 0x86, 0xc0, 0x7f, 0xd3, 0x7f, 0xaf, 0x84, 0x29, 0x50, 0xf1, 0x6f, 0x98, 0x2e, 0x4d,
|
||||||
|
0xc8, 0x2a, 0x25, 0xae, 0x8a, 0xaa, 0x88, 0xf2, 0x6e, 0x2b, 0x50, 0xc1, 0x6f, 0xd3, 0x6f, 0xf4, 0x7f, 0x98, 0x2e,
|
||||||
|
0xb6, 0xc8, 0xe0, 0x6e, 0x00, 0xb2, 0x32, 0x2f, 0x33, 0x54, 0x83, 0x86, 0xf1, 0x6f, 0xc3, 0x7f, 0x04, 0x30, 0x30,
|
||||||
|
0x30, 0xf4, 0x7f, 0xd0, 0x7f, 0xb2, 0x7f, 0xe3, 0x30, 0xc5, 0x6f, 0x56, 0x40, 0x45, 0x41, 0x28, 0x08, 0x03, 0x14,
|
||||||
|
0x0e, 0xb4, 0x08, 0xbc, 0x82, 0x40, 0x10, 0x0a, 0x2f, 0x54, 0x26, 0x05, 0x91, 0x7f, 0x44, 0x28, 0xa3, 0x7f, 0x98,
|
||||||
|
0x2e, 0xd9, 0xc0, 0x08, 0xb9, 0x33, 0x30, 0x53, 0x09, 0xc1, 0x6f, 0xd3, 0x6f, 0xf4, 0x6f, 0x83, 0x17, 0x47, 0x40,
|
||||||
|
0x6c, 0x15, 0xb2, 0x6f, 0xbe, 0x09, 0x75, 0x0b, 0x90, 0x42, 0x45, 0x42, 0x51, 0x0e, 0x32, 0xbc, 0x02, 0x89, 0xa1,
|
||||||
|
0x6f, 0x7e, 0x86, 0xf4, 0x7f, 0xd0, 0x7f, 0xb2, 0x7f, 0x04, 0x30, 0x91, 0x6f, 0xd6, 0x2f, 0xeb, 0x6f, 0xa0, 0x5e,
|
||||||
|
0xb8, 0x2e, 0x03, 0x2e, 0x97, 0x00, 0x1b, 0xbc, 0x60, 0x50, 0x9f, 0xbc, 0x0c, 0xb8, 0xf0, 0x7f, 0x40, 0xb2, 0xeb,
|
||||||
|
0x7f, 0x2b, 0x2f, 0x03, 0x2e, 0x7f, 0x00, 0x41, 0x40, 0x01, 0x2e, 0xc8, 0x00, 0x01, 0x1a, 0x11, 0x2f, 0x37, 0x58,
|
||||||
|
0x23, 0x2e, 0xc8, 0x00, 0x10, 0x41, 0xa0, 0x7f, 0x38, 0x81, 0x01, 0x41, 0xd0, 0x7f, 0xb1, 0x7f, 0x98, 0x2e, 0x64,
|
||||||
|
0xcf, 0xd0, 0x6f, 0x07, 0x80, 0xa1, 0x6f, 0x11, 0x42, 0x00, 0x2e, 0xb1, 0x6f, 0x01, 0x42, 0x11, 0x30, 0x01, 0x2e,
|
||||||
|
0xfc, 0x00, 0x00, 0xa8, 0x03, 0x30, 0xcb, 0x22, 0x4a, 0x25, 0x01, 0x2e, 0x7f, 0x00, 0x3c, 0x89, 0x35, 0x52, 0x05,
|
||||||
|
0x54, 0x98, 0x2e, 0xc4, 0xce, 0xc1, 0x6f, 0xf0, 0x6f, 0x98, 0x2e, 0x95, 0xcf, 0x04, 0x2d, 0x01, 0x30, 0xf0, 0x6f,
|
||||||
|
0x98, 0x2e, 0x95, 0xcf, 0xeb, 0x6f, 0xa0, 0x5f, 0xb8, 0x2e, 0x03, 0x2e, 0xb3, 0x00, 0x02, 0x32, 0xf0, 0x30, 0x03,
|
||||||
|
0x31, 0x30, 0x50, 0x8a, 0x08, 0x08, 0x08, 0xcb, 0x08, 0xe0, 0x7f, 0x80, 0xb2, 0xf3, 0x7f, 0xdb, 0x7f, 0x25, 0x2f,
|
||||||
|
0x03, 0x2e, 0xca, 0x00, 0x41, 0x90, 0x04, 0x2f, 0x01, 0x30, 0x23, 0x2e, 0xca, 0x00, 0x98, 0x2e, 0x3f, 0x03, 0xc0,
|
||||||
|
0xb2, 0x05, 0x2f, 0x03, 0x2e, 0xda, 0x00, 0x00, 0x30, 0x41, 0x04, 0x23, 0x2e, 0xda, 0x00, 0x98, 0x2e, 0x92, 0xb2,
|
||||||
|
0x10, 0x25, 0xf0, 0x6f, 0x00, 0xb2, 0x05, 0x2f, 0x01, 0x2e, 0xda, 0x00, 0x02, 0x30, 0x10, 0x04, 0x21, 0x2e, 0xda,
|
||||||
|
0x00, 0x40, 0xb2, 0x01, 0x2f, 0x23, 0x2e, 0xc8, 0x01, 0xdb, 0x6f, 0xe0, 0x6f, 0xd0, 0x5f, 0x80, 0x2e, 0x95, 0xcf,
|
||||||
|
0x01, 0x30, 0xe0, 0x6f, 0x98, 0x2e, 0x95, 0xcf, 0x11, 0x30, 0x23, 0x2e, 0xca, 0x00, 0xdb, 0x6f, 0xd0, 0x5f, 0xb8,
|
||||||
|
0x2e, 0xd0, 0x50, 0x0a, 0x25, 0x33, 0x84, 0x55, 0x50, 0xd2, 0x7f, 0xe2, 0x7f, 0x03, 0x8c, 0xc0, 0x7f, 0xbb, 0x7f,
|
||||||
|
0x00, 0x30, 0x05, 0x5a, 0x39, 0x54, 0x51, 0x41, 0xa5, 0x7f, 0x96, 0x7f, 0x80, 0x7f, 0x98, 0x2e, 0xd9, 0xc0, 0x05,
|
||||||
|
0x30, 0xf5, 0x7f, 0x20, 0x25, 0x91, 0x6f, 0x3b, 0x58, 0x3d, 0x5c, 0x3b, 0x56, 0x98, 0x2e, 0x67, 0xcc, 0xc1, 0x6f,
|
||||||
|
0xd5, 0x6f, 0x52, 0x40, 0x50, 0x43, 0xc1, 0x7f, 0xd5, 0x7f, 0x10, 0x25, 0x98, 0x2e, 0xfe, 0xc9, 0x10, 0x25, 0x98,
|
||||||
|
0x2e, 0x74, 0xc0, 0x86, 0x6f, 0x30, 0x28, 0x92, 0x6f, 0x82, 0x8c, 0xa5, 0x6f, 0x6f, 0x52, 0x69, 0x0e, 0x39, 0x54,
|
||||||
|
0xdb, 0x2f, 0x19, 0xa0, 0x15, 0x30, 0x03, 0x2f, 0x00, 0x30, 0x21, 0x2e, 0x81, 0x01, 0x0a, 0x2d, 0x01, 0x2e, 0x81,
|
||||||
|
0x01, 0x05, 0x28, 0x42, 0x36, 0x21, 0x2e, 0x81, 0x01, 0x02, 0x0e, 0x01, 0x2f, 0x98, 0x2e, 0xf3, 0x03, 0x57, 0x50,
|
||||||
|
0x12, 0x30, 0x01, 0x40, 0x98, 0x2e, 0xfe, 0xc9, 0x51, 0x6f, 0x0b, 0x5c, 0x8e, 0x0e, 0x3b, 0x6f, 0x57, 0x58, 0x02,
|
||||||
|
0x30, 0x21, 0x2e, 0x95, 0x01, 0x45, 0x6f, 0x2a, 0x8d, 0xd2, 0x7f, 0xcb, 0x7f, 0x13, 0x2f, 0x02, 0x30, 0x3f, 0x50,
|
||||||
|
0xd2, 0x7f, 0xa8, 0x0e, 0x0e, 0x2f, 0xc0, 0x6f, 0x53, 0x54, 0x02, 0x00, 0x51, 0x54, 0x42, 0x0e, 0x10, 0x30, 0x59,
|
||||||
|
0x52, 0x02, 0x30, 0x01, 0x2f, 0x00, 0x2e, 0x03, 0x2d, 0x50, 0x42, 0x42, 0x42, 0x12, 0x30, 0xd2, 0x7f, 0x80, 0xb2,
|
||||||
|
0x03, 0x2f, 0x00, 0x30, 0x21, 0x2e, 0x80, 0x01, 0x12, 0x2d, 0x01, 0x2e, 0xc9, 0x00, 0x02, 0x80, 0x05, 0x2e, 0x80,
|
||||||
|
0x01, 0x11, 0x30, 0x91, 0x28, 0x00, 0x40, 0x25, 0x2e, 0x80, 0x01, 0x10, 0x0e, 0x05, 0x2f, 0x01, 0x2e, 0x7f, 0x01,
|
||||||
|
0x01, 0x90, 0x01, 0x2f, 0x98, 0x2e, 0xf3, 0x03, 0x00, 0x2e, 0xa0, 0x41, 0x01, 0x90, 0xa6, 0x7f, 0x90, 0x2e, 0xe3,
|
||||||
|
0xb4, 0x01, 0x2e, 0x95, 0x01, 0x00, 0xa8, 0x90, 0x2e, 0xe3, 0xb4, 0x5b, 0x54, 0x95, 0x80, 0x82, 0x40, 0x80, 0xb2,
|
||||||
|
0x02, 0x40, 0x2d, 0x8c, 0x3f, 0x52, 0x96, 0x7f, 0x90, 0x2e, 0xc2, 0xb3, 0x29, 0x0e, 0x76, 0x2f, 0x01, 0x2e, 0xc9,
|
||||||
|
0x00, 0x00, 0x40, 0x81, 0x28, 0x45, 0x52, 0xb3, 0x30, 0x98, 0x2e, 0x0f, 0xca, 0x5d, 0x54, 0x80, 0x7f, 0x00, 0x2e,
|
||||||
|
0xa1, 0x40, 0x72, 0x7f, 0x82, 0x80, 0x82, 0x40, 0x60, 0x7f, 0x98, 0x2e, 0xfe, 0xc9, 0x10, 0x25, 0x98, 0x2e, 0x74,
|
||||||
|
0xc0, 0x62, 0x6f, 0x05, 0x30, 0x87, 0x40, 0xc0, 0x91, 0x04, 0x30, 0x05, 0x2f, 0x05, 0x2e, 0x83, 0x01, 0x80, 0xb2,
|
||||||
|
0x14, 0x30, 0x00, 0x2f, 0x04, 0x30, 0x05, 0x2e, 0xc9, 0x00, 0x73, 0x6f, 0x81, 0x40, 0xe2, 0x40, 0x69, 0x04, 0x11,
|
||||||
|
0x0f, 0xe1, 0x40, 0x16, 0x30, 0xfe, 0x29, 0xcb, 0x40, 0x02, 0x2f, 0x83, 0x6f, 0x83, 0x0f, 0x22, 0x2f, 0x47, 0x56,
|
||||||
|
0x13, 0x0f, 0x12, 0x30, 0x77, 0x2f, 0x49, 0x54, 0x42, 0x0e, 0x12, 0x30, 0x73, 0x2f, 0x00, 0x91, 0x0a, 0x2f, 0x01,
|
||||||
|
0x2e, 0x8b, 0x01, 0x19, 0xa8, 0x02, 0x30, 0x6c, 0x2f, 0x63, 0x50, 0x00, 0x2e, 0x17, 0x42, 0x05, 0x42, 0x68, 0x2c,
|
||||||
|
0x12, 0x30, 0x0b, 0x25, 0x08, 0x0f, 0x50, 0x30, 0x02, 0x2f, 0x21, 0x2e, 0x83, 0x01, 0x03, 0x2d, 0x40, 0x30, 0x21,
|
||||||
|
0x2e, 0x83, 0x01, 0x2b, 0x2e, 0x85, 0x01, 0x5a, 0x2c, 0x12, 0x30, 0x00, 0x91, 0x2b, 0x25, 0x04, 0x2f, 0x63, 0x50,
|
||||||
|
0x02, 0x30, 0x17, 0x42, 0x17, 0x2c, 0x02, 0x42, 0x98, 0x2e, 0xfe, 0xc9, 0x10, 0x25, 0x98, 0x2e, 0x74, 0xc0, 0x05,
|
||||||
|
0x2e, 0xc9, 0x00, 0x81, 0x84, 0x5b, 0x30, 0x82, 0x40, 0x37, 0x2e, 0x83, 0x01, 0x02, 0x0e, 0x07, 0x2f, 0x5f, 0x52,
|
||||||
|
0x40, 0x30, 0x62, 0x40, 0x41, 0x40, 0x91, 0x0e, 0x01, 0x2f, 0x21, 0x2e, 0x83, 0x01, 0x05, 0x30, 0x2b, 0x2e, 0x85,
|
||||||
|
0x01, 0x12, 0x30, 0x36, 0x2c, 0x16, 0x30, 0x15, 0x25, 0x81, 0x7f, 0x98, 0x2e, 0xfe, 0xc9, 0x10, 0x25, 0x98, 0x2e,
|
||||||
|
0x74, 0xc0, 0x19, 0xa2, 0x16, 0x30, 0x15, 0x2f, 0x05, 0x2e, 0x97, 0x01, 0x80, 0x6f, 0x82, 0x0e, 0x05, 0x2f, 0x01,
|
||||||
|
0x2e, 0x86, 0x01, 0x06, 0x28, 0x21, 0x2e, 0x86, 0x01, 0x0b, 0x2d, 0x03, 0x2e, 0x87, 0x01, 0x5f, 0x54, 0x4e, 0x28,
|
||||||
|
0x91, 0x42, 0x00, 0x2e, 0x82, 0x40, 0x90, 0x0e, 0x01, 0x2f, 0x21, 0x2e, 0x88, 0x01, 0x02, 0x30, 0x13, 0x2c, 0x05,
|
||||||
|
0x30, 0xc0, 0x6f, 0x08, 0x1c, 0xa8, 0x0f, 0x16, 0x30, 0x05, 0x30, 0x5b, 0x50, 0x09, 0x2f, 0x02, 0x80, 0x2d, 0x2e,
|
||||||
|
0x82, 0x01, 0x05, 0x42, 0x05, 0x80, 0x00, 0x2e, 0x02, 0x42, 0x3e, 0x80, 0x00, 0x2e, 0x06, 0x42, 0x02, 0x30, 0x90,
|
||||||
|
0x6f, 0x3e, 0x88, 0x01, 0x40, 0x04, 0x41, 0x4c, 0x28, 0x01, 0x42, 0x07, 0x80, 0x10, 0x25, 0x24, 0x40, 0x00, 0x40,
|
||||||
|
0x00, 0xa8, 0xf5, 0x22, 0x23, 0x29, 0x44, 0x42, 0x7a, 0x82, 0x7e, 0x88, 0x43, 0x40, 0x04, 0x41, 0x00, 0xab, 0xf5,
|
||||||
|
0x23, 0xdf, 0x28, 0x43, 0x42, 0xd9, 0xa0, 0x14, 0x2f, 0x00, 0x90, 0x02, 0x2f, 0xd2, 0x6f, 0x81, 0xb2, 0x05, 0x2f,
|
||||||
|
0x63, 0x54, 0x06, 0x28, 0x90, 0x42, 0x85, 0x42, 0x09, 0x2c, 0x02, 0x30, 0x5b, 0x50, 0x03, 0x80, 0x29, 0x2e, 0x7e,
|
||||||
|
0x01, 0x2b, 0x2e, 0x82, 0x01, 0x05, 0x42, 0x12, 0x30, 0x2b, 0x2e, 0x83, 0x01, 0x45, 0x82, 0x00, 0x2e, 0x40, 0x40,
|
||||||
|
0x7a, 0x82, 0x02, 0xa0, 0x08, 0x2f, 0x63, 0x50, 0x3b, 0x30, 0x15, 0x42, 0x05, 0x42, 0x37, 0x80, 0x37, 0x2e, 0x7e,
|
||||||
|
0x01, 0x05, 0x42, 0x12, 0x30, 0x01, 0x2e, 0xc9, 0x00, 0x02, 0x8c, 0x40, 0x40, 0x84, 0x41, 0x7a, 0x8c, 0x04, 0x0f,
|
||||||
|
0x03, 0x2f, 0x01, 0x2e, 0x8b, 0x01, 0x19, 0xa4, 0x04, 0x2f, 0x2b, 0x2e, 0x82, 0x01, 0x98, 0x2e, 0xf3, 0x03, 0x12,
|
||||||
|
0x30, 0x81, 0x90, 0x61, 0x52, 0x08, 0x2f, 0x65, 0x42, 0x65, 0x42, 0x43, 0x80, 0x39, 0x84, 0x82, 0x88, 0x05, 0x42,
|
||||||
|
0x45, 0x42, 0x85, 0x42, 0x05, 0x43, 0x00, 0x2e, 0x80, 0x41, 0x00, 0x90, 0x90, 0x2e, 0xe1, 0xb4, 0x65, 0x54, 0xc1,
|
||||||
|
0x6f, 0x80, 0x40, 0x00, 0xb2, 0x43, 0x58, 0x69, 0x50, 0x44, 0x2f, 0x55, 0x5c, 0xb7, 0x87, 0x8c, 0x0f, 0x0d, 0x2e,
|
||||||
|
0x96, 0x01, 0xc4, 0x40, 0x36, 0x2f, 0x41, 0x56, 0x8b, 0x0e, 0x2a, 0x2f, 0x0b, 0x52, 0xa1, 0x0e, 0x0a, 0x2f, 0x05,
|
||||||
|
0x2e, 0x8f, 0x01, 0x14, 0x25, 0x98, 0x2e, 0xfe, 0xc9, 0x4b, 0x54, 0x02, 0x0f, 0x69, 0x50, 0x05, 0x30, 0x65, 0x54,
|
||||||
|
0x15, 0x2f, 0x03, 0x2e, 0x8e, 0x01, 0x4d, 0x5c, 0x8e, 0x0f, 0x3a, 0x2f, 0x05, 0x2e, 0x8f, 0x01, 0x98, 0x2e, 0xfe,
|
||||||
|
0xc9, 0x4f, 0x54, 0x82, 0x0f, 0x05, 0x30, 0x69, 0x50, 0x65, 0x54, 0x30, 0x2f, 0x6d, 0x52, 0x15, 0x30, 0x42, 0x8c,
|
||||||
|
0x45, 0x42, 0x04, 0x30, 0x2b, 0x2c, 0x84, 0x43, 0x6b, 0x52, 0x42, 0x8c, 0x00, 0x2e, 0x85, 0x43, 0x15, 0x30, 0x24,
|
||||||
|
0x2c, 0x45, 0x42, 0x8e, 0x0f, 0x20, 0x2f, 0x0d, 0x2e, 0x8e, 0x01, 0xb1, 0x0e, 0x1c, 0x2f, 0x23, 0x2e, 0x8e, 0x01,
|
||||||
|
0x1a, 0x2d, 0x0e, 0x0e, 0x17, 0x2f, 0xa1, 0x0f, 0x15, 0x2f, 0x23, 0x2e, 0x8d, 0x01, 0x13, 0x2d, 0x98, 0x2e, 0x74,
|
||||||
|
0xc0, 0x43, 0x54, 0xc2, 0x0e, 0x0a, 0x2f, 0x65, 0x50, 0x04, 0x80, 0x0b, 0x30, 0x06, 0x82, 0x0b, 0x42, 0x79, 0x80,
|
||||||
|
0x41, 0x40, 0x12, 0x30, 0x25, 0x2e, 0x8c, 0x01, 0x01, 0x42, 0x05, 0x30, 0x69, 0x50, 0x65, 0x54, 0x84, 0x82, 0x43,
|
||||||
|
0x84, 0xbe, 0x8c, 0x84, 0x40, 0x86, 0x41, 0x26, 0x29, 0x94, 0x42, 0xbe, 0x8e, 0xd5, 0x7f, 0x19, 0xa1, 0x43, 0x40,
|
||||||
|
0x0b, 0x2e, 0x8c, 0x01, 0x84, 0x40, 0xc7, 0x41, 0x5d, 0x29, 0x27, 0x29, 0x45, 0x42, 0x84, 0x42, 0xc2, 0x7f, 0x01,
|
||||||
|
0x2f, 0xc0, 0xb3, 0x1d, 0x2f, 0x05, 0x2e, 0x94, 0x01, 0x99, 0xa0, 0x01, 0x2f, 0x80, 0xb3, 0x13, 0x2f, 0x80, 0xb3,
|
||||||
|
0x18, 0x2f, 0xc0, 0xb3, 0x16, 0x2f, 0x12, 0x40, 0x01, 0x40, 0x92, 0x7f, 0x98, 0x2e, 0x74, 0xc0, 0x92, 0x6f, 0x10,
|
||||||
|
0x0f, 0x20, 0x30, 0x03, 0x2f, 0x10, 0x30, 0x21, 0x2e, 0x7e, 0x01, 0x0a, 0x2d, 0x21, 0x2e, 0x7e, 0x01, 0x07, 0x2d,
|
||||||
|
0x20, 0x30, 0x21, 0x2e, 0x7e, 0x01, 0x03, 0x2d, 0x10, 0x30, 0x21, 0x2e, 0x7e, 0x01, 0xc2, 0x6f, 0x01, 0x2e, 0xc9,
|
||||||
|
0x00, 0xbc, 0x84, 0x02, 0x80, 0x82, 0x40, 0x00, 0x40, 0x90, 0x0e, 0xd5, 0x6f, 0x02, 0x2f, 0x15, 0x30, 0x98, 0x2e,
|
||||||
|
0xf3, 0x03, 0x41, 0x91, 0x05, 0x30, 0x07, 0x2f, 0x67, 0x50, 0x3d, 0x80, 0x2b, 0x2e, 0x8f, 0x01, 0x05, 0x42, 0x04,
|
||||||
|
0x80, 0x00, 0x2e, 0x05, 0x42, 0x02, 0x2c, 0x00, 0x30, 0x00, 0x30, 0xa2, 0x6f, 0x98, 0x8a, 0x86, 0x40, 0x80, 0xa7,
|
||||||
|
0x05, 0x2f, 0x98, 0x2e, 0xf3, 0x03, 0xc0, 0x30, 0x21, 0x2e, 0x95, 0x01, 0x06, 0x25, 0x1a, 0x25, 0xe2, 0x6f, 0x76,
|
||||||
|
0x82, 0x96, 0x40, 0x56, 0x43, 0x51, 0x0e, 0xfb, 0x2f, 0xbb, 0x6f, 0x30, 0x5f, 0xb8, 0x2e, 0x01, 0x2e, 0xb8, 0x00,
|
||||||
|
0x01, 0x31, 0x41, 0x08, 0x40, 0xb2, 0x20, 0x50, 0xf2, 0x30, 0x02, 0x08, 0xfb, 0x7f, 0x01, 0x30, 0x10, 0x2f, 0x05,
|
||||||
|
0x2e, 0xcc, 0x00, 0x81, 0x90, 0xe0, 0x7f, 0x03, 0x2f, 0x23, 0x2e, 0xcc, 0x00, 0x98, 0x2e, 0x55, 0xb6, 0x98, 0x2e,
|
||||||
|
0x1d, 0xb5, 0x10, 0x25, 0xfb, 0x6f, 0xe0, 0x6f, 0xe0, 0x5f, 0x80, 0x2e, 0x95, 0xcf, 0x98, 0x2e, 0x95, 0xcf, 0x10,
|
||||||
|
0x30, 0x21, 0x2e, 0xcc, 0x00, 0xfb, 0x6f, 0xe0, 0x5f, 0xb8, 0x2e, 0x00, 0x51, 0x05, 0x58, 0xeb, 0x7f, 0x2a, 0x25,
|
||||||
|
0x89, 0x52, 0x6f, 0x5a, 0x89, 0x50, 0x13, 0x41, 0x06, 0x40, 0xb3, 0x01, 0x16, 0x42, 0xcb, 0x16, 0x06, 0x40, 0xf3,
|
||||||
|
0x02, 0x13, 0x42, 0x65, 0x0e, 0xf5, 0x2f, 0x05, 0x40, 0x14, 0x30, 0x2c, 0x29, 0x04, 0x42, 0x08, 0xa1, 0x00, 0x30,
|
||||||
|
0x90, 0x2e, 0x52, 0xb6, 0xb3, 0x88, 0xb0, 0x8a, 0xb6, 0x84, 0xa4, 0x7f, 0xc4, 0x7f, 0xb5, 0x7f, 0xd5, 0x7f, 0x92,
|
||||||
|
0x7f, 0x73, 0x30, 0x04, 0x30, 0x55, 0x40, 0x42, 0x40, 0x8a, 0x17, 0xf3, 0x08, 0x6b, 0x01, 0x90, 0x02, 0x53, 0xb8,
|
||||||
|
0x4b, 0x82, 0xad, 0xbe, 0x71, 0x7f, 0x45, 0x0a, 0x09, 0x54, 0x84, 0x7f, 0x98, 0x2e, 0xd9, 0xc0, 0xa3, 0x6f, 0x7b,
|
||||||
|
0x54, 0xd0, 0x42, 0xa3, 0x7f, 0xf2, 0x7f, 0x60, 0x7f, 0x20, 0x25, 0x71, 0x6f, 0x75, 0x5a, 0x77, 0x58, 0x79, 0x5c,
|
||||||
|
0x75, 0x56, 0x98, 0x2e, 0x67, 0xcc, 0xb1, 0x6f, 0x62, 0x6f, 0x50, 0x42, 0xb1, 0x7f, 0xb3, 0x30, 0x10, 0x25, 0x98,
|
||||||
|
0x2e, 0x0f, 0xca, 0x84, 0x6f, 0x20, 0x29, 0x71, 0x6f, 0x92, 0x6f, 0xa5, 0x6f, 0x76, 0x82, 0x6a, 0x0e, 0x73, 0x30,
|
||||||
|
0x00, 0x30, 0xd0, 0x2f, 0xd2, 0x6f, 0xd1, 0x7f, 0xb4, 0x7f, 0x98, 0x2e, 0x2b, 0xb7, 0x15, 0xbd, 0x0b, 0xb8, 0x02,
|
||||||
|
0x0a, 0xc2, 0x6f, 0xc0, 0x7f, 0x98, 0x2e, 0x2b, 0xb7, 0x15, 0xbd, 0x0b, 0xb8, 0x42, 0x0a, 0xc0, 0x6f, 0x08, 0x17,
|
||||||
|
0x41, 0x18, 0x89, 0x16, 0xe1, 0x18, 0xd0, 0x18, 0xa1, 0x7f, 0x27, 0x25, 0x16, 0x25, 0x98, 0x2e, 0x79, 0xc0, 0x8b,
|
||||||
|
0x54, 0x90, 0x7f, 0xb3, 0x30, 0x82, 0x40, 0x80, 0x90, 0x0d, 0x2f, 0x7d, 0x52, 0x92, 0x6f, 0x98, 0x2e, 0x0f, 0xca,
|
||||||
|
0xb2, 0x6f, 0x90, 0x0e, 0x06, 0x2f, 0x8b, 0x50, 0x14, 0x30, 0x42, 0x6f, 0x51, 0x6f, 0x14, 0x42, 0x12, 0x42, 0x01,
|
||||||
|
0x42, 0x00, 0x2e, 0x31, 0x6f, 0x98, 0x2e, 0x74, 0xc0, 0x41, 0x6f, 0x80, 0x7f, 0x98, 0x2e, 0x74, 0xc0, 0x82, 0x6f,
|
||||||
|
0x10, 0x04, 0x43, 0x52, 0x01, 0x0f, 0x05, 0x2e, 0xcb, 0x00, 0x00, 0x30, 0x04, 0x30, 0x21, 0x2f, 0x51, 0x6f, 0x43,
|
||||||
|
0x58, 0x8c, 0x0e, 0x04, 0x30, 0x1c, 0x2f, 0x85, 0x88, 0x41, 0x6f, 0x04, 0x41, 0x8c, 0x0f, 0x04, 0x30, 0x16, 0x2f,
|
||||||
|
0x84, 0x88, 0x00, 0x2e, 0x04, 0x41, 0x04, 0x05, 0x8c, 0x0e, 0x04, 0x30, 0x0f, 0x2f, 0x82, 0x88, 0x31, 0x6f, 0x04,
|
||||||
|
0x41, 0x04, 0x05, 0x8c, 0x0e, 0x04, 0x30, 0x08, 0x2f, 0x83, 0x88, 0x00, 0x2e, 0x04, 0x41, 0x8c, 0x0f, 0x04, 0x30,
|
||||||
|
0x02, 0x2f, 0x21, 0x2e, 0xad, 0x01, 0x14, 0x30, 0x00, 0x91, 0x14, 0x2f, 0x03, 0x2e, 0xa1, 0x01, 0x41, 0x90, 0x0e,
|
||||||
|
0x2f, 0x03, 0x2e, 0xad, 0x01, 0x14, 0x30, 0x4c, 0x28, 0x23, 0x2e, 0xad, 0x01, 0x46, 0xa0, 0x06, 0x2f, 0x81, 0x84,
|
||||||
|
0x8d, 0x52, 0x48, 0x82, 0x82, 0x40, 0x21, 0x2e, 0xa1, 0x01, 0x42, 0x42, 0x5c, 0x2c, 0x02, 0x30, 0x05, 0x2e, 0xaa,
|
||||||
|
0x01, 0x80, 0xb2, 0x02, 0x30, 0x55, 0x2f, 0x03, 0x2e, 0xa9, 0x01, 0x92, 0x6f, 0xb3, 0x30, 0x98, 0x2e, 0x0f, 0xca,
|
||||||
|
0xb2, 0x6f, 0x90, 0x0f, 0x00, 0x30, 0x02, 0x30, 0x4a, 0x2f, 0xa2, 0x6f, 0x87, 0x52, 0x91, 0x00, 0x85, 0x52, 0x51,
|
||||||
|
0x0e, 0x02, 0x2f, 0x00, 0x2e, 0x43, 0x2c, 0x02, 0x30, 0xc2, 0x6f, 0x7f, 0x52, 0x91, 0x0e, 0x02, 0x30, 0x3c, 0x2f,
|
||||||
|
0x51, 0x6f, 0x81, 0x54, 0x98, 0x2e, 0xfe, 0xc9, 0x10, 0x25, 0xb3, 0x30, 0x21, 0x25, 0x98, 0x2e, 0x0f, 0xca, 0x32,
|
||||||
|
0x6f, 0xc0, 0x7f, 0xb3, 0x30, 0x12, 0x25, 0x98, 0x2e, 0x0f, 0xca, 0x42, 0x6f, 0xb0, 0x7f, 0xb3, 0x30, 0x12, 0x25,
|
||||||
|
0x98, 0x2e, 0x0f, 0xca, 0xb2, 0x6f, 0x90, 0x28, 0x83, 0x52, 0x98, 0x2e, 0xfe, 0xc9, 0xc2, 0x6f, 0x90, 0x0f, 0x00,
|
||||||
|
0x30, 0x02, 0x30, 0x1d, 0x2f, 0x05, 0x2e, 0xa1, 0x01, 0x80, 0xb2, 0x12, 0x30, 0x0f, 0x2f, 0x42, 0x6f, 0x03, 0x2e,
|
||||||
|
0xab, 0x01, 0x91, 0x0e, 0x02, 0x30, 0x12, 0x2f, 0x52, 0x6f, 0x03, 0x2e, 0xac, 0x01, 0x91, 0x0f, 0x02, 0x30, 0x0c,
|
||||||
|
0x2f, 0x21, 0x2e, 0xaa, 0x01, 0x0a, 0x2c, 0x12, 0x30, 0x03, 0x2e, 0xcb, 0x00, 0x8d, 0x58, 0x08, 0x89, 0x41, 0x40,
|
||||||
|
0x11, 0x43, 0x00, 0x43, 0x25, 0x2e, 0xa1, 0x01, 0xd4, 0x6f, 0x8f, 0x52, 0x00, 0x43, 0x3a, 0x89, 0x00, 0x2e, 0x10,
|
||||||
|
0x43, 0x10, 0x43, 0x61, 0x0e, 0xfb, 0x2f, 0x03, 0x2e, 0xa0, 0x01, 0x11, 0x1a, 0x02, 0x2f, 0x02, 0x25, 0x21, 0x2e,
|
||||||
|
0xa0, 0x01, 0xeb, 0x6f, 0x00, 0x5f, 0xb8, 0x2e, 0x91, 0x52, 0x10, 0x30, 0x02, 0x30, 0x95, 0x56, 0x52, 0x42, 0x4b,
|
||||||
|
0x0e, 0xfc, 0x2f, 0x8d, 0x54, 0x88, 0x82, 0x93, 0x56, 0x80, 0x42, 0x53, 0x42, 0x40, 0x42, 0x42, 0x86, 0x83, 0x54,
|
||||||
|
0xc0, 0x2e, 0xc2, 0x42, 0x00, 0x2e, 0xa3, 0x52, 0x00, 0x51, 0x52, 0x40, 0x47, 0x40, 0x1a, 0x25, 0x01, 0x2e, 0x97,
|
||||||
|
0x00, 0x8f, 0xbe, 0x72, 0x86, 0xfb, 0x7f, 0x0b, 0x30, 0x7c, 0xbf, 0xa5, 0x50, 0x10, 0x08, 0xdf, 0xba, 0x70, 0x88,
|
||||||
|
0xf8, 0xbf, 0xcb, 0x42, 0xd3, 0x7f, 0x6c, 0xbb, 0xfc, 0xbb, 0xc5, 0x0a, 0x90, 0x7f, 0x1b, 0x7f, 0x0b, 0x43, 0xc0,
|
||||||
|
0xb2, 0xe5, 0x7f, 0xb7, 0x7f, 0xa6, 0x7f, 0xc4, 0x7f, 0x90, 0x2e, 0x1c, 0xb7, 0x07, 0x2e, 0xd2, 0x00, 0xc0, 0xb2,
|
||||||
|
0x0b, 0x2f, 0x97, 0x52, 0x01, 0x2e, 0xcd, 0x00, 0x82, 0x7f, 0x98, 0x2e, 0xbb, 0xcc, 0x0b, 0x30, 0x37, 0x2e, 0xd2,
|
||||||
|
0x00, 0x82, 0x6f, 0x90, 0x6f, 0x1a, 0x25, 0x00, 0xb2, 0x8b, 0x7f, 0x14, 0x2f, 0xa6, 0xbd, 0x25, 0xbd, 0xb6, 0xb9,
|
||||||
|
0x2f, 0xb9, 0x80, 0xb2, 0xd4, 0xb0, 0x0c, 0x2f, 0x99, 0x54, 0x9b, 0x56, 0x0b, 0x30, 0x0b, 0x2e, 0xb1, 0x00, 0xa1,
|
||||||
|
0x58, 0x9b, 0x42, 0xdb, 0x42, 0x6c, 0x09, 0x2b, 0x2e, 0xb1, 0x00, 0x8b, 0x42, 0xcb, 0x42, 0x86, 0x7f, 0x73, 0x84,
|
||||||
|
0xa7, 0x56, 0xc3, 0x08, 0x39, 0x52, 0x05, 0x50, 0x72, 0x7f, 0x63, 0x7f, 0x98, 0x2e, 0xc2, 0xc0, 0xe1, 0x6f, 0x62,
|
||||||
|
0x6f, 0xd1, 0x0a, 0x01, 0x2e, 0xcd, 0x00, 0xd5, 0x6f, 0xc4, 0x6f, 0x72, 0x6f, 0x97, 0x52, 0x9d, 0x5c, 0x98, 0x2e,
|
||||||
|
0x06, 0xcd, 0x23, 0x6f, 0x90, 0x6f, 0x99, 0x52, 0xc0, 0xb2, 0x04, 0xbd, 0x54, 0x40, 0xaf, 0xb9, 0x45, 0x40, 0xe1,
|
||||||
|
0x7f, 0x02, 0x30, 0x06, 0x2f, 0xc0, 0xb2, 0x02, 0x30, 0x03, 0x2f, 0x9b, 0x5c, 0x12, 0x30, 0x94, 0x43, 0x85, 0x43,
|
||||||
|
0x03, 0xbf, 0x6f, 0xbb, 0x80, 0xb3, 0x20, 0x2f, 0x06, 0x6f, 0x26, 0x01, 0x16, 0x6f, 0x6e, 0x03, 0x45, 0x42, 0xc0,
|
||||||
|
0x90, 0x29, 0x2e, 0xce, 0x00, 0x9b, 0x52, 0x14, 0x2f, 0x9b, 0x5c, 0x00, 0x2e, 0x93, 0x41, 0x86, 0x41, 0xe3, 0x04,
|
||||||
|
0xae, 0x07, 0x80, 0xab, 0x04, 0x2f, 0x80, 0x91, 0x0a, 0x2f, 0x86, 0x6f, 0x73, 0x0f, 0x07, 0x2f, 0x83, 0x6f, 0xc0,
|
||||||
|
0xb2, 0x04, 0x2f, 0x54, 0x42, 0x45, 0x42, 0x12, 0x30, 0x04, 0x2c, 0x11, 0x30, 0x02, 0x2c, 0x11, 0x30, 0x11, 0x30,
|
||||||
|
0x02, 0xbc, 0x0f, 0xb8, 0xd2, 0x7f, 0x00, 0xb2, 0x0a, 0x2f, 0x01, 0x2e, 0xfc, 0x00, 0x05, 0x2e, 0xc7, 0x01, 0x10,
|
||||||
|
0x1a, 0x02, 0x2f, 0x21, 0x2e, 0xc7, 0x01, 0x03, 0x2d, 0x02, 0x2c, 0x01, 0x30, 0x01, 0x30, 0xb0, 0x6f, 0x98, 0x2e,
|
||||||
|
0x95, 0xcf, 0xd1, 0x6f, 0xa0, 0x6f, 0x98, 0x2e, 0x95, 0xcf, 0xe2, 0x6f, 0x9f, 0x52, 0x01, 0x2e, 0xce, 0x00, 0x82,
|
||||||
|
0x40, 0x50, 0x42, 0x0c, 0x2c, 0x42, 0x42, 0x11, 0x30, 0x23, 0x2e, 0xd2, 0x00, 0x01, 0x30, 0xb0, 0x6f, 0x98, 0x2e,
|
||||||
|
0x95, 0xcf, 0xa0, 0x6f, 0x01, 0x30, 0x98, 0x2e, 0x95, 0xcf, 0x00, 0x2e, 0xfb, 0x6f, 0x00, 0x5f, 0xb8, 0x2e, 0x83,
|
||||||
|
0x86, 0x01, 0x30, 0x00, 0x30, 0x94, 0x40, 0x24, 0x18, 0x06, 0x00, 0x53, 0x0e, 0x4f, 0x02, 0xf9, 0x2f, 0xb8, 0x2e,
|
||||||
|
0xa9, 0x52, 0x00, 0x2e, 0x60, 0x40, 0x41, 0x40, 0x0d, 0xbc, 0x98, 0xbc, 0xc0, 0x2e, 0x01, 0x0a, 0x0f, 0xb8, 0xab,
|
||||||
|
0x52, 0x53, 0x3c, 0x52, 0x40, 0x40, 0x40, 0x4b, 0x00, 0x82, 0x16, 0x26, 0xb9, 0x01, 0xb8, 0x41, 0x40, 0x10, 0x08,
|
||||||
|
0x97, 0xb8, 0x01, 0x08, 0xc0, 0x2e, 0x11, 0x30, 0x01, 0x08, 0x43, 0x86, 0x25, 0x40, 0x04, 0x40, 0xd8, 0xbe, 0x2c,
|
||||||
|
0x0b, 0x22, 0x11, 0x54, 0x42, 0x03, 0x80, 0x4b, 0x0e, 0xf6, 0x2f, 0xb8, 0x2e, 0x9f, 0x50, 0x10, 0x50, 0xad, 0x52,
|
||||||
|
0x05, 0x2e, 0xd3, 0x00, 0xfb, 0x7f, 0x00, 0x2e, 0x13, 0x40, 0x93, 0x42, 0x41, 0x0e, 0xfb, 0x2f, 0x98, 0x2e, 0xa5,
|
||||||
|
0xb7, 0x98, 0x2e, 0x87, 0xcf, 0x01, 0x2e, 0xd9, 0x00, 0x00, 0xb2, 0xfb, 0x6f, 0x0b, 0x2f, 0x01, 0x2e, 0x69, 0xf7,
|
||||||
|
0xb1, 0x3f, 0x01, 0x08, 0x01, 0x30, 0xf0, 0x5f, 0x23, 0x2e, 0xd9, 0x00, 0x21, 0x2e, 0x69, 0xf7, 0x80, 0x2e, 0x7a,
|
||||||
|
0xb7, 0xf0, 0x5f, 0xb8, 0x2e, 0x01, 0x2e, 0xc0, 0xf8, 0x03, 0x2e, 0xfc, 0xf5, 0x15, 0x54, 0xaf, 0x56, 0x82, 0x08,
|
||||||
|
0x0b, 0x2e, 0x69, 0xf7, 0xcb, 0x0a, 0xb1, 0x58, 0x80, 0x90, 0xdd, 0xbe, 0x4c, 0x08, 0x5f, 0xb9, 0x59, 0x22, 0x80,
|
||||||
|
0x90, 0x07, 0x2f, 0x03, 0x34, 0xc3, 0x08, 0xf2, 0x3a, 0x0a, 0x08, 0x02, 0x35, 0xc0, 0x90, 0x4a, 0x0a, 0x48, 0x22,
|
||||||
|
0xc0, 0x2e, 0x23, 0x2e, 0xfc, 0xf5, 0x10, 0x50, 0xfb, 0x7f, 0x98, 0x2e, 0x56, 0xc7, 0x98, 0x2e, 0x49, 0xc3, 0x10,
|
||||||
|
0x30, 0xfb, 0x6f, 0xf0, 0x5f, 0x21, 0x2e, 0xcc, 0x00, 0x21, 0x2e, 0xca, 0x00, 0xb8, 0x2e, 0x03, 0x2e, 0xd3, 0x00,
|
||||||
|
0x16, 0xb8, 0x02, 0x34, 0x4a, 0x0c, 0x21, 0x2e, 0x2d, 0xf5, 0xc0, 0x2e, 0x23, 0x2e, 0xd3, 0x00, 0x03, 0xbc, 0x21,
|
||||||
|
0x2e, 0xd5, 0x00, 0x03, 0x2e, 0xd5, 0x00, 0x40, 0xb2, 0x10, 0x30, 0x21, 0x2e, 0x77, 0x00, 0x01, 0x30, 0x05, 0x2f,
|
||||||
|
0x05, 0x2e, 0xd8, 0x00, 0x80, 0x90, 0x01, 0x2f, 0x23, 0x2e, 0x6f, 0xf5, 0xc0, 0x2e, 0x21, 0x2e, 0xd9, 0x00, 0x11,
|
||||||
|
0x30, 0x81, 0x08, 0x01, 0x2e, 0x6a, 0xf7, 0x71, 0x3f, 0x23, 0xbd, 0x01, 0x08, 0x02, 0x0a, 0xc0, 0x2e, 0x21, 0x2e,
|
||||||
|
0x6a, 0xf7, 0x30, 0x25, 0x00, 0x30, 0x21, 0x2e, 0x5a, 0xf5, 0x10, 0x50, 0x21, 0x2e, 0x7b, 0x00, 0x21, 0x2e, 0x7c,
|
||||||
|
0x00, 0xfb, 0x7f, 0x98, 0x2e, 0xc3, 0xb7, 0x40, 0x30, 0x21, 0x2e, 0xd4, 0x00, 0xfb, 0x6f, 0xf0, 0x5f, 0x03, 0x25,
|
||||||
|
0x80, 0x2e, 0xaf, 0xb7, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00,
|
||||||
|
0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e,
|
||||||
|
0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80,
|
||||||
|
0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x01, 0x2e, 0x5d, 0xf7, 0x08, 0xbc, 0x80, 0xac, 0x0e, 0xbb, 0x02, 0x2f,
|
||||||
|
0x00, 0x30, 0x41, 0x04, 0x82, 0x06, 0xc0, 0xa4, 0x00, 0x30, 0x11, 0x2f, 0x40, 0xa9, 0x03, 0x2f, 0x40, 0x91, 0x0d,
|
||||||
|
0x2f, 0x00, 0xa7, 0x0b, 0x2f, 0x80, 0xb3, 0xb3, 0x58, 0x02, 0x2f, 0x90, 0xa1, 0x26, 0x13, 0x20, 0x23, 0x80, 0x90,
|
||||||
|
0x10, 0x30, 0x01, 0x2f, 0xcc, 0x0e, 0x00, 0x2f, 0x00, 0x30, 0xb8, 0x2e, 0xb5, 0x50, 0x18, 0x08, 0x08, 0xbc, 0x88,
|
||||||
|
0xb6, 0x0d, 0x17, 0xc6, 0xbd, 0x56, 0xbc, 0xb7, 0x58, 0xda, 0xba, 0x04, 0x01, 0x1d, 0x0a, 0x10, 0x50, 0x05, 0x30,
|
||||||
|
0x32, 0x25, 0x45, 0x03, 0xfb, 0x7f, 0xf6, 0x30, 0x21, 0x25, 0x98, 0x2e, 0x37, 0xca, 0x16, 0xb5, 0x9a, 0xbc, 0x06,
|
||||||
|
0xb8, 0x80, 0xa8, 0x41, 0x0a, 0x0e, 0x2f, 0x80, 0x90, 0x02, 0x2f, 0x2d, 0x50, 0x48, 0x0f, 0x09, 0x2f, 0xbf, 0xa0,
|
||||||
|
0x04, 0x2f, 0xbf, 0x90, 0x06, 0x2f, 0xb7, 0x54, 0xca, 0x0f, 0x03, 0x2f, 0x00, 0x2e, 0x02, 0x2c, 0xb7, 0x52, 0x2d,
|
||||||
|
0x52, 0xf2, 0x33, 0x98, 0x2e, 0xd9, 0xc0, 0xfb, 0x6f, 0xf1, 0x37, 0xc0, 0x2e, 0x01, 0x08, 0xf0, 0x5f, 0xbf, 0x56,
|
||||||
|
0xb9, 0x54, 0xd0, 0x40, 0xc4, 0x40, 0x0b, 0x2e, 0xfd, 0xf3, 0xbf, 0x52, 0x90, 0x42, 0x94, 0x42, 0x95, 0x42, 0x05,
|
||||||
|
0x30, 0xc1, 0x50, 0x0f, 0x88, 0x06, 0x40, 0x04, 0x41, 0x96, 0x42, 0xc5, 0x42, 0x48, 0xbe, 0x73, 0x30, 0x0d, 0x2e,
|
||||||
|
0xd8, 0x00, 0x4f, 0xba, 0x84, 0x42, 0x03, 0x42, 0x81, 0xb3, 0x02, 0x2f, 0x2b, 0x2e, 0x6f, 0xf5, 0x06, 0x2d, 0x05,
|
||||||
|
0x2e, 0x77, 0xf7, 0xbd, 0x56, 0x93, 0x08, 0x25, 0x2e, 0x77, 0xf7, 0xbb, 0x54, 0x25, 0x2e, 0xc2, 0xf5, 0x07, 0x2e,
|
||||||
|
0xfd, 0xf3, 0x42, 0x30, 0xb4, 0x33, 0xda, 0x0a, 0x4c, 0x00, 0x27, 0x2e, 0xfd, 0xf3, 0x43, 0x40, 0xd4, 0x3f, 0xdc,
|
||||||
|
0x08, 0x43, 0x42, 0x00, 0x2e, 0x00, 0x2e, 0x43, 0x40, 0x24, 0x30, 0xdc, 0x0a, 0x43, 0x42, 0x04, 0x80, 0x03, 0x2e,
|
||||||
|
0xfd, 0xf3, 0x4a, 0x0a, 0x23, 0x2e, 0xfd, 0xf3, 0x61, 0x34, 0xc0, 0x2e, 0x01, 0x42, 0x00, 0x2e, 0x60, 0x50, 0x1a,
|
||||||
|
0x25, 0x7a, 0x86, 0xe0, 0x7f, 0xf3, 0x7f, 0x03, 0x25, 0xc3, 0x52, 0x41, 0x84, 0xdb, 0x7f, 0x33, 0x30, 0x98, 0x2e,
|
||||||
|
0x16, 0xc2, 0x1a, 0x25, 0x7d, 0x82, 0xf0, 0x6f, 0xe2, 0x6f, 0x32, 0x25, 0x16, 0x40, 0x94, 0x40, 0x26, 0x01, 0x85,
|
||||||
|
0x40, 0x8e, 0x17, 0xc4, 0x42, 0x6e, 0x03, 0x95, 0x42, 0x41, 0x0e, 0xf4, 0x2f, 0xdb, 0x6f, 0xa0, 0x5f, 0xb8, 0x2e,
|
||||||
|
0xb0, 0x51, 0xfb, 0x7f, 0x98, 0x2e, 0xe8, 0x0d, 0x5a, 0x25, 0x98, 0x2e, 0x0f, 0x0e, 0xcb, 0x58, 0x32, 0x87, 0xc4,
|
||||||
|
0x7f, 0x65, 0x89, 0x6b, 0x8d, 0xc5, 0x5a, 0x65, 0x7f, 0xe1, 0x7f, 0x83, 0x7f, 0xa6, 0x7f, 0x74, 0x7f, 0xd0, 0x7f,
|
||||||
|
0xb6, 0x7f, 0x94, 0x7f, 0x17, 0x30, 0xc7, 0x52, 0xc9, 0x54, 0x51, 0x7f, 0x00, 0x2e, 0x85, 0x6f, 0x42, 0x7f, 0x00,
|
||||||
|
0x2e, 0x51, 0x41, 0x45, 0x81, 0x42, 0x41, 0x13, 0x40, 0x3b, 0x8a, 0x00, 0x40, 0x4b, 0x04, 0xd0, 0x06, 0xc0, 0xac,
|
||||||
|
0x85, 0x7f, 0x02, 0x2f, 0x02, 0x30, 0x51, 0x04, 0xd3, 0x06, 0x41, 0x84, 0x05, 0x30, 0x5d, 0x02, 0xc9, 0x16, 0xdf,
|
||||||
|
0x08, 0xd3, 0x00, 0x8d, 0x02, 0xaf, 0xbc, 0xb1, 0xb9, 0x59, 0x0a, 0x65, 0x6f, 0x11, 0x43, 0xa1, 0xb4, 0x52, 0x41,
|
||||||
|
0x53, 0x41, 0x01, 0x43, 0x34, 0x7f, 0x65, 0x7f, 0x26, 0x31, 0xe5, 0x6f, 0xd4, 0x6f, 0x98, 0x2e, 0x37, 0xca, 0x32,
|
||||||
|
0x6f, 0x75, 0x6f, 0x83, 0x40, 0x42, 0x41, 0x23, 0x7f, 0x12, 0x7f, 0xf6, 0x30, 0x40, 0x25, 0x51, 0x25, 0x98, 0x2e,
|
||||||
|
0x37, 0xca, 0x14, 0x6f, 0x20, 0x05, 0x70, 0x6f, 0x25, 0x6f, 0x69, 0x07, 0xa2, 0x6f, 0x31, 0x6f, 0x0b, 0x30, 0x04,
|
||||||
|
0x42, 0x9b, 0x42, 0x8b, 0x42, 0x55, 0x42, 0x32, 0x7f, 0x40, 0xa9, 0xc3, 0x6f, 0x71, 0x7f, 0x02, 0x30, 0xd0, 0x40,
|
||||||
|
0xc3, 0x7f, 0x03, 0x2f, 0x40, 0x91, 0x15, 0x2f, 0x00, 0xa7, 0x13, 0x2f, 0x00, 0xa4, 0x11, 0x2f, 0x84, 0xbd, 0x98,
|
||||||
|
0x2e, 0x79, 0xca, 0x55, 0x6f, 0xb7, 0x54, 0x54, 0x41, 0x82, 0x00, 0xf3, 0x3f, 0x45, 0x41, 0xcb, 0x02, 0xf6, 0x30,
|
||||||
|
0x98, 0x2e, 0x37, 0xca, 0x35, 0x6f, 0xa4, 0x6f, 0x41, 0x43, 0x03, 0x2c, 0x00, 0x43, 0xa4, 0x6f, 0x35, 0x6f, 0x17,
|
||||||
|
0x30, 0x42, 0x6f, 0x51, 0x6f, 0x93, 0x40, 0x42, 0x82, 0x00, 0x41, 0xc3, 0x00, 0x03, 0x43, 0x51, 0x7f, 0x00, 0x2e,
|
||||||
|
0x94, 0x40, 0x41, 0x41, 0x4c, 0x02, 0xc4, 0x6f, 0xd1, 0x56, 0x63, 0x0e, 0x74, 0x6f, 0x51, 0x43, 0xa5, 0x7f, 0x8a,
|
||||||
|
0x2f, 0x09, 0x2e, 0xd8, 0x00, 0x01, 0xb3, 0x21, 0x2f, 0xcb, 0x58, 0x90, 0x6f, 0x13, 0x41, 0xb6, 0x6f, 0xe4, 0x7f,
|
||||||
|
0x00, 0x2e, 0x91, 0x41, 0x14, 0x40, 0x92, 0x41, 0x15, 0x40, 0x17, 0x2e, 0x6f, 0xf5, 0xb6, 0x7f, 0xd0, 0x7f, 0xcb,
|
||||||
|
0x7f, 0x98, 0x2e, 0x00, 0x0c, 0x07, 0x15, 0xc2, 0x6f, 0x14, 0x0b, 0x29, 0x2e, 0x6f, 0xf5, 0xc3, 0xa3, 0xc1, 0x8f,
|
||||||
|
0xe4, 0x6f, 0xd0, 0x6f, 0xe6, 0x2f, 0x14, 0x30, 0x05, 0x2e, 0x6f, 0xf5, 0x14, 0x0b, 0x29, 0x2e, 0x6f, 0xf5, 0x18,
|
||||||
|
0x2d, 0xcd, 0x56, 0x04, 0x32, 0xb5, 0x6f, 0x1c, 0x01, 0x51, 0x41, 0x52, 0x41, 0xc3, 0x40, 0xb5, 0x7f, 0xe4, 0x7f,
|
||||||
|
0x98, 0x2e, 0x1f, 0x0c, 0xe4, 0x6f, 0x21, 0x87, 0x00, 0x43, 0x04, 0x32, 0xcf, 0x54, 0x5a, 0x0e, 0xef, 0x2f, 0x15,
|
||||||
|
0x54, 0x09, 0x2e, 0x77, 0xf7, 0x22, 0x0b, 0x29, 0x2e, 0x77, 0xf7, 0xfb, 0x6f, 0x50, 0x5e, 0xb8, 0x2e, 0x10, 0x50,
|
||||||
|
0x01, 0x2e, 0xd4, 0x00, 0x00, 0xb2, 0xfb, 0x7f, 0x51, 0x2f, 0x01, 0xb2, 0x48, 0x2f, 0x02, 0xb2, 0x42, 0x2f, 0x03,
|
||||||
|
0x90, 0x56, 0x2f, 0xd7, 0x52, 0x79, 0x80, 0x42, 0x40, 0x81, 0x84, 0x00, 0x40, 0x42, 0x42, 0x98, 0x2e, 0x93, 0x0c,
|
||||||
|
0xd9, 0x54, 0xd7, 0x50, 0xa1, 0x40, 0x98, 0xbd, 0x82, 0x40, 0x3e, 0x82, 0xda, 0x0a, 0x44, 0x40, 0x8b, 0x16, 0xe3,
|
||||||
|
0x00, 0x53, 0x42, 0x00, 0x2e, 0x43, 0x40, 0x9a, 0x02, 0x52, 0x42, 0x00, 0x2e, 0x41, 0x40, 0x15, 0x54, 0x4a, 0x0e,
|
||||||
|
0x3a, 0x2f, 0x3a, 0x82, 0x00, 0x30, 0x41, 0x40, 0x21, 0x2e, 0x85, 0x0f, 0x40, 0xb2, 0x0a, 0x2f, 0x98, 0x2e, 0xb1,
|
||||||
|
0x0c, 0x98, 0x2e, 0x45, 0x0e, 0x98, 0x2e, 0x5b, 0x0e, 0xfb, 0x6f, 0xf0, 0x5f, 0x00, 0x30, 0x80, 0x2e, 0xce, 0xb7,
|
||||||
|
0xdd, 0x52, 0xd3, 0x54, 0x42, 0x42, 0x4f, 0x84, 0x73, 0x30, 0xdb, 0x52, 0x83, 0x42, 0x1b, 0x30, 0x6b, 0x42, 0x23,
|
||||||
|
0x30, 0x27, 0x2e, 0xd7, 0x00, 0x37, 0x2e, 0xd4, 0x00, 0x21, 0x2e, 0xd6, 0x00, 0x7a, 0x84, 0x17, 0x2c, 0x42, 0x42,
|
||||||
|
0x30, 0x30, 0x21, 0x2e, 0xd4, 0x00, 0x12, 0x2d, 0x21, 0x30, 0x00, 0x30, 0x23, 0x2e, 0xd4, 0x00, 0x21, 0x2e, 0x7b,
|
||||||
|
0xf7, 0x0b, 0x2d, 0x17, 0x30, 0x98, 0x2e, 0x51, 0x0c, 0xd5, 0x50, 0x0c, 0x82, 0x72, 0x30, 0x2f, 0x2e, 0xd4, 0x00,
|
||||||
|
0x25, 0x2e, 0x7b, 0xf7, 0x40, 0x42, 0x00, 0x2e, 0xfb, 0x6f, 0xf0, 0x5f, 0xb8, 0x2e, 0x70, 0x50, 0x0a, 0x25, 0x39,
|
||||||
|
0x86, 0xfb, 0x7f, 0xe1, 0x32, 0x62, 0x30, 0x98, 0x2e, 0xc2, 0xc4, 0xb5, 0x56, 0xa5, 0x6f, 0xab, 0x08, 0x91, 0x6f,
|
||||||
|
0x4b, 0x08, 0xdf, 0x56, 0xc4, 0x6f, 0x23, 0x09, 0x4d, 0xba, 0x93, 0xbc, 0x8c, 0x0b, 0xd1, 0x6f, 0x0b, 0x09, 0xcb,
|
||||||
|
0x52, 0xe1, 0x5e, 0x56, 0x42, 0xaf, 0x09, 0x4d, 0xba, 0x23, 0xbd, 0x94, 0x0a, 0xe5, 0x6f, 0x68, 0xbb, 0xeb, 0x08,
|
||||||
|
0xbd, 0xb9, 0x63, 0xbe, 0xfb, 0x6f, 0x52, 0x42, 0xe3, 0x0a, 0xc0, 0x2e, 0x43, 0x42, 0x90, 0x5f, 0xd1, 0x50, 0x03,
|
||||||
|
0x2e, 0x25, 0xf3, 0x13, 0x40, 0x00, 0x40, 0x9b, 0xbc, 0x9b, 0xb4, 0x08, 0xbd, 0xb8, 0xb9, 0x98, 0xbc, 0xda, 0x0a,
|
||||||
|
0x08, 0xb6, 0x89, 0x16, 0xc0, 0x2e, 0x19, 0x00, 0x62, 0x02, 0x10, 0x50, 0xfb, 0x7f, 0x98, 0x2e, 0x81, 0x0d, 0x01,
|
||||||
|
0x2e, 0xd4, 0x00, 0x31, 0x30, 0x08, 0x04, 0xfb, 0x6f, 0x01, 0x30, 0xf0, 0x5f, 0x23, 0x2e, 0xd6, 0x00, 0x21, 0x2e,
|
||||||
|
0xd7, 0x00, 0xb8, 0x2e, 0x01, 0x2e, 0xd7, 0x00, 0x03, 0x2e, 0xd6, 0x00, 0x48, 0x0e, 0x01, 0x2f, 0x80, 0x2e, 0x1f,
|
||||||
|
0x0e, 0xb8, 0x2e, 0xe3, 0x50, 0x21, 0x34, 0x01, 0x42, 0x82, 0x30, 0xc1, 0x32, 0x25, 0x2e, 0x62, 0xf5, 0x01, 0x00,
|
||||||
|
0x22, 0x30, 0x01, 0x40, 0x4a, 0x0a, 0x01, 0x42, 0xb8, 0x2e, 0xe3, 0x54, 0xf0, 0x3b, 0x83, 0x40, 0xd8, 0x08, 0xe5,
|
||||||
|
0x52, 0x83, 0x42, 0x00, 0x30, 0x83, 0x30, 0x50, 0x42, 0xc4, 0x32, 0x27, 0x2e, 0x64, 0xf5, 0x94, 0x00, 0x50, 0x42,
|
||||||
|
0x40, 0x42, 0xd3, 0x3f, 0x84, 0x40, 0x7d, 0x82, 0xe3, 0x08, 0x40, 0x42, 0x83, 0x42, 0xb8, 0x2e, 0xdd, 0x52, 0x00,
|
||||||
|
0x30, 0x40, 0x42, 0x7c, 0x86, 0xb9, 0x52, 0x09, 0x2e, 0x70, 0x0f, 0xbf, 0x54, 0xc4, 0x42, 0xd3, 0x86, 0x54, 0x40,
|
||||||
|
0x55, 0x40, 0x94, 0x42, 0x85, 0x42, 0x21, 0x2e, 0xd7, 0x00, 0x42, 0x40, 0x25, 0x2e, 0xfd, 0xf3, 0xc0, 0x42, 0x7e,
|
||||||
|
0x82, 0x05, 0x2e, 0x7d, 0x00, 0x80, 0xb2, 0x14, 0x2f, 0x05, 0x2e, 0x89, 0x00, 0x27, 0xbd, 0x2f, 0xb9, 0x80, 0x90,
|
||||||
|
0x02, 0x2f, 0x21, 0x2e, 0x6f, 0xf5, 0x0c, 0x2d, 0x07, 0x2e, 0x71, 0x0f, 0x14, 0x30, 0x1c, 0x09, 0x05, 0x2e, 0x77,
|
||||||
|
0xf7, 0xbd, 0x56, 0x47, 0xbe, 0x93, 0x08, 0x94, 0x0a, 0x25, 0x2e, 0x77, 0xf7, 0xe7, 0x54, 0x50, 0x42, 0x4a, 0x0e,
|
||||||
|
0xfc, 0x2f, 0xb8, 0x2e, 0x50, 0x50, 0x02, 0x30, 0x43, 0x86, 0xe5, 0x50, 0xfb, 0x7f, 0xe3, 0x7f, 0xd2, 0x7f, 0xc0,
|
||||||
|
0x7f, 0xb1, 0x7f, 0x00, 0x2e, 0x41, 0x40, 0x00, 0x40, 0x48, 0x04, 0x98, 0x2e, 0x74, 0xc0, 0x1e, 0xaa, 0xd3, 0x6f,
|
||||||
|
0x14, 0x30, 0xb1, 0x6f, 0xe3, 0x22, 0xc0, 0x6f, 0x52, 0x40, 0xe4, 0x6f, 0x4c, 0x0e, 0x12, 0x42, 0xd3, 0x7f, 0xeb,
|
||||||
|
0x2f, 0x03, 0x2e, 0x86, 0x0f, 0x40, 0x90, 0x11, 0x30, 0x03, 0x2f, 0x23, 0x2e, 0x86, 0x0f, 0x02, 0x2c, 0x00, 0x30,
|
||||||
|
0xd0, 0x6f, 0xfb, 0x6f, 0xb0, 0x5f, 0xb8, 0x2e, 0x40, 0x50, 0xf1, 0x7f, 0x0a, 0x25, 0x3c, 0x86, 0xeb, 0x7f, 0x41,
|
||||||
|
0x33, 0x22, 0x30, 0x98, 0x2e, 0xc2, 0xc4, 0xd3, 0x6f, 0xf4, 0x30, 0xdc, 0x09, 0x47, 0x58, 0xc2, 0x6f, 0x94, 0x09,
|
||||||
|
0xeb, 0x58, 0x6a, 0xbb, 0xdc, 0x08, 0xb4, 0xb9, 0xb1, 0xbd, 0xe9, 0x5a, 0x95, 0x08, 0x21, 0xbd, 0xf6, 0xbf, 0x77,
|
||||||
|
0x0b, 0x51, 0xbe, 0xf1, 0x6f, 0xeb, 0x6f, 0x52, 0x42, 0x54, 0x42, 0xc0, 0x2e, 0x43, 0x42, 0xc0, 0x5f, 0x50, 0x50,
|
||||||
|
0xf5, 0x50, 0x31, 0x30, 0x11, 0x42, 0xfb, 0x7f, 0x7b, 0x30, 0x0b, 0x42, 0x11, 0x30, 0x02, 0x80, 0x23, 0x33, 0x01,
|
||||||
|
0x42, 0x03, 0x00, 0x07, 0x2e, 0x80, 0x03, 0x05, 0x2e, 0xd3, 0x00, 0x23, 0x52, 0xe2, 0x7f, 0xd3, 0x7f, 0xc0, 0x7f,
|
||||||
|
0x98, 0x2e, 0xb6, 0x0e, 0xd1, 0x6f, 0x08, 0x0a, 0x1a, 0x25, 0x7b, 0x86, 0xd0, 0x7f, 0x01, 0x33, 0x12, 0x30, 0x98,
|
||||||
|
0x2e, 0xc2, 0xc4, 0xd1, 0x6f, 0x08, 0x0a, 0x00, 0xb2, 0x0d, 0x2f, 0xe3, 0x6f, 0x01, 0x2e, 0x80, 0x03, 0x51, 0x30,
|
||||||
|
0xc7, 0x86, 0x23, 0x2e, 0x21, 0xf2, 0x08, 0xbc, 0xc0, 0x42, 0x98, 0x2e, 0xa5, 0xb7, 0x00, 0x2e, 0x00, 0x2e, 0xd0,
|
||||||
|
0x2e, 0xb0, 0x6f, 0x0b, 0xb8, 0x03, 0x2e, 0x1b, 0x00, 0x08, 0x1a, 0xb0, 0x7f, 0x70, 0x30, 0x04, 0x2f, 0x21, 0x2e,
|
||||||
|
0x21, 0xf2, 0x00, 0x2e, 0x00, 0x2e, 0xd0, 0x2e, 0x98, 0x2e, 0x6d, 0xc0, 0x98, 0x2e, 0x5d, 0xc0, 0xed, 0x50, 0x98,
|
||||||
|
0x2e, 0x44, 0xcb, 0xef, 0x50, 0x98, 0x2e, 0x46, 0xc3, 0xf1, 0x50, 0x98, 0x2e, 0x53, 0xc7, 0x35, 0x50, 0x98, 0x2e,
|
||||||
|
0x64, 0xcf, 0x10, 0x30, 0x98, 0x2e, 0xdc, 0x03, 0x20, 0x26, 0xc0, 0x6f, 0x02, 0x31, 0x12, 0x42, 0xab, 0x33, 0x0b,
|
||||||
|
0x42, 0x37, 0x80, 0x01, 0x30, 0x01, 0x42, 0xf3, 0x37, 0xf7, 0x52, 0xfb, 0x50, 0x44, 0x40, 0xa2, 0x0a, 0x42, 0x42,
|
||||||
|
0x8b, 0x31, 0x09, 0x2e, 0x5e, 0xf7, 0xf9, 0x54, 0xe3, 0x08, 0x83, 0x42, 0x1b, 0x42, 0x23, 0x33, 0x4b, 0x00, 0xbc,
|
||||||
|
0x84, 0x0b, 0x40, 0x33, 0x30, 0x83, 0x42, 0x0b, 0x42, 0xe0, 0x7f, 0xd1, 0x7f, 0x98, 0x2e, 0x58, 0xb7, 0xd1, 0x6f,
|
||||||
|
0x80, 0x30, 0x40, 0x42, 0x03, 0x30, 0xe0, 0x6f, 0xf3, 0x54, 0x04, 0x30, 0x00, 0x2e, 0x00, 0x2e, 0x01, 0x89, 0x62,
|
||||||
|
0x0e, 0xfa, 0x2f, 0x43, 0x42, 0x11, 0x30, 0xfb, 0x6f, 0xc0, 0x2e, 0x01, 0x42, 0xb0, 0x5f, 0xc1, 0x4a, 0x00, 0x00,
|
||||||
|
0x6d, 0x57, 0x00, 0x00, 0x77, 0x8e, 0x00, 0x00, 0xe0, 0xff, 0xff, 0xff, 0xd3, 0xff, 0xff, 0xff, 0xe5, 0xff, 0xff,
|
||||||
|
0xff, 0xee, 0xe1, 0xff, 0xff, 0x7c, 0x13, 0x00, 0x00, 0x46, 0xe6, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x2e, 0x00, 0xc1, 0x80,
|
||||||
|
0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1,
|
||||||
|
0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00,
|
||||||
|
0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e,
|
||||||
|
0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80,
|
||||||
|
0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1,
|
||||||
|
0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00,
|
||||||
|
0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e,
|
||||||
|
0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80,
|
||||||
|
0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1,
|
||||||
|
0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00,
|
||||||
|
0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e,
|
||||||
|
0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80, 0x2e, 0x00, 0xc1, 0x80,
|
||||||
|
0x2e, 0x00, 0xc1
|
||||||
|
};
|
||||||
177
Drivers/bmi270-module/source/bmi270.cpp
Normal file
177
Drivers/bmi270-module/source/bmi270.cpp
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#include <drivers/bmi270.h>
|
||||||
|
#include <bmi270_module.h>
|
||||||
|
#include <drivers/bmi270_config_data.h>
|
||||||
|
#include <tactility/device.h>
|
||||||
|
#include <tactility/drivers/i2c_controller.h>
|
||||||
|
#include <tactility/log.h>
|
||||||
|
|
||||||
|
#define TAG "BMI270"
|
||||||
|
|
||||||
|
static constexpr uint8_t REG_CHIP_ID = 0x00; // read: expect 0x24
|
||||||
|
static constexpr uint8_t REG_DATA_ACC = 0x0C; // 6 bytes: acc X/Y/Z LSB/MSB
|
||||||
|
static constexpr uint8_t REG_DATA_GYR = 0x12; // 6 bytes: gyr X/Y/Z LSB/MSB
|
||||||
|
static constexpr uint8_t REG_INTERNAL_ST = 0x21; // bit0: init done
|
||||||
|
static constexpr uint8_t REG_ACC_CONF = 0x40; // ODR + BWP + filter_perf
|
||||||
|
static constexpr uint8_t REG_ACC_RANGE = 0x41; // range selector
|
||||||
|
static constexpr uint8_t REG_GYR_CONF = 0x42; // ODR + BWP
|
||||||
|
static constexpr uint8_t REG_GYR_RANGE = 0x43; // range selector
|
||||||
|
static constexpr uint8_t REG_INIT_CTRL = 0x59; // 0=start upload, 1=done
|
||||||
|
static constexpr uint8_t REG_INIT_ADDR_0 = 0x5B; // burst address low nibble
|
||||||
|
// REG_INIT_ADDR_1 = 0x5C written together with 0x5B (2-byte burst)
|
||||||
|
static constexpr uint8_t REG_INIT_DATA = 0x5E; // config burst write target
|
||||||
|
static constexpr uint8_t REG_PWR_CONF = 0x7C; // 0=disable adv. power save
|
||||||
|
static constexpr uint8_t REG_PWR_CTRL = 0x7D; // bit1=gyr_en, bit2=acc_en
|
||||||
|
static constexpr uint8_t REG_CMD = 0x7E; // 0xB6 = soft reset
|
||||||
|
|
||||||
|
// ACC_CONF: filter_perf=1, bwp=normal(2), odr=100Hz(8) → 0xA8
|
||||||
|
static constexpr uint8_t ACC_CONF_VAL = 0xA8;
|
||||||
|
static constexpr uint8_t ACC_RANGE_VAL = 0x02; // ±8g
|
||||||
|
// GYR_CONF: filter_perf=1, noise_perf=1, bwp=normal(2), odr=100Hz(8) → 0xE8
|
||||||
|
static constexpr uint8_t GYR_CONF_VAL = 0xE8;
|
||||||
|
static constexpr uint8_t GYR_RANGE_VAL = 0x00; // ±2000°/s
|
||||||
|
|
||||||
|
// Scaling: full-scale / 2^15
|
||||||
|
static constexpr float ACCEL_SCALE = 8.0f / 32768.0f; // g per LSB (±8g)
|
||||||
|
static constexpr float GYRO_SCALE = 2000.0f / 32768.0f; // °/s per LSB (±2000°/s)
|
||||||
|
|
||||||
|
// Config upload chunk size (bytes of config data per I2C transaction)
|
||||||
|
static constexpr size_t CHUNK_SIZE = 64;
|
||||||
|
|
||||||
|
static constexpr TickType_t I2C_TIMEOUT_TICKS = pdMS_TO_TICKS(10);
|
||||||
|
|
||||||
|
#define GET_CONFIG(device) (static_cast<const Bmi270Config*>((device)->config))
|
||||||
|
|
||||||
|
// region Helpers
|
||||||
|
|
||||||
|
static bool configure(Device* i2c_controller, uint8_t address) {
|
||||||
|
// Disable advanced power save before uploading
|
||||||
|
if (i2c_controller_register8_set(i2c_controller, address, REG_PWR_CONF, 0x00, I2C_TIMEOUT_TICKS) != ERROR_NONE) return false;
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(1));
|
||||||
|
|
||||||
|
// Signal start of config upload
|
||||||
|
if (i2c_controller_register8_set(i2c_controller, address, REG_INIT_CTRL, 0x00, I2C_TIMEOUT_TICKS) != ERROR_NONE) return false;
|
||||||
|
|
||||||
|
// Upload config in CHUNK_SIZE-byte bursts
|
||||||
|
// The half-word address (hwAddr) increments by CHUNK_SIZE/2 per chunk
|
||||||
|
constexpr size_t config_data_size = sizeof(bmi270_config_data);
|
||||||
|
for (size_t offset = 0; offset < config_data_size; offset += CHUNK_SIZE) {
|
||||||
|
// Set INIT_ADDR_0 and INIT_ADDR_1 (consecutive registers 0x5B/0x5C)
|
||||||
|
auto hardware_address = static_cast<uint16_t>(offset / 2);
|
||||||
|
uint8_t address_buffer[2] = {
|
||||||
|
static_cast<uint8_t>(hardware_address & 0x0Fu), // INIT_ADDR_0: bits [3:0]
|
||||||
|
static_cast<uint8_t>((hardware_address >> 4) & 0xFFu) // INIT_ADDR_1: bits [11:4]
|
||||||
|
};
|
||||||
|
|
||||||
|
if (i2c_controller_write_register(i2c_controller, address, REG_INIT_ADDR_0, address_buffer, 2, I2C_TIMEOUT_TICKS) != ERROR_NONE) return false;
|
||||||
|
|
||||||
|
// Write chunk to INIT_DATA register.
|
||||||
|
// Copy to a stack buffer first: the config array may live in DROM (SPI flash)
|
||||||
|
// which is not DMA-accessible; the I2C driver requires DRAM-backed buffers.
|
||||||
|
size_t chunk_length = (offset + CHUNK_SIZE <= config_data_size) ? CHUNK_SIZE : (config_data_size - offset);
|
||||||
|
uint8_t chunk_buffer[CHUNK_SIZE];
|
||||||
|
memcpy(chunk_buffer, bmi270_config_data + offset, chunk_length);
|
||||||
|
if (i2c_controller_write_register(i2c_controller, address, REG_INIT_DATA, chunk_buffer, static_cast<uint16_t>(chunk_length), I2C_TIMEOUT_TICKS) != ERROR_NONE) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Signal end of config upload
|
||||||
|
if (i2c_controller_register8_set(i2c_controller, address, REG_INIT_CTRL, 0x01, I2C_TIMEOUT_TICKS) != ERROR_NONE) return false;
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(20));
|
||||||
|
|
||||||
|
// Verify initialization
|
||||||
|
uint8_t status = 0;
|
||||||
|
if (i2c_controller_register8_get(i2c_controller, address, REG_INTERNAL_ST, &status, I2C_TIMEOUT_TICKS) != ERROR_NONE) return false;
|
||||||
|
return (status & 0x01u) != 0; // bit 0 = init_ok
|
||||||
|
}
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
// region Driver lifecycle
|
||||||
|
|
||||||
|
static error_t start(Device* device) {
|
||||||
|
auto* i2c_controller = device_get_parent(device);
|
||||||
|
if (device_get_type(i2c_controller) != &I2C_CONTROLLER_TYPE) {
|
||||||
|
LOG_E(TAG, "Parent is not an I2C controller");
|
||||||
|
return ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto address = GET_CONFIG(device)->address;
|
||||||
|
|
||||||
|
// Verify chip ID
|
||||||
|
uint8_t chip_id= 0;
|
||||||
|
if (i2c_controller_register8_get(i2c_controller, address, REG_CHIP_ID, &chip_id, I2C_TIMEOUT_TICKS) != ERROR_NONE || chip_id != 0x24) {
|
||||||
|
return ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Soft reset — clears all registers; datasheet specifies 2 ms startup time.
|
||||||
|
// Use 20 ms to be safe and allow the chip to fully re-initialise before
|
||||||
|
// any further I2C traffic (a second chip-ID read immediately after reset
|
||||||
|
// is unreliable and not part of the Bosch SensorAPI init flow).
|
||||||
|
if (i2c_controller_register8_set(i2c_controller, address, REG_CMD, 0xB6, I2C_TIMEOUT_TICKS) != ERROR_NONE) return ERROR_RESOURCE;
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(20));
|
||||||
|
|
||||||
|
// Upload 8KB configuration (enables internal feature engine)
|
||||||
|
if (!configure(i2c_controller, address)) {
|
||||||
|
return ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure accelerometer: ODR=100Hz, normal filter, ±8g
|
||||||
|
if (i2c_controller_register8_set(i2c_controller, address, REG_ACC_CONF, ACC_CONF_VAL, I2C_TIMEOUT_TICKS) != ERROR_NONE) return ERROR_RESOURCE;
|
||||||
|
if (i2c_controller_register8_set(i2c_controller, address, REG_ACC_RANGE, ACC_RANGE_VAL, I2C_TIMEOUT_TICKS) != ERROR_NONE) return ERROR_RESOURCE;
|
||||||
|
|
||||||
|
// Configure gyroscope: ODR=100Hz, normal filter, ±2000°/s
|
||||||
|
if (i2c_controller_register8_set(i2c_controller, address, REG_GYR_CONF, GYR_CONF_VAL, I2C_TIMEOUT_TICKS) != ERROR_NONE) return ERROR_RESOURCE;
|
||||||
|
if (i2c_controller_register8_set(i2c_controller, address, REG_GYR_RANGE, GYR_RANGE_VAL, I2C_TIMEOUT_TICKS) != ERROR_NONE) return ERROR_RESOURCE;
|
||||||
|
|
||||||
|
// Enable accelerometer and gyroscope (bit1=gyr_en, bit2=acc_en)
|
||||||
|
if (i2c_controller_register8_set(i2c_controller, address, REG_PWR_CTRL, 0x06, I2C_TIMEOUT_TICKS) != ERROR_NONE) return ERROR_RESOURCE;
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(2));
|
||||||
|
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t stop(Device* device) {
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// endregion
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
error_t bmi270_read(Device* device, Bmi270Data* data) {
|
||||||
|
auto* i2c_controller = device_get_parent(device);
|
||||||
|
|
||||||
|
auto address = GET_CONFIG(device)->address;
|
||||||
|
|
||||||
|
// Burst-read 12 bytes: acc X/Y/Z (6 bytes) + gyro X/Y/Z (6 bytes)
|
||||||
|
// Registers: 0x0C–0x17 are contiguous for acc+gyro in I2C mode (no dummy byte)
|
||||||
|
uint8_t buffer[12] = {};
|
||||||
|
error_t error = i2c_controller_read_register(i2c_controller, address, REG_DATA_ACC, buffer, sizeof(buffer), I2C_TIMEOUT_TICKS);
|
||||||
|
if (error != ERROR_NONE) return error;
|
||||||
|
|
||||||
|
auto toI16 = [](uint8_t lo, uint8_t hi) -> int16_t {
|
||||||
|
return static_cast<int16_t>(static_cast<uint16_t>(hi) << 8 | lo);
|
||||||
|
};
|
||||||
|
|
||||||
|
data->ax = toI16(buffer[0], buffer[1]) * ACCEL_SCALE;
|
||||||
|
data->ay = toI16(buffer[2], buffer[3]) * ACCEL_SCALE;
|
||||||
|
data->az = toI16(buffer[4], buffer[5]) * ACCEL_SCALE;
|
||||||
|
data->gx = toI16(buffer[6], buffer[7]) * GYRO_SCALE;
|
||||||
|
data->gy = toI16(buffer[8], buffer[9]) * GYRO_SCALE;
|
||||||
|
data->gz = toI16(buffer[10], buffer[11]) * GYRO_SCALE;
|
||||||
|
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
Driver bmi270_driver = {
|
||||||
|
.name = "bmi270",
|
||||||
|
.compatible = (const char*[]) { "bosch,bmi270", nullptr},
|
||||||
|
.start_device = start,
|
||||||
|
.stop_device = stop,
|
||||||
|
.api = nullptr,
|
||||||
|
.device_type = nullptr,
|
||||||
|
.owner = &bmi270_module,
|
||||||
|
.internal = nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
34
Drivers/bmi270-module/source/module.cpp
Normal file
34
Drivers/bmi270-module/source/module.cpp
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#include <tactility/check.h>
|
||||||
|
#include <tactility/driver.h>
|
||||||
|
#include <tactility/module.h>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
extern Driver bmi270_driver;
|
||||||
|
|
||||||
|
static error_t start() {
|
||||||
|
/* We crash when construct fails, because if a single driver fails to construct,
|
||||||
|
* there is no guarantee that the previously constructed drivers can be destroyed */
|
||||||
|
check(driver_construct_add(&bmi270_driver) == ERROR_NONE);
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t stop() {
|
||||||
|
/* We crash when destruct fails, because if a single driver fails to destruct,
|
||||||
|
* there is no guarantee that the previously destroyed drivers can be recovered */
|
||||||
|
check(driver_remove_destruct(&bmi270_driver) == ERROR_NONE);
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern const ModuleSymbol bmi270_module_symbols[];
|
||||||
|
|
||||||
|
Module bmi270_module = {
|
||||||
|
.name = "bmi270",
|
||||||
|
.start = start,
|
||||||
|
.stop = stop,
|
||||||
|
.symbols = bmi270_module_symbols,
|
||||||
|
.internal = nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
8
Drivers/bmi270-module/source/symbols.c
Normal file
8
Drivers/bmi270-module/source/symbols.c
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#include <drivers/bmi270.h>
|
||||||
|
#include <tactility/module.h>
|
||||||
|
|
||||||
|
const struct ModuleSymbol bmi270_module_symbols[] = {
|
||||||
|
DEFINE_MODULE_SYMBOL(bmi270_read),
|
||||||
|
MODULE_SYMBOL_TERMINATOR
|
||||||
|
};
|
||||||
@ -2,40 +2,16 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <tactility/error.h>
|
|
||||||
#include <tactility/freertos/freertos.h>
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct Device;
|
|
||||||
|
|
||||||
struct Pi4ioe5v6408Config {
|
struct Pi4ioe5v6408Config {
|
||||||
/** Address on bus */
|
/** Address on bus */
|
||||||
uint8_t address;
|
uint8_t address;
|
||||||
};
|
};
|
||||||
|
|
||||||
error_t pi4ioe5v6408_set_direction(struct Device* device, uint8_t bits, TickType_t timeout);
|
|
||||||
|
|
||||||
error_t pi4ioe5v6408_set_output_level(struct Device* device, uint8_t bits, TickType_t timeout);
|
|
||||||
|
|
||||||
error_t pi4ioe5v6408_get_output_level(struct Device* device, uint8_t* bits, TickType_t timeout);
|
|
||||||
|
|
||||||
error_t pi4ioe5v6408_set_output_high_impedance(struct Device* device, uint8_t bits, TickType_t timeout);
|
|
||||||
|
|
||||||
error_t pi4ioe5v6408_set_input_default_level(struct Device* device, uint8_t bits, TickType_t timeout);
|
|
||||||
|
|
||||||
error_t pi4ioe5v6408_set_pull_enable(struct Device* device, uint8_t bits, TickType_t timeout);
|
|
||||||
|
|
||||||
error_t pi4ioe5v6408_set_pull_select(struct Device* device, uint8_t bits, TickType_t timeout);
|
|
||||||
|
|
||||||
error_t pi4ioe5v6408_get_input_level(struct Device* device, uint8_t* bits, TickType_t timeout);
|
|
||||||
|
|
||||||
error_t pi4ioe5v6408_set_interrupt_mask(struct Device* device, uint8_t bits, TickType_t timeout);
|
|
||||||
|
|
||||||
error_t pi4ioe5v6408_get_interrupt_level(struct Device* device, uint8_t* bits, TickType_t timeout);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -6,7 +6,6 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
extern Driver pi4ioe5v6408_driver;
|
extern Driver pi4ioe5v6408_driver;
|
||||||
extern const ModuleSymbol pi4ioe5v6408_module_symbols[];
|
|
||||||
|
|
||||||
static error_t start() {
|
static error_t start() {
|
||||||
/* We crash when construct fails, because if a single driver fails to construct,
|
/* We crash when construct fails, because if a single driver fails to construct,
|
||||||
@ -26,7 +25,7 @@ Module pi4ioe5v6408_module = {
|
|||||||
.name = "pi4ioe5v6408",
|
.name = "pi4ioe5v6408",
|
||||||
.start = start,
|
.start = start,
|
||||||
.stop = stop,
|
.stop = stop,
|
||||||
.symbols = pi4ioe5v6408_module_symbols,
|
.symbols = nullptr,
|
||||||
.internal = nullptr
|
.internal = nullptr
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,8 @@
|
|||||||
#include <pi4ioe5v6408_module.h>
|
#include <pi4ioe5v6408_module.h>
|
||||||
#include <tactility/device.h>
|
#include <tactility/device.h>
|
||||||
#include <tactility/driver.h>
|
#include <tactility/driver.h>
|
||||||
|
#include <tactility/drivers/gpio_controller.h>
|
||||||
|
#include <tactility/drivers/gpio_descriptor.h>
|
||||||
#include <tactility/drivers/i2c_controller.h>
|
#include <tactility/drivers/i2c_controller.h>
|
||||||
#include <tactility/log.h>
|
#include <tactility/log.h>
|
||||||
|
|
||||||
@ -27,72 +29,181 @@ static error_t start(Device* device) {
|
|||||||
return ERROR_RESOURCE;
|
return ERROR_RESOURCE;
|
||||||
}
|
}
|
||||||
LOG_I(TAG, "Started PI4IOE5V6408 device %s", device->name);
|
LOG_I(TAG, "Started PI4IOE5V6408 device %s", device->name);
|
||||||
return ERROR_NONE;
|
|
||||||
|
return gpio_controller_init_descriptors(device, 8, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static error_t stop(Device* device) {
|
static error_t stop(Device* device) {
|
||||||
|
check(gpio_controller_deinit_descriptors(device) == ERROR_NONE);
|
||||||
return ERROR_NONE;
|
return ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
error_t pi4ioe5v6408_set_direction(Device* device, uint8_t bits, TickType_t timeout) {
|
|
||||||
|
static error_t set_level(GpioDescriptor* descriptor, bool high) {
|
||||||
|
auto* device = descriptor->controller;
|
||||||
auto* parent = device_get_parent(device);
|
auto* parent = device_get_parent(device);
|
||||||
return i2c_controller_register8_set(parent, GET_CONFIG(device)->address, PI4_REGISTER_DIRECTION, bits, timeout);
|
auto address = GET_CONFIG(device)->address;
|
||||||
|
uint8_t bit = 1 << descriptor->pin;
|
||||||
|
|
||||||
|
if (high) {
|
||||||
|
return i2c_controller_register8_set_bits(parent, address, PI4_REGISTER_OUTPUT_LEVEL, bit, portMAX_DELAY);
|
||||||
|
} else {
|
||||||
|
return i2c_controller_register8_reset_bits(parent, address, PI4_REGISTER_OUTPUT_LEVEL, bit, portMAX_DELAY);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t pi4ioe5v6408_set_output_level(Device* device, uint8_t bits, TickType_t timeout) {
|
static error_t get_level(GpioDescriptor* descriptor, bool* high) {
|
||||||
|
auto* device = descriptor->controller;
|
||||||
auto* parent = device_get_parent(device);
|
auto* parent = device_get_parent(device);
|
||||||
return i2c_controller_register8_set(parent, GET_CONFIG(device)->address, PI4_REGISTER_OUTPUT_LEVEL, bits, timeout);
|
auto address = GET_CONFIG(device)->address;
|
||||||
|
uint8_t bits;
|
||||||
|
|
||||||
|
error_t err = i2c_controller_register8_get(parent, address, PI4_REGISTER_INPUT_LEVEL, &bits, portMAX_DELAY);
|
||||||
|
if (err != ERROR_NONE) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
*high = (bits & (1 << descriptor->pin)) != 0;
|
||||||
|
return ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t pi4ioe5v6408_get_output_level(Device* device, uint8_t* bits, TickType_t timeout) {
|
static error_t set_flags(GpioDescriptor* descriptor, gpio_flags_t flags) {
|
||||||
|
auto* device = descriptor->controller;
|
||||||
auto* parent = device_get_parent(device);
|
auto* parent = device_get_parent(device);
|
||||||
return i2c_controller_register8_get(parent, GET_CONFIG(device)->address, PI4_REGISTER_OUTPUT_LEVEL, bits, timeout);
|
auto address = GET_CONFIG(device)->address;
|
||||||
|
uint8_t bit = 1 << descriptor->pin;
|
||||||
|
|
||||||
|
error_t err;
|
||||||
|
|
||||||
|
// Direction
|
||||||
|
if (flags & GPIO_FLAG_DIRECTION_OUTPUT) {
|
||||||
|
err = i2c_controller_register8_set_bits(parent, address, PI4_REGISTER_DIRECTION, bit, portMAX_DELAY);
|
||||||
|
} else {
|
||||||
|
err = i2c_controller_register8_reset_bits(parent, address, PI4_REGISTER_DIRECTION, bit, portMAX_DELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err != ERROR_NONE) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// High Impedance
|
||||||
|
if (flags & GPIO_FLAG_HIGH_IMPEDANCE) {
|
||||||
|
err = i2c_controller_register8_set_bits(parent, address, PI4_REGISTER_OUTPUT_HIGH_IMPEDANCE, bit, portMAX_DELAY);
|
||||||
|
} else {
|
||||||
|
err = i2c_controller_register8_reset_bits(parent, address, PI4_REGISTER_OUTPUT_HIGH_IMPEDANCE, bit, portMAX_DELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err != ERROR_NONE) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pull-up/down
|
||||||
|
if (flags & (GPIO_FLAG_PULL_UP | GPIO_FLAG_PULL_DOWN)) {
|
||||||
|
// Set pull up or pull down
|
||||||
|
if (flags & GPIO_FLAG_PULL_UP) {
|
||||||
|
err = i2c_controller_register8_set_bits(parent, address, PI4_REGISTER_PULL_SELECT, bit, portMAX_DELAY);
|
||||||
|
} else {
|
||||||
|
err = i2c_controller_register8_reset_bits(parent, address, PI4_REGISTER_PULL_SELECT, bit, portMAX_DELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err != ERROR_NONE) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable pull-up/down
|
||||||
|
err = i2c_controller_register8_set_bits(parent, address, PI4_REGISTER_PULL_ENABLE, bit, portMAX_DELAY);
|
||||||
|
} else {
|
||||||
|
// Disable pull-up/down
|
||||||
|
err = i2c_controller_register8_reset_bits(parent, address, PI4_REGISTER_PULL_ENABLE, bit, portMAX_DELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t pi4ioe5v6408_set_output_high_impedance(struct Device* device, uint8_t bits, TickType_t timeout) {
|
static error_t get_flags(GpioDescriptor* descriptor, gpio_flags_t* flags) {
|
||||||
|
auto* device = descriptor->controller;
|
||||||
auto* parent = device_get_parent(device);
|
auto* parent = device_get_parent(device);
|
||||||
return i2c_controller_register8_set(parent, GET_CONFIG(device)->address, PI4_REGISTER_OUTPUT_HIGH_IMPEDANCE, bits, timeout);
|
auto address = GET_CONFIG(device)->address;
|
||||||
|
uint8_t bit = 1 << descriptor->pin;
|
||||||
|
uint8_t val;
|
||||||
|
error_t err;
|
||||||
|
|
||||||
|
gpio_flags_t f = GPIO_FLAG_NONE;
|
||||||
|
|
||||||
|
// Direction
|
||||||
|
err = i2c_controller_register8_get(parent, address, PI4_REGISTER_DIRECTION, &val, portMAX_DELAY);
|
||||||
|
if (err != ERROR_NONE) return err;
|
||||||
|
if (val & bit) {
|
||||||
|
f |= GPIO_FLAG_DIRECTION_OUTPUT;
|
||||||
|
} else {
|
||||||
|
f |= GPIO_FLAG_DIRECTION_INPUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pull-up/down
|
||||||
|
err = i2c_controller_register8_get(parent, address, PI4_REGISTER_PULL_ENABLE, &val, portMAX_DELAY);
|
||||||
|
if (err != ERROR_NONE) return err;
|
||||||
|
if (val & bit) {
|
||||||
|
err = i2c_controller_register8_get(parent, address, PI4_REGISTER_PULL_SELECT, &val, portMAX_DELAY);
|
||||||
|
if (err != ERROR_NONE) return err;
|
||||||
|
if (val & bit) {
|
||||||
|
f |= GPIO_FLAG_PULL_UP;
|
||||||
|
} else {
|
||||||
|
f |= GPIO_FLAG_PULL_DOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// High Impedance
|
||||||
|
err = i2c_controller_register8_get(parent, address, PI4_REGISTER_OUTPUT_HIGH_IMPEDANCE, &val, portMAX_DELAY);
|
||||||
|
if (err != ERROR_NONE) return err;
|
||||||
|
if (val & bit) {
|
||||||
|
f |= GPIO_FLAG_HIGH_IMPEDANCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
*flags = f;
|
||||||
|
return ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t pi4ioe5v6408_set_input_default_level(struct Device* device, uint8_t bits, TickType_t timeout) {
|
static error_t get_native_pin_number(GpioDescriptor* descriptor, void* pin_number) {
|
||||||
auto* parent = device_get_parent(device);
|
return ERROR_NOT_SUPPORTED;
|
||||||
return i2c_controller_register8_set(parent, GET_CONFIG(device)->address, PI4_REGISTER_INPUT_DEFAULT_LEVEL, bits, timeout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t pi4ioe5v6408_set_pull_enable(struct Device* device, uint8_t bits, TickType_t timeout) {
|
static error_t add_callback(GpioDescriptor* descriptor, void (*callback)(void*), void* arg) {
|
||||||
auto* parent = device_get_parent(device);
|
return ERROR_NOT_SUPPORTED;
|
||||||
return i2c_controller_register8_set(parent, GET_CONFIG(device)->address, PI4_REGISTER_PULL_ENABLE, bits, timeout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t pi4ioe5v6408_set_pull_select(struct Device* device, uint8_t bits, TickType_t timeout) {
|
static error_t remove_callback(GpioDescriptor* descriptor) {
|
||||||
auto* parent = device_get_parent(device);
|
return ERROR_NOT_SUPPORTED;
|
||||||
return i2c_controller_register8_set(parent, GET_CONFIG(device)->address, PI4_REGISTER_PULL_SELECT, bits, timeout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t pi4ioe5v6408_get_input_level(struct Device* device, uint8_t* bits, TickType_t timeout) {
|
static error_t enable_interrupt(GpioDescriptor* descriptor) {
|
||||||
auto* parent = device_get_parent(device);
|
return ERROR_NOT_SUPPORTED;
|
||||||
return i2c_controller_register8_get(parent, GET_CONFIG(device)->address, PI4_REGISTER_INPUT_LEVEL, bits, timeout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t pi4ioe5v6408_set_interrupt_mask(struct Device* device, uint8_t bits, TickType_t timeout) {
|
static error_t disable_interrupt(GpioDescriptor* descriptor) {
|
||||||
auto* parent = device_get_parent(device);
|
return ERROR_NOT_SUPPORTED;
|
||||||
return i2c_controller_register8_set(parent, GET_CONFIG(device)->address, PI4_REGISTER_INTERRUPT_MASK, bits, timeout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t pi4ioe5v6408_get_interrupt_level(struct Device* device, uint8_t* bits, TickType_t timeout) {
|
const static GpioControllerApi pi4_gpio_api = {
|
||||||
auto* parent = device_get_parent(device);
|
.set_level = set_level,
|
||||||
return i2c_controller_register8_get(parent, GET_CONFIG(device)->address, PI4_REGISTER_INTERRUPT_LEVEL, bits, timeout);
|
.get_level = get_level,
|
||||||
}
|
.set_flags = set_flags,
|
||||||
|
.get_flags = get_flags,
|
||||||
|
.get_native_pin_number = get_native_pin_number,
|
||||||
|
.add_callback = add_callback,
|
||||||
|
.remove_callback = remove_callback,
|
||||||
|
.enable_interrupt = enable_interrupt,
|
||||||
|
.disable_interrupt = disable_interrupt
|
||||||
|
};
|
||||||
|
|
||||||
Driver pi4ioe5v6408_driver = {
|
Driver pi4ioe5v6408_driver = {
|
||||||
.name = "pi4ioe5v6408",
|
.name = "pi4ioe5v6408",
|
||||||
.compatible = (const char*[]) { "diodes,pi4ioe5v6408", nullptr},
|
.compatible = (const char*[]) { "diodes,pi4ioe5v6408", nullptr},
|
||||||
.start_device = start,
|
.start_device = start,
|
||||||
.stop_device = stop,
|
.stop_device = stop,
|
||||||
.api = nullptr,
|
.api = static_cast<const void*>(&pi4_gpio_api),
|
||||||
.device_type = nullptr,
|
.device_type = &GPIO_CONTROLLER_TYPE,
|
||||||
.owner = &pi4ioe5v6408_module,
|
.owner = &pi4ioe5v6408_module,
|
||||||
.internal = nullptr
|
.internal = nullptr
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,15 +0,0 @@
|
|||||||
#include <drivers/pi4ioe5v6408.h>
|
|
||||||
#include <tactility/module.h>
|
|
||||||
|
|
||||||
const struct ModuleSymbol pi4ioe5v6408_module_symbols[] = {
|
|
||||||
DEFINE_MODULE_SYMBOL(pi4ioe5v6408_set_direction),
|
|
||||||
DEFINE_MODULE_SYMBOL(pi4ioe5v6408_set_output_level),
|
|
||||||
DEFINE_MODULE_SYMBOL(pi4ioe5v6408_set_output_high_impedance),
|
|
||||||
DEFINE_MODULE_SYMBOL(pi4ioe5v6408_set_input_default_level),
|
|
||||||
DEFINE_MODULE_SYMBOL(pi4ioe5v6408_set_pull_enable),
|
|
||||||
DEFINE_MODULE_SYMBOL(pi4ioe5v6408_set_pull_select),
|
|
||||||
DEFINE_MODULE_SYMBOL(pi4ioe5v6408_get_input_level),
|
|
||||||
DEFINE_MODULE_SYMBOL(pi4ioe5v6408_set_interrupt_mask),
|
|
||||||
DEFINE_MODULE_SYMBOL(pi4ioe5v6408_get_interrupt_level),
|
|
||||||
MODULE_SYMBOL_TERMINATOR
|
|
||||||
};
|
|
||||||
@ -60,6 +60,8 @@ const struct ModuleSymbol lvgl_module_symbols[] = {
|
|||||||
DEFINE_MODULE_SYMBOL(lv_obj_get_group),
|
DEFINE_MODULE_SYMBOL(lv_obj_get_group),
|
||||||
DEFINE_MODULE_SYMBOL(lv_obj_get_user_data),
|
DEFINE_MODULE_SYMBOL(lv_obj_get_user_data),
|
||||||
DEFINE_MODULE_SYMBOL(lv_obj_get_state),
|
DEFINE_MODULE_SYMBOL(lv_obj_get_state),
|
||||||
|
DEFINE_MODULE_SYMBOL(lv_obj_get_scroll_bottom),
|
||||||
|
DEFINE_MODULE_SYMBOL(lv_obj_get_scroll_y),
|
||||||
DEFINE_MODULE_SYMBOL(lv_obj_has_flag),
|
DEFINE_MODULE_SYMBOL(lv_obj_has_flag),
|
||||||
DEFINE_MODULE_SYMBOL(lv_obj_has_flag_any),
|
DEFINE_MODULE_SYMBOL(lv_obj_has_flag_any),
|
||||||
DEFINE_MODULE_SYMBOL(lv_obj_has_state),
|
DEFINE_MODULE_SYMBOL(lv_obj_has_state),
|
||||||
@ -158,7 +160,15 @@ const struct ModuleSymbol lvgl_module_symbols[] = {
|
|||||||
DEFINE_MODULE_SYMBOL(lv_obj_set_style_min_height),
|
DEFINE_MODULE_SYMBOL(lv_obj_set_style_min_height),
|
||||||
DEFINE_MODULE_SYMBOL(lv_obj_set_style_max_height),
|
DEFINE_MODULE_SYMBOL(lv_obj_set_style_max_height),
|
||||||
// lv_font
|
// lv_font
|
||||||
|
DEFINE_MODULE_SYMBOL(lv_font_get_bitmap_fmt_txt),
|
||||||
DEFINE_MODULE_SYMBOL(lv_font_get_default),
|
DEFINE_MODULE_SYMBOL(lv_font_get_default),
|
||||||
|
DEFINE_MODULE_SYMBOL(lv_font_get_glyph_bitmap),
|
||||||
|
DEFINE_MODULE_SYMBOL(lv_font_get_glyph_dsc),
|
||||||
|
DEFINE_MODULE_SYMBOL(lv_font_get_glyph_dsc_fmt_txt),
|
||||||
|
DEFINE_MODULE_SYMBOL(lv_font_get_glyph_static_bitmap),
|
||||||
|
DEFINE_MODULE_SYMBOL(lv_font_get_glyph_width),
|
||||||
|
DEFINE_MODULE_SYMBOL(lv_font_get_line_height),
|
||||||
|
DEFINE_MODULE_SYMBOL(lv_font_set_kerning),
|
||||||
// lv_theme
|
// lv_theme
|
||||||
DEFINE_MODULE_SYMBOL(lv_theme_get_color_primary),
|
DEFINE_MODULE_SYMBOL(lv_theme_get_color_primary),
|
||||||
DEFINE_MODULE_SYMBOL(lv_theme_get_color_secondary),
|
DEFINE_MODULE_SYMBOL(lv_theme_get_color_secondary),
|
||||||
@ -422,5 +432,8 @@ const struct ModuleSymbol lvgl_module_symbols[] = {
|
|||||||
DEFINE_MODULE_SYMBOL(lv_spangroup_refresh),
|
DEFINE_MODULE_SYMBOL(lv_spangroup_refresh),
|
||||||
DEFINE_MODULE_SYMBOL(lv_span_get_style),
|
DEFINE_MODULE_SYMBOL(lv_span_get_style),
|
||||||
DEFINE_MODULE_SYMBOL(lv_span_set_text),
|
DEFINE_MODULE_SYMBOL(lv_span_set_text),
|
||||||
|
// lv_binfont
|
||||||
|
DEFINE_MODULE_SYMBOL(lv_binfont_create),
|
||||||
|
DEFINE_MODULE_SYMBOL(lv_binfont_destroy),
|
||||||
MODULE_SYMBOL_TERMINATOR
|
MODULE_SYMBOL_TERMINATOR
|
||||||
};
|
};
|
||||||
@ -6,5 +6,5 @@ idf_component_register(
|
|||||||
SRCS ${SOURCES}
|
SRCS ${SOURCES}
|
||||||
INCLUDE_DIRS "include/"
|
INCLUDE_DIRS "include/"
|
||||||
PRIV_INCLUDE_DIRS "private/"
|
PRIV_INCLUDE_DIRS "private/"
|
||||||
REQUIRES TactilityKernel driver
|
REQUIRES TactilityKernel driver vfs fatfs
|
||||||
)
|
)
|
||||||
|
|||||||
53
Platforms/platform-esp32/bindings/espressif,esp32-sdmmc.yaml
Normal file
53
Platforms/platform-esp32/bindings/espressif,esp32-sdmmc.yaml
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
description: ESP32 SDMMC
|
||||||
|
|
||||||
|
compatible: "espressif,esp32-sdmmc"
|
||||||
|
|
||||||
|
properties:
|
||||||
|
pin-clk:
|
||||||
|
type: phandle-array
|
||||||
|
required: true
|
||||||
|
pin-cmd:
|
||||||
|
type: phandle-array
|
||||||
|
required: true
|
||||||
|
pin-d0:
|
||||||
|
type: phandle-array
|
||||||
|
required: true
|
||||||
|
pin-d1:
|
||||||
|
type: phandle-array
|
||||||
|
default: GPIO_PIN_SPEC_NONE
|
||||||
|
pin-d2:
|
||||||
|
type: phandle-array
|
||||||
|
default: GPIO_PIN_SPEC_NONE
|
||||||
|
pin-d3:
|
||||||
|
type: phandle-array
|
||||||
|
default: GPIO_PIN_SPEC_NONE
|
||||||
|
pin-d4:
|
||||||
|
type: phandle-array
|
||||||
|
default: GPIO_PIN_SPEC_NONE
|
||||||
|
pin-d5:
|
||||||
|
type: phandle-array
|
||||||
|
default: GPIO_PIN_SPEC_NONE
|
||||||
|
pin-d6:
|
||||||
|
type: phandle-array
|
||||||
|
default: GPIO_PIN_SPEC_NONE
|
||||||
|
pin-d7:
|
||||||
|
type: phandle-array
|
||||||
|
default: GPIO_PIN_SPEC_NONE
|
||||||
|
pin-cd:
|
||||||
|
type: phandle-array
|
||||||
|
default: GPIO_PIN_SPEC_NONE
|
||||||
|
pin-wp:
|
||||||
|
type: phandle-array
|
||||||
|
default: GPIO_PIN_SPEC_NONE
|
||||||
|
bus-width:
|
||||||
|
type: int
|
||||||
|
required: true
|
||||||
|
description: Bus width in bits
|
||||||
|
wp-active-high:
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
description: Whether the WP pin is active high
|
||||||
|
enable-uhs:
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
description: Enable UHS mode
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <tactility/bindings/bindings.h>
|
||||||
|
#include <tactility/drivers/esp32_sdmmc.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
DEFINE_DEVICETREE(esp32_sdmmc, struct Esp32SdmmcConfig)
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#pragma once
|
||||||
|
#include <soc/soc_caps.h>
|
||||||
|
#if SOC_SDMMC_HOST_SUPPORTED
|
||||||
|
|
||||||
|
#include <sd_protocol_types.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <tactility/drivers/gpio.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct Esp32SdmmcConfig {
|
||||||
|
struct GpioPinSpec pin_clk;
|
||||||
|
struct GpioPinSpec pin_cmd;
|
||||||
|
struct GpioPinSpec pin_d0;
|
||||||
|
struct GpioPinSpec pin_d1;
|
||||||
|
struct GpioPinSpec pin_d2;
|
||||||
|
struct GpioPinSpec pin_d3;
|
||||||
|
struct GpioPinSpec pin_d4;
|
||||||
|
struct GpioPinSpec pin_d5;
|
||||||
|
struct GpioPinSpec pin_d6;
|
||||||
|
struct GpioPinSpec pin_d7;
|
||||||
|
struct GpioPinSpec pin_cd;
|
||||||
|
struct GpioPinSpec pin_wp;
|
||||||
|
uint8_t bus_width;
|
||||||
|
bool wp_active_high;
|
||||||
|
bool enable_uhs;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the SD card handle for the given device.
|
||||||
|
* @param[in] device the device to get the card handle for
|
||||||
|
* @return the SD card handle, or NULL if the device is not mounted
|
||||||
|
*/
|
||||||
|
sdmmc_card_t* esp32_sdmmc_get_card(struct Device* device);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#pragma once
|
||||||
|
#include <soc/soc_caps.h>
|
||||||
|
#if SOC_SDMMC_HOST_SUPPORTED
|
||||||
|
#include <tactility/filesystem/file_system.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct Esp32SdmmcConfig;
|
||||||
|
typedef void* Esp32SdmmcHandle;
|
||||||
|
|
||||||
|
extern Esp32SdmmcHandle esp32_sdmmc_fs_alloc(const struct Esp32SdmmcConfig* config, const char* mount_path);
|
||||||
|
|
||||||
|
extern void esp32_sdmmc_fs_free(Esp32SdmmcHandle handle);
|
||||||
|
|
||||||
|
extern sdmmc_card_t* esp32_sdmmc_fs_get_card(Esp32SdmmcHandle handle);
|
||||||
|
|
||||||
|
extern const FileSystemApi esp32_sdmmc_fs_api;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
@ -12,7 +12,12 @@
|
|||||||
|
|
||||||
#define TAG "esp32_gpio"
|
#define TAG "esp32_gpio"
|
||||||
|
|
||||||
|
struct Esp32GpioInternal {
|
||||||
|
uint8_t isr_service_ref_count = 0;
|
||||||
|
};
|
||||||
|
|
||||||
#define GET_CONFIG(device) ((struct Esp32GpioConfig*)device->config)
|
#define GET_CONFIG(device) ((struct Esp32GpioConfig*)device->config)
|
||||||
|
#define GET_INTERNAL_FROM_DESCRIPTOR(gpio_descriptor) ((struct Esp32GpioInternal*)gpio_descriptor->controller_context)
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
@ -97,15 +102,76 @@ static error_t get_native_pin_number(GpioDescriptor* descriptor, void* pin_numbe
|
|||||||
return ERROR_NONE;
|
return ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static error_t add_callback(GpioDescriptor* descriptor, void (*callback)(void*), void* arg) {
|
||||||
|
auto* internal = GET_INTERNAL_FROM_DESCRIPTOR(descriptor);
|
||||||
|
if (internal->isr_service_ref_count == 0) {
|
||||||
|
auto esp_error = gpio_install_isr_service(0);
|
||||||
|
if (esp_error != ESP_OK && esp_error != ESP_ERR_INVALID_STATE) {
|
||||||
|
return esp_err_to_error(esp_error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto esp_error = gpio_isr_handler_add(static_cast<gpio_num_t>(descriptor->pin), callback, arg);
|
||||||
|
|
||||||
|
if (esp_error == ESP_OK) {
|
||||||
|
internal->isr_service_ref_count++;
|
||||||
|
} else if (internal->isr_service_ref_count == 0) {
|
||||||
|
gpio_uninstall_isr_service();
|
||||||
|
}
|
||||||
|
|
||||||
|
return esp_err_to_error(esp_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t remove_callback(GpioDescriptor* descriptor) {
|
||||||
|
auto esp_error = gpio_isr_handler_remove(static_cast<gpio_num_t>(descriptor->pin));
|
||||||
|
if (esp_error == ESP_OK) {
|
||||||
|
auto* internal = GET_INTERNAL_FROM_DESCRIPTOR(descriptor);
|
||||||
|
check(internal->isr_service_ref_count > 0);
|
||||||
|
internal->isr_service_ref_count--;
|
||||||
|
if (internal->isr_service_ref_count == 0) {
|
||||||
|
gpio_uninstall_isr_service();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return esp_err_to_error(esp_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t enable_interrupt(GpioDescriptor* descriptor) {
|
||||||
|
auto esp_error = gpio_intr_enable(static_cast<gpio_num_t>(descriptor->pin));
|
||||||
|
return esp_err_to_error(esp_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t disable_interrupt(GpioDescriptor* descriptor) {
|
||||||
|
auto esp_error = gpio_intr_disable(static_cast<gpio_num_t>(descriptor->pin));
|
||||||
|
return esp_err_to_error(esp_error);
|
||||||
|
}
|
||||||
|
|
||||||
static error_t start(Device* device) {
|
static error_t start(Device* device) {
|
||||||
ESP_LOGI(TAG, "start %s", device->name);
|
LOG_I(TAG, "start %s", device->name);
|
||||||
auto pin_count = GET_CONFIG(device)->gpioCount;
|
const Esp32GpioConfig* config = GET_CONFIG(device);
|
||||||
return gpio_controller_init_descriptors(device, pin_count, nullptr);
|
auto* internal = new Esp32GpioInternal();
|
||||||
|
return gpio_controller_init_descriptors(device, config->gpioCount, internal);
|
||||||
}
|
}
|
||||||
|
|
||||||
static error_t stop(Device* device) {
|
static error_t stop(Device* device) {
|
||||||
ESP_LOGI(TAG, "stop %s", device->name);
|
LOG_I(TAG, "stop %s", device->name);
|
||||||
return gpio_controller_deinit_descriptors(device);
|
const Esp32GpioConfig* config = GET_CONFIG(device);
|
||||||
|
auto* internal = static_cast<Esp32GpioInternal*>(gpio_controller_get_controller_context(device));
|
||||||
|
|
||||||
|
// First, remove all ISR handlers to prevent callbacks during cleanup
|
||||||
|
for (uint8_t i = 0; i < config->gpioCount; ++i) {
|
||||||
|
gpio_isr_handler_remove(static_cast<gpio_num_t>(i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then uninstall ISR service
|
||||||
|
if (internal->isr_service_ref_count > 0) {
|
||||||
|
gpio_uninstall_isr_service();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now safe to deinit descriptors and delete internal
|
||||||
|
check(gpio_controller_deinit_descriptors(device) == ERROR_NONE);
|
||||||
|
delete internal;
|
||||||
|
|
||||||
|
return ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
const static GpioControllerApi esp32_gpio_api = {
|
const static GpioControllerApi esp32_gpio_api = {
|
||||||
@ -113,17 +179,21 @@ const static GpioControllerApi esp32_gpio_api = {
|
|||||||
.get_level = get_level,
|
.get_level = get_level,
|
||||||
.set_flags = set_flags,
|
.set_flags = set_flags,
|
||||||
.get_flags = get_flags,
|
.get_flags = get_flags,
|
||||||
.get_native_pin_number = get_native_pin_number
|
.get_native_pin_number = get_native_pin_number,
|
||||||
|
.add_callback = add_callback,
|
||||||
|
.remove_callback = remove_callback,
|
||||||
|
.enable_interrupt = enable_interrupt,
|
||||||
|
.disable_interrupt = disable_interrupt
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct Module platform_esp32_module;
|
extern Module platform_esp32_module;
|
||||||
|
|
||||||
Driver esp32_gpio_driver = {
|
Driver esp32_gpio_driver = {
|
||||||
.name = "esp32_gpio",
|
.name = "esp32_gpio",
|
||||||
.compatible = (const char*[]) { "espressif,esp32-gpio", nullptr },
|
.compatible = (const char*[]) { "espressif,esp32-gpio", nullptr },
|
||||||
.start_device = start,
|
.start_device = start,
|
||||||
.stop_device = stop,
|
.stop_device = stop,
|
||||||
.api = (void*)&esp32_gpio_api,
|
.api = static_cast<const void*>(&esp32_gpio_api),
|
||||||
.device_type = &GPIO_CONTROLLER_TYPE,
|
.device_type = &GPIO_CONTROLLER_TYPE,
|
||||||
.owner = &platform_esp32_module,
|
.owner = &platform_esp32_module,
|
||||||
.internal = nullptr
|
.internal = nullptr
|
||||||
|
|||||||
185
Platforms/platform-esp32/source/drivers/esp32_sdmmc.cpp
Normal file
185
Platforms/platform-esp32/source/drivers/esp32_sdmmc.cpp
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#include <soc/soc_caps.h>
|
||||||
|
#if SOC_SDMMC_HOST_SUPPORTED
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
|
||||||
|
#include <tactility/concurrent/recursive_mutex.h>
|
||||||
|
#include <tactility/device.h>
|
||||||
|
#include <tactility/drivers/esp32_gpio_helpers.h>
|
||||||
|
#include <tactility/drivers/esp32_sdmmc.h>
|
||||||
|
#include <tactility/drivers/esp32_sdmmc_fs.h>
|
||||||
|
#include <tactility/drivers/gpio_descriptor.h>
|
||||||
|
#include <tactility/filesystem/file_system.h>
|
||||||
|
#include <tactility/log.h>
|
||||||
|
|
||||||
|
#define TAG "esp32_sdmmc"
|
||||||
|
|
||||||
|
#define GET_CONFIG(device) ((const struct Esp32SdmmcConfig*)device->config)
|
||||||
|
#define GET_DATA(device) ((struct Esp32SdmmcInternal*)device_get_driver_data(device))
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
struct Esp32SdmmcInternal {
|
||||||
|
RecursiveMutex mutex = {};
|
||||||
|
bool initialized = false;
|
||||||
|
Esp32SdmmcHandle esp32_sdmmc_fs_handle = nullptr;
|
||||||
|
FileSystem* file_system = nullptr;
|
||||||
|
|
||||||
|
// Pin descriptors
|
||||||
|
GpioDescriptor* pin_clk_descriptor = nullptr;
|
||||||
|
GpioDescriptor* pin_cmd_descriptor = nullptr;
|
||||||
|
GpioDescriptor* pin_d0_descriptor = nullptr;
|
||||||
|
GpioDescriptor* pin_d1_descriptor = nullptr;
|
||||||
|
GpioDescriptor* pin_d2_descriptor = nullptr;
|
||||||
|
GpioDescriptor* pin_d3_descriptor = nullptr;
|
||||||
|
GpioDescriptor* pin_d4_descriptor = nullptr;
|
||||||
|
GpioDescriptor* pin_d5_descriptor = nullptr;
|
||||||
|
GpioDescriptor* pin_d6_descriptor = nullptr;
|
||||||
|
GpioDescriptor* pin_d7_descriptor = nullptr;
|
||||||
|
GpioDescriptor* pin_cd_descriptor = nullptr;
|
||||||
|
GpioDescriptor* pin_wp_descriptor = nullptr;
|
||||||
|
|
||||||
|
explicit Esp32SdmmcInternal() {
|
||||||
|
recursive_mutex_construct(&mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
~Esp32SdmmcInternal() {
|
||||||
|
cleanup_pins();
|
||||||
|
recursive_mutex_destruct(&mutex);
|
||||||
|
if (esp32_sdmmc_fs_handle) esp32_sdmmc_fs_free(esp32_sdmmc_fs_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanup_pins() {
|
||||||
|
release_pin(&pin_clk_descriptor);
|
||||||
|
release_pin(&pin_cmd_descriptor);
|
||||||
|
release_pin(&pin_d0_descriptor);
|
||||||
|
release_pin(&pin_d1_descriptor);
|
||||||
|
release_pin(&pin_d2_descriptor);
|
||||||
|
release_pin(&pin_d3_descriptor);
|
||||||
|
release_pin(&pin_d4_descriptor);
|
||||||
|
release_pin(&pin_d5_descriptor);
|
||||||
|
release_pin(&pin_d6_descriptor);
|
||||||
|
release_pin(&pin_d7_descriptor);
|
||||||
|
release_pin(&pin_cd_descriptor);
|
||||||
|
release_pin(&pin_wp_descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void lock() { recursive_mutex_lock(&mutex); }
|
||||||
|
|
||||||
|
void unlock() { recursive_mutex_unlock(&mutex); }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static error_t start(Device* device) {
|
||||||
|
LOG_I(TAG, "start %s", device->name);
|
||||||
|
auto* data = new (std::nothrow) Esp32SdmmcInternal();
|
||||||
|
if (!data) return ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
data->lock();
|
||||||
|
device_set_driver_data(device, data);
|
||||||
|
|
||||||
|
auto* sdmmc_config = GET_CONFIG(device);
|
||||||
|
|
||||||
|
// Acquire pins from the specified GPIO pin specs. Optional pins are allowed.
|
||||||
|
bool pins_ok =
|
||||||
|
acquire_pin_or_set_null(sdmmc_config->pin_clk, &data->pin_clk_descriptor) &&
|
||||||
|
acquire_pin_or_set_null(sdmmc_config->pin_cmd, &data->pin_cmd_descriptor) &&
|
||||||
|
acquire_pin_or_set_null(sdmmc_config->pin_d0, &data->pin_d0_descriptor) &&
|
||||||
|
acquire_pin_or_set_null(sdmmc_config->pin_d1, &data->pin_d1_descriptor) &&
|
||||||
|
acquire_pin_or_set_null(sdmmc_config->pin_d2, &data->pin_d2_descriptor) &&
|
||||||
|
acquire_pin_or_set_null(sdmmc_config->pin_d3, &data->pin_d3_descriptor) &&
|
||||||
|
acquire_pin_or_set_null(sdmmc_config->pin_d4, &data->pin_d4_descriptor) &&
|
||||||
|
acquire_pin_or_set_null(sdmmc_config->pin_d5, &data->pin_d5_descriptor) &&
|
||||||
|
acquire_pin_or_set_null(sdmmc_config->pin_d6, &data->pin_d6_descriptor) &&
|
||||||
|
acquire_pin_or_set_null(sdmmc_config->pin_d7, &data->pin_d7_descriptor) &&
|
||||||
|
acquire_pin_or_set_null(sdmmc_config->pin_cd, &data->pin_cd_descriptor) &&
|
||||||
|
acquire_pin_or_set_null(sdmmc_config->pin_wp, &data->pin_wp_descriptor);
|
||||||
|
|
||||||
|
if (!pins_ok) {
|
||||||
|
LOG_E(TAG, "Failed to acquire required one or more pins");
|
||||||
|
data->cleanup_pins();
|
||||||
|
device_set_driver_data(device, nullptr);
|
||||||
|
data->unlock();
|
||||||
|
delete data;
|
||||||
|
return ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->esp32_sdmmc_fs_handle = esp32_sdmmc_fs_alloc(sdmmc_config, "/sdcard");
|
||||||
|
if (!data->esp32_sdmmc_fs_handle) {
|
||||||
|
data->cleanup_pins();
|
||||||
|
device_set_driver_data(device, nullptr);
|
||||||
|
data->unlock();
|
||||||
|
delete data;
|
||||||
|
return ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
data->file_system = file_system_add(&esp32_sdmmc_fs_api, data->esp32_sdmmc_fs_handle);
|
||||||
|
if (file_system_mount(data->file_system) != ERROR_NONE) {
|
||||||
|
// Error is not recoverable at the time, but it might be recoverable later,
|
||||||
|
// so we don't return start() failure.
|
||||||
|
LOG_E(TAG, "Failed to mount SD card filesystem");
|
||||||
|
}
|
||||||
|
|
||||||
|
data->initialized = true;
|
||||||
|
data->unlock();
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t stop(Device* device) {
|
||||||
|
LOG_I(TAG, "stop %s", device->name);
|
||||||
|
auto* data = GET_DATA(device);
|
||||||
|
if (!data) return ERROR_NONE;
|
||||||
|
|
||||||
|
data->lock();
|
||||||
|
|
||||||
|
if (file_system_is_mounted(data->file_system)) {
|
||||||
|
if (file_system_unmount(data->file_system) != ERROR_NONE) {
|
||||||
|
LOG_E(TAG, "Failed to unmount SD card filesystem");
|
||||||
|
data->unlock();
|
||||||
|
return ERROR_RESOURCE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free file system
|
||||||
|
file_system_remove(data->file_system);
|
||||||
|
data->file_system = nullptr;
|
||||||
|
// Free file system data
|
||||||
|
esp32_sdmmc_fs_free(data->esp32_sdmmc_fs_handle);
|
||||||
|
data->esp32_sdmmc_fs_handle = nullptr;
|
||||||
|
|
||||||
|
data->cleanup_pins();
|
||||||
|
device_set_driver_data(device, nullptr);
|
||||||
|
|
||||||
|
data->unlock();
|
||||||
|
delete data;
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
sdmmc_card_t* esp32_sdmmc_get_card(Device* device) {
|
||||||
|
if (!device_is_ready(device)) return nullptr;
|
||||||
|
auto* data = GET_DATA(device);
|
||||||
|
if (!data) return nullptr;
|
||||||
|
|
||||||
|
data->lock();
|
||||||
|
auto* card = esp32_sdmmc_fs_get_card(data->esp32_sdmmc_fs_handle);
|
||||||
|
data->unlock();
|
||||||
|
|
||||||
|
return card;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern Module platform_esp32_module;
|
||||||
|
|
||||||
|
Driver esp32_sdmmc_driver = {
|
||||||
|
.name = "esp32_sdmmc",
|
||||||
|
.compatible = (const char*[]) { "espressif,esp32-sdmmc", nullptr },
|
||||||
|
.start_device = start,
|
||||||
|
.stop_device = stop,
|
||||||
|
.api = nullptr,
|
||||||
|
.device_type = nullptr,
|
||||||
|
.owner = &platform_esp32_module,
|
||||||
|
.internal = nullptr
|
||||||
|
};
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
179
Platforms/platform-esp32/source/drivers/esp32_sdmmc_fs.cpp
Normal file
179
Platforms/platform-esp32/source/drivers/esp32_sdmmc_fs.cpp
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#include <soc/soc_caps.h>
|
||||||
|
#if SOC_SDMMC_HOST_SUPPORTED
|
||||||
|
#include <tactility/device.h>
|
||||||
|
#include <tactility/drivers/esp32_sdmmc.h>
|
||||||
|
#include <tactility/drivers/esp32_sdmmc_fs.h>
|
||||||
|
#include <tactility/filesystem/file_system.h>
|
||||||
|
#include <tactility/drivers/gpio_descriptor.h>
|
||||||
|
#include <tactility/log.h>
|
||||||
|
|
||||||
|
#include <driver/sdmmc_host.h>
|
||||||
|
#include <esp_vfs_fat.h>
|
||||||
|
#include <sdmmc_cmd.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#if SOC_SD_PWR_CTRL_SUPPORTED
|
||||||
|
#include <sd_pwr_ctrl_by_on_chip_ldo.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define TAG "esp32_sdmmc_fs"
|
||||||
|
|
||||||
|
#define GET_DATA(data) static_cast<Esp32SdmmcFsData*>(data)
|
||||||
|
|
||||||
|
struct Esp32SdmmcFsData {
|
||||||
|
const std::string mount_path;
|
||||||
|
const Esp32SdmmcConfig* config;
|
||||||
|
sdmmc_card_t* card;
|
||||||
|
#if SOC_SD_PWR_CTRL_SUPPORTED
|
||||||
|
sd_pwr_ctrl_handle_t pwr_ctrl_handle;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
Esp32SdmmcFsData(const Esp32SdmmcConfig* config, const std::string& mount_path) :
|
||||||
|
mount_path(mount_path),
|
||||||
|
config(config),
|
||||||
|
card(nullptr)
|
||||||
|
#if SOC_SD_PWR_CTRL_SUPPORTED
|
||||||
|
,pwr_ctrl_handle(nullptr)
|
||||||
|
#endif
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
static gpio_num_t to_native_pin(GpioPinSpec pin_spec) {
|
||||||
|
if (pin_spec.gpio_controller == nullptr) { return GPIO_NUM_NC; }
|
||||||
|
return static_cast<gpio_num_t>(pin_spec.pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
static error_t get_path(void* data, char* out_path, size_t out_path_size);
|
||||||
|
|
||||||
|
Esp32SdmmcHandle esp32_sdmmc_fs_alloc(const Esp32SdmmcConfig* config, const char* mount_path) {
|
||||||
|
return new(std::nothrow) Esp32SdmmcFsData(config, mount_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
sdmmc_card_t* esp32_sdmmc_fs_get_card(Esp32SdmmcHandle handle) {
|
||||||
|
return GET_DATA(handle)->card;
|
||||||
|
}
|
||||||
|
|
||||||
|
void esp32_sdmmc_fs_free(Esp32SdmmcHandle handle) {
|
||||||
|
auto* fs_data = GET_DATA(handle);
|
||||||
|
delete fs_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t mount(void* data) {
|
||||||
|
auto* fs_data = GET_DATA(data);
|
||||||
|
auto* config = fs_data->config;
|
||||||
|
|
||||||
|
LOG_I(TAG, "Mounting %s", fs_data->mount_path.c_str());
|
||||||
|
|
||||||
|
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
|
||||||
|
.format_if_mount_failed = false,
|
||||||
|
.max_files = 4,
|
||||||
|
.allocation_unit_size = 0, // Default is sector size
|
||||||
|
.disk_status_check_enable = false,
|
||||||
|
.use_one_fat = false
|
||||||
|
};
|
||||||
|
|
||||||
|
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
|
||||||
|
|
||||||
|
#if SOC_SD_PWR_CTRL_SUPPORTED
|
||||||
|
sd_pwr_ctrl_ldo_config_t ldo_config = {
|
||||||
|
.ldo_chan_id = 4, // LDO4 is typically used for SDMMC on ESP32-S3
|
||||||
|
};
|
||||||
|
esp_err_t pwr_err = sd_pwr_ctrl_new_on_chip_ldo(&ldo_config, &fs_data->pwr_ctrl_handle);
|
||||||
|
if (pwr_err != ESP_OK) {
|
||||||
|
LOG_E(TAG, "Failed to create SD power control driver, err=0x%x", pwr_err);
|
||||||
|
return ERROR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
host.pwr_ctrl_handle = fs_data->pwr_ctrl_handle;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint32_t slot_config_flags = 0;
|
||||||
|
if (config->enable_uhs) slot_config_flags |= SDMMC_SLOT_FLAG_UHS1;
|
||||||
|
if (config->wp_active_high) slot_config_flags |= SDMMC_SLOT_FLAG_WP_ACTIVE_HIGH;
|
||||||
|
|
||||||
|
sdmmc_slot_config_t slot_config = {
|
||||||
|
.clk = to_native_pin(config->pin_clk),
|
||||||
|
.cmd = to_native_pin(config->pin_cmd),
|
||||||
|
.d0 = to_native_pin(config->pin_d0),
|
||||||
|
.d1 = to_native_pin(config->pin_d1),
|
||||||
|
.d2 = to_native_pin(config->pin_d2),
|
||||||
|
.d3 = to_native_pin(config->pin_d3),
|
||||||
|
.d4 = to_native_pin(config->pin_d4),
|
||||||
|
.d5 = to_native_pin(config->pin_d5),
|
||||||
|
.d6 = to_native_pin(config->pin_d6),
|
||||||
|
.d7 = to_native_pin(config->pin_d7),
|
||||||
|
.cd = to_native_pin(config->pin_cd),
|
||||||
|
.wp = to_native_pin(config->pin_wp),
|
||||||
|
.width = config->bus_width,
|
||||||
|
.flags = slot_config_flags
|
||||||
|
};
|
||||||
|
|
||||||
|
esp_err_t result = esp_vfs_fat_sdmmc_mount(fs_data->mount_path.c_str(), &host, &slot_config, &mount_config, &fs_data->card);
|
||||||
|
|
||||||
|
if (result != ESP_OK || fs_data->card == nullptr) {
|
||||||
|
if (result == ESP_FAIL) {
|
||||||
|
LOG_E(TAG, "Mounting failed. Ensure the card is formatted with FAT.");
|
||||||
|
} else {
|
||||||
|
LOG_E(TAG, "Mounting failed: %s", esp_err_to_name(result));
|
||||||
|
}
|
||||||
|
#if SOC_SD_PWR_CTRL_SUPPORTED
|
||||||
|
if (fs_data->pwr_ctrl_handle) {
|
||||||
|
sd_pwr_ctrl_del_on_chip_ldo(fs_data->pwr_ctrl_handle);
|
||||||
|
fs_data->pwr_ctrl_handle = nullptr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return ERROR_UNDEFINED;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_I(TAG, "Mounted %s", fs_data->mount_path.c_str());
|
||||||
|
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t unmount(void* data) {
|
||||||
|
auto* fs_data = GET_DATA(data);
|
||||||
|
LOG_I(TAG, "Unmounting %s", fs_data->mount_path.c_str());
|
||||||
|
|
||||||
|
if (esp_vfs_fat_sdcard_unmount(fs_data->mount_path.c_str(), fs_data->card) != ESP_OK) {
|
||||||
|
LOG_E(TAG, "Unmount failed for %s", fs_data->mount_path.c_str());
|
||||||
|
return ERROR_UNDEFINED;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs_data->card = nullptr;
|
||||||
|
|
||||||
|
#if SOC_SD_PWR_CTRL_SUPPORTED
|
||||||
|
if (fs_data->pwr_ctrl_handle) {
|
||||||
|
sd_pwr_ctrl_del_on_chip_ldo(fs_data->pwr_ctrl_handle);
|
||||||
|
fs_data->pwr_ctrl_handle = nullptr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
LOG_I(TAG, "Unmounted %s", fs_data->mount_path.c_str());
|
||||||
|
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_mounted(void* data) {
|
||||||
|
const auto* fs_data = GET_DATA(data);
|
||||||
|
if (fs_data->card == nullptr) return false;
|
||||||
|
return sdmmc_get_status(fs_data->card) == ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t get_path(void* data, char* out_path, size_t out_path_size) {
|
||||||
|
const auto* fs_data = GET_DATA(data);
|
||||||
|
if (fs_data->mount_path.size() >= out_path_size) return ERROR_BUFFER_OVERFLOW;
|
||||||
|
strncpy(out_path, fs_data->mount_path.c_str(), out_path_size);
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
const FileSystemApi esp32_sdmmc_fs_api = {
|
||||||
|
.mount = mount,
|
||||||
|
.unmount = unmount,
|
||||||
|
.is_mounted = is_mounted,
|
||||||
|
.get_path = get_path
|
||||||
|
};
|
||||||
|
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
@ -2,11 +2,11 @@
|
|||||||
#include <tactility/device.h>
|
#include <tactility/device.h>
|
||||||
#include <tactility/drivers/esp32_spi.h>
|
#include <tactility/drivers/esp32_spi.h>
|
||||||
#include <tactility/concurrent/recursive_mutex.h>
|
#include <tactility/concurrent/recursive_mutex.h>
|
||||||
|
#include <tactility/log.h>
|
||||||
|
|
||||||
#include "tactility/drivers/gpio_descriptor.h"
|
#include "tactility/drivers/gpio_descriptor.h"
|
||||||
#include <tactility/drivers/esp32_gpio_helpers.h>
|
#include <tactility/drivers/esp32_gpio_helpers.h>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <esp_log.h>
|
|
||||||
#include <new>
|
#include <new>
|
||||||
#include <soc/gpio_num.h>
|
#include <soc/gpio_num.h>
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ static error_t start(Device* device) {
|
|||||||
acquire_pin_or_set_null(dts_config->pin_hd, &data->hd_descriptor);
|
acquire_pin_or_set_null(dts_config->pin_hd, &data->hd_descriptor);
|
||||||
|
|
||||||
if (!pins_ok) {
|
if (!pins_ok) {
|
||||||
ESP_LOGE(TAG, "Failed to acquire required SPI pins");
|
LOG_E(TAG, "Failed to acquire required SPI pins");
|
||||||
data->cleanup_pins();
|
data->cleanup_pins();
|
||||||
device_set_driver_data(device, nullptr);
|
device_set_driver_data(device, nullptr);
|
||||||
delete data;
|
delete data;
|
||||||
@ -113,7 +113,7 @@ static error_t start(Device* device) {
|
|||||||
data->cleanup_pins();
|
data->cleanup_pins();
|
||||||
device_set_driver_data(device, nullptr);
|
device_set_driver_data(device, nullptr);
|
||||||
delete data;
|
delete data;
|
||||||
ESP_LOGE(TAG, "Failed to initialize SPI bus: %s", esp_err_to_name(ret));
|
LOG_E(TAG, "Failed to initialize SPI bus: %s", esp_err_to_name(ret));
|
||||||
return ERROR_RESOURCE;
|
return ERROR_RESOURCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,7 +122,7 @@ static error_t start(Device* device) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static error_t stop(Device* device) {
|
static error_t stop(Device* device) {
|
||||||
ESP_LOGI(TAG, "stop %s", device->name);
|
LOG_I(TAG, "stop %s", device->name);
|
||||||
auto* driver_data = GET_DATA(device);
|
auto* driver_data = GET_DATA(device);
|
||||||
auto* dts_config = GET_CONFIG(device);
|
auto* dts_config = GET_CONFIG(device);
|
||||||
|
|
||||||
|
|||||||
@ -2,11 +2,16 @@
|
|||||||
#include <tactility/driver.h>
|
#include <tactility/driver.h>
|
||||||
#include <tactility/module.h>
|
#include <tactility/module.h>
|
||||||
|
|
||||||
|
#include <soc/soc_caps.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
extern Driver esp32_gpio_driver;
|
extern Driver esp32_gpio_driver;
|
||||||
extern Driver esp32_i2c_driver;
|
extern Driver esp32_i2c_driver;
|
||||||
extern Driver esp32_i2s_driver;
|
extern Driver esp32_i2s_driver;
|
||||||
|
#if SOC_SDMMC_HOST_SUPPORTED
|
||||||
|
extern Driver esp32_sdmmc_driver;
|
||||||
|
#endif
|
||||||
extern Driver esp32_spi_driver;
|
extern Driver esp32_spi_driver;
|
||||||
extern Driver esp32_uart_driver;
|
extern Driver esp32_uart_driver;
|
||||||
|
|
||||||
@ -16,6 +21,9 @@ static error_t start() {
|
|||||||
check(driver_construct_add(&esp32_gpio_driver) == ERROR_NONE);
|
check(driver_construct_add(&esp32_gpio_driver) == ERROR_NONE);
|
||||||
check(driver_construct_add(&esp32_i2c_driver) == ERROR_NONE);
|
check(driver_construct_add(&esp32_i2c_driver) == ERROR_NONE);
|
||||||
check(driver_construct_add(&esp32_i2s_driver) == ERROR_NONE);
|
check(driver_construct_add(&esp32_i2s_driver) == ERROR_NONE);
|
||||||
|
#if SOC_SDMMC_HOST_SUPPORTED
|
||||||
|
check(driver_construct_add(&esp32_sdmmc_driver) == ERROR_NONE);
|
||||||
|
#endif
|
||||||
check(driver_construct_add(&esp32_spi_driver) == ERROR_NONE);
|
check(driver_construct_add(&esp32_spi_driver) == ERROR_NONE);
|
||||||
check(driver_construct_add(&esp32_uart_driver) == ERROR_NONE);
|
check(driver_construct_add(&esp32_uart_driver) == ERROR_NONE);
|
||||||
return ERROR_NONE;
|
return ERROR_NONE;
|
||||||
@ -27,12 +35,15 @@ static error_t stop() {
|
|||||||
check(driver_remove_destruct(&esp32_gpio_driver) == ERROR_NONE);
|
check(driver_remove_destruct(&esp32_gpio_driver) == ERROR_NONE);
|
||||||
check(driver_remove_destruct(&esp32_i2c_driver) == ERROR_NONE);
|
check(driver_remove_destruct(&esp32_i2c_driver) == ERROR_NONE);
|
||||||
check(driver_remove_destruct(&esp32_i2s_driver) == ERROR_NONE);
|
check(driver_remove_destruct(&esp32_i2s_driver) == ERROR_NONE);
|
||||||
|
#if SOC_SDMMC_HOST_SUPPORTED
|
||||||
|
check(driver_remove_destruct(&esp32_sdmmc_driver) == ERROR_NONE);
|
||||||
|
#endif
|
||||||
check(driver_remove_destruct(&esp32_spi_driver) == ERROR_NONE);
|
check(driver_remove_destruct(&esp32_spi_driver) == ERROR_NONE);
|
||||||
check(driver_remove_destruct(&esp32_uart_driver) == ERROR_NONE);
|
check(driver_remove_destruct(&esp32_uart_driver) == ERROR_NONE);
|
||||||
return ERROR_NONE;
|
return ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Module platform_esp32_module = {
|
Module platform_esp32_module = {
|
||||||
.name = "platform-esp32",
|
.name = "platform-esp32",
|
||||||
.start = start,
|
.start = start,
|
||||||
.stop = stop,
|
.stop = stop,
|
||||||
|
|||||||
@ -21,6 +21,6 @@ constexpr auto* MOUNT_POINT_DATA = "/data";
|
|||||||
constexpr auto* MOUNT_POINT_DATA = "data";
|
constexpr auto* MOUNT_POINT_DATA = "data";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::vector<dirent> getMountPoints();
|
std::vector<dirent> getFileSystemDirents();
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|||||||
@ -2,10 +2,15 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include <tactility/filesystem/file_system.h>
|
||||||
|
|
||||||
|
|
||||||
namespace tt {
|
namespace tt {
|
||||||
|
|
||||||
bool findFirstMountedSdCardPath(std::string& path);
|
bool findFirstMountedSdCardPath(std::string& path);
|
||||||
|
|
||||||
|
FileSystem* findSdcardFileSystem(bool mustBeMounted);
|
||||||
|
|
||||||
std::string getSystemRootPath();
|
std::string getSystemRootPath();
|
||||||
|
|
||||||
std::string getTempPath();
|
std::string getTempPath();
|
||||||
|
|||||||
@ -2,9 +2,11 @@
|
|||||||
|
|
||||||
#include <tactility/hal/Device.h>
|
#include <tactility/hal/Device.h>
|
||||||
|
|
||||||
#include <Tactility/TactilityCore.h>
|
|
||||||
#include <Tactility/Lock.h>
|
#include <Tactility/Lock.h>
|
||||||
|
#include <Tactility/TactilityCore.h>
|
||||||
|
|
||||||
|
|
||||||
|
struct FileSystem;
|
||||||
namespace tt::hal::sdcard {
|
namespace tt::hal::sdcard {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -31,11 +33,12 @@ public:
|
|||||||
private:
|
private:
|
||||||
|
|
||||||
MountBehaviour mountBehaviour;
|
MountBehaviour mountBehaviour;
|
||||||
|
FileSystem* fileSystem;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
explicit SdCardDevice(MountBehaviour mountBehaviour) : mountBehaviour(mountBehaviour) {}
|
explicit SdCardDevice(MountBehaviour mountBehaviour);
|
||||||
~SdCardDevice() override = default;
|
~SdCardDevice() override;
|
||||||
|
|
||||||
Type getType() const final { return Type::SdCard; };
|
Type getType() const final { return Type::SdCard; };
|
||||||
|
|
||||||
|
|||||||
@ -1,93 +0,0 @@
|
|||||||
#ifdef ESP_PLATFORM
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "SdCardDevice.h"
|
|
||||||
|
|
||||||
#include <Tactility/RecursiveMutex.h>
|
|
||||||
#include <tactility/hal/Device.h>
|
|
||||||
#include <sd_protocol_types.h>
|
|
||||||
#include <soc/gpio_num.h>
|
|
||||||
#include <utility>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace tt::hal::sdcard {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* SD card interface for the SDMMC interface.
|
|
||||||
*/
|
|
||||||
class SdmmcDevice final : public SdCardDevice {
|
|
||||||
|
|
||||||
std::shared_ptr<RecursiveMutex> mutex = std::make_shared<RecursiveMutex>();
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
struct Config {
|
|
||||||
Config(
|
|
||||||
gpio_num_t pinClock,
|
|
||||||
gpio_num_t pinCmd,
|
|
||||||
gpio_num_t pinD0,
|
|
||||||
gpio_num_t pinD1,
|
|
||||||
gpio_num_t pinD2,
|
|
||||||
gpio_num_t pinD3,
|
|
||||||
MountBehaviour mountBehaviourAtBoot,
|
|
||||||
uint8_t busWidth = 4
|
|
||||||
) :
|
|
||||||
pinClock(pinClock),
|
|
||||||
pinCmd(pinCmd),
|
|
||||||
pinD0(pinD0),
|
|
||||||
pinD1(pinD1),
|
|
||||||
pinD2(pinD2),
|
|
||||||
pinD3(pinD3),
|
|
||||||
mountBehaviourAtBoot(mountBehaviourAtBoot),
|
|
||||||
busWidth(busWidth)
|
|
||||||
{}
|
|
||||||
|
|
||||||
int spiFrequencyKhz;
|
|
||||||
gpio_num_t pinClock;
|
|
||||||
gpio_num_t pinCmd;
|
|
||||||
gpio_num_t pinD0;
|
|
||||||
gpio_num_t pinD1;
|
|
||||||
gpio_num_t pinD2;
|
|
||||||
gpio_num_t pinD3;
|
|
||||||
MountBehaviour mountBehaviourAtBoot;
|
|
||||||
uint8_t busWidth;
|
|
||||||
bool formatOnMountFailed = false;
|
|
||||||
uint16_t maxOpenFiles = 4;
|
|
||||||
uint16_t allocUnitSize = 16 * 1024;
|
|
||||||
bool statusCheckEnabled = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
std::string mountPath;
|
|
||||||
sdmmc_card_t* card = nullptr;
|
|
||||||
std::shared_ptr<Config> config;
|
|
||||||
|
|
||||||
bool applyGpioWorkAround();
|
|
||||||
bool mountInternal(const std::string& mountPath);
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
explicit SdmmcDevice(std::unique_ptr<Config> config) : SdCardDevice(config->mountBehaviourAtBoot),
|
|
||||||
config(std::move(config))
|
|
||||||
{}
|
|
||||||
|
|
||||||
std::string getName() const override { return "SDMMC"; }
|
|
||||||
std::string getDescription() const override { return "SD card via SDMMC interface"; }
|
|
||||||
|
|
||||||
bool mount(const std::string& mountPath) override;
|
|
||||||
bool unmount() override;
|
|
||||||
std::string getMountPath() const override { return mountPath; }
|
|
||||||
|
|
||||||
std::shared_ptr<Lock> getLock() const override { return mutex; }
|
|
||||||
|
|
||||||
State getState(TickType_t timeout) const override;
|
|
||||||
|
|
||||||
/** return card when mounted, otherwise return nullptr */
|
|
||||||
sdmmc_card_t* getCard() { return card; }
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -2,56 +2,36 @@
|
|||||||
|
|
||||||
#include "Tactility/TactilityConfig.h"
|
#include "Tactility/TactilityConfig.h"
|
||||||
#include <tactility/hal/Device.h>
|
#include <tactility/hal/Device.h>
|
||||||
#include "Tactility/hal/sdcard/SdCardDevice.h"
|
|
||||||
|
|
||||||
#include <Tactility/file/File.h>
|
#include <Tactility/file/File.h>
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <vector>
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <tactility/filesystem/file_system.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace tt::file {
|
namespace tt::file {
|
||||||
|
|
||||||
std::vector<dirent> getMountPoints() {
|
std::vector<dirent> getFileSystemDirents() {
|
||||||
std::vector<dirent> dir_entries;
|
std::vector<dirent> dir_entries;
|
||||||
dir_entries.clear();
|
|
||||||
|
|
||||||
// Data partition
|
file_system_for_each(&dir_entries, [](auto* fs, void* context) {
|
||||||
auto data_dirent = dirent{
|
if (!file_system_is_mounted(fs)) return true;
|
||||||
.d_ino = 1,
|
char path[128];
|
||||||
.d_type = TT_DT_DIR,
|
if (file_system_get_path(fs, path, sizeof(path)) != ERROR_NONE) return true;
|
||||||
.d_name = { 0 }
|
auto mount_name = std::string(path).substr(1);
|
||||||
};
|
if (!config::SHOW_SYSTEM_PARTITION && mount_name.starts_with(SYSTEM_PARTITION_NAME)) return true;
|
||||||
strcpy(data_dirent.d_name, DATA_PARTITION_NAME);
|
auto dir_entry = dirent {
|
||||||
dir_entries.push_back(data_dirent);
|
.d_ino = 2,
|
||||||
|
|
||||||
// SD card partitions
|
|
||||||
auto sdcards = tt::hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
|
||||||
for (auto& sdcard : sdcards) {
|
|
||||||
auto state = sdcard->getState();
|
|
||||||
if (state == hal::sdcard::SdCardDevice::State::Mounted) {
|
|
||||||
auto mount_name = sdcard->getMountPath().substr(1);
|
|
||||||
auto dir_entry = dirent {
|
|
||||||
.d_ino = 2,
|
|
||||||
.d_type = TT_DT_DIR,
|
|
||||||
.d_name = { 0 }
|
|
||||||
};
|
|
||||||
assert(mount_name.length() < sizeof(dirent::d_name));
|
|
||||||
strcpy(dir_entry.d_name, mount_name.c_str());
|
|
||||||
dir_entries.push_back(dir_entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config::SHOW_SYSTEM_PARTITION) {
|
|
||||||
// System partition
|
|
||||||
auto system_dirent = dirent{
|
|
||||||
.d_ino = 0,
|
|
||||||
.d_type = TT_DT_DIR,
|
.d_type = TT_DT_DIR,
|
||||||
.d_name = { 0 }
|
.d_name = { 0 }
|
||||||
};
|
};
|
||||||
strcpy(system_dirent.d_name, SYSTEM_PARTITION_NAME);
|
auto& dir_entries = *static_cast<std::vector<dirent>*>(context);
|
||||||
dir_entries.push_back(system_dirent);
|
strcpy(dir_entry.d_name, mount_name.c_str());
|
||||||
}
|
dir_entries.push_back(dir_entry);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
return dir_entries;
|
return dir_entries;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,11 +5,47 @@
|
|||||||
|
|
||||||
#include <esp_vfs_fat.h>
|
#include <esp_vfs_fat.h>
|
||||||
#include <nvs_flash.h>
|
#include <nvs_flash.h>
|
||||||
|
#include <tactility/error.h>
|
||||||
|
#include <tactility/filesystem/file_system.h>
|
||||||
|
|
||||||
namespace tt {
|
namespace tt {
|
||||||
|
|
||||||
static const auto LOGGER = Logger("Partitions");
|
static const auto LOGGER = Logger("Partitions");
|
||||||
|
|
||||||
|
// region file_system stub
|
||||||
|
|
||||||
|
struct PartitionFsData {
|
||||||
|
const char* path;
|
||||||
|
};
|
||||||
|
|
||||||
|
static error_t mount(void* data) {
|
||||||
|
return ERROR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t unmount(void* data) {
|
||||||
|
return ERROR_NOT_SUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_mounted(void* data) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t get_path(void* data, char* out_path, size_t out_path_size) {
|
||||||
|
auto* fs_data = static_cast<PartitionFsData*>(data);
|
||||||
|
if (strlen(fs_data->path) >= out_path_size) return ERROR_BUFFER_OVERFLOW;
|
||||||
|
strncpy(out_path, fs_data->path, out_path_size);
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSystemApi partition_fs_api = {
|
||||||
|
.mount = mount,
|
||||||
|
.unmount = unmount,
|
||||||
|
.is_mounted = is_mounted,
|
||||||
|
.get_path = get_path
|
||||||
|
};
|
||||||
|
|
||||||
|
// endregion file_system stub
|
||||||
|
|
||||||
static esp_err_t initNvsFlashSafely() {
|
static esp_err_t initNvsFlashSafely() {
|
||||||
esp_err_t result = nvs_flash_init();
|
esp_err_t result = nvs_flash_init();
|
||||||
if (result == ESP_ERR_NVS_NO_FREE_PAGES || result == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
if (result == ESP_ERR_NVS_NO_FREE_PAGES || result == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||||
@ -56,6 +92,8 @@ esp_err_t initPartitionsEsp() {
|
|||||||
LOGGER.error("Failed to mount /system ({})", esp_err_to_name(system_result));
|
LOGGER.error("Failed to mount /system ({})", esp_err_to_name(system_result));
|
||||||
} else {
|
} else {
|
||||||
LOGGER.info("Mounted /system");
|
LOGGER.info("Mounted /system");
|
||||||
|
static auto system_fs_data = PartitionFsData("/system");
|
||||||
|
file_system_add(&partition_fs_api, &system_fs_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto data_result = esp_vfs_fat_spiflash_mount_rw_wl("/data", "data", &mount_config, &data_wl_handle);
|
auto data_result = esp_vfs_fat_spiflash_mount_rw_wl("/data", "data", &mount_config, &data_wl_handle);
|
||||||
@ -63,6 +101,8 @@ esp_err_t initPartitionsEsp() {
|
|||||||
LOGGER.error("Failed to mount /data ({})", esp_err_to_name(data_result));
|
LOGGER.error("Failed to mount /data ({})", esp_err_to_name(data_result));
|
||||||
} else {
|
} else {
|
||||||
LOGGER.info("Mounted /data");
|
LOGGER.info("Mounted /data");
|
||||||
|
static auto data_fs_data = PartitionFsData("/data");
|
||||||
|
file_system_add(&partition_fs_api, &data_fs_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return system_result == ESP_OK && data_result == ESP_OK;
|
return system_result == ESP_OK && data_result == ESP_OK;
|
||||||
|
|||||||
@ -2,25 +2,37 @@
|
|||||||
|
|
||||||
#include <Tactility/app/AppManifestParsing.h>
|
#include <Tactility/app/AppManifestParsing.h>
|
||||||
#include <Tactility/MountPoints.h>
|
#include <Tactility/MountPoints.h>
|
||||||
#include <Tactility/hal/sdcard/SdCardDevice.h>
|
|
||||||
|
|
||||||
#include <format>
|
#include <format>
|
||||||
|
#include <tactility/filesystem/file_system.h>
|
||||||
|
|
||||||
namespace tt {
|
namespace tt {
|
||||||
|
|
||||||
bool findFirstMountedSdCardPath(std::string& path) {
|
bool findFirstMountedSdCardPath(std::string& path) {
|
||||||
// const auto sdcards = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
auto* fs = findSdcardFileSystem(true);
|
||||||
bool is_set = false;
|
if (fs == nullptr) return false;
|
||||||
hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard, [&is_set, &path](const auto& device) {
|
char found_path[128];
|
||||||
if (device->isMounted()) {
|
if (file_system_get_path(fs, found_path, sizeof(found_path)) != ERROR_NONE) return false;
|
||||||
path = device->getMountPath();
|
path = found_path;
|
||||||
is_set = true;
|
return true;
|
||||||
return false; // stop iterating
|
}
|
||||||
} else {
|
|
||||||
return true;
|
FileSystem* findSdcardFileSystem(bool mustBeMounted) {
|
||||||
|
FileSystem* found = nullptr;
|
||||||
|
file_system_for_each(&found, [](auto* fs, void* context) {
|
||||||
|
char path[128];
|
||||||
|
if (file_system_get_path(fs, path, sizeof(path)) != ERROR_NONE) return true;
|
||||||
|
// TODO: Find a better way to identify SD card paths
|
||||||
|
if (std::string(path).starts_with("/sdcard")) {
|
||||||
|
*static_cast<FileSystem**>(context) = fs;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
});
|
});
|
||||||
return is_set;
|
if (found && mustBeMounted && !file_system_is_mounted(found)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string getSystemRootPath() {
|
std::string getSystemRootPath() {
|
||||||
|
|||||||
@ -8,19 +8,19 @@
|
|||||||
#include <Tactility/Tactility.h>
|
#include <Tactility/Tactility.h>
|
||||||
#include <Tactility/TactilityConfig.h>
|
#include <Tactility/TactilityConfig.h>
|
||||||
|
|
||||||
#include <Tactility/app/AppManifestParsing.h>
|
|
||||||
#include <Tactility/app/AppRegistration.h>
|
|
||||||
#include <Tactility/CpuAffinity.h>
|
#include <Tactility/CpuAffinity.h>
|
||||||
#include <Tactility/DispatcherThread.h>
|
#include <Tactility/DispatcherThread.h>
|
||||||
|
#include <Tactility/LogMessages.h>
|
||||||
|
#include <Tactility/Logger.h>
|
||||||
|
#include <Tactility/MountPoints.h>
|
||||||
|
#include <Tactility/Paths.h>
|
||||||
|
#include <Tactility/app/AppManifestParsing.h>
|
||||||
|
#include <Tactility/app/AppRegistration.h>
|
||||||
#include <Tactility/file/File.h>
|
#include <Tactility/file/File.h>
|
||||||
#include <Tactility/file/FileLock.h>
|
#include <Tactility/file/FileLock.h>
|
||||||
#include <Tactility/file/PropertiesFile.h>
|
#include <Tactility/file/PropertiesFile.h>
|
||||||
#include <Tactility/hal/HalPrivate.h>
|
#include <Tactility/hal/HalPrivate.h>
|
||||||
#include <Tactility/hal/sdcard/SdCardDevice.h>
|
|
||||||
#include <Tactility/Logger.h>
|
|
||||||
#include <Tactility/LogMessages.h>
|
|
||||||
#include <Tactility/lvgl/LvglPrivate.h>
|
#include <Tactility/lvgl/LvglPrivate.h>
|
||||||
#include <Tactility/MountPoints.h>
|
|
||||||
#include <Tactility/network/NtpPrivate.h>
|
#include <Tactility/network/NtpPrivate.h>
|
||||||
#include <Tactility/service/ServiceManifest.h>
|
#include <Tactility/service/ServiceManifest.h>
|
||||||
#include <Tactility/service/ServiceRegistration.h>
|
#include <Tactility/service/ServiceRegistration.h>
|
||||||
@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
#include <tactility/concurrent/thread.h>
|
#include <tactility/concurrent/thread.h>
|
||||||
#include <tactility/drivers/uart_controller.h>
|
#include <tactility/drivers/uart_controller.h>
|
||||||
|
#include <tactility/filesystem/file_system.h>
|
||||||
#include <tactility/hal_device_module.h>
|
#include <tactility/hal_device_module.h>
|
||||||
#include <tactility/kernel_init.h>
|
#include <tactility/kernel_init.h>
|
||||||
#include <tactility/lvgl_module.h>
|
#include <tactility/lvgl_module.h>
|
||||||
@ -49,7 +50,6 @@ namespace service {
|
|||||||
// Primary
|
// Primary
|
||||||
namespace gps { extern const ServiceManifest manifest; }
|
namespace gps { extern const ServiceManifest manifest; }
|
||||||
namespace wifi { extern const ServiceManifest manifest; }
|
namespace wifi { extern const ServiceManifest manifest; }
|
||||||
namespace sdcard { extern const ServiceManifest manifest; }
|
|
||||||
#ifdef ESP_PLATFORM
|
#ifdef ESP_PLATFORM
|
||||||
namespace development { extern const ServiceManifest manifest; }
|
namespace development { extern const ServiceManifest manifest; }
|
||||||
#endif
|
#endif
|
||||||
@ -228,22 +228,18 @@ static void registerInstalledApps(const std::string& path) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static void registerInstalledAppsFromSdCard(const std::shared_ptr<hal::sdcard::SdCardDevice>& sdcard) {
|
static void registerInstalledAppsFromFileSystems() {
|
||||||
auto sdcard_root_path = sdcard->getMountPath();
|
file_system_for_each(nullptr, [](auto* fs, void* context) {
|
||||||
auto app_path = std::format("{}/app", sdcard_root_path);
|
if (!file_system_is_mounted(fs)) return true;
|
||||||
if (file::isDirectory(app_path)) {
|
char path[128];
|
||||||
registerInstalledApps(app_path);
|
if (file_system_get_path(fs, path, sizeof(path)) != ERROR_NONE) return true;
|
||||||
}
|
const auto app_path = std::format("{}/app", path);
|
||||||
}
|
if (!app_path.starts_with(file::MOUNT_POINT_SYSTEM) && file::isDirectory(app_path)) {
|
||||||
|
LOGGER.info("Registering apps from {}", app_path);
|
||||||
static void registerInstalledAppsFromSdCards() {
|
registerInstalledApps(app_path);
|
||||||
auto sdcard_devices = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
|
||||||
for (const auto& sdcard : sdcard_devices) {
|
|
||||||
if (sdcard->isMounted()) {
|
|
||||||
LOGGER.info("Registering apps from {}", sdcard->getMountPath());
|
|
||||||
registerInstalledAppsFromSdCard(sdcard);
|
|
||||||
}
|
}
|
||||||
}
|
return true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static void registerAndStartSecondaryServices() {
|
static void registerAndStartSecondaryServices() {
|
||||||
@ -266,9 +262,6 @@ static void registerAndStartSecondaryServices() {
|
|||||||
static void registerAndStartPrimaryServices() {
|
static void registerAndStartPrimaryServices() {
|
||||||
LOGGER.info("Registering and starting primary system services");
|
LOGGER.info("Registering and starting primary system services");
|
||||||
addService(service::gps::manifest);
|
addService(service::gps::manifest);
|
||||||
if (hal::hasDevice(hal::Device::Type::SdCard)) {
|
|
||||||
addService(service::sdcard::manifest);
|
|
||||||
}
|
|
||||||
addService(service::wifi::manifest);
|
addService(service::wifi::manifest);
|
||||||
#ifdef ESP_PLATFORM
|
#ifdef ESP_PLATFORM
|
||||||
addService(service::development::manifest);
|
addService(service::development::manifest);
|
||||||
@ -301,26 +294,19 @@ void createTempDirectory(const std::string& rootPath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void prepareFileSystems() {
|
void prepareFileSystems() {
|
||||||
// Temporary directories for SD cards
|
file_system_for_each(nullptr, [](auto* fs, void* context) {
|
||||||
auto sdcard_devices = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
if (!file_system_is_mounted(fs)) return true;
|
||||||
for (const auto& sdcard : sdcard_devices) {
|
char path[128];
|
||||||
if (sdcard->isMounted()) {
|
if (file_system_get_path(fs, path, sizeof(path)) != ERROR_NONE) return true;
|
||||||
createTempDirectory(sdcard->getMountPath());
|
if (std::string(path) == file::MOUNT_POINT_SYSTEM) return true;
|
||||||
}
|
createTempDirectory(path);
|
||||||
}
|
return true;
|
||||||
// Temporary directory for /data
|
});
|
||||||
if (file::isDirectory(file::MOUNT_POINT_DATA)) {
|
|
||||||
createTempDirectory(file::MOUNT_POINT_DATA);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void registerApps() {
|
void registerApps() {
|
||||||
registerInternalApps();
|
registerInternalApps();
|
||||||
auto data_apps_path = std::format("{}/app", file::MOUNT_POINT_DATA);
|
registerInstalledAppsFromFileSystems();
|
||||||
if (file::isDirectory(data_apps_path)) {
|
|
||||||
registerInstalledApps(data_apps_path);
|
|
||||||
}
|
|
||||||
registerInstalledAppsFromSdCards();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void run(const Configuration& config, Module* dtsModules[], DtsDevice dtsDevices[]) {
|
void run(const Configuration& config, Module* dtsModules[], DtsDevice dtsDevices[]) {
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
#include <Tactility/app/files/State.h>
|
#include <Tactility/app/files/State.h>
|
||||||
#include <Tactility/app/AppContext.h>
|
#include <Tactility/app/AppContext.h>
|
||||||
|
|
||||||
#include <Tactility/Assets.h>
|
|
||||||
#include <Tactility/service/loader/Loader.h>
|
#include <Tactility/service/loader/Loader.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|||||||
@ -51,7 +51,7 @@ bool State::setEntriesForPath(const std::string& path) {
|
|||||||
bool get_mount_points = (kernel::getPlatform() == kernel::PlatformEsp) && (path == "/");
|
bool get_mount_points = (kernel::getPlatform() == kernel::PlatformEsp) && (path == "/");
|
||||||
if (get_mount_points) {
|
if (get_mount_points) {
|
||||||
LOGGER.info("Setting custom root");
|
LOGGER.info("Setting custom root");
|
||||||
dir_entries = file::getMountPoints();
|
dir_entries = file::getFileSystemDirents();
|
||||||
current_path = path;
|
current_path = path;
|
||||||
selected_child_entry = "";
|
selected_child_entry = "";
|
||||||
action = ActionNone;
|
action = ActionNone;
|
||||||
|
|||||||
@ -6,10 +6,11 @@
|
|||||||
#include <Tactility/MountPoints.h>
|
#include <Tactility/MountPoints.h>
|
||||||
#include <Tactility/kernel/Platform.h>
|
#include <Tactility/kernel/Platform.h>
|
||||||
|
|
||||||
|
#include <Tactility/LogMessages.h>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <dirent.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <dirent.h>
|
|
||||||
|
|
||||||
namespace tt::app::fileselection {
|
namespace tt::app::fileselection {
|
||||||
|
|
||||||
@ -36,6 +37,12 @@ std::string State::getSelectedChildPath() const {
|
|||||||
bool State::setEntriesForPath(const std::string& path) {
|
bool State::setEntriesForPath(const std::string& path) {
|
||||||
LOGGER.info("Changing path: {} -> {}", current_path, path);
|
LOGGER.info("Changing path: {} -> {}", current_path, path);
|
||||||
|
|
||||||
|
auto lock = mutex.asScopedLock();
|
||||||
|
if (!lock.lock(100)) {
|
||||||
|
LOGGER.error(LOG_MESSAGE_MUTEX_LOCK_FAILED_FMT, "setEntriesForPath");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ESP32 does not have a root directory, so we have to create it manually.
|
* ESP32 does not have a root directory, so we have to create it manually.
|
||||||
* We'll add the NVS Flash partitions and the binding for the sdcard.
|
* We'll add the NVS Flash partitions and the binding for the sdcard.
|
||||||
@ -43,7 +50,7 @@ bool State::setEntriesForPath(const std::string& path) {
|
|||||||
bool show_custom_root = (kernel::getPlatform() == kernel::PlatformEsp) && (path == "/");
|
bool show_custom_root = (kernel::getPlatform() == kernel::PlatformEsp) && (path == "/");
|
||||||
if (show_custom_root) {
|
if (show_custom_root) {
|
||||||
LOGGER.info("Setting custom root");
|
LOGGER.info("Setting custom root");
|
||||||
dir_entries = file::getMountPoints();
|
dir_entries = file::getFileSystemDirents();
|
||||||
current_path = path;
|
current_path = path;
|
||||||
selected_child_entry = "";
|
selected_child_entry = "";
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@ -1,18 +1,18 @@
|
|||||||
#include <Tactility/Tactility.h>
|
#include <Tactility/Tactility.h>
|
||||||
#include <Tactility/TactilityConfig.h>
|
#include <Tactility/TactilityConfig.h>
|
||||||
|
|
||||||
|
|
||||||
#if TT_FEATURE_SCREENSHOT_ENABLED
|
#if TT_FEATURE_SCREENSHOT_ENABLED
|
||||||
|
|
||||||
#include <Tactility/app/App.h>
|
#include <Tactility/app/App.h>
|
||||||
#include <Tactility/app/AppManifest.h>
|
#include <Tactility/app/AppManifest.h>
|
||||||
#include <Tactility/hal/sdcard/SdCardDevice.h>
|
|
||||||
#include <Tactility/kernel/Platform.h>
|
#include <Tactility/kernel/Platform.h>
|
||||||
#include <Tactility/Logger.h>
|
#include <Tactility/Logger.h>
|
||||||
#include <Tactility/lvgl/Lvgl.h>
|
#include <Tactility/lvgl/Lvgl.h>
|
||||||
#include <Tactility/lvgl/LvglSync.h>
|
#include <Tactility/lvgl/LvglSync.h>
|
||||||
#include <Tactility/lvgl/Toolbar.h>
|
#include <Tactility/lvgl/Toolbar.h>
|
||||||
#include <Tactility/service/screenshot/Screenshot.h>
|
#include <Tactility/service/screenshot/Screenshot.h>
|
||||||
|
|
||||||
|
#include <Tactility/Paths.h>
|
||||||
#include <Tactility/Timer.h>
|
#include <Tactility/Timer.h>
|
||||||
|
|
||||||
#include <tactility/lvgl_icon_shared.h>
|
#include <tactility/lvgl_icon_shared.h>
|
||||||
@ -204,12 +204,9 @@ void ScreenshotApp::createFilePathWidgets(lv_obj_t* parent) {
|
|||||||
lv_textarea_set_one_line(pathTextArea, true);
|
lv_textarea_set_one_line(pathTextArea, true);
|
||||||
lv_obj_set_flex_grow(pathTextArea, 1);
|
lv_obj_set_flex_grow(pathTextArea, 1);
|
||||||
if (kernel::getPlatform() == kernel::PlatformEsp) {
|
if (kernel::getPlatform() == kernel::PlatformEsp) {
|
||||||
auto sdcard_devices = tt::hal::findDevices<tt::hal::sdcard::SdCardDevice>(tt::hal::Device::Type::SdCard);
|
std::string sdcard_path;
|
||||||
if (sdcard_devices.size() > 1) {
|
if (findFirstMountedSdCardPath(sdcard_path)) {
|
||||||
LOGGER.warn("Found multiple SD card devices - picking first");
|
std::string lvgl_mount_path = lvgl::PATH_PREFIX + sdcard_path + "/screenshots";
|
||||||
}
|
|
||||||
if (!sdcard_devices.empty() && sdcard_devices.front()->isMounted()) {
|
|
||||||
std::string lvgl_mount_path = lvgl::PATH_PREFIX + sdcard_devices.front()->getMountPath();
|
|
||||||
lv_textarea_set_text(pathTextArea, lvgl_mount_path.c_str());
|
lv_textarea_set_text(pathTextArea, lvgl_mount_path.c_str());
|
||||||
} else {
|
} else {
|
||||||
lv_textarea_set_text(pathTextArea, "Error: no SD card");
|
lv_textarea_set_text(pathTextArea, "Error: no SD card");
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
#include <Tactility/TactilityConfig.h>
|
#include <Tactility/TactilityConfig.h>
|
||||||
#include <Tactility/lvgl/LvglSync.h>
|
#include <Tactility/lvgl/LvglSync.h>
|
||||||
#include <Tactility/lvgl/Toolbar.h>
|
#include <Tactility/lvgl/Toolbar.h>
|
||||||
#include <Tactility/hal/sdcard/SdCardDevice.h>
|
|
||||||
#include <Tactility/Tactility.h>
|
#include <Tactility/Tactility.h>
|
||||||
#include <Tactility/Timer.h>
|
#include <Tactility/Timer.h>
|
||||||
|
|
||||||
|
#include <Tactility/Paths.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <format>
|
#include <format>
|
||||||
@ -321,7 +321,6 @@ class SystemInfoApp final : public App {
|
|||||||
|
|
||||||
bool hasExternalMem = false;
|
bool hasExternalMem = false;
|
||||||
bool hasDataStorage = false;
|
bool hasDataStorage = false;
|
||||||
bool hasSdcardStorage = false;
|
|
||||||
bool hasSystemStorage = false;
|
bool hasSystemStorage = false;
|
||||||
|
|
||||||
void updateMemory() {
|
void updateMemory() {
|
||||||
@ -343,14 +342,9 @@ class SystemInfoApp final : public App {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasSdcardStorage) {
|
std::string sdcard_path;
|
||||||
const auto sdcard_devices = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
if (findFirstMountedSdCardPath(sdcard_path) && esp_vfs_fat_info(sdcard_path.c_str(), &storage_total, &storage_free) == ESP_OK) {
|
||||||
for (const auto& sdcard : sdcard_devices) {
|
updateMemoryBar(sdcardStorageBar, storage_free, storage_total);
|
||||||
if (sdcard->isMounted() && esp_vfs_fat_info(sdcard->getMountPath().c_str(), &storage_total, &storage_free) == ESP_OK) {
|
|
||||||
updateMemoryBar(sdcardStorageBar, storage_free, storage_total);
|
|
||||||
break; // Only update first SD card
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasSystemStorage) {
|
if (hasSystemStorage) {
|
||||||
@ -624,13 +618,9 @@ class SystemInfoApp final : public App {
|
|||||||
dataStorageBar = createMemoryBar(storage_tab, file::MOUNT_POINT_DATA);
|
dataStorageBar = createMemoryBar(storage_tab, file::MOUNT_POINT_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto sdcard_devices = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
std::string sdcard_path;
|
||||||
for (const auto& sdcard : sdcard_devices) {
|
if (findFirstMountedSdCardPath(sdcard_path) && esp_vfs_fat_info(sdcard_path.c_str(), &storage_total, &storage_free) == ESP_OK) {
|
||||||
if (sdcard->isMounted() && esp_vfs_fat_info(sdcard->getMountPath().c_str(), &storage_total, &storage_free) == ESP_OK) {
|
sdcardStorageBar = createMemoryBar(storage_tab, sdcard_path.c_str());
|
||||||
hasSdcardStorage = true;
|
|
||||||
sdcardStorageBar = createMemoryBar(storage_tab, sdcard->getMountPath().c_str());
|
|
||||||
break; // Only show first SD card
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config::SHOW_SYSTEM_PARTITION) {
|
if (config::SHOW_SYSTEM_PARTITION) {
|
||||||
|
|||||||
52
Tactility/Source/hal/sdcard/SdCardDevice.cpp
Normal file
52
Tactility/Source/hal/sdcard/SdCardDevice.cpp
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#include <Tactility/hal/sdcard/SdCardDevice.h>
|
||||||
|
|
||||||
|
#include <tactility/filesystem/file_system.h>
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
namespace tt::hal::sdcard {
|
||||||
|
|
||||||
|
static error_t mount(void* data) {
|
||||||
|
auto* device = static_cast<SdCardDevice*>(data);
|
||||||
|
auto path = device->getMountPath();
|
||||||
|
if (!device->mount(path)) return ERROR_UNDEFINED;
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t unmount(void* data) {
|
||||||
|
auto* device = static_cast<SdCardDevice*>(data);
|
||||||
|
if (!device->unmount()) return ERROR_UNDEFINED;
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool is_mounted(void* data) {
|
||||||
|
auto* device = static_cast<SdCardDevice*>(data);
|
||||||
|
return device->isMounted();
|
||||||
|
}
|
||||||
|
|
||||||
|
static error_t get_path(void* data, char* out_path, size_t out_path_size) {
|
||||||
|
auto* device = static_cast<SdCardDevice*>(data);
|
||||||
|
const auto mount_path = device->getMountPath();
|
||||||
|
if (mount_path.size() >= out_path_size) return ERROR_BUFFER_OVERFLOW;
|
||||||
|
if (mount_path.empty()) return ERROR_INVALID_STATE;
|
||||||
|
strncpy(out_path, mount_path.c_str(), out_path_size);
|
||||||
|
return ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSystemApi sdCardDeviceApi = {
|
||||||
|
.mount = mount,
|
||||||
|
.unmount = unmount,
|
||||||
|
.is_mounted = is_mounted,
|
||||||
|
.get_path = get_path
|
||||||
|
};
|
||||||
|
|
||||||
|
SdCardDevice::SdCardDevice(MountBehaviour mountBehaviour) : mountBehaviour(mountBehaviour) {
|
||||||
|
fileSystem = file_system_add(&sdCardDeviceApi, this);
|
||||||
|
check(fileSystem != nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
SdCardDevice::~SdCardDevice() {
|
||||||
|
file_system_remove(fileSystem);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,123 +0,0 @@
|
|||||||
#ifdef ESP_PLATFORM
|
|
||||||
#include <soc/soc_caps.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(ESP_PLATFORM) && defined(SOC_SDMMC_HOST_SUPPORTED)
|
|
||||||
|
|
||||||
#include <Tactility/hal/sdcard/SdmmcDevice.h>
|
|
||||||
#include <Tactility/Logger.h>
|
|
||||||
|
|
||||||
#include <esp_vfs_fat.h>
|
|
||||||
#include <sdmmc_cmd.h>
|
|
||||||
#include <driver/sdmmc_host.h>
|
|
||||||
|
|
||||||
namespace tt::hal::sdcard {
|
|
||||||
|
|
||||||
static const auto LOGGER = Logger("SdmmcDevice");
|
|
||||||
|
|
||||||
bool SdmmcDevice::mountInternal(const std::string& newMountPath) {
|
|
||||||
LOGGER.info("Mounting {}", newMountPath);
|
|
||||||
|
|
||||||
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
|
|
||||||
.format_if_mount_failed = config->formatOnMountFailed,
|
|
||||||
.max_files = config->maxOpenFiles,
|
|
||||||
.allocation_unit_size = config->allocUnitSize,
|
|
||||||
.disk_status_check_enable = config->statusCheckEnabled,
|
|
||||||
.use_one_fat = false
|
|
||||||
};
|
|
||||||
|
|
||||||
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
|
|
||||||
|
|
||||||
sdmmc_slot_config_t slot_config = {
|
|
||||||
.clk = config->pinClock,
|
|
||||||
.cmd = config->pinCmd,
|
|
||||||
.d0 = config->pinD0,
|
|
||||||
.d1 = config->pinD1,
|
|
||||||
.d2 = config->pinD2,
|
|
||||||
.d3 = config->pinD3,
|
|
||||||
.d4 = static_cast<gpio_num_t>(0),
|
|
||||||
.d5 = static_cast<gpio_num_t>(0),
|
|
||||||
.d6 = static_cast<gpio_num_t>(0),
|
|
||||||
.d7 = static_cast<gpio_num_t>(0),
|
|
||||||
.cd = GPIO_NUM_NC,
|
|
||||||
.wp = GPIO_NUM_NC,
|
|
||||||
.width = config->busWidth,
|
|
||||||
.flags = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
esp_err_t result = esp_vfs_fat_sdmmc_mount(newMountPath.c_str(), &host, &slot_config, &mount_config, &card);
|
|
||||||
|
|
||||||
if (result != ESP_OK || card == nullptr) {
|
|
||||||
if (result == ESP_FAIL) {
|
|
||||||
LOGGER.error("Mounting failed. Ensure the card is formatted with FAT.");
|
|
||||||
} else {
|
|
||||||
LOGGER.error("Mounting failed ({})", esp_err_to_name(result));
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mountPath = newMountPath;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SdmmcDevice::mount(const std::string& newMountPath) {
|
|
||||||
auto lock = getLock()->asScopedLock();
|
|
||||||
lock.lock();
|
|
||||||
|
|
||||||
if (mountInternal(newMountPath)) {
|
|
||||||
LOGGER.info("Mounted at {}", newMountPath);
|
|
||||||
sdmmc_card_print_info(stdout, card);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
LOGGER.error("Mount failed for {}", newMountPath);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SdmmcDevice::unmount() {
|
|
||||||
auto lock = getLock()->asScopedLock();
|
|
||||||
lock.lock();
|
|
||||||
|
|
||||||
if (card == nullptr) {
|
|
||||||
LOGGER.error("Can't unmount: not mounted");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (esp_vfs_fat_sdcard_unmount(mountPath.c_str(), card) != ESP_OK) {
|
|
||||||
LOGGER.error("Unmount failed for {}", mountPath);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
LOGGER.info("Unmounted {}", mountPath);
|
|
||||||
mountPath = "";
|
|
||||||
card = nullptr;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
SdmmcDevice::State SdmmcDevice::getState(TickType_t timeout) const {
|
|
||||||
if (card == nullptr) {
|
|
||||||
return State::Unmounted;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The SD card and the screen are on the same SPI bus.
|
|
||||||
* Writing and reading to the bus from 2 devices at the same time causes crashes.
|
|
||||||
* This work-around ensures that this check is only happening when LVGL isn't rendering.
|
|
||||||
*/
|
|
||||||
auto lock = getLock()->asScopedLock();
|
|
||||||
bool locked = lock.lock(timeout);
|
|
||||||
if (!locked) {
|
|
||||||
return State::Timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sdmmc_get_status(card) != ESP_OK) {
|
|
||||||
return State::Error;
|
|
||||||
}
|
|
||||||
|
|
||||||
return State::Mounted;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,10 +1,13 @@
|
|||||||
#ifdef ESP_PLATFORM
|
#ifdef ESP_PLATFORM
|
||||||
|
|
||||||
|
#include <soc/soc_caps.h>
|
||||||
|
|
||||||
#include <Tactility/hal/usb/Usb.h>
|
#include <Tactility/hal/usb/Usb.h>
|
||||||
#include <Tactility/hal/sdcard/SpiSdCardDevice.h>
|
#include <Tactility/hal/sdcard/SpiSdCardDevice.h>
|
||||||
#include <Tactility/hal/usb/UsbTusb.h>
|
#include <Tactility/hal/usb/UsbTusb.h>
|
||||||
|
|
||||||
#include <Tactility/Logger.h>
|
#include <Tactility/Logger.h>
|
||||||
|
#include <tactility/drivers/esp32_sdmmc.h>
|
||||||
|
|
||||||
namespace tt::hal::usb {
|
namespace tt::hal::usb {
|
||||||
|
|
||||||
@ -21,29 +24,41 @@ static Mode currentMode = Mode::Default;
|
|||||||
static RTC_NOINIT_ATTR BootModeData bootModeData;
|
static RTC_NOINIT_ATTR BootModeData bootModeData;
|
||||||
|
|
||||||
sdmmc_card_t* getCard() {
|
sdmmc_card_t* getCard() {
|
||||||
auto sdcards = findDevices<sdcard::SpiSdCardDevice>(Device::Type::SdCard);
|
sdmmc_card_t* sdcard = nullptr;
|
||||||
|
|
||||||
std::shared_ptr<sdcard::SpiSdCardDevice> usable_sdcard;
|
// Find old HAL SD card device:
|
||||||
for (auto& sdcard : sdcards) {
|
auto sdcards = findDevices<sdcard::SpiSdCardDevice>(Device::Type::SdCard);
|
||||||
auto sdcard_candidate = std::static_pointer_cast<sdcard::SpiSdCardDevice>(sdcard);
|
for (auto& device : sdcards) {
|
||||||
if (sdcard_candidate != nullptr && sdcard_candidate->isMounted() && sdcard_candidate->getCard() != nullptr) {
|
auto sdcard_device= std::static_pointer_cast<sdcard::SpiSdCardDevice>(device);
|
||||||
usable_sdcard = sdcard_candidate;
|
if (sdcard_device != nullptr && sdcard_device->isMounted() && sdcard_device->getCard() != nullptr) {
|
||||||
|
sdcard = sdcard_device->getCard();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (usable_sdcard == nullptr) {
|
#if SOC_SDMMC_HOST_SUPPORTED
|
||||||
LOGGER.warn("Couldn't find a mounted SpiSdCard");
|
// Find ESP32 SDMMC device:
|
||||||
return nullptr;
|
if (sdcard == nullptr) {
|
||||||
|
device_for_each(&sdcard, [](auto* device, void* context) {
|
||||||
|
if (device_is_ready(device) && device_is_compatible(device, "espressif,esp32-sdmmc")) {
|
||||||
|
auto** sdcard = static_cast<sdmmc_card_t**>(context);
|
||||||
|
auto* sdmmc_card = esp32_sdmmc_get_card(device);
|
||||||
|
if (sdmmc_card) {
|
||||||
|
*sdcard = sdmmc_card;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (sdcard == nullptr) {
|
||||||
|
LOGGER.warn("Couldn't find a mounted SD card");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto* sdmmc_card = usable_sdcard->getCard();
|
return sdcard;
|
||||||
if (sdmmc_card == nullptr) {
|
|
||||||
LOGGER.warn("SD card has no card object available");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return sdmmc_card;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool canStartNewMode() {
|
static bool canStartNewMode() {
|
||||||
|
|||||||
@ -1,88 +0,0 @@
|
|||||||
#include <Tactility/hal/sdcard/SdCardDevice.h>
|
|
||||||
#include <Tactility/Logger.h>
|
|
||||||
#include <Tactility/LogMessages.h>
|
|
||||||
#include <Tactility/Mutex.h>
|
|
||||||
#include <Tactility/service/ServiceContext.h>
|
|
||||||
#include <Tactility/service/ServiceRegistration.h>
|
|
||||||
#include <Tactility/Tactility.h>
|
|
||||||
#include <Tactility/Timer.h>
|
|
||||||
|
|
||||||
namespace tt::service::sdcard {
|
|
||||||
|
|
||||||
static const auto LOGGER = Logger("SdcardService");
|
|
||||||
|
|
||||||
extern const ServiceManifest manifest;
|
|
||||||
|
|
||||||
class SdCardService final : public Service {
|
|
||||||
|
|
||||||
Mutex mutex;
|
|
||||||
std::unique_ptr<Timer> updateTimer;
|
|
||||||
hal::sdcard::SdCardDevice::State lastState = hal::sdcard::SdCardDevice::State::Unmounted;
|
|
||||||
|
|
||||||
bool lock(TickType_t timeout) const {
|
|
||||||
return mutex.lock(timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
void unlock() const {
|
|
||||||
mutex.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void update() {
|
|
||||||
// TODO: Support multiple SD cards
|
|
||||||
auto sdcard = hal::findFirstDevice<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
|
||||||
if (sdcard == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lock(50)) {
|
|
||||||
auto new_state = sdcard->getState();
|
|
||||||
|
|
||||||
if (new_state == hal::sdcard::SdCardDevice::State::Error) {
|
|
||||||
LOGGER.error("Sdcard error - unmounting. Did you eject the card in an unsafe manner?");
|
|
||||||
sdcard->unmount();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (new_state != lastState) {
|
|
||||||
lastState = new_state;
|
|
||||||
}
|
|
||||||
|
|
||||||
unlock();
|
|
||||||
} else {
|
|
||||||
LOGGER.warn(LOG_MESSAGE_MUTEX_LOCK_FAILED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
bool onStart(ServiceContext& serviceContext) override {
|
|
||||||
if (hal::findFirstDevice<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard) == nullptr) {
|
|
||||||
LOGGER.warn("No SD card device found - not starting Service");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto service = findServiceById<SdCardService>(manifest.id);
|
|
||||||
updateTimer = std::make_unique<Timer>(Timer::Type::Periodic, 1000, [service] {
|
|
||||||
service->update();
|
|
||||||
});
|
|
||||||
|
|
||||||
// We want to try and scan more often in case of startup or scan lock failure
|
|
||||||
updateTimer->start();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void onStop(ServiceContext& serviceContext) override {
|
|
||||||
if (updateTimer != nullptr) {
|
|
||||||
// Stop thread
|
|
||||||
updateTimer->stop();
|
|
||||||
updateTimer = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
extern const ServiceManifest manifest = {
|
|
||||||
.id = "sdcard",
|
|
||||||
.createService = create<SdCardService>
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
@ -2,8 +2,8 @@
|
|||||||
|
|
||||||
#include <Tactility/Logger.h>
|
#include <Tactility/Logger.h>
|
||||||
#include <Tactility/Mutex.h>
|
#include <Tactility/Mutex.h>
|
||||||
|
#include <Tactility/Paths.h>
|
||||||
#include <Tactility/Timer.h>
|
#include <Tactility/Timer.h>
|
||||||
#include <tactility/check.h>
|
|
||||||
#include <Tactility/hal/power/PowerDevice.h>
|
#include <Tactility/hal/power/PowerDevice.h>
|
||||||
#include <Tactility/hal/sdcard/SdCardDevice.h>
|
#include <Tactility/hal/sdcard/SdCardDevice.h>
|
||||||
#include <Tactility/lvgl/Lvgl.h>
|
#include <Tactility/lvgl/Lvgl.h>
|
||||||
@ -13,6 +13,7 @@
|
|||||||
#include <Tactility/service/ServiceRegistration.h>
|
#include <Tactility/service/ServiceRegistration.h>
|
||||||
#include <Tactility/service/gps/GpsService.h>
|
#include <Tactility/service/gps/GpsService.h>
|
||||||
#include <Tactility/service/wifi/Wifi.h>
|
#include <Tactility/service/wifi/Wifi.h>
|
||||||
|
#include <tactility/check.h>
|
||||||
|
|
||||||
#include <tactility/lvgl_icon_statusbar.h>
|
#include <tactility/lvgl_icon_statusbar.h>
|
||||||
|
|
||||||
@ -56,18 +57,9 @@ static const char* getWifiStatusIcon(wifi::RadioState state) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* getSdCardStatusIcon(hal::sdcard::SdCardDevice::State state) {
|
static const char* getSdCardStatusIcon(bool mounted) {
|
||||||
switch (state) {
|
if (mounted) return LVGL_ICON_STATUSBAR_SD_CARD;
|
||||||
using enum hal::sdcard::SdCardDevice::State;
|
return LVGL_ICON_STATUSBAR_SD_CARD_ALERT;
|
||||||
case Mounted:
|
|
||||||
return LVGL_ICON_STATUSBAR_SD_CARD;
|
|
||||||
case Error:
|
|
||||||
case Unmounted:
|
|
||||||
case Timeout:
|
|
||||||
return LVGL_ICON_STATUSBAR_SD_CARD_ALERT;
|
|
||||||
default:
|
|
||||||
check(false, "Unhandled SdCard state");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char* getPowerStatusIcon() {
|
static const char* getPowerStatusIcon() {
|
||||||
@ -172,20 +164,21 @@ class StatusbarService final : public Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void updateSdCardIcon() {
|
void updateSdCardIcon() {
|
||||||
auto sdcards = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
auto* sdcard_fs = findSdcardFileSystem(false);
|
||||||
// TODO: Support multiple SD cards
|
// TODO: Support multiple SD cards
|
||||||
auto sdcard = sdcards.empty() ? nullptr : sdcards[0];
|
if (sdcard_fs != nullptr) {
|
||||||
if (sdcard != nullptr) {
|
auto mounted = file_system_is_mounted(sdcard_fs);
|
||||||
auto state = sdcard->getState(50 / portTICK_PERIOD_MS);
|
auto* desired_icon = getSdCardStatusIcon(mounted);
|
||||||
if (state != hal::sdcard::SdCardDevice::State::Timeout) {
|
if (sdcard_last_icon != desired_icon) {
|
||||||
auto* desired_icon = getSdCardStatusIcon(state);
|
lvgl::statusbar_icon_set_image(sdcard_icon_id, desired_icon);
|
||||||
if (sdcard_last_icon != desired_icon) {
|
lvgl::statusbar_icon_set_visibility(sdcard_icon_id, true);
|
||||||
lvgl::statusbar_icon_set_image(sdcard_icon_id, desired_icon);
|
sdcard_last_icon = desired_icon;
|
||||||
lvgl::statusbar_icon_set_visibility(sdcard_icon_id, true);
|
}
|
||||||
sdcard_last_icon = desired_icon;
|
} else {
|
||||||
}
|
if (sdcard_last_icon != nullptr) {
|
||||||
|
lvgl::statusbar_icon_set_visibility(sdcard_icon_id, false);
|
||||||
|
sdcard_last_icon = nullptr;
|
||||||
}
|
}
|
||||||
// TODO: Consider tracking how long the SD card has been in unknown status and then show error
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -27,6 +27,7 @@
|
|||||||
#include <Tactility/StringUtils.h>
|
#include <Tactility/StringUtils.h>
|
||||||
|
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
|
#include <tactility/filesystem/file_system.h>
|
||||||
|
|
||||||
#if TT_FEATURE_SCREENSHOT_ENABLED
|
#if TT_FEATURE_SCREENSHOT_ENABLED
|
||||||
#include <lv_screenshot.h>
|
#include <lv_screenshot.h>
|
||||||
@ -764,20 +765,24 @@ esp_err_t WebServerService::handleFsList(httpd_req_t* request) {
|
|||||||
|
|
||||||
std::ostringstream json;
|
std::ostringstream json;
|
||||||
json << "{\"path\":\"" << norm << "\",\"entries\":[";
|
json << "{\"path\":\"" << norm << "\",\"entries\":[";
|
||||||
|
struct FsIterContext {
|
||||||
|
std::ostringstream& json;
|
||||||
|
uint16_t count = 0;
|
||||||
|
};
|
||||||
|
FsIterContext fs_iter_context { json };
|
||||||
// Special handling for root: show available mount points
|
// Special handling for root: show available mount points
|
||||||
if (norm == "/") {
|
if (norm == "/") {
|
||||||
// Always show /data
|
file_system_for_each(&fs_iter_context, [] (auto* fs, void* context) {
|
||||||
json << "{\"name\":\"data\",\"type\":\"dir\",\"size\":0}";
|
auto* fs_iter_context = static_cast<FsIterContext*>(context);
|
||||||
|
char path[128];
|
||||||
// Show /sdcard if mounted
|
if (file_system_is_mounted(fs) && file_system_get_path(fs, path, sizeof(path)) == ERROR_NONE && strcmp(path, "/system") != 0) {
|
||||||
const auto sdcard_devices = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
fs_iter_context->count++;
|
||||||
for (const auto& sdcard : sdcard_devices) {
|
if (fs_iter_context->count != 1) fs_iter_context->json << ","; // add separator between json array entries
|
||||||
if (sdcard->isMounted()) {
|
fs_iter_context->json << "{\"name\":\"" << path << "\",\"type\":\"dir\",\"size\":0}";
|
||||||
json << ",{\"name\":\"sdcard\",\"type\":\"dir\",\"size\":0}";
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
json << "]}";
|
json << "]}";
|
||||||
} else {
|
} else {
|
||||||
std::vector<dirent> entries;
|
std::vector<dirent> entries;
|
||||||
@ -1160,34 +1165,38 @@ esp_err_t WebServerService::handleApiSysinfo(httpd_req_t* request) {
|
|||||||
json << "\"storage\":{";
|
json << "\"storage\":{";
|
||||||
uint64_t storage_total = 0, storage_free = 0;
|
uint64_t storage_total = 0, storage_free = 0;
|
||||||
|
|
||||||
// Data partition
|
struct FsIterContext {
|
||||||
json << "\"data\":{";
|
std::ostringstream& json;
|
||||||
if (esp_vfs_fat_info(file::MOUNT_POINT_DATA, &storage_total, &storage_free) == ESP_OK) {
|
uint16_t count = 0;
|
||||||
json << "\"free\":" << storage_free << ",";
|
};
|
||||||
json << "\"total\":" << storage_total << ",";
|
FsIterContext fs_iter_context { json };
|
||||||
json << "\"mounted\":true";
|
file_system_for_each(&fs_iter_context, [] (auto* fs, void* context) {
|
||||||
} else {
|
char mount_path[128] = "";
|
||||||
json << "\"mounted\":false";
|
if (file_system_get_path(fs, mount_path, sizeof(mount_path)) != ERROR_NONE) return true;
|
||||||
}
|
if (strcmp(mount_path, "/system") == 0) return true; // Hide system partition
|
||||||
json << "},";
|
|
||||||
|
|
||||||
// SD card - check all sdcard devices
|
bool mounted = file_system_is_mounted(fs);
|
||||||
json << "\"sdcard\":{";
|
auto* fs_iter_context = static_cast<FsIterContext*>(context);
|
||||||
bool sdcard_found = false;
|
auto& json_context = fs_iter_context->json;
|
||||||
const auto sdcard_devices = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
std::string mount_path_cpp = mount_path;
|
||||||
for (const auto& sdcard : sdcard_devices) {
|
|
||||||
if (sdcard->isMounted() && esp_vfs_fat_info(sdcard->getMountPath().c_str(), &storage_total, &storage_free) == ESP_OK) {
|
fs_iter_context->count++;
|
||||||
json << "\"free\":" << storage_free << ",";
|
if (fs_iter_context->count != 1) json_context << ","; // add separator between json array entries
|
||||||
json << "\"total\":" << storage_total << ",";
|
json_context << "\"" << mount_path_cpp.substr(1) << "\":{";
|
||||||
json << "\"mounted\":true";
|
|
||||||
sdcard_found = true;
|
uint64_t storage_total = 0, storage_free = 0;
|
||||||
break;
|
if (esp_vfs_fat_info(mount_path, &storage_total, &storage_free) == ESP_OK) {
|
||||||
|
json_context << "\"free\":" << storage_free << ",";
|
||||||
|
json_context << "\"total\":" << storage_total << ",";
|
||||||
|
} else {
|
||||||
|
json_context << "\"free\":0,";
|
||||||
|
json_context << "\"total\":0,";
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (!sdcard_found) {
|
json_context << "\"mounted\":" << (mounted ? "true" : "false") << "";
|
||||||
json << "\"mounted\":false";
|
json_context << "}";
|
||||||
}
|
return true;
|
||||||
json << "}";
|
});
|
||||||
|
|
||||||
json << "},"; // end storage
|
json << "},"; // end storage
|
||||||
|
|
||||||
@ -1459,14 +1468,7 @@ esp_err_t WebServerService::handleApiScreenshot(httpd_req_t* request) {
|
|||||||
#if TT_FEATURE_SCREENSHOT_ENABLED
|
#if TT_FEATURE_SCREENSHOT_ENABLED
|
||||||
// Determine save location: prefer SD card root if mounted, otherwise /data
|
// Determine save location: prefer SD card root if mounted, otherwise /data
|
||||||
std::string save_path;
|
std::string save_path;
|
||||||
auto sdcard_devices = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
if (!findFirstMountedSdCardPath(save_path)) {
|
||||||
for (const auto& sdcard : sdcard_devices) {
|
|
||||||
if (sdcard->isMounted()) {
|
|
||||||
save_path = sdcard->getMountPath();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (save_path.empty()) {
|
|
||||||
save_path = file::MOUNT_POINT_DATA;
|
save_path = file::MOUNT_POINT_DATA;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1543,7 +1545,7 @@ esp_err_t WebServerService::handleFsTree(httpd_req_t* request) {
|
|||||||
std::ostringstream json;
|
std::ostringstream json;
|
||||||
json << "{";
|
json << "{";
|
||||||
// Gather mount points
|
// Gather mount points
|
||||||
auto mounts = file::getMountPoints();
|
auto mounts = file::getFileSystemDirents();
|
||||||
json << "\"mounts\": [";
|
json << "\"mounts\": [";
|
||||||
bool firstMount = true;
|
bool firstMount = true;
|
||||||
for (auto& m : mounts) {
|
for (auto& m : mounts) {
|
||||||
|
|||||||
@ -6,13 +6,14 @@
|
|||||||
#include <Tactility/Logger.h>
|
#include <Tactility/Logger.h>
|
||||||
#include <Tactility/service/wifi/WifiApSettings.h>
|
#include <Tactility/service/wifi/WifiApSettings.h>
|
||||||
|
|
||||||
|
#include <Tactility/Paths.h>
|
||||||
|
#include <Tactility/Tactility.h>
|
||||||
|
#include <Tactility/hal/sdcard/SdCardDevice.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <Tactility/Tactility.h>
|
|
||||||
#include <Tactility/hal/sdcard/SdCardDevice.h>
|
|
||||||
|
|
||||||
namespace tt::service::wifi {
|
namespace tt::service::wifi {
|
||||||
|
|
||||||
@ -118,18 +119,14 @@ static void importWifiApSettingsFromDir(const std::string& path) {
|
|||||||
void bootSplashInit() {
|
void bootSplashInit() {
|
||||||
getMainDispatcher().dispatch([] {
|
getMainDispatcher().dispatch([] {
|
||||||
// First import any provisioning files placed on the system data partition.
|
// First import any provisioning files placed on the system data partition.
|
||||||
const std::string settings_path = file::getChildPath(file::MOUNT_POINT_DATA, "settings");
|
const std::string data_settings_path = file::getChildPath(file::MOUNT_POINT_DATA, "settings");
|
||||||
importWifiApSettingsFromDir(settings_path);
|
importWifiApSettingsFromDir(data_settings_path);
|
||||||
|
|
||||||
// Then scan attached SD cards as before.
|
// Then scan attached SD cards as before.
|
||||||
const auto sdcards = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
std::string sdcard_path;
|
||||||
for (auto& sdcard : sdcards) {
|
if (findFirstMountedSdCardPath((sdcard_path))) {
|
||||||
if (sdcard->isMounted()) {
|
const std::string sd_settings_path = file::getChildPath(sdcard_path, "settings");
|
||||||
const std::string settings_path = file::getChildPath(sdcard->getMountPath(), "settings");
|
importWifiApSettingsFromDir(sd_settings_path);
|
||||||
importWifiApSettingsFromDir(settings_path);
|
|
||||||
} else {
|
|
||||||
LOGGER.warn("Skipping unmounted SD card {}", sdcard->getMountPath());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
#include <Tactility/Logger.h>
|
#include <Tactility/Logger.h>
|
||||||
#include <Tactility/settings/BootSettings.h>
|
#include <Tactility/settings/BootSettings.h>
|
||||||
|
|
||||||
|
#include <Tactility/Paths.h>
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -18,9 +19,9 @@ constexpr auto* PROPERTIES_KEY_LAUNCHER_APP_ID = "launcherAppId";
|
|||||||
constexpr auto* PROPERTIES_KEY_AUTO_START_APP_ID = "autoStartAppId";
|
constexpr auto* PROPERTIES_KEY_AUTO_START_APP_ID = "autoStartAppId";
|
||||||
|
|
||||||
static std::string getPropertiesFilePath() {
|
static std::string getPropertiesFilePath() {
|
||||||
const auto sdcards = hal::findDevices<hal::sdcard::SdCardDevice>(hal::Device::Type::SdCard);
|
std::string sdcard_path;
|
||||||
for (auto& sdcard : sdcards) {
|
if (findFirstMountedSdCardPath(sdcard_path)) {
|
||||||
std::string path = std::format(PROPERTIES_FILE_FORMAT, sdcard->getMountPath());
|
std::string path = std::format(PROPERTIES_FILE_FORMAT, sdcard_path);
|
||||||
if (file::isFile(path)) {
|
if (file::isFile(path)) {
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,6 +5,19 @@
|
|||||||
|
|
||||||
#include <bits/functexcept.h>
|
#include <bits/functexcept.h>
|
||||||
|
|
||||||
|
#include <tactility/module.h>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
// std::map / std::set red-black tree non-template helpers.
|
||||||
|
// We use the mangled names directly (same pattern as string.cpp) to avoid
|
||||||
|
// ambiguity from the overloaded const/non-const variants in stl_tree.h.
|
||||||
|
void* _ZSt18_Rb_tree_decrementPSt18_Rb_tree_node_base(void*);
|
||||||
|
void* _ZSt18_Rb_tree_incrementPSt18_Rb_tree_node_base(void*);
|
||||||
|
void _ZSt29_Rb_tree_insert_and_rebalancebPSt18_Rb_tree_node_baseS0_RS_(bool, void*, void*, void*);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
const esp_elfsym stl_symbols[] = {
|
const esp_elfsym stl_symbols[] = {
|
||||||
// Note: You have to use the mangled names here
|
// Note: You have to use the mangled names here
|
||||||
{ "_ZSt17__throw_bad_allocv", (void*)&(std::__throw_bad_alloc) },
|
{ "_ZSt17__throw_bad_allocv", (void*)&(std::__throw_bad_alloc) },
|
||||||
@ -12,7 +25,11 @@ const esp_elfsym stl_symbols[] = {
|
|||||||
{ "_ZSt25__throw_bad_function_callv", (void*)&(std::__throw_bad_function_call) },
|
{ "_ZSt25__throw_bad_function_callv", (void*)&(std::__throw_bad_function_call) },
|
||||||
{ "_ZSt20__throw_length_errorPKc", (void*)&(std::__throw_length_error) },
|
{ "_ZSt20__throw_length_errorPKc", (void*)&(std::__throw_length_error) },
|
||||||
{ "_ZSt19__throw_logic_errorPKc", (void*)&std::__throw_logic_error },
|
{ "_ZSt19__throw_logic_errorPKc", (void*)&std::__throw_logic_error },
|
||||||
// { "", (void*)&(std::) },
|
{ "_ZSt24__throw_out_of_range_fmtPKcz", (void*)&std::__throw_out_of_range_fmt },
|
||||||
|
// std::map / std::set (red-black tree internals)
|
||||||
|
DEFINE_MODULE_SYMBOL(_ZSt18_Rb_tree_decrementPSt18_Rb_tree_node_base),
|
||||||
|
DEFINE_MODULE_SYMBOL(_ZSt18_Rb_tree_incrementPSt18_Rb_tree_node_base),
|
||||||
|
DEFINE_MODULE_SYMBOL(_ZSt29_Rb_tree_insert_and_rebalancebPSt18_Rb_tree_node_baseS0_RS_),
|
||||||
// delimiter
|
// delimiter
|
||||||
ESP_ELFSYM_END
|
ESP_ELFSYM_END
|
||||||
};
|
};
|
||||||
|
|||||||
@ -33,6 +33,7 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <driver/ledc.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <esp_log.h>
|
#include <esp_log.h>
|
||||||
@ -44,6 +45,7 @@
|
|||||||
#include <lwip/sockets.h>
|
#include <lwip/sockets.h>
|
||||||
#include <lwip/netdb.h>
|
#include <lwip/netdb.h>
|
||||||
#include <lwip/inet.h>
|
#include <lwip/inet.h>
|
||||||
|
#include <miniz.h>
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
@ -221,6 +223,7 @@ const esp_elfsym main_symbols[] {
|
|||||||
ESP_ELFSYM_EXPORT(strtod),
|
ESP_ELFSYM_EXPORT(strtod),
|
||||||
ESP_ELFSYM_EXPORT(strrchr),
|
ESP_ELFSYM_EXPORT(strrchr),
|
||||||
ESP_ELFSYM_EXPORT(strtol),
|
ESP_ELFSYM_EXPORT(strtol),
|
||||||
|
ESP_ELFSYM_EXPORT(strtoul),
|
||||||
ESP_ELFSYM_EXPORT(strcspn),
|
ESP_ELFSYM_EXPORT(strcspn),
|
||||||
ESP_ELFSYM_EXPORT(strncat),
|
ESP_ELFSYM_EXPORT(strncat),
|
||||||
ESP_ELFSYM_EXPORT(strpbrk),
|
ESP_ELFSYM_EXPORT(strpbrk),
|
||||||
@ -393,6 +396,7 @@ const esp_elfsym main_symbols[] {
|
|||||||
ESP_ELFSYM_EXPORT(gpio_config),
|
ESP_ELFSYM_EXPORT(gpio_config),
|
||||||
ESP_ELFSYM_EXPORT(gpio_get_level),
|
ESP_ELFSYM_EXPORT(gpio_get_level),
|
||||||
ESP_ELFSYM_EXPORT(gpio_set_level),
|
ESP_ELFSYM_EXPORT(gpio_set_level),
|
||||||
|
ESP_ELFSYM_EXPORT(gpio_reset_pin),
|
||||||
// driver/i2s_common.h
|
// driver/i2s_common.h
|
||||||
ESP_ELFSYM_EXPORT(i2s_new_channel),
|
ESP_ELFSYM_EXPORT(i2s_new_channel),
|
||||||
ESP_ELFSYM_EXPORT(i2s_del_channel),
|
ESP_ELFSYM_EXPORT(i2s_del_channel),
|
||||||
@ -409,8 +413,30 @@ const esp_elfsym main_symbols[] {
|
|||||||
ESP_ELFSYM_EXPORT(i2s_channel_reconfig_std_clock),
|
ESP_ELFSYM_EXPORT(i2s_channel_reconfig_std_clock),
|
||||||
ESP_ELFSYM_EXPORT(i2s_channel_reconfig_std_slot),
|
ESP_ELFSYM_EXPORT(i2s_channel_reconfig_std_slot),
|
||||||
ESP_ELFSYM_EXPORT(i2s_channel_reconfig_std_gpio),
|
ESP_ELFSYM_EXPORT(i2s_channel_reconfig_std_gpio),
|
||||||
|
// miniz.h
|
||||||
|
ESP_ELFSYM_EXPORT(tinfl_decompress),
|
||||||
|
ESP_ELFSYM_EXPORT(tinfl_decompress_mem_to_callback),
|
||||||
|
ESP_ELFSYM_EXPORT(tinfl_decompress_mem_to_mem),
|
||||||
|
// ledc
|
||||||
|
ESP_ELFSYM_EXPORT(ledc_update_duty),
|
||||||
|
ESP_ELFSYM_EXPORT(ledc_set_freq),
|
||||||
|
ESP_ELFSYM_EXPORT(ledc_channel_config),
|
||||||
|
ESP_ELFSYM_EXPORT(ledc_set_duty),
|
||||||
|
ESP_ELFSYM_EXPORT(ledc_set_fade),
|
||||||
|
ESP_ELFSYM_EXPORT(ledc_set_fade_with_step),
|
||||||
|
ESP_ELFSYM_EXPORT(ledc_set_fade_with_time),
|
||||||
|
ESP_ELFSYM_EXPORT(ledc_set_fade_step_and_start),
|
||||||
|
ESP_ELFSYM_EXPORT(ledc_set_fade_time_and_start),
|
||||||
|
ESP_ELFSYM_EXPORT(ledc_set_pin),
|
||||||
|
ESP_ELFSYM_EXPORT(ledc_timer_config),
|
||||||
|
ESP_ELFSYM_EXPORT(ledc_timer_pause),
|
||||||
|
ESP_ELFSYM_EXPORT(ledc_timer_resume),
|
||||||
|
ESP_ELFSYM_EXPORT(ledc_timer_rst),
|
||||||
// esp_heap_caps.h
|
// esp_heap_caps.h
|
||||||
ESP_ELFSYM_EXPORT(heap_caps_get_total_size),
|
ESP_ELFSYM_EXPORT(heap_caps_get_total_size),
|
||||||
|
ESP_ELFSYM_EXPORT(heap_caps_get_allocated_size),
|
||||||
|
ESP_ELFSYM_EXPORT(heap_caps_get_free_size),
|
||||||
|
ESP_ELFSYM_EXPORT(heap_caps_get_largest_free_block),
|
||||||
// delimiter
|
// delimiter
|
||||||
ESP_ELFSYM_END
|
ESP_ELFSYM_END
|
||||||
};
|
};
|
||||||
|
|||||||
@ -7,10 +7,9 @@ extern "C" {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <tactility/device.h>
|
#include <tactility/device.h>
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define GPIO_FLAGS_MASK 0x1f
|
#define GPIO_FLAGS_MASK 0xff
|
||||||
|
|
||||||
#define GPIO_PIN_NONE -1
|
#define GPIO_PIN_NONE -1
|
||||||
|
|
||||||
@ -27,6 +26,7 @@ extern "C" {
|
|||||||
#define GPIO_FLAG_INTERRUPT_BITMASK (0b111 << 5) // 3 bits to hold the values [0, 5]
|
#define GPIO_FLAG_INTERRUPT_BITMASK (0b111 << 5) // 3 bits to hold the values [0, 5]
|
||||||
#define GPIO_FLAG_INTERRUPT_FROM_OPTIONS(options) (gpio_int_type_t)((options & GPIO_FLAG_INTERRUPT_BITMASK) >> 5)
|
#define GPIO_FLAG_INTERRUPT_FROM_OPTIONS(options) (gpio_int_type_t)((options & GPIO_FLAG_INTERRUPT_BITMASK) >> 5)
|
||||||
#define GPIO_FLAG_INTERRUPT_TO_OPTIONS(options, interrupt) (options | (interrupt << 5))
|
#define GPIO_FLAG_INTERRUPT_TO_OPTIONS(options, interrupt) (options | (interrupt << 5))
|
||||||
|
#define GPIO_FLAG_HIGH_IMPEDANCE (1 << 8)
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
GPIO_INTERRUPT_DISABLE = 0,
|
GPIO_INTERRUPT_DISABLE = 0,
|
||||||
|
|||||||
@ -52,6 +52,36 @@ struct GpioControllerApi {
|
|||||||
* @return ERROR_NONE if successful
|
* @return ERROR_NONE if successful
|
||||||
*/
|
*/
|
||||||
error_t (*get_native_pin_number)(struct GpioDescriptor* descriptor, void* pin_number);
|
error_t (*get_native_pin_number)(struct GpioDescriptor* descriptor, void* pin_number);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a callback to be called when a GPIO interrupt occurs.
|
||||||
|
* @param[in] descriptor the pin descriptor
|
||||||
|
* @param[in] callback the callback function
|
||||||
|
* @param[in] arg the argument to pass to the callback
|
||||||
|
* @return ERROR_NONE if successful, ERROR_NOT_SUPPORTED if not implemented
|
||||||
|
*/
|
||||||
|
error_t (*add_callback)(struct GpioDescriptor* descriptor, void (*callback)(void*), void* arg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes a callback from a GPIO interrupt.
|
||||||
|
* @param[in] descriptor the pin descriptor
|
||||||
|
* @return ERROR_NONE if successful, ERROR_NOT_SUPPORTED if not implemented
|
||||||
|
*/
|
||||||
|
error_t (*remove_callback)(struct GpioDescriptor* descriptor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the interrupt for a GPIO pin.
|
||||||
|
* @param[in] descriptor the pin descriptor
|
||||||
|
* @return ERROR_NONE if successful, ERROR_NOT_SUPPORTED if not implemented
|
||||||
|
*/
|
||||||
|
error_t (*enable_interrupt)(struct GpioDescriptor* descriptor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disables the interrupt for a GPIO pin.
|
||||||
|
* @param[in] descriptor the pin descriptor
|
||||||
|
* @return ERROR_NONE if successful, ERROR_NOT_SUPPORTED if not implemented
|
||||||
|
*/
|
||||||
|
error_t (*disable_interrupt)(struct GpioDescriptor* descriptor);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GpioDescriptor* gpio_descriptor_acquire(
|
struct GpioDescriptor* gpio_descriptor_acquire(
|
||||||
@ -118,6 +148,36 @@ error_t gpio_descriptor_get_flags(struct GpioDescriptor* descriptor, gpio_flags_
|
|||||||
*/
|
*/
|
||||||
error_t gpio_descriptor_get_native_pin_number(struct GpioDescriptor* descriptor, void* pin_number);
|
error_t gpio_descriptor_get_native_pin_number(struct GpioDescriptor* descriptor, void* pin_number);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a callback to be called when a GPIO interrupt occurs.
|
||||||
|
* @param[in] descriptor the pin descriptor
|
||||||
|
* @param[in] callback the callback function
|
||||||
|
* @param[in] arg the argument to pass to the callback
|
||||||
|
* @return ERROR_NONE if successful, ERROR_NOT_SUPPORTED if not implemented
|
||||||
|
*/
|
||||||
|
error_t gpio_descriptor_add_callback(struct GpioDescriptor* descriptor, void (*callback)(void*), void* arg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes a callback from a GPIO interrupt.
|
||||||
|
* @param[in] descriptor the pin descriptor
|
||||||
|
* @return ERROR_NONE if successful, ERROR_NOT_SUPPORTED if not implemented
|
||||||
|
*/
|
||||||
|
error_t gpio_descriptor_remove_callback(struct GpioDescriptor* descriptor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Enables the interrupt for a GPIO pin.
|
||||||
|
* @param[in] descriptor the pin descriptor
|
||||||
|
* @return ERROR_NONE if successful, ERROR_NOT_SUPPORTED if not implemented
|
||||||
|
*/
|
||||||
|
error_t gpio_descriptor_enable_interrupt(struct GpioDescriptor* descriptor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Disables the interrupt for a GPIO pin.
|
||||||
|
* @param[in] descriptor the pin descriptor
|
||||||
|
* @return ERROR_NONE if successful, ERROR_NOT_SUPPORTED if not implemented
|
||||||
|
*/
|
||||||
|
error_t gpio_descriptor_disable_interrupt(struct GpioDescriptor* descriptor);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the number of pins supported by the controller.
|
* @brief Gets the number of pins supported by the controller.
|
||||||
* @param[in] device the GPIO controller device
|
* @param[in] device the GPIO controller device
|
||||||
@ -141,6 +201,15 @@ error_t gpio_controller_init_descriptors(struct Device* device, uint32_t pin_cou
|
|||||||
*/
|
*/
|
||||||
error_t gpio_controller_deinit_descriptors(struct Device* device);
|
error_t gpio_controller_deinit_descriptors(struct Device* device);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unlike other drivers, a GPIO controller's internal data is created and set by gpio_controller_init_descriptors()
|
||||||
|
* This means that the specific controller implementation cannot set the device's driver data, as it's already set by the GPIO controller base coded
|
||||||
|
* When calling init descriptors, the caller can pass a controller_context, which is an optional pointer that holds the implementation's internal data.
|
||||||
|
* @param device the GPIO controller device
|
||||||
|
* @return the context void pointer
|
||||||
|
*/
|
||||||
|
void* gpio_controller_get_controller_context(struct Device* device);
|
||||||
|
|
||||||
extern const struct DeviceType GPIO_CONTROLLER_TYPE;
|
extern const struct DeviceType GPIO_CONTROLLER_TYPE;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@ -11,6 +11,11 @@ struct GpioDescriptor {
|
|||||||
gpio_pin_t pin;
|
gpio_pin_t pin;
|
||||||
/** @brief Current owner */
|
/** @brief Current owner */
|
||||||
enum GpioOwnerType owner_type;
|
enum GpioOwnerType owner_type;
|
||||||
/** @brief Implementation-specific context (e.g. from esp32 controller internally) */
|
/**
|
||||||
|
* @brief Implementation-specific context (e.g. from esp32 controller internally)
|
||||||
|
* Unlike other drivers, a GPIO controller's internal data is created and set by gpio_controller_init_descriptors()
|
||||||
|
* This means that the specific controller implementation cannot set the device's driver data, as it's already set by the GPIO controller base coded.
|
||||||
|
* When calling init descriptors, the caller can pass a controller_context, which is an optional pointer that holds the implementation's internal data.
|
||||||
|
*/
|
||||||
void* controller_context;
|
void* controller_context;
|
||||||
};
|
};
|
||||||
|
|||||||
205
TactilityKernel/include/tactility/drivers/wifi.h
Normal file
205
TactilityKernel/include/tactility/drivers/wifi.h
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <tactility/error.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct Device;
|
||||||
|
|
||||||
|
enum WifiAuthenticationType {
|
||||||
|
WIFI_AUTHENTICATION_TYPE_OPEN = 0,
|
||||||
|
WIFI_AUTHENTICATION_TYPE_WEP,
|
||||||
|
WIFI_AUTHENTICATION_TYPE_WPA_PSK,
|
||||||
|
WIFI_AUTHENTICATION_TYPE_WPA2_PSK,
|
||||||
|
WIFI_AUTHENTICATION_TYPE_WPA_WPA2_PSK,
|
||||||
|
WIFI_AUTHENTICATION_TYPE_WPA2_ENTERPRISE,
|
||||||
|
WIFI_AUTHENTICATION_TYPE_WPA3_PSK,
|
||||||
|
WIFI_AUTHENTICATION_TYPE_WPA2_WPA3_PSK,
|
||||||
|
WIFI_AUTHENTICATION_TYPE_WAPI_PSK,
|
||||||
|
WIFI_AUTHENTICATION_TYPE_OWE,
|
||||||
|
WIFI_AUTHENTICATION_TYPE_WPA3_ENT_192,
|
||||||
|
WIFI_AUTHENTICATION_TYPE_WPA3_EXT_PSK,
|
||||||
|
WIFI_AUTHENTICATION_TYPE_WPA3_EXT_PSK_MIXED_MODE,
|
||||||
|
WIFI_AUTHENTICATION_TYPE_MAX
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WifiApRecord {
|
||||||
|
char ssid[33]; // 32 bytes + null terminator
|
||||||
|
int8_t rssi;
|
||||||
|
int32_t channel;
|
||||||
|
enum WifiAuthenticationType authentication_type;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum WifiRadioState {
|
||||||
|
WIFI_RADIO_STATE_OFF,
|
||||||
|
WIFI_RADIO_STATE_ON_PENDING,
|
||||||
|
WIFI_RADIO_STATE_ON,
|
||||||
|
WIFI_RADIO_STATE_OFF_PENDING,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum WifiStationState {
|
||||||
|
WIFI_STATION_STATE_DISCONNECTED,
|
||||||
|
WIFI_STATION_STATE_CONNECTION_PENDING,
|
||||||
|
WIFI_STATION_STATE_CONNECTED
|
||||||
|
};
|
||||||
|
|
||||||
|
enum WifiAccessPointState {
|
||||||
|
WIFI_ACCESS_POINT_STATE_STARTED,
|
||||||
|
WIFI_ACCESS_POINT_STATE_STOPPED,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum WifiEventType {
|
||||||
|
/** Radio state changed */
|
||||||
|
WIFI_EVENT_TYPE_RADIO_STATE_CHANGED,
|
||||||
|
/** WifiStationState changed */
|
||||||
|
WIFI_EVENT_TYPE_STATION_STATE_CHANGED,
|
||||||
|
/** WifiAccessPointState changed */
|
||||||
|
WIFI_EVENT_TYPE_STATION_CONNECTION_RESULT,
|
||||||
|
/** WifiAccessPointState changed */
|
||||||
|
WIFI_EVENT_TYPE_ACCESS_POINT_STATE_CHANGED,
|
||||||
|
/** Started scanning for access points */
|
||||||
|
WIFI_EVENT_TYPE_SCAN_STARTED,
|
||||||
|
/** Finished scanning for access points */
|
||||||
|
WIFI_EVENT_TYPE_SCAN_FINISHED,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum WifiStationConnectionError {
|
||||||
|
WIFI_STATION_CONNECTION_ERROR_NONE,
|
||||||
|
/** Wrong password */
|
||||||
|
WIFI_STATION_CONNECTION_ERROR_WRONG_CREDENTIALS,
|
||||||
|
/** Failed to connect in a timely manner */
|
||||||
|
WIFI_STATION_CONNECTION_ERROR_TIMEOUT,
|
||||||
|
/** SSID not found */
|
||||||
|
WIFI_STATION_CONNECTION_ERROR_TARGET_NOT_FOUND,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct WifiEvent {
|
||||||
|
enum WifiEventType type;
|
||||||
|
union {
|
||||||
|
enum WifiRadioState radio_state;
|
||||||
|
enum WifiStationState station_state;
|
||||||
|
enum WifiAccessPointState access_point_state;
|
||||||
|
enum WifiStationConnectionError connection_error;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void (*WifiEventCallback)(struct Device* device, void* callback_context, struct WifiEvent event);
|
||||||
|
|
||||||
|
struct WifiApi {
|
||||||
|
/**
|
||||||
|
* Get the radio state of the device.
|
||||||
|
* @param[in] device the wifi device
|
||||||
|
* @param[out] state the radio state
|
||||||
|
* @return ERROR_NONE on success
|
||||||
|
*/
|
||||||
|
error_t (*get_radio_state)(struct Device* device, enum WifiRadioState* state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the station state of the device.
|
||||||
|
* @param[in] device the wifi device
|
||||||
|
* @param[out] state the station state
|
||||||
|
* @return ERROR_NONE on success
|
||||||
|
*/
|
||||||
|
error_t (*get_station_state)(struct Device* device, enum WifiStationState* state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the access point state of the device.
|
||||||
|
* @param[in] device the wifi device
|
||||||
|
* @param[out] state the access point state
|
||||||
|
* @return ERROR_NONE on success
|
||||||
|
*/
|
||||||
|
error_t (*get_access_point_state)(struct Device* device, enum WifiAccessPointState* state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the device is currently scanning for access points.
|
||||||
|
* @param[in] device the wifi device
|
||||||
|
* @return true when scanning
|
||||||
|
*/
|
||||||
|
bool (*is_scanning)(struct Device* device);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start a scan for access points.
|
||||||
|
* @param[in] device the wifi device
|
||||||
|
* @return ERROR_NONE on success
|
||||||
|
*/
|
||||||
|
error_t (*scan)(struct Device* device);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the scan results of the device.
|
||||||
|
* @param[in] device the wifi device
|
||||||
|
* @param[out] results the buffer to store the scan results
|
||||||
|
* @param[in, out] num_results the number of scan results: it's first used as input to determine the size of the buffer, and then as output to get the actual number of results
|
||||||
|
* @return ERROR_NONE on success
|
||||||
|
*/
|
||||||
|
error_t (*get_scan_results)(struct Device* device, struct WifiApRecord* results, size_t* num_results);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the IPv4 address of the device.
|
||||||
|
* @param[in] device the device
|
||||||
|
* @param[out] ipv4 the buffer to store the IPv4 address (must be at least 16 bytes, will be null-terminated)
|
||||||
|
* @return ERROR_NONE on success
|
||||||
|
*/
|
||||||
|
error_t (*station_get_ipv4_address)(struct Device* device, char* ipv4);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the SSID of the access point the device is currently connected to.
|
||||||
|
* @param[in] device the wifi device
|
||||||
|
* @param[out] ssid the buffer to store the SSID (must be at least 33 bytes, will be null-terminated)
|
||||||
|
* @return ERROR_NONE on success
|
||||||
|
*/
|
||||||
|
error_t (*station_get_target_ssid)(struct Device* device, char* ssid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Connect to an access point.
|
||||||
|
* @param[in] device the wifi device
|
||||||
|
* @param[in] ssid the SSID of the access point
|
||||||
|
* @param[in] password the password of the access point
|
||||||
|
* @param[in] channel the Wi-Fi channel to connect to (0 means "any" / no preference)
|
||||||
|
* @return ERROR_NONE on success
|
||||||
|
*/
|
||||||
|
error_t (*station_connect)(struct Device* device, const char* ssid, const char* password, int32_t channel);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disconnect from the current access point.
|
||||||
|
* @param[in] device the wifi device
|
||||||
|
* @return ERROR_NONE on success
|
||||||
|
*/
|
||||||
|
error_t (*station_disconnect)(struct Device* device);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the RSSI of the current access point.
|
||||||
|
* @param[in] device the wifi device
|
||||||
|
* @param[out] rssi the buffer to store the RSSI
|
||||||
|
* @return ERROR_NONE on success
|
||||||
|
*/
|
||||||
|
error_t (*station_get_rssi)(struct Device* device, int32_t* rssi);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a WifiEvent callback.
|
||||||
|
* @param[in] device the wifi device
|
||||||
|
* @param[in] callback_context the context to pass to the callback
|
||||||
|
* @param[in] callback the callback function
|
||||||
|
* @return ERROR_NONE on success
|
||||||
|
*/
|
||||||
|
error_t (*add_event_callback)(struct Device* device, void* callback_context, WifiEventCallback callback);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a WifiEvent callback.
|
||||||
|
* @param[in] device the wifi device
|
||||||
|
* @param[in] callback the callback function
|
||||||
|
* @return ERROR_NONE on success
|
||||||
|
*/
|
||||||
|
error_t (*remove_event_callback)(struct Device* device, WifiEventCallback callback);
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const struct DeviceType WIFI_TYPE;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
106
TactilityKernel/include/tactility/filesystem/file_system.h
Normal file
106
TactilityKernel/include/tactility/filesystem/file_system.h
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <tactility/error.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct FileSystem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief File system API.
|
||||||
|
*
|
||||||
|
* Provides a set of function pointers to interact with a specific file system implementation.
|
||||||
|
*/
|
||||||
|
struct FileSystemApi {
|
||||||
|
/**
|
||||||
|
* @brief Mounts the file system.
|
||||||
|
* @param[in] data file system private data
|
||||||
|
* @return ERROR_NONE on success, or an error code
|
||||||
|
*/
|
||||||
|
error_t (*mount)(void* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unmounts the file system.
|
||||||
|
* @param[in] data file system private data
|
||||||
|
* @return ERROR_NONE on success, or an error code
|
||||||
|
*/
|
||||||
|
error_t (*unmount)(void* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if the file system is mounted.
|
||||||
|
* @param[in] data file system private data
|
||||||
|
* @return true if mounted, false otherwise
|
||||||
|
*/
|
||||||
|
bool (*is_mounted)(void* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the mount path.
|
||||||
|
* @param[in] data file system private data
|
||||||
|
* @param[out] out_path buffer to store the path
|
||||||
|
* @param[in] out_path_size size of the output buffer
|
||||||
|
* @return ERROR_NONE on success, or an error code
|
||||||
|
*/
|
||||||
|
error_t (*get_path)(void* data, char* out_path, size_t out_path_size);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Registers a new file system.
|
||||||
|
* @param[in] fs_api the file system API implementation
|
||||||
|
* @param[in] data private data for the file system
|
||||||
|
* @return the registered FileSystem object
|
||||||
|
*/
|
||||||
|
struct FileSystem* file_system_add(const struct FileSystemApi* fs_api, void* data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes a registered file system.
|
||||||
|
* @note The file system must be unmounted before removal.
|
||||||
|
* @param[in] fs the FileSystem object to remove
|
||||||
|
*/
|
||||||
|
void file_system_remove(struct FileSystem* fs);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Iterates over all registered file systems.
|
||||||
|
* @param[in] callback_context context passed to the callback
|
||||||
|
* @param[in] callback function called for each file system. Return true to continue, false to stop.
|
||||||
|
*/
|
||||||
|
void file_system_for_each(void* callback_context, bool (*callback)(struct FileSystem* fs, void* context));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Mounts the file system.
|
||||||
|
* @param[in] fs the FileSystem object
|
||||||
|
* @return ERROR_NONE on success, or an error code
|
||||||
|
*/
|
||||||
|
error_t file_system_mount(struct FileSystem* fs);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @warning Unmounting can fail (e.g. when the device is busy), so you might need to retry it.
|
||||||
|
* @brief Unmounts the file system.
|
||||||
|
* @param[in] fs the FileSystem object
|
||||||
|
* @return ERROR_NONE on success, or an error code
|
||||||
|
*/
|
||||||
|
error_t file_system_unmount(struct FileSystem* fs);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if the file system is mounted.
|
||||||
|
* @param[in] fs the FileSystem object
|
||||||
|
* @return true if mounted, false otherwise
|
||||||
|
*/
|
||||||
|
bool file_system_is_mounted(struct FileSystem* fs);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the mount path.
|
||||||
|
* @param[in] fs the FileSystem object
|
||||||
|
* @param[out] out_path buffer to store the path
|
||||||
|
* @param[in] out_path_size size of the output buffer
|
||||||
|
* @return ERROR_NONE on success, or an error code
|
||||||
|
*/
|
||||||
|
error_t file_system_get_path(struct FileSystem* fs, char* out_path, size_t out_path_size);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@ -118,6 +118,7 @@ error_t module_construct_add_start(struct Module* module);
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Check if the module is started.
|
* @brief Check if the module is started.
|
||||||
|
* Can be used when module isn't constructed yet.
|
||||||
* @param module module to check
|
* @param module module to check
|
||||||
* @return true if the module is started, false otherwise
|
* @return true if the module is started, false otherwise
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -14,22 +14,25 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
struct GpioControllerData {
|
struct GpioControllerData {
|
||||||
struct Mutex mutex {};
|
Mutex mutex {};
|
||||||
uint32_t pin_count;
|
uint32_t pin_count;
|
||||||
struct GpioDescriptor* descriptors = nullptr;
|
GpioDescriptor* descriptors = nullptr;
|
||||||
|
void* controller_context;
|
||||||
|
|
||||||
explicit GpioControllerData(uint32_t pin_count) : pin_count(pin_count) {
|
explicit GpioControllerData(
|
||||||
|
uint32_t pin_count, void* controller_context
|
||||||
|
) : pin_count(pin_count), controller_context(controller_context) {
|
||||||
mutex_construct(&mutex);
|
mutex_construct(&mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t init_descriptors(Device* device, void* controller_context) {
|
error_t init_descriptors(Device* device) {
|
||||||
descriptors = (struct GpioDescriptor*)calloc(pin_count, sizeof(struct GpioDescriptor));
|
descriptors = static_cast<GpioDescriptor*>(calloc(pin_count, sizeof(GpioDescriptor)));
|
||||||
if (!descriptors) return ERROR_OUT_OF_MEMORY;
|
if (!descriptors) return ERROR_OUT_OF_MEMORY;
|
||||||
for (uint32_t i = 0; i < pin_count; ++i) {
|
for (uint32_t i = 0; i < pin_count; ++i) {
|
||||||
descriptors[i].controller = device;
|
descriptors[i].controller = device;
|
||||||
descriptors[i].pin = (gpio_pin_t)i;
|
descriptors[i].pin = static_cast<gpio_pin_t>(i);
|
||||||
descriptors[i].owner_type = GPIO_OWNER_NONE;
|
descriptors[i].owner_type = GPIO_OWNER_NONE;
|
||||||
descriptors[i].controller_context = controller_context;
|
descriptors[i].controller_context = this->controller_context;
|
||||||
}
|
}
|
||||||
return ERROR_NONE;
|
return ERROR_NONE;
|
||||||
}
|
}
|
||||||
@ -42,14 +45,14 @@ struct GpioControllerData {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GpioDescriptor* gpio_descriptor_acquire(
|
GpioDescriptor* gpio_descriptor_acquire(
|
||||||
struct Device* controller,
|
Device* controller,
|
||||||
gpio_pin_t pin_number,
|
gpio_pin_t pin_number,
|
||||||
enum GpioOwnerType owner
|
GpioOwnerType owner
|
||||||
) {
|
) {
|
||||||
check(owner != GPIO_OWNER_NONE);
|
check(owner != GPIO_OWNER_NONE);
|
||||||
|
|
||||||
auto* data = (struct GpioControllerData*)device_get_driver_data(controller);
|
auto* data = static_cast<struct GpioControllerData*>(device_get_driver_data(controller));
|
||||||
|
|
||||||
mutex_lock(&data->mutex);
|
mutex_lock(&data->mutex);
|
||||||
if (pin_number >= data->pin_count) {
|
if (pin_number >= data->pin_count) {
|
||||||
@ -57,7 +60,7 @@ struct GpioDescriptor* gpio_descriptor_acquire(
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct GpioDescriptor* desc = &data->descriptors[pin_number];
|
GpioDescriptor* desc = &data->descriptors[pin_number];
|
||||||
if (desc->owner_type != GPIO_OWNER_NONE) {
|
if (desc->owner_type != GPIO_OWNER_NONE) {
|
||||||
mutex_unlock(&data->mutex);
|
mutex_unlock(&data->mutex);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -69,22 +72,27 @@ struct GpioDescriptor* gpio_descriptor_acquire(
|
|||||||
return desc;
|
return desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t gpio_descriptor_release(struct GpioDescriptor* descriptor) {
|
error_t gpio_descriptor_release(GpioDescriptor* descriptor) {
|
||||||
|
auto* data = static_cast<struct GpioControllerData*>(device_get_driver_data(descriptor->controller));
|
||||||
|
mutex_lock(&data->mutex);
|
||||||
descriptor->owner_type = GPIO_OWNER_NONE;
|
descriptor->owner_type = GPIO_OWNER_NONE;
|
||||||
|
mutex_unlock(&data->mutex);
|
||||||
return ERROR_NONE;
|
return ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t gpio_controller_get_pin_count(struct Device* device, uint32_t* count) {
|
error_t gpio_controller_get_pin_count(Device* device, uint32_t* count) {
|
||||||
auto* data = (struct GpioControllerData*)device_get_driver_data(device);
|
auto* data = static_cast<struct GpioControllerData*>(device_get_driver_data(device));
|
||||||
|
mutex_lock(&data->mutex);
|
||||||
*count = data->pin_count;
|
*count = data->pin_count;
|
||||||
|
mutex_unlock(&data->mutex);
|
||||||
return ERROR_NONE;
|
return ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t gpio_controller_init_descriptors(struct Device* device, uint32_t pin_count, void* controller_context) {
|
error_t gpio_controller_init_descriptors(Device* device, uint32_t pin_count, void* controller_context) {
|
||||||
auto* data = new(std::nothrow) GpioControllerData(pin_count);
|
auto* data = new(std::nothrow) GpioControllerData(pin_count, controller_context);
|
||||||
if (!data) return ERROR_OUT_OF_MEMORY;
|
if (!data) return ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
if (data->init_descriptors(device, controller_context) != ERROR_NONE) {
|
if (data->init_descriptors(device) != ERROR_NONE) {
|
||||||
delete data;
|
delete data;
|
||||||
return ERROR_OUT_OF_MEMORY;
|
return ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
@ -93,49 +101,82 @@ error_t gpio_controller_init_descriptors(struct Device* device, uint32_t pin_cou
|
|||||||
return ERROR_NONE;
|
return ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t gpio_controller_deinit_descriptors(struct Device* device) {
|
error_t gpio_controller_deinit_descriptors(Device* device) {
|
||||||
auto* data = static_cast<struct GpioControllerData*>(device_get_driver_data(device));
|
auto* data = static_cast<struct GpioControllerData*>(device_get_driver_data(device));
|
||||||
delete data;
|
|
||||||
device_set_driver_data(device, nullptr);
|
device_set_driver_data(device, nullptr);
|
||||||
|
delete data;
|
||||||
return ERROR_NONE;
|
return ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t gpio_descriptor_set_level(struct GpioDescriptor* descriptor, bool high) {
|
void* gpio_controller_get_controller_context(Device* device) {
|
||||||
|
auto* data = static_cast<struct GpioControllerData*>(device_get_driver_data(device));
|
||||||
|
return data->controller_context;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t gpio_descriptor_set_level(GpioDescriptor* descriptor, bool high) {
|
||||||
const auto* driver = device_get_driver(descriptor->controller);
|
const auto* driver = device_get_driver(descriptor->controller);
|
||||||
return GPIO_INTERNAL_API(driver)->set_level(descriptor, high);
|
return GPIO_INTERNAL_API(driver)->set_level(descriptor, high);
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t gpio_descriptor_get_level(struct GpioDescriptor* descriptor, bool* high) {
|
error_t gpio_descriptor_get_level(GpioDescriptor* descriptor, bool* high) {
|
||||||
const auto* driver = device_get_driver(descriptor->controller);
|
const auto* driver = device_get_driver(descriptor->controller);
|
||||||
return GPIO_INTERNAL_API(driver)->get_level(descriptor, high);
|
return GPIO_INTERNAL_API(driver)->get_level(descriptor, high);
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t gpio_descriptor_set_flags(struct GpioDescriptor* descriptor, gpio_flags_t flags) {
|
error_t gpio_descriptor_set_flags(GpioDescriptor* descriptor, gpio_flags_t flags) {
|
||||||
const auto* driver = device_get_driver(descriptor->controller);
|
const auto* driver = device_get_driver(descriptor->controller);
|
||||||
return GPIO_INTERNAL_API(driver)->set_flags(descriptor, flags);
|
return GPIO_INTERNAL_API(driver)->set_flags(descriptor, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t gpio_descriptor_get_flags(struct GpioDescriptor* descriptor, gpio_flags_t* flags) {
|
error_t gpio_descriptor_get_flags(GpioDescriptor* descriptor, gpio_flags_t* flags) {
|
||||||
const auto* driver = device_get_driver(descriptor->controller);
|
const auto* driver = device_get_driver(descriptor->controller);
|
||||||
return GPIO_INTERNAL_API(driver)->get_flags(descriptor, flags);
|
return GPIO_INTERNAL_API(driver)->get_flags(descriptor, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t gpio_descriptor_get_pin_number(struct GpioDescriptor* descriptor, gpio_pin_t* pin) {
|
error_t gpio_descriptor_get_pin_number(GpioDescriptor* descriptor, gpio_pin_t* pin) {
|
||||||
*pin = descriptor->pin;
|
*pin = descriptor->pin;
|
||||||
return ERROR_NONE;
|
return ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t gpio_descriptor_get_native_pin_number(struct GpioDescriptor* descriptor, void* pin_number) {
|
error_t gpio_descriptor_get_native_pin_number(GpioDescriptor* descriptor, void* pin_number) {
|
||||||
const auto* driver = device_get_driver(descriptor->controller);
|
const auto* driver = device_get_driver(descriptor->controller);
|
||||||
return GPIO_INTERNAL_API(driver)->get_native_pin_number(descriptor, pin_number);
|
return GPIO_INTERNAL_API(driver)->get_native_pin_number(descriptor, pin_number);
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t gpio_descriptor_get_owner_type(struct GpioDescriptor* descriptor, GpioOwnerType* owner_type) {
|
error_t gpio_descriptor_add_callback(GpioDescriptor* descriptor, void (*callback)(void*), void* arg) {
|
||||||
|
const auto* driver = device_get_driver(descriptor->controller);
|
||||||
|
auto* api = GPIO_INTERNAL_API(driver);
|
||||||
|
if (!api->add_callback) return ERROR_NOT_SUPPORTED;
|
||||||
|
return api->add_callback(descriptor, callback, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t gpio_descriptor_remove_callback(GpioDescriptor* descriptor) {
|
||||||
|
const auto* driver = device_get_driver(descriptor->controller);
|
||||||
|
auto* api = GPIO_INTERNAL_API(driver);
|
||||||
|
if (!api->remove_callback) return ERROR_NOT_SUPPORTED;
|
||||||
|
return api->remove_callback(descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t gpio_descriptor_enable_interrupt(GpioDescriptor* descriptor) {
|
||||||
|
const auto* driver = device_get_driver(descriptor->controller);
|
||||||
|
auto* api = GPIO_INTERNAL_API(driver);
|
||||||
|
if (!api->enable_interrupt) return ERROR_NOT_SUPPORTED;
|
||||||
|
return api->enable_interrupt(descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t gpio_descriptor_disable_interrupt(GpioDescriptor* descriptor) {
|
||||||
|
const auto* driver = device_get_driver(descriptor->controller);
|
||||||
|
auto* api = GPIO_INTERNAL_API(driver);
|
||||||
|
if (!api->disable_interrupt) return ERROR_NOT_SUPPORTED;
|
||||||
|
return api->disable_interrupt(descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t gpio_descriptor_get_owner_type(GpioDescriptor* descriptor, GpioOwnerType* owner_type) {
|
||||||
*owner_type = descriptor->owner_type;
|
*owner_type = descriptor->owner_type;
|
||||||
return ERROR_NONE;
|
return ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct DeviceType GPIO_CONTROLLER_TYPE {
|
const DeviceType GPIO_CONTROLLER_TYPE {
|
||||||
.name = "gpio-controller"
|
.name = "gpio-controller"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
93
TactilityKernel/source/filesystem/file_system.cpp
Normal file
93
TactilityKernel/source/filesystem/file_system.cpp
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <tactility/concurrent/mutex.h>
|
||||||
|
#include <tactility/concurrent/recursive_mutex.h>
|
||||||
|
#include <tactility/filesystem/file_system.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
// Define the internal FileSystem structure
|
||||||
|
struct FileSystem {
|
||||||
|
const FileSystemApi* api;
|
||||||
|
void* data;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Global list of file systems and its mutex
|
||||||
|
struct FileSystemsLedger {
|
||||||
|
std::vector<FileSystem*> file_systems;
|
||||||
|
// Use recursive mutex so that file_system_for_each() can lock within the callback
|
||||||
|
RecursiveMutex mutex {};
|
||||||
|
|
||||||
|
FileSystemsLedger() { recursive_mutex_construct(&mutex); }
|
||||||
|
~FileSystemsLedger() { recursive_mutex_destruct(&mutex); }
|
||||||
|
|
||||||
|
void lock() { recursive_mutex_lock(&mutex); }
|
||||||
|
bool is_locked() { return recursive_mutex_is_locked(&mutex); }
|
||||||
|
void unlock() { recursive_mutex_unlock(&mutex); }
|
||||||
|
};
|
||||||
|
|
||||||
|
static FileSystemsLedger& get_ledger() {
|
||||||
|
static FileSystemsLedger ledger;
|
||||||
|
return ledger;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
FileSystem* file_system_add(const FileSystemApi* fs_api, void* data) {
|
||||||
|
auto& ledger = get_ledger();
|
||||||
|
check(!ledger.is_locked()); // ensure file_system_for_each() doesn't add a filesystem while iterating
|
||||||
|
ledger.lock();
|
||||||
|
|
||||||
|
auto* fs = new(std::nothrow) struct FileSystem();
|
||||||
|
check(fs != nullptr);
|
||||||
|
fs->api = fs_api;
|
||||||
|
fs->data = data;
|
||||||
|
ledger.file_systems.push_back(fs);
|
||||||
|
|
||||||
|
ledger.unlock();
|
||||||
|
return fs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void file_system_remove(FileSystem* fs) {
|
||||||
|
check(!file_system_is_mounted(fs));
|
||||||
|
auto& ledger = get_ledger();
|
||||||
|
check(!ledger.is_locked()); // ensure file_system_for_each() doesn't remove a filesystem while iterating
|
||||||
|
ledger.lock();
|
||||||
|
|
||||||
|
auto it = std::ranges::find(ledger.file_systems, fs);
|
||||||
|
if (it != ledger.file_systems.end()) {
|
||||||
|
ledger.file_systems.erase(it);
|
||||||
|
delete fs;
|
||||||
|
}
|
||||||
|
|
||||||
|
ledger.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void file_system_for_each(void* callback_context, bool (*callback)(FileSystem* fs, void* context)) {
|
||||||
|
auto& ledger = get_ledger();
|
||||||
|
ledger.lock();
|
||||||
|
for (auto* fs : ledger.file_systems) {
|
||||||
|
if (!callback(fs, callback_context)) break;
|
||||||
|
}
|
||||||
|
ledger.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t file_system_mount(FileSystem* fs) {
|
||||||
|
// Assuming 'device' is accessible or passed via a different mechanism
|
||||||
|
// as it's required by the FileSystemApi signatures.
|
||||||
|
return fs->api->mount(fs->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t file_system_unmount(FileSystem* fs) {
|
||||||
|
return fs->api->unmount(fs->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool file_system_is_mounted(FileSystem* fs) {
|
||||||
|
return fs->api->is_mounted(fs->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
error_t file_system_get_path(FileSystem* fs, char* out_path, size_t out_path_size) {
|
||||||
|
return fs->api->get_path(fs->data, out_path, out_path_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,3 +1,7 @@
|
|||||||
|
#include <tactility/concurrent/dispatcher.h>
|
||||||
|
#include <tactility/concurrent/event_group.h>
|
||||||
|
#include <tactility/concurrent/thread.h>
|
||||||
|
#include <tactility/concurrent/timer.h>
|
||||||
#include <tactility/device.h>
|
#include <tactility/device.h>
|
||||||
#include <tactility/driver.h>
|
#include <tactility/driver.h>
|
||||||
#include <tactility/drivers/gpio_controller.h>
|
#include <tactility/drivers/gpio_controller.h>
|
||||||
@ -6,14 +10,14 @@
|
|||||||
#include <tactility/drivers/root.h>
|
#include <tactility/drivers/root.h>
|
||||||
#include <tactility/drivers/spi_controller.h>
|
#include <tactility/drivers/spi_controller.h>
|
||||||
#include <tactility/drivers/uart_controller.h>
|
#include <tactility/drivers/uart_controller.h>
|
||||||
#include <tactility/concurrent/dispatcher.h>
|
|
||||||
#include <tactility/concurrent/event_group.h>
|
|
||||||
#include <tactility/concurrent/thread.h>
|
|
||||||
#include <tactility/concurrent/timer.h>
|
|
||||||
#include <tactility/error.h>
|
#include <tactility/error.h>
|
||||||
#include <tactility/log.h>
|
#include <tactility/filesystem/file_system.h>
|
||||||
#include <tactility/module.h>
|
#include <tactility/module.h>
|
||||||
|
|
||||||
|
#ifndef ESP_PLATFORM
|
||||||
|
#include <tactility/log.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This file is a C file instead of C++, so we can import all headers as C code.
|
* This file is a C file instead of C++, so we can import all headers as C code.
|
||||||
* The intent is to catch errors that only show up when compiling as C and not as C++.
|
* The intent is to catch errors that only show up when compiling as C and not as C++.
|
||||||
@ -153,6 +157,11 @@ const struct ModuleSymbol KERNEL_SYMBOLS[] = {
|
|||||||
DEFINE_MODULE_SYMBOL(timer_set_callback_priority),
|
DEFINE_MODULE_SYMBOL(timer_set_callback_priority),
|
||||||
// error
|
// error
|
||||||
DEFINE_MODULE_SYMBOL(error_to_string),
|
DEFINE_MODULE_SYMBOL(error_to_string),
|
||||||
|
// file system
|
||||||
|
DEFINE_MODULE_SYMBOL(file_system_mount),
|
||||||
|
DEFINE_MODULE_SYMBOL(file_system_unmount),
|
||||||
|
DEFINE_MODULE_SYMBOL(file_system_is_mounted),
|
||||||
|
DEFINE_MODULE_SYMBOL(file_system_get_path),
|
||||||
// log
|
// log
|
||||||
#ifndef ESP_PLATFORM
|
#ifndef ESP_PLATFORM
|
||||||
DEFINE_MODULE_SYMBOL(log_generic),
|
DEFINE_MODULE_SYMBOL(log_generic),
|
||||||
|
|||||||
@ -12,8 +12,8 @@ struct ModuleInternal {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct ModuleLedger {
|
struct ModuleLedger {
|
||||||
std::vector<struct Module*> modules;
|
std::vector<Module*> modules;
|
||||||
struct Mutex mutex {};
|
Mutex mutex {};
|
||||||
|
|
||||||
ModuleLedger() { mutex_construct(&mutex); }
|
ModuleLedger() { mutex_construct(&mutex); }
|
||||||
~ModuleLedger() { mutex_destruct(&mutex); }
|
~ModuleLedger() { mutex_destruct(&mutex); }
|
||||||
@ -23,36 +23,37 @@ static ModuleLedger ledger;
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
error_t module_construct(struct Module* module) {
|
error_t module_construct(Module* module) {
|
||||||
module->internal = new (std::nothrow) ModuleInternal();
|
module->internal = new (std::nothrow) ModuleInternal();
|
||||||
if (module->internal == nullptr) return ERROR_OUT_OF_MEMORY;
|
if (module->internal == nullptr) return ERROR_OUT_OF_MEMORY;
|
||||||
return ERROR_NONE;
|
return ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t module_destruct(struct Module* module) {
|
error_t module_destruct(Module* module) {
|
||||||
delete static_cast<ModuleInternal*>(module->internal);
|
delete static_cast<ModuleInternal*>(module->internal);
|
||||||
module->internal = nullptr;
|
module->internal = nullptr;
|
||||||
return ERROR_NONE;
|
return ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t module_add(struct Module* module) {
|
error_t module_add(Module* module) {
|
||||||
mutex_lock(&ledger.mutex);
|
mutex_lock(&ledger.mutex);
|
||||||
ledger.modules.push_back(module);
|
ledger.modules.push_back(module);
|
||||||
mutex_unlock(&ledger.mutex);
|
mutex_unlock(&ledger.mutex);
|
||||||
return ERROR_NONE;
|
return ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t module_remove(struct Module* module) {
|
error_t module_remove(Module* module) {
|
||||||
mutex_lock(&ledger.mutex);
|
mutex_lock(&ledger.mutex);
|
||||||
ledger.modules.erase(std::remove(ledger.modules.begin(), ledger.modules.end(), module), ledger.modules.end());
|
ledger.modules.erase(std::remove(ledger.modules.begin(), ledger.modules.end(), module), ledger.modules.end());
|
||||||
mutex_unlock(&ledger.mutex);
|
mutex_unlock(&ledger.mutex);
|
||||||
return ERROR_NONE;
|
return ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t module_start(struct Module* module) {
|
error_t module_start(Module* module) {
|
||||||
LOG_I(TAG, "start %s", module->name);
|
LOG_I(TAG, "start %s", module->name);
|
||||||
|
|
||||||
auto* internal = static_cast<ModuleInternal*>(module->internal);
|
auto* internal = module->internal;
|
||||||
|
if (internal == nullptr) return ERROR_INVALID_STATE;
|
||||||
if (internal->started) return ERROR_NONE;
|
if (internal->started) return ERROR_NONE;
|
||||||
|
|
||||||
error_t error = module->start();
|
error_t error = module->start();
|
||||||
@ -61,13 +62,15 @@ error_t module_start(struct Module* module) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool module_is_started(struct Module* module) {
|
bool module_is_started(struct Module* module) {
|
||||||
return static_cast<ModuleInternal*>(module->internal)->started;
|
auto* internal = module->internal;
|
||||||
|
return internal != nullptr && internal->started;
|
||||||
}
|
}
|
||||||
|
|
||||||
error_t module_stop(struct Module* module) {
|
error_t module_stop(struct Module* module) {
|
||||||
LOG_I(TAG, "stop %s", module->name);
|
LOG_I(TAG, "stop %s", module->name);
|
||||||
|
|
||||||
auto* internal = static_cast<ModuleInternal*>(module->internal);
|
auto* internal = module->internal;
|
||||||
|
if (internal == nullptr) return ERROR_INVALID_STATE;
|
||||||
if (!internal->started) return ERROR_NONE;
|
if (!internal->started) return ERROR_NONE;
|
||||||
|
|
||||||
error_t error = module->stop();
|
error_t error = module->stop();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user