mirror of
https://github.com/ByteWelder/Tactility.git
synced 2026-10-17 02:45:05 +00:00
Tab5, CoreS3, StackChan and app icons (#662)
This commit is contained in:
parent
85b61e1e43
commit
7c508bbaa0
@ -19,3 +19,10 @@ display.shape=rectangle
|
||||
display.dpi=200
|
||||
|
||||
lvgl.colorDepth=16
|
||||
|
||||
sdkconfig.CONFIG_ESP_VIDEO_ENABLE_DVP_VIDEO_DEVICE=y
|
||||
sdkconfig.CONFIG_CAMERA_GC0308=y
|
||||
sdkconfig.CONFIG_CAMERA_GC0308_DVP_RGB565_BE_320X240_20FPS=y
|
||||
sdkconfig.CONFIG_CAMERA_GC0308_DVP_RGB565_BE_640X480_16FPS=n
|
||||
sdkconfig.CONFIG_CAMERA_GC0308_DVP_YUV422_YUYV_640X480_16FPS=n
|
||||
sdkconfig.CONFIG_CAMERA_GC0308_DVP_DEFAULT_FMT_RGB565_BE_320X240_20FPS=y
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
#include <bindings/es7210.h>
|
||||
#include <bindings/ft5x06.h>
|
||||
#include <bindings/ili9341.h>
|
||||
#include <bindings/gc0308.h>
|
||||
|
||||
// SD card is not supported because of a hardware problem:
|
||||
// The display uses pin 35 as input (MISO), but the SPI bus (and SD card) uses the same pin as DC (output).
|
||||
@ -64,6 +65,7 @@
|
||||
bmi270 {
|
||||
compatible = "bosch,bmi270";
|
||||
reg = <0x69>;
|
||||
invert-x;
|
||||
};
|
||||
|
||||
bm8563 {
|
||||
@ -151,6 +153,25 @@
|
||||
// capsules on their own.
|
||||
input-gain-percent = <400>;
|
||||
};
|
||||
|
||||
gc0308 {
|
||||
compatible = "galaxycore,gc0308";
|
||||
reg = <0x21>;
|
||||
rotation-offset = <0>;
|
||||
xclk-frequency-hz = <20000000>;
|
||||
pin-d0 = <&gpio0 39 GPIO_FLAG_NONE>;
|
||||
pin-d1 = <&gpio0 40 GPIO_FLAG_NONE>;
|
||||
pin-d2 = <&gpio0 41 GPIO_FLAG_NONE>;
|
||||
pin-d3 = <&gpio0 42 GPIO_FLAG_NONE>;
|
||||
pin-d4 = <&gpio0 15 GPIO_FLAG_NONE>;
|
||||
pin-d5 = <&gpio0 16 GPIO_FLAG_NONE>;
|
||||
pin-d6 = <&gpio0 48 GPIO_FLAG_NONE>;
|
||||
pin-d7 = <&gpio0 47 GPIO_FLAG_NONE>;
|
||||
pin-vsync = <&gpio0 46 GPIO_FLAG_NONE>;
|
||||
pin-de = <&gpio0 38 GPIO_FLAG_NONE>;
|
||||
pin-pclk = <&gpio0 45 GPIO_FLAG_NONE>;
|
||||
pin-reset = <&aw9523b 8 GPIO_FLAG_ACTIVE_LOW>;
|
||||
};
|
||||
};
|
||||
|
||||
port_a: grove0 {
|
||||
|
||||
@ -5,6 +5,7 @@ dependencies:
|
||||
- Drivers/aw9523b-module
|
||||
- Drivers/axp2101-module
|
||||
- Drivers/bm8563-module
|
||||
- Drivers/gc0308-module
|
||||
- Drivers/bmi270-module
|
||||
- Drivers/es7210-module
|
||||
- Drivers/ft5x06-module
|
||||
|
||||
@ -19,3 +19,10 @@ display.shape=rectangle
|
||||
display.dpi=200
|
||||
|
||||
lvgl.colorDepth=16
|
||||
|
||||
sdkconfig.CONFIG_ESP_VIDEO_ENABLE_DVP_VIDEO_DEVICE=y
|
||||
sdkconfig.CONFIG_CAMERA_GC0308=y
|
||||
sdkconfig.CONFIG_CAMERA_GC0308_DVP_RGB565_BE_320X240_20FPS=y
|
||||
sdkconfig.CONFIG_CAMERA_GC0308_DVP_RGB565_BE_640X480_16FPS=n
|
||||
sdkconfig.CONFIG_CAMERA_GC0308_DVP_YUV422_YUYV_640X480_16FPS=n
|
||||
sdkconfig.CONFIG_CAMERA_GC0308_DVP_DEFAULT_FMT_RGB565_BE_320X240_20FPS=y
|
||||
|
||||
@ -19,10 +19,11 @@
|
||||
#include <bindings/bm8563.h>
|
||||
#include <bindings/bmi270.h>
|
||||
#include <bindings/es7210.h>
|
||||
#include <bindings/ft6x36.h>
|
||||
#include <bindings/ft5x06.h>
|
||||
#include <bindings/ili9341.h>
|
||||
#include <bindings/ina226.h>
|
||||
#include <bindings/py32ioexpander.h>
|
||||
#include <bindings/gc0308.h>
|
||||
|
||||
// Reference: https://docs.m5stack.com/en/StackChan
|
||||
/ {
|
||||
@ -69,6 +70,7 @@
|
||||
bmi270 {
|
||||
compatible = "bosch,bmi270";
|
||||
reg = <0x69>;
|
||||
invert-x;
|
||||
};
|
||||
|
||||
bm8563 {
|
||||
@ -143,10 +145,10 @@
|
||||
};
|
||||
|
||||
touch {
|
||||
compatible = "focaltech,ft6x36";
|
||||
compatible = "focaltech,ft5x06";
|
||||
reg = <0x38>;
|
||||
x-max = <319>;
|
||||
y-max = <239>;
|
||||
x-max = <320>;
|
||||
y-max = <240>;
|
||||
pin-reset = <&aw9523b 0 GPIO_FLAG_NONE>;
|
||||
};
|
||||
|
||||
@ -165,8 +167,26 @@
|
||||
input-gain-percent = <400>;
|
||||
};
|
||||
|
||||
gc0308 {
|
||||
compatible = "galaxycore,gc0308";
|
||||
reg = <0x21>;
|
||||
rotation-offset = <0>;
|
||||
xclk-frequency-hz = <20000000>;
|
||||
pin-d0 = <&gpio0 39 GPIO_FLAG_NONE>;
|
||||
pin-d1 = <&gpio0 40 GPIO_FLAG_NONE>;
|
||||
pin-d2 = <&gpio0 41 GPIO_FLAG_NONE>;
|
||||
pin-d3 = <&gpio0 42 GPIO_FLAG_NONE>;
|
||||
pin-d4 = <&gpio0 15 GPIO_FLAG_NONE>;
|
||||
pin-d5 = <&gpio0 16 GPIO_FLAG_NONE>;
|
||||
pin-d6 = <&gpio0 48 GPIO_FLAG_NONE>;
|
||||
pin-d7 = <&gpio0 47 GPIO_FLAG_NONE>;
|
||||
pin-vsync = <&gpio0 46 GPIO_FLAG_NONE>;
|
||||
pin-de = <&gpio0 38 GPIO_FLAG_NONE>;
|
||||
pin-pclk = <&gpio0 45 GPIO_FLAG_NONE>;
|
||||
pin-reset = <&aw9523b 8 GPIO_FLAG_ACTIVE_LOW>;
|
||||
};
|
||||
|
||||
// TODO: Si12T 3-zone head touch @ 0x68 — INT active-low, 10kΩ pull-up to 3.3V; driver not yet implemented
|
||||
// TODO: GC0308 camera @ 0x21 — requires i2c_master driver, not yet available
|
||||
// TODO: LTR-553ALS-WA proximity/light @ 0x23 — no driver yet
|
||||
// TODO: BMM150 magnetometer @ 0x10 — accessible only via BMI270 aux I2C
|
||||
};
|
||||
|
||||
@ -5,9 +5,10 @@ dependencies:
|
||||
- Drivers/aw9523b-module
|
||||
- Drivers/axp2101-module
|
||||
- Drivers/bm8563-module
|
||||
- Drivers/gc0308-module
|
||||
- Drivers/bmi270-module
|
||||
- Drivers/es7210-module
|
||||
- Drivers/ft6x36-module
|
||||
- Drivers/ft5x06-module
|
||||
- Drivers/ili9341-module
|
||||
- Drivers/ina226-module
|
||||
- Drivers/py32ioexpander-module
|
||||
|
||||
@ -56,7 +56,11 @@ bool pulse_display_reset_pins(Device* io_expander0) {
|
||||
gpio_descriptor_set_level(lcd_reset_pin, true);
|
||||
gpio_descriptor_set_level(touch_reset_pin, true);
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
gpio_descriptor_set_level(lcd_reset_pin, false);
|
||||
if (gpio_descriptor_set_flags(lcd_reset_pin, GPIO_FLAG_DIRECTION_INPUT | GPIO_FLAG_PULL_UP) != ERROR_NONE) {
|
||||
gpio_descriptor_release(lcd_reset_pin);
|
||||
gpio_descriptor_release(touch_reset_pin);
|
||||
return false;
|
||||
}
|
||||
gpio_descriptor_set_level(touch_reset_pin, false);
|
||||
|
||||
gpio_descriptor_release(lcd_reset_pin);
|
||||
|
||||
@ -122,6 +122,7 @@
|
||||
|
||||
sc2356 {
|
||||
compatible = "smartsens,sc2356";
|
||||
rotation-offset = <270>;
|
||||
reg = <0x36>;
|
||||
// Pulsed by the sc2356 driver itself in start_device, not a gpio-hog: the driver's
|
||||
// I2C probe otherwise races a bare hog's pin release with no settle delay (the hog
|
||||
|
||||
@ -1,5 +1,31 @@
|
||||
description: Bosch BMI270 6-axis IMU
|
||||
|
||||
include: ["i2c-device.yaml"]
|
||||
include: [ "i2c-device.yaml" ]
|
||||
|
||||
compatible: "bosch,bmi270"
|
||||
|
||||
properties:
|
||||
swap-xy:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Swap the X and Y axes
|
||||
swap-xz:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Swap the X and Z axes
|
||||
swap-yz:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Swap the Y and Z axes
|
||||
invert-x:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Invert the X axis
|
||||
invert-y:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Invert the Y axis
|
||||
invert-z:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Invert the Z axis
|
||||
|
||||
@ -14,6 +14,12 @@ extern "C" {
|
||||
struct Bmi270Config {
|
||||
/** Address on bus */
|
||||
uint8_t address;
|
||||
bool swap_xy;
|
||||
bool swap_xz;
|
||||
bool swap_yz;
|
||||
bool invert_x;
|
||||
bool invert_y;
|
||||
bool invert_z;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -6,6 +6,8 @@
|
||||
#include <tactility/drivers/i2c_controller.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#define TAG "BMI270"
|
||||
|
||||
static constexpr uint8_t REG_CHIP_ID = 0x00; // read: expect 0x24
|
||||
@ -165,9 +167,21 @@ error_t bmi270_read_accel(Device* device, ImuAccelData* data) {
|
||||
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;
|
||||
float axes[3] = {
|
||||
toI16(buffer[0], buffer[1]) * ACCEL_SCALE,
|
||||
toI16(buffer[2], buffer[3]) * ACCEL_SCALE,
|
||||
toI16(buffer[4], buffer[5]) * ACCEL_SCALE,
|
||||
};
|
||||
const auto& config = *GET_CONFIG(device);
|
||||
if (config.swap_xy) std::swap(axes[0], axes[1]);
|
||||
if (config.swap_xz) std::swap(axes[0], axes[2]);
|
||||
if (config.swap_yz) std::swap(axes[1], axes[2]);
|
||||
if (config.invert_x) axes[0] = -axes[0];
|
||||
if (config.invert_y) axes[1] = -axes[1];
|
||||
if (config.invert_z) axes[2] = -axes[2];
|
||||
data->ax = axes[0];
|
||||
data->ay = axes[1];
|
||||
data->az = axes[2];
|
||||
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
11
Drivers/gc0308-module/CMakeLists.txt
Normal file
11
Drivers/gc0308-module/CMakeLists.txt
Normal file
@ -0,0 +1,11 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/../../Buildscripts/module.cmake")
|
||||
|
||||
file(GLOB_RECURSE SOURCE_FILES "source/*.c*")
|
||||
|
||||
tactility_add_module(gc0308-module
|
||||
SRCS ${SOURCE_FILES}
|
||||
INCLUDE_DIRS include/
|
||||
REQUIRES TactilityKernel platform-esp32 esp_video esp_cam_sensor driver esp_new_jpeg
|
||||
)
|
||||
195
Drivers/gc0308-module/LICENSE-Apache-2.0.md
Normal file
195
Drivers/gc0308-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.
|
||||
|
||||
8
Drivers/gc0308-module/README.md
Normal file
8
Drivers/gc0308-module/README.md
Normal file
@ -0,0 +1,8 @@
|
||||
# GC0308 Camera Driver
|
||||
|
||||
A driver for the `GC0308` 0.3MP camera sensor by GalaxyCore.
|
||||
|
||||
- Datasheet: https://m5stack.oss-cn-shenzhen.aliyuncs.com/resource/docs/datasheet/core/K128%20CoreS3/GC0308.PDF
|
||||
- ESP Video Components: https://github.com/espressif/esp-video-components
|
||||
|
||||
License: [Apache v2.0](LICENSE-Apache-2.0.md)
|
||||
46
Drivers/gc0308-module/bindings/galaxycore,gc0308.yaml
Normal file
46
Drivers/gc0308-module/bindings/galaxycore,gc0308.yaml
Normal file
@ -0,0 +1,46 @@
|
||||
description: GalaxyCore GC0308 0.3MP camera sensor
|
||||
|
||||
include: [ "i2c-device.yaml" ]
|
||||
|
||||
compatible: "galaxycore,gc0308"
|
||||
|
||||
properties:
|
||||
rotation-offset:
|
||||
type: int
|
||||
enum: [ 0, 90, 180, 270 ]
|
||||
default: 0
|
||||
description: Clockwise mounting correction in degrees (0, 90, 180 or 270).
|
||||
xclk-frequency-hz:
|
||||
type: int
|
||||
default: 20000000
|
||||
description: DVP sensor master clock frequency.
|
||||
pin-d0:
|
||||
type: phandles
|
||||
pin-d1:
|
||||
type: phandles
|
||||
pin-d2:
|
||||
type: phandles
|
||||
pin-d3:
|
||||
type: phandles
|
||||
pin-d4:
|
||||
type: phandles
|
||||
pin-d5:
|
||||
type: phandles
|
||||
pin-d6:
|
||||
type: phandles
|
||||
pin-d7:
|
||||
type: phandles
|
||||
pin-vsync:
|
||||
type: phandles
|
||||
pin-de:
|
||||
type: phandles
|
||||
pin-pclk:
|
||||
type: phandles
|
||||
pin-xclk:
|
||||
type: phandles
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
pin-reset:
|
||||
type: phandles
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
description: >
|
||||
Reset GPIO pin. Pulsed (asserted then released, with a settle delay) before the sensor is probed in start_device. Typically wired through a board's IO expander rather than a direct SoC GPIO, so it's handled here via the generic gpio_descriptor API.
|
||||
15
Drivers/gc0308-module/include/bindings/gc0308.h
Normal file
15
Drivers/gc0308-module/include/bindings/gc0308.h
Normal file
@ -0,0 +1,15 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include <tactility/bindings/bindings.h>
|
||||
#include <drivers/gc0308.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
DEFINE_DEVICETREE(gc0308, struct Gc0308Config)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
124
Drivers/gc0308-module/include/drivers/gc0308.h
Normal file
124
Drivers/gc0308-module/include/drivers/gc0308.h
Normal file
@ -0,0 +1,124 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <tactility/drivers/camera.h>
|
||||
#include <tactility/drivers/gpio.h>
|
||||
#include <tactility/error.h>
|
||||
|
||||
struct Device;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Gc0308Config {
|
||||
/** SCCB I2C address (0x21) */
|
||||
uint8_t address;
|
||||
|
||||
/** Clockwise mounting correction applied after the requested display rotation. */
|
||||
uint16_t rotation_offset;
|
||||
|
||||
uint32_t xclk_frequency_hz;
|
||||
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_vsync;
|
||||
struct GpioPinSpec pin_de;
|
||||
struct GpioPinSpec pin_pclk;
|
||||
struct GpioPinSpec pin_xclk;
|
||||
|
||||
// Reset pin. GPIO_PIN_SPEC_NONE if the sensor's reset is tied high on the board (or otherwise
|
||||
// not under our control), in which case start_device skips the reset pulse entirely and goes
|
||||
// straight to probing.
|
||||
struct GpioPinSpec pin_reset;
|
||||
};
|
||||
|
||||
/**
|
||||
* Opaque camera handle returned by gc0308_open().
|
||||
* Not thread-safe: the capture flow (gc0308_get_frame/gc0308_capture_jpeg + gc0308_release_frame)
|
||||
* must be driven from a single consumer at a time.
|
||||
*/
|
||||
typedef CameraHandle Gc0308Handle;
|
||||
|
||||
/**
|
||||
* Initialize the esp_video DVP subsystem and open the DVP video device.
|
||||
* Reuses the parent I2C controller's bus handle for SCCB communication.
|
||||
* Must be called before any other gc0308_* functions.
|
||||
* @param device the gc0308 device from the device tree
|
||||
* @param handle out: opaque handle to pass to subsequent calls
|
||||
* @return ERROR_NONE on success
|
||||
*/
|
||||
error_t gc0308_open(struct Device* device, Gc0308Handle* handle);
|
||||
|
||||
/**
|
||||
* Stop streaming, unmap frame buffers, and release all resources.
|
||||
* @param handle handle returned by gc0308_open()
|
||||
* @return ERROR_NONE on success
|
||||
*/
|
||||
error_t gc0308_close(Gc0308Handle handle);
|
||||
|
||||
/**
|
||||
* Dequeue one RGB565 frame. Blocks until a frame is available or the timeout expires.
|
||||
* The caller must call gc0308_release_frame() to return the buffer to the camera queue.
|
||||
* @param handle handle returned by gc0308_open()
|
||||
* @param buf out: pointer to the DMA-mapped RGB565 frame buffer
|
||||
* @param len out: byte length of buf (width * height * 2)
|
||||
* @param timeout_ms maximum time to wait in milliseconds
|
||||
* @param out_width optional out: width of buf at the moment it was produced, atomic with the frame data (may be NULL)
|
||||
* @param out_height optional out: height of buf at the moment it was produced, atomic with the frame data (may be NULL)
|
||||
* @return ERROR_NONE on success, ERROR_TIMEOUT if no frame arrived in time
|
||||
*/
|
||||
error_t gc0308_get_frame(Gc0308Handle handle, uint8_t** buf, size_t* len, uint32_t timeout_ms, uint32_t* out_width, uint32_t* out_height);
|
||||
|
||||
/**
|
||||
* Return the last dequeued frame buffer to the V4L2 capture queue.
|
||||
* Must be called after each successful gc0308_get_frame().
|
||||
* @param handle handle returned by gc0308_open()
|
||||
* @return ERROR_NONE on success
|
||||
*/
|
||||
error_t gc0308_release_frame(Gc0308Handle handle);
|
||||
|
||||
/**
|
||||
* Return the frame width in pixels.
|
||||
* @param handle handle returned by gc0308_open()
|
||||
*/
|
||||
uint32_t gc0308_get_width(Gc0308Handle handle);
|
||||
|
||||
/**
|
||||
* Return the frame height in pixels.
|
||||
* @param handle handle returned by gc0308_open()
|
||||
*/
|
||||
uint32_t gc0308_get_height(Gc0308Handle handle);
|
||||
|
||||
/**
|
||||
* Set the requested clockwise rotation. Subsequent frames are software-rotated
|
||||
* and their reported dimensions reflect the requested orientation.
|
||||
* Can be called at any time while the handle is open, including during streaming.
|
||||
* @param handle handle returned by gc0308_open()
|
||||
* @param rotation new rotation
|
||||
* @return ERROR_NONE on success
|
||||
*/
|
||||
error_t gc0308_set_rotation(Gc0308Handle handle, CameraRotation rotation);
|
||||
|
||||
/**
|
||||
* Capture one frame and JPEG-encode it using the hardware JPEG encoder.
|
||||
* Allocates output buffer in SPIRAM; caller must free it with memory_free().
|
||||
* @param handle handle returned by gc0308_open()
|
||||
* @param out_buf out: pointer to JPEG-encoded data (caller must free)
|
||||
* @param out_len out: byte length of JPEG data
|
||||
* @param quality JPEG quality 1-100
|
||||
* @return ERROR_NONE on success
|
||||
*/
|
||||
error_t gc0308_capture_jpeg(Gc0308Handle handle, uint8_t** out_buf, size_t* out_len, uint8_t quality);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
14
Drivers/gc0308-module/include/gc0308_module.h
Normal file
14
Drivers/gc0308-module/include/gc0308_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 gc0308_module;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
3
Drivers/gc0308-module/module.yaml
Normal file
3
Drivers/gc0308-module/module.yaml
Normal file
@ -0,0 +1,3 @@
|
||||
dependencies:
|
||||
- TactilityKernel
|
||||
bindings: bindings
|
||||
552
Drivers/gc0308-module/source/gc0308.cpp
Normal file
552
Drivers/gc0308-module/source/gc0308.cpp
Normal file
@ -0,0 +1,552 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#include <drivers/gc0308.h>
|
||||
#include <gc0308_module.h>
|
||||
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/drivers/esp32_i2c_master.h>
|
||||
#include <tactility/drivers/gpio_controller.h>
|
||||
#include <tactility/drivers/i2c_controller.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#include <esp_heap_caps.h>
|
||||
#include <esp_video_device.h>
|
||||
#include <esp_video_init.h>
|
||||
#include <freertos/task.h>
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <linux/videodev2.h>
|
||||
#include <sys/errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/poll.h>
|
||||
|
||||
#include <esp_jpeg_enc.h>
|
||||
|
||||
#include <cstring>
|
||||
#include <freertos/semphr.h>
|
||||
|
||||
#define TAG "GC0308"
|
||||
|
||||
static constexpr int VIDEO_BUFFER_COUNT = 2;
|
||||
static bool s_video_initialized = false;
|
||||
static SemaphoreHandle_t s_video_init_mutex = nullptr;
|
||||
static uint32_t s_video_handle_count = 0;
|
||||
|
||||
struct Gc0308State : CameraHandleData {
|
||||
int fd;
|
||||
// Native sensor output dimensions
|
||||
uint32_t native_width;
|
||||
uint32_t native_height;
|
||||
// Frames are returned in the requested orientation.
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint8_t* buffers[VIDEO_BUFFER_COUNT];
|
||||
size_t buf_lengths[VIDEO_BUFFER_COUNT];
|
||||
int last_dqbuf_index;
|
||||
uint8_t* frame_buf;
|
||||
size_t frame_buf_size;
|
||||
jpeg_enc_handle_t encoder;
|
||||
i2c_master_bus_handle_t sccb_bus;
|
||||
CameraRotation rotation;
|
||||
SemaphoreHandle_t rotation_mutex; // protects rotation, width, height
|
||||
uint32_t encoder_width;
|
||||
uint32_t encoder_height;
|
||||
};
|
||||
|
||||
#define GET_CONFIG(device) (static_cast<const Gc0308Config*>((device)->config))
|
||||
|
||||
static gpio_num_t pin_or_nc(const GpioPinSpec& pin) {
|
||||
return pin.gpio_controller == nullptr ? GPIO_NUM_NC : static_cast<gpio_num_t>(pin.pin);
|
||||
}
|
||||
|
||||
static CameraRotation add_rotation(CameraRotation rotation, uint16_t offset) {
|
||||
return static_cast<CameraRotation>((static_cast<uint16_t>(rotation) + offset) % 360);
|
||||
}
|
||||
|
||||
static error_t reset_pulse(GpioDescriptor* descriptor) {
|
||||
// Release is attempted unconditionally, even if assert failed - leaving the expander output
|
||||
// asserted on an assert failure would hold the sensor in reset for the rest of boot.
|
||||
const bool assert_ok = gpio_descriptor_set_level(descriptor, true) == ERROR_NONE; // assert
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
const bool release_ok = gpio_descriptor_set_level(descriptor, false) == ERROR_NONE; // release
|
||||
vTaskDelay(pdMS_TO_TICKS(10));
|
||||
return (assert_ok && release_ok) ? ERROR_NONE : ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
static error_t start(Device* device) {
|
||||
auto* i2c = device_get_parent(device);
|
||||
if (device_get_type(i2c) != &I2C_CONTROLLER_TYPE) {
|
||||
LOG_E(TAG, "Parent is not an I2C controller");
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
const auto* config = GET_CONFIG(device);
|
||||
//auto address = config->address;
|
||||
|
||||
// Reset is pulsed (not just held released) so the sensor reaches a known state regardless of
|
||||
// whatever it inherited from a previous boot
|
||||
if (config->pin_reset.gpio_controller != nullptr) {
|
||||
// Merge with the devicetree-supplied flags (e.g. GPIO_FLAG_ACTIVE_LOW) rather than
|
||||
// overwriting them, so a board that wires reset active-high isn't silently forced to
|
||||
// active-low polarity.
|
||||
auto* reset_descriptor = gpio_descriptor_acquire(config->pin_reset.gpio_controller, config->pin_reset.pin, config->pin_reset.flags | GPIO_FLAG_DIRECTION_OUTPUT, GPIO_OWNER_GPIO);
|
||||
if (reset_descriptor == nullptr) {
|
||||
LOG_E(TAG, "Failed to acquire reset pin");
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
error_t reset_error = reset_pulse(reset_descriptor);
|
||||
gpio_descriptor_release(reset_descriptor);
|
||||
if (reset_error != ERROR_NONE) {
|
||||
LOG_E(TAG, "Failed to pulse reset pin");
|
||||
return reset_error;
|
||||
}
|
||||
}
|
||||
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static error_t stop([[maybe_unused]] Device* device) {
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
static SemaphoreHandle_t get_video_init_mutex() {
|
||||
static portMUX_TYPE creation_lock = portMUX_INITIALIZER_UNLOCKED;
|
||||
portENTER_CRITICAL(&creation_lock);
|
||||
if (!s_video_init_mutex) {
|
||||
s_video_init_mutex = xSemaphoreCreateMutex();
|
||||
if (!s_video_init_mutex) {
|
||||
LOG_E(TAG, "Failed to create video init mutex");
|
||||
}
|
||||
}
|
||||
portEXIT_CRITICAL(&creation_lock);
|
||||
return s_video_init_mutex;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
error_t gc0308_open(Device* device, Gc0308Handle* out_handle) {
|
||||
if (!device || !out_handle) return ERROR_INVALID_ARGUMENT;
|
||||
|
||||
auto* state = static_cast<Gc0308State*>(heap_caps_calloc(1, sizeof(Gc0308State), MALLOC_CAP_DEFAULT));
|
||||
if (!state) return ERROR_OUT_OF_MEMORY;
|
||||
state->device = device;
|
||||
state->fd = -1;
|
||||
state->last_dqbuf_index = -1;
|
||||
state->rotation_mutex = xSemaphoreCreateMutex();
|
||||
if (!state->rotation_mutex) {
|
||||
heap_caps_free(state);
|
||||
return ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
state->rotation = CAMERA_ROTATION_0;
|
||||
struct v4l2_format fmt = {};
|
||||
|
||||
// Retrieve bus handle from the parent I2C controller
|
||||
auto* i2c = device_get_parent(device);
|
||||
state->sccb_bus = esp32_i2c_master_get_bus_handle(i2c);
|
||||
if (!state->sccb_bus) {
|
||||
LOG_E(TAG, "Failed to get i2c_master bus handle from parent device");
|
||||
vSemaphoreDelete(state->rotation_mutex);
|
||||
heap_caps_free(state);
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
const auto* config = GET_CONFIG(device);
|
||||
bool video_handle_acquired = false;
|
||||
|
||||
// esp_video_init only needs to run once across all gc0308_open calls.
|
||||
{
|
||||
SemaphoreHandle_t init_mutex = get_video_init_mutex();
|
||||
if (!init_mutex) {
|
||||
vSemaphoreDelete(state->rotation_mutex);
|
||||
heap_caps_free(state);
|
||||
return ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
xSemaphoreTake(init_mutex, portMAX_DELAY);
|
||||
if (!s_video_initialized) {
|
||||
esp_video_init_dvp_config_t dvp_config = {
|
||||
.sccb_config = {
|
||||
.init_sccb = false,
|
||||
.i2c_handle = state->sccb_bus,
|
||||
.freq = 100000,
|
||||
},
|
||||
.reset_pin = GPIO_NUM_NC,
|
||||
.pwdn_pin = GPIO_NUM_NC,
|
||||
.dvp_pin = {
|
||||
.data_width = CAM_CTLR_DATA_WIDTH_8,
|
||||
.data_io = {
|
||||
static_cast<gpio_num_t>(config->pin_d0.pin),
|
||||
static_cast<gpio_num_t>(config->pin_d1.pin),
|
||||
static_cast<gpio_num_t>(config->pin_d2.pin),
|
||||
static_cast<gpio_num_t>(config->pin_d3.pin),
|
||||
static_cast<gpio_num_t>(config->pin_d4.pin),
|
||||
static_cast<gpio_num_t>(config->pin_d5.pin),
|
||||
static_cast<gpio_num_t>(config->pin_d6.pin),
|
||||
static_cast<gpio_num_t>(config->pin_d7.pin),
|
||||
},
|
||||
.vsync_io = static_cast<gpio_num_t>(config->pin_vsync.pin),
|
||||
.de_io = static_cast<gpio_num_t>(config->pin_de.pin),
|
||||
.pclk_io = static_cast<gpio_num_t>(config->pin_pclk.pin),
|
||||
.xclk_io = pin_or_nc(config->pin_xclk),
|
||||
},
|
||||
.xclk_freq = config->xclk_frequency_hz,
|
||||
};
|
||||
esp_video_init_config_t video_config = { .dvp = &dvp_config };
|
||||
esp_err_t esp_err = esp_video_init_with_flags(&video_config, ESP_VIDEO_INIT_FLAGS_DVP);
|
||||
if (esp_err != ESP_OK) {
|
||||
LOG_E(TAG, "esp_video_init DVP failed: %s", esp_err_to_name(esp_err));
|
||||
xSemaphoreGive(init_mutex);
|
||||
vSemaphoreDelete(state->rotation_mutex);
|
||||
heap_caps_free(state);
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
s_video_initialized = true;
|
||||
}
|
||||
++s_video_handle_count;
|
||||
video_handle_acquired = true;
|
||||
xSemaphoreGive(init_mutex);
|
||||
}
|
||||
|
||||
state->fd = open(ESP_VIDEO_DVP_DEVICE_NAME, O_RDONLY);
|
||||
if (state->fd < 0) {
|
||||
LOG_E(TAG, "Failed to open %s", ESP_VIDEO_DVP_DEVICE_NAME);
|
||||
goto err_close;
|
||||
}
|
||||
|
||||
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
if (ioctl(state->fd, VIDIOC_G_FMT, &fmt) != 0) {
|
||||
LOG_E(TAG, "VIDIOC_G_FMT failed");
|
||||
goto err_close;
|
||||
}
|
||||
state->native_width = fmt.fmt.pix.width;
|
||||
state->native_height = fmt.fmt.pix.height;
|
||||
state->frame_buf_size = (size_t)state->native_width * state->native_height * 2;
|
||||
state->rotation = add_rotation(CAMERA_ROTATION_0, config->rotation_offset);
|
||||
if (state->rotation == CAMERA_ROTATION_90 || state->rotation == CAMERA_ROTATION_270) {
|
||||
state->width = state->native_height;
|
||||
state->height = state->native_width;
|
||||
} else {
|
||||
state->width = state->native_width;
|
||||
state->height = state->native_height;
|
||||
}
|
||||
state->frame_buf = static_cast<uint8_t*>(heap_caps_aligned_alloc(16, state->frame_buf_size, MALLOC_CAP_SPIRAM));
|
||||
if (!state->frame_buf) goto err_close;
|
||||
|
||||
{
|
||||
struct v4l2_requestbuffers request = {};
|
||||
request.count = VIDEO_BUFFER_COUNT;
|
||||
request.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
request.memory = V4L2_MEMORY_MMAP;
|
||||
if (ioctl(state->fd, VIDIOC_REQBUFS, &request) != 0) goto err_close;
|
||||
}
|
||||
for (int i = 0; i < VIDEO_BUFFER_COUNT; i++) {
|
||||
struct v4l2_buffer buffer = {};
|
||||
buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
buffer.memory = V4L2_MEMORY_MMAP;
|
||||
buffer.index = i;
|
||||
if (ioctl(state->fd, VIDIOC_QUERYBUF, &buffer) != 0) goto err_unmap;
|
||||
state->buf_lengths[i] = buffer.length;
|
||||
state->buffers[i] = static_cast<uint8_t*>(mmap(nullptr, buffer.length, PROT_READ | PROT_WRITE, MAP_SHARED, state->fd, buffer.m.offset));
|
||||
if (state->buffers[i] == MAP_FAILED) {
|
||||
state->buffers[i] = nullptr;
|
||||
goto err_unmap;
|
||||
}
|
||||
if (ioctl(state->fd, VIDIOC_QBUF, &buffer) != 0) goto err_unmap;
|
||||
}
|
||||
{
|
||||
int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
if (ioctl(state->fd, VIDIOC_STREAMON, &type) != 0) goto err_unmap;
|
||||
}
|
||||
|
||||
{
|
||||
jpeg_enc_config_t encoder_config = {
|
||||
.width = static_cast<int>(state->width),
|
||||
.height = static_cast<int>(state->height),
|
||||
.src_type = JPEG_PIXEL_FORMAT_RGB565_LE,
|
||||
.subsampling = JPEG_SUBSAMPLE_420,
|
||||
.quality = 80,
|
||||
.rotate = JPEG_ROTATE_0D,
|
||||
.task_enable = false,
|
||||
.hfm_task_priority = 13,
|
||||
.hfm_task_core = 1,
|
||||
};
|
||||
if (jpeg_enc_open(&encoder_config, &state->encoder) != JPEG_ERR_OK) goto err_unmap;
|
||||
state->encoder_width = state->width;
|
||||
state->encoder_height = state->height;
|
||||
}
|
||||
|
||||
LOG_I(TAG, "Video format: %lux%lu native", (unsigned long)state->native_width, (unsigned long)state->native_height);
|
||||
|
||||
*out_handle = state;
|
||||
return ERROR_NONE;
|
||||
|
||||
err_unmap:
|
||||
if (state->encoder) {
|
||||
jpeg_enc_close(state->encoder);
|
||||
state->encoder = nullptr;
|
||||
}
|
||||
{
|
||||
int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
ioctl(state->fd, VIDIOC_STREAMOFF, &type);
|
||||
}
|
||||
for (int i = 0; i < VIDEO_BUFFER_COUNT; i++) {
|
||||
if (state->buffers[i]) munmap(state->buffers[i], state->buf_lengths[i]);
|
||||
}
|
||||
err_close:
|
||||
if (state->fd >= 0) close(state->fd);
|
||||
if (video_handle_acquired) {
|
||||
SemaphoreHandle_t init_mutex = get_video_init_mutex();
|
||||
xSemaphoreTake(init_mutex, portMAX_DELAY);
|
||||
--s_video_handle_count;
|
||||
if (s_video_handle_count == 0 && s_video_initialized) {
|
||||
esp_video_deinit_with_flags(ESP_VIDEO_INIT_FLAGS_DVP);
|
||||
s_video_initialized = false;
|
||||
}
|
||||
xSemaphoreGive(init_mutex);
|
||||
}
|
||||
vSemaphoreDelete(state->rotation_mutex);
|
||||
heap_caps_free(state->frame_buf);
|
||||
heap_caps_free(state);
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
error_t gc0308_close(Gc0308Handle handle) {
|
||||
if (!handle) return ERROR_INVALID_ARGUMENT;
|
||||
auto* state = static_cast<Gc0308State*>(handle);
|
||||
|
||||
if (state->encoder) jpeg_enc_close(state->encoder);
|
||||
int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
ioctl(state->fd, VIDIOC_STREAMOFF, &type);
|
||||
for (int i = 0; i < VIDEO_BUFFER_COUNT; i++) {
|
||||
if (state->buffers[i]) munmap(state->buffers[i], state->buf_lengths[i]);
|
||||
}
|
||||
heap_caps_free(state->frame_buf);
|
||||
close(state->fd);
|
||||
SemaphoreHandle_t init_mutex = get_video_init_mutex();
|
||||
xSemaphoreTake(init_mutex, portMAX_DELAY);
|
||||
if (s_video_handle_count > 0) --s_video_handle_count;
|
||||
if (s_video_handle_count == 0 && s_video_initialized) {
|
||||
esp_video_deinit_with_flags(ESP_VIDEO_INIT_FLAGS_DVP);
|
||||
s_video_initialized = false;
|
||||
}
|
||||
xSemaphoreGive(init_mutex);
|
||||
if (state->rotation_mutex) vSemaphoreDelete(state->rotation_mutex);
|
||||
// Bus handle is owned by esp32_i2c_master driver - do not delete it
|
||||
heap_caps_free(state);
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
error_t gc0308_set_rotation(Gc0308Handle handle, CameraRotation rotation) {
|
||||
if (!handle) return ERROR_INVALID_ARGUMENT;
|
||||
auto* state = static_cast<Gc0308State*>(handle);
|
||||
CameraRotation effective_rotation = add_rotation(rotation, GET_CONFIG(state->device)->rotation_offset);
|
||||
|
||||
xSemaphoreTake(state->rotation_mutex, portMAX_DELAY);
|
||||
|
||||
if (state->rotation == effective_rotation) {
|
||||
xSemaphoreGive(state->rotation_mutex);
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
bool needs_swap = (effective_rotation == CAMERA_ROTATION_90 || effective_rotation == CAMERA_ROTATION_270);
|
||||
|
||||
state->rotation = effective_rotation;
|
||||
if (needs_swap) {
|
||||
state->width = state->native_height;
|
||||
state->height = state->native_width;
|
||||
} else {
|
||||
state->width = state->native_width;
|
||||
state->height = state->native_height;
|
||||
}
|
||||
|
||||
xSemaphoreGive(state->rotation_mutex);
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
error_t gc0308_get_frame(Gc0308Handle handle, uint8_t** buf, size_t* len, uint32_t timeout_ms, uint32_t* out_width, uint32_t* out_height) {
|
||||
if (!handle || !buf || !len) return ERROR_INVALID_ARGUMENT;
|
||||
auto* state = static_cast<Gc0308State*>(handle);
|
||||
|
||||
struct pollfd poll_descriptor = { .fd = state->fd, .events = POLLIN };
|
||||
int poll_result = poll(&poll_descriptor, 1, static_cast<int>(timeout_ms));
|
||||
if (poll_result == 0) return ERROR_TIMEOUT;
|
||||
if (poll_result < 0) return ERROR_RESOURCE;
|
||||
|
||||
struct v4l2_buffer buffer = {};
|
||||
buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
buffer.memory = V4L2_MEMORY_MMAP;
|
||||
if (ioctl(state->fd, VIDIOC_DQBUF, &buffer) != 0) return ERROR_RESOURCE;
|
||||
state->last_dqbuf_index = static_cast<int>(buffer.index);
|
||||
|
||||
if (buffer.index >= VIDEO_BUFFER_COUNT || buffer.bytesused != state->frame_buf_size ||
|
||||
(buffer.flags & V4L2_BUF_FLAG_ERROR) != 0) {
|
||||
gc0308_release_frame(handle);
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
xSemaphoreTake(state->rotation_mutex, portMAX_DELAY);
|
||||
CameraRotation rotation = state->rotation;
|
||||
uint32_t frame_width = state->width;
|
||||
uint32_t frame_height = state->height;
|
||||
|
||||
size_t copy_length = state->frame_buf_size;
|
||||
const uint8_t* source = state->buffers[buffer.index];
|
||||
for (uint32_t y = 0; y < frame_height; y++) {
|
||||
for (uint32_t x = 0; x < frame_width; x++) {
|
||||
uint32_t source_x;
|
||||
uint32_t source_y;
|
||||
switch (rotation) {
|
||||
case CAMERA_ROTATION_90:
|
||||
source_x = y;
|
||||
source_y = state->native_height - 1 - x;
|
||||
break;
|
||||
case CAMERA_ROTATION_180:
|
||||
source_x = state->native_width - 1 - x;
|
||||
source_y = state->native_height - 1 - y;
|
||||
break;
|
||||
case CAMERA_ROTATION_270:
|
||||
source_x = state->native_width - 1 - y;
|
||||
source_y = x;
|
||||
break;
|
||||
default:
|
||||
source_x = x;
|
||||
source_y = y;
|
||||
break;
|
||||
}
|
||||
|
||||
size_t source_offset = ((size_t)source_y * state->native_width + source_x) * 2;
|
||||
size_t destination_offset = ((size_t)y * frame_width + x) * 2;
|
||||
if (source_offset + 1 >= copy_length) continue;
|
||||
state->frame_buf[destination_offset] = source[source_offset + 1];
|
||||
state->frame_buf[destination_offset + 1] = source[source_offset];
|
||||
}
|
||||
}
|
||||
xSemaphoreGive(state->rotation_mutex);
|
||||
|
||||
*buf = state->frame_buf;
|
||||
*len = (size_t)frame_width * frame_height * 2;
|
||||
if (out_width != nullptr) {
|
||||
*out_width = frame_width;
|
||||
}
|
||||
if (out_height != nullptr) {
|
||||
*out_height = frame_height;
|
||||
}
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
error_t gc0308_release_frame(Gc0308Handle handle) {
|
||||
if (!handle) return ERROR_INVALID_ARGUMENT;
|
||||
auto* state = static_cast<Gc0308State*>(handle);
|
||||
|
||||
if (state->last_dqbuf_index < 0) return ERROR_INVALID_STATE;
|
||||
struct v4l2_buffer buffer = {};
|
||||
buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
|
||||
buffer.memory = V4L2_MEMORY_MMAP;
|
||||
buffer.index = static_cast<uint32_t>(state->last_dqbuf_index);
|
||||
state->last_dqbuf_index = -1;
|
||||
return ioctl(state->fd, VIDIOC_QBUF, &buffer) == 0 ? ERROR_NONE : ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
uint32_t gc0308_get_width(Gc0308Handle handle) {
|
||||
if (!handle) return 0;
|
||||
auto* state = static_cast<Gc0308State*>(handle);
|
||||
xSemaphoreTake(state->rotation_mutex, portMAX_DELAY);
|
||||
uint32_t width = state->width;
|
||||
xSemaphoreGive(state->rotation_mutex);
|
||||
return width;
|
||||
}
|
||||
|
||||
uint32_t gc0308_get_height(Gc0308Handle handle) {
|
||||
if (!handle) return 0;
|
||||
auto* state = static_cast<Gc0308State*>(handle);
|
||||
xSemaphoreTake(state->rotation_mutex, portMAX_DELAY);
|
||||
uint32_t height = state->height;
|
||||
xSemaphoreGive(state->rotation_mutex);
|
||||
return height;
|
||||
}
|
||||
|
||||
error_t gc0308_capture_jpeg(Gc0308Handle handle, uint8_t** out_buf, size_t* out_len, uint8_t quality) {
|
||||
if (!handle || !out_buf || !out_len) return ERROR_INVALID_ARGUMENT;
|
||||
auto* state = static_cast<Gc0308State*>(handle);
|
||||
|
||||
// Dequeue one frame. Dimensions come back atomically with the frame data itself,
|
||||
// so they can't drift if a concurrent gc0308_set_rotation() changes state->width/height.
|
||||
uint8_t* frame = nullptr;
|
||||
size_t frame_len = 0;
|
||||
uint32_t frame_width = 0;
|
||||
uint32_t frame_height = 0;
|
||||
error_t err = gc0308_get_frame(handle, &frame, &frame_len, 500, &frame_width, &frame_height);
|
||||
if (err != ERROR_NONE) return err;
|
||||
if (frame == nullptr || frame_len == 0) {
|
||||
gc0308_release_frame(handle);
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
size_t image_size = (size_t)frame_width * frame_height * 2;
|
||||
uint8_t* aligned_input = static_cast<uint8_t*>(heap_caps_aligned_alloc(16, image_size, MALLOC_CAP_SPIRAM));
|
||||
uint8_t* jpeg_output = static_cast<uint8_t*>(heap_caps_aligned_alloc(16, image_size, MALLOC_CAP_SPIRAM));
|
||||
if (!aligned_input || !jpeg_output) {
|
||||
heap_caps_free(aligned_input);
|
||||
heap_caps_free(jpeg_output);
|
||||
gc0308_release_frame(handle);
|
||||
return ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
memcpy(aligned_input, frame, frame_len);
|
||||
if (state->encoder_width != frame_width || state->encoder_height != frame_height) {
|
||||
if (state->encoder) jpeg_enc_close(state->encoder);
|
||||
state->encoder = nullptr;
|
||||
jpeg_enc_config_t cfg = DEFAULT_JPEG_ENC_CONFIG();
|
||||
cfg.width = static_cast<int>(frame_width);
|
||||
cfg.height = static_cast<int>(frame_height);
|
||||
cfg.src_type = JPEG_PIXEL_FORMAT_RGB565_LE;
|
||||
cfg.subsampling = JPEG_SUBSAMPLE_420;
|
||||
cfg.quality = quality;
|
||||
if (jpeg_enc_open(&cfg, &state->encoder) != JPEG_ERR_OK) {
|
||||
heap_caps_free(aligned_input);
|
||||
heap_caps_free(jpeg_output);
|
||||
gc0308_release_frame(handle);
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
state->encoder_width = frame_width;
|
||||
state->encoder_height = frame_height;
|
||||
}
|
||||
jpeg_enc_set_quality(state->encoder, quality);
|
||||
int encoded_size = 0;
|
||||
jpeg_error_t encode_error = jpeg_enc_process(state->encoder, aligned_input, static_cast<int>(frame_len), jpeg_output, static_cast<int>(image_size), &encoded_size);
|
||||
heap_caps_free(aligned_input);
|
||||
gc0308_release_frame(handle);
|
||||
|
||||
if (encode_error != JPEG_ERR_OK || encoded_size <= 0) {
|
||||
LOG_E(TAG, "JPEG conversion failed: %d", static_cast<int>(encode_error));
|
||||
heap_caps_free(jpeg_output);
|
||||
return ERROR_RESOURCE;
|
||||
}
|
||||
|
||||
*out_buf = jpeg_output;
|
||||
*out_len = encoded_size;
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
CameraApi gc0308_camera_api = {
|
||||
.open = gc0308_open,
|
||||
.close = gc0308_close,
|
||||
.get_frame = gc0308_get_frame,
|
||||
.release_frame = gc0308_release_frame,
|
||||
.get_width = gc0308_get_width,
|
||||
.get_height = gc0308_get_height,
|
||||
.set_rotation = gc0308_set_rotation,
|
||||
.capture_jpeg = gc0308_capture_jpeg
|
||||
};
|
||||
|
||||
Driver gc0308_driver = {
|
||||
.name = "gc0308",
|
||||
.compatible = (const char*[]) { "galaxycore,gc0308", nullptr },
|
||||
.start_device = start,
|
||||
.stop_device = stop,
|
||||
.api = &gc0308_camera_api,
|
||||
.device_type = &CAMERA_TYPE,
|
||||
.owner = &gc0308_module,
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
} // extern "C"
|
||||
23
Drivers/gc0308-module/source/module.cpp
Normal file
23
Drivers/gc0308-module/source/module.cpp
Normal file
@ -0,0 +1,23 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
#include <tactility/driver.h>
|
||||
#include <tactility/module.h>
|
||||
|
||||
extern "C" {
|
||||
|
||||
extern Driver gc0308_driver;
|
||||
|
||||
static Driver* const gc0308_drivers[] = {
|
||||
&gc0308_driver,
|
||||
nullptr
|
||||
};
|
||||
|
||||
Module gc0308_module = {
|
||||
.name = "gc0308",
|
||||
.start = nullptr,
|
||||
.stop = nullptr,
|
||||
.drivers = gc0308_drivers,
|
||||
.symbols = nullptr,
|
||||
.internal = nullptr
|
||||
};
|
||||
|
||||
} // extern "C"
|
||||
@ -1,5 +1,31 @@
|
||||
description: InvenSense (TDK) MPU-6886 6-axis IMU
|
||||
|
||||
include: ["i2c-device.yaml"]
|
||||
include: [ "i2c-device.yaml" ]
|
||||
|
||||
compatible: "invensense,mpu6886"
|
||||
|
||||
properties:
|
||||
swap-xy:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Swap the X and Y axes
|
||||
swap-xz:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Swap the X and Z axes
|
||||
swap-yz:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Swap the Y and Z axes
|
||||
invert-x:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Invert the X axis
|
||||
invert-y:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Invert the Y axis
|
||||
invert-z:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Invert the Z axis
|
||||
|
||||
@ -14,6 +14,12 @@ extern "C" {
|
||||
struct Mpu6886Config {
|
||||
/** Address on bus */
|
||||
uint8_t address;
|
||||
bool swap_xy;
|
||||
bool swap_xz;
|
||||
bool swap_yz;
|
||||
bool invert_x;
|
||||
bool invert_y;
|
||||
bool invert_z;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -5,6 +5,8 @@
|
||||
#include <tactility/drivers/i2c_controller.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#define TAG "MPU6886"
|
||||
|
||||
// Register map
|
||||
@ -139,9 +141,21 @@ error_t mpu6886_read_accel(Device* device, ImuAccelData* data) {
|
||||
error_t error = i2c_controller_read_register(i2c_controller, address, REG_ACCEL_XOUT_H, buf, sizeof(buf), I2C_TIMEOUT_TICKS);
|
||||
if (error != ERROR_NONE) return error;
|
||||
|
||||
data->ax = toI16(buf[0], buf[1]) * ACCEL_SCALE;
|
||||
data->ay = toI16(buf[2], buf[3]) * ACCEL_SCALE;
|
||||
data->az = toI16(buf[4], buf[5]) * ACCEL_SCALE;
|
||||
float axes[3] = {
|
||||
toI16(buf[0], buf[1]) * ACCEL_SCALE,
|
||||
toI16(buf[2], buf[3]) * ACCEL_SCALE,
|
||||
toI16(buf[4], buf[5]) * ACCEL_SCALE,
|
||||
};
|
||||
const auto& config = *GET_CONFIG(device);
|
||||
if (config.swap_xy) std::swap(axes[0], axes[1]);
|
||||
if (config.swap_xz) std::swap(axes[0], axes[2]);
|
||||
if (config.swap_yz) std::swap(axes[1], axes[2]);
|
||||
if (config.invert_x) axes[0] = -axes[0];
|
||||
if (config.invert_y) axes[1] = -axes[1];
|
||||
if (config.invert_z) axes[2] = -axes[2];
|
||||
data->ax = axes[0];
|
||||
data->ay = axes[1];
|
||||
data->az = axes[2];
|
||||
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
@ -3,3 +3,29 @@ description: QST QMI8658 6-axis IMU
|
||||
include: [ "i2c-device.yaml" ]
|
||||
|
||||
compatible: "qst,qmi8658"
|
||||
|
||||
properties:
|
||||
swap-xy:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Swap the X and Y axes
|
||||
swap-xz:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Swap the X and Z axes
|
||||
swap-yz:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Swap the Y and Z axes
|
||||
invert-x:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Invert the X axis
|
||||
invert-y:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Invert the Y axis
|
||||
invert-z:
|
||||
type: boolean
|
||||
default: false
|
||||
description: Invert the Z axis
|
||||
|
||||
@ -14,6 +14,12 @@ extern "C" {
|
||||
struct Qmi8658Config {
|
||||
/** I2C address (0x6A when SA0=low, 0x6B when SA0=high) */
|
||||
uint8_t address;
|
||||
bool swap_xy;
|
||||
bool swap_xz;
|
||||
bool swap_yz;
|
||||
bool invert_x;
|
||||
bool invert_y;
|
||||
bool invert_z;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -5,6 +5,8 @@
|
||||
#include <tactility/drivers/i2c_controller.h>
|
||||
#include <tactility/log.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#define TAG "QMI8658"
|
||||
|
||||
// Register map (QMI8658 datasheet)
|
||||
@ -107,9 +109,21 @@ error_t qmi8658_read_accel(Device* device, ImuAccelData* data) {
|
||||
return static_cast<int16_t>(static_cast<uint16_t>(hi) << 8 | lo);
|
||||
};
|
||||
|
||||
data->ax = toI16(buf[0], buf[1]) * ACCEL_SCALE;
|
||||
data->ay = toI16(buf[2], buf[3]) * ACCEL_SCALE;
|
||||
data->az = toI16(buf[4], buf[5]) * ACCEL_SCALE;
|
||||
float axes[3] = {
|
||||
toI16(buf[0], buf[1]) * ACCEL_SCALE,
|
||||
toI16(buf[2], buf[3]) * ACCEL_SCALE,
|
||||
toI16(buf[4], buf[5]) * ACCEL_SCALE,
|
||||
};
|
||||
const auto& config = *GET_CONFIG(device);
|
||||
if (config.swap_xy) std::swap(axes[0], axes[1]);
|
||||
if (config.swap_xz) std::swap(axes[0], axes[2]);
|
||||
if (config.swap_yz) std::swap(axes[1], axes[2]);
|
||||
if (config.invert_x) axes[0] = -axes[0];
|
||||
if (config.invert_y) axes[1] = -axes[1];
|
||||
if (config.invert_z) axes[2] = -axes[2];
|
||||
data->ax = axes[0];
|
||||
data->ay = axes[1];
|
||||
data->az = axes[2];
|
||||
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
@ -5,11 +5,13 @@ include: [ "i2c-device.yaml" ]
|
||||
compatible: "smartsens,sc2356"
|
||||
|
||||
properties:
|
||||
rotation-offset:
|
||||
type: int
|
||||
enum: [ 0, 90, 180, 270 ]
|
||||
default: 0
|
||||
description: Clockwise mounting correction in degrees (0, 90, 180 or 270).
|
||||
pin-reset:
|
||||
type: phandles
|
||||
default: GPIO_PIN_SPEC_NONE
|
||||
description: >
|
||||
Reset GPIO pin. Pulsed (asserted then released, with a settle delay) before the sensor is
|
||||
probed in start_device. Typically wired through a board's IO expander rather than a direct
|
||||
SoC GPIO, so it's handled here via the generic gpio_descriptor API rather than
|
||||
esp_video_init's csi_config.reset_pin (which only accepts native SoC GPIOs).
|
||||
Reset GPIO pin. Pulsed (asserted then released, with a settle delay) before the sensor is probed in start_device. Typically wired through a board's IO expander rather than a direct SoC GPIO, so it's handled here via the generic gpio_descriptor API rather than esp_video_init's csi_config.reset_pin (which only accepts native SoC GPIOs).
|
||||
|
||||
@ -18,6 +18,9 @@ struct Sc2356Config {
|
||||
/** SCCB I2C address (0x36) */
|
||||
uint8_t address;
|
||||
|
||||
/** Clockwise mounting correction applied after the requested display rotation. */
|
||||
uint16_t rotation_offset;
|
||||
|
||||
// Reset pin. GPIO_PIN_SPEC_NONE if the sensor's reset is tied high on the board (or otherwise
|
||||
// not under our control), in which case start_device skips the reset pulse entirely and goes
|
||||
// straight to probing.
|
||||
|
||||
@ -64,6 +64,10 @@ struct Sc2356State : CameraHandleData {
|
||||
|
||||
#define GET_CONFIG(device) (static_cast<const Sc2356Config*>((device)->config))
|
||||
|
||||
static CameraRotation add_rotation(CameraRotation rotation, uint16_t offset) {
|
||||
return static_cast<CameraRotation>((static_cast<uint16_t>(rotation) + offset) % 360);
|
||||
}
|
||||
|
||||
// Reset timings per the SC2356/SC202CS datasheet's power-up sequence: hold reset asserted for at
|
||||
// least 1ms, then wait for the sensor's internal power-on/clock startup (datasheet specifies a
|
||||
// minimum before the first SCCB transaction - 10ms gives comfortable margin) before probing.
|
||||
@ -170,7 +174,7 @@ error_t sc2356_open(Device* device, Sc2356Handle* out_handle) {
|
||||
return ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
state->rotation = CAMERA_ROTATION_0;
|
||||
state->rotation = add_rotation(CAMERA_ROTATION_0, GET_CONFIG(device)->rotation_offset);
|
||||
|
||||
// Retrieve bus handle from the parent I2C controller
|
||||
auto* i2c = device_get_parent(device);
|
||||
@ -390,17 +394,18 @@ error_t sc2356_close(Sc2356Handle handle) {
|
||||
error_t sc2356_set_rotation(Sc2356Handle handle, CameraRotation rotation) {
|
||||
if (!handle) return ERROR_INVALID_ARGUMENT;
|
||||
auto* state = static_cast<Sc2356State*>(handle);
|
||||
CameraRotation effective_rotation = add_rotation(rotation, GET_CONFIG(state->device)->rotation_offset);
|
||||
|
||||
xSemaphoreTake(state->rotation_mutex, portMAX_DELAY);
|
||||
|
||||
if (state->rotation == rotation) {
|
||||
if (state->rotation == effective_rotation) {
|
||||
xSemaphoreGive(state->rotation_mutex);
|
||||
return ERROR_NONE;
|
||||
}
|
||||
|
||||
bool needs_swap = (rotation == CAMERA_ROTATION_90 || rotation == CAMERA_ROTATION_270);
|
||||
bool needs_swap = (effective_rotation == CAMERA_ROTATION_90 || effective_rotation == CAMERA_ROTATION_270);
|
||||
|
||||
state->rotation = rotation;
|
||||
state->rotation = effective_rotation;
|
||||
if (needs_swap) {
|
||||
state->width = state->native_height;
|
||||
state->height = state->native_width;
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
# ST7123 display + touch controller
|
||||
|
||||
- Datasheet: https://m5stack-doc.oss-cn-shenzhen.aliyuncs.com/1132/ST7123_SPEC_Preliminary_V0.5.pdf
|
||||
- Datasheet: https://m5stack-doc.oss-cn-shenzhen.aliyuncs.com/1132/ST7123-TDDI-Interface-Protocol-V01.11.pdf.pdf
|
||||
|
||||
Two drivers for the Sitronix `ST7123`, sharing this module since they're the same physical chip
|
||||
family and commonly used together:
|
||||
|
||||
|
||||
@ -111,6 +111,9 @@ shared_symbol_code_point_names = [
|
||||
"usb", # Power (settings) app
|
||||
"wifi", # WiFi (settings) app
|
||||
"bluetooth", # Bluetooth (settings) app
|
||||
"terminal",
|
||||
"logo_dev",
|
||||
"camera",
|
||||
]
|
||||
|
||||
# Get more from https://fonts.google.com/icons?icon.set=Material+Symbols&icon.style=Rounded
|
||||
|
||||
@ -45,3 +45,6 @@
|
||||
#define LVGL_ICON_SHARED_USB "\xEE\x87\xA0"
|
||||
#define LVGL_ICON_SHARED_WIFI "\xEE\x98\xBE"
|
||||
#define LVGL_ICON_SHARED_BLUETOOTH "\xEE\x86\xA7"
|
||||
#define LVGL_ICON_SHARED_TERMINAL "\xEE\xAE\x8E"
|
||||
#define LVGL_ICON_SHARED_LOGO_DEV "\xEE\xAB\x96"
|
||||
#define LVGL_ICON_SHARED_CAMERA "\xEE\x8E\xAF"
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/*******************************************************************************
|
||||
* Size: 12 px
|
||||
* Bpp: 2
|
||||
* Opts: --no-compress --no-prefilter --bpp 2 --size 12 --font MaterialSymbolsRounded.ttf -r 0xE145,0xE5C3,0xE770,0xEF40,0xEBCC,0xEFE6,0xEF4A,0xE5CD,0xF15C,0xE668,0xE92E,0xE326,0xEB97,0xE745,0xEC1C,0xE2C7,0xF720,0xF090,0xE8AF,0xE30F,0xE8FD,0xE9F4,0xE3F4,0xE316,0xE90F,0xEA07,0xE9B9,0xE159,0xE5D2,0xE28D,0xE5D4,0xE405,0xE89C,0xF8C7,0xE5D5,0xEF7A,0xE8B8,0xE9F7,0xE55D,0xF028,0xE1E0,0xE63E,0xE1A7 --format lvgl -o ../source-fonts/material_symbols_shared_12.c --force-fast-kern-format
|
||||
* Opts: --no-compress --no-prefilter --bpp 2 --size 12 --font MaterialSymbolsRounded.ttf -r 0xE145,0xE5C3,0xE770,0xEF40,0xEBCC,0xEFE6,0xEF4A,0xE5CD,0xF15C,0xE668,0xE92E,0xE326,0xEB97,0xE745,0xEC1C,0xE2C7,0xF720,0xF090,0xE8AF,0xE30F,0xE8FD,0xE9F4,0xE3F4,0xE316,0xE90F,0xEA07,0xE9B9,0xE159,0xE5D2,0xE28D,0xE5D4,0xE405,0xE89C,0xF8C7,0xE5D5,0xEF7A,0xE8B8,0xE9F7,0xE55D,0xF028,0xE1E0,0xE63E,0xE1A7,0xEB8E,0xEAD6,0xE3AF --format lvgl -o ../source-fonts/material_symbols_shared_12.c --force-fast-kern-format
|
||||
******************************************************************************/
|
||||
|
||||
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||
@ -67,6 +67,12 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
||||
0x0, 0xc3, 0xa0, 0xc, 0x37, 0xa4, 0xc3, 0x1a,
|
||||
0x4c, 0x3f, 0xfc, 0xff,
|
||||
|
||||
/* U+E3AF "" */
|
||||
0x6, 0xf9, 0x2, 0xd2, 0x78, 0x74, 0x50, 0xd9,
|
||||
0x8e, 0xaa, 0xc3, 0xf4, 0x3c, 0x1f, 0xc3, 0xaa,
|
||||
0xb2, 0x67, 0x5, 0x1d, 0x2d, 0x87, 0x80, 0x6f,
|
||||
0x90,
|
||||
|
||||
/* U+E3F4 "" */
|
||||
0x15, 0x55, 0xb, 0xaa, 0xac, 0x90, 0x0, 0xc9,
|
||||
0x0, 0xc, 0x90, 0x0, 0xc9, 0x1, 0xc, 0x97,
|
||||
@ -178,6 +184,17 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
||||
0xff, 0xe7, 0x31, 0xcd, 0x2e, 0xab, 0x80, 0x6f,
|
||||
0x90,
|
||||
|
||||
/* U+EAD6 "" */
|
||||
0x15, 0x55, 0x7, 0xaa, 0xac, 0xa0, 0x0, 0x9a,
|
||||
0x4, 0x9, 0xa6, 0x86, 0x9a, 0x68, 0xd9, 0xa9,
|
||||
0x94, 0x9a, 0x0, 0x9, 0x65, 0x55, 0xd2, 0xaa,
|
||||
0xa8,
|
||||
|
||||
/* U+EB8E "" */
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0, 0x3c,
|
||||
0xa0, 0x3, 0xc3, 0x40, 0x3c, 0xa1, 0x93, 0xc0,
|
||||
0x19, 0x3f, 0xff, 0xff,
|
||||
|
||||
/* U+EB97 "" */
|
||||
0x15, 0x55, 0x4e, 0xaa, 0xab, 0xc0, 0x0, 0x3c,
|
||||
0xaa, 0x63, 0xc1, 0x0, 0x3c, 0xdf, 0xf3, 0xc1,
|
||||
@ -261,39 +278,42 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
|
||||
{.bitmap_index = 152, .adv_w = 192, .box_w = 6, .box_h = 4, .ofs_x = 3, .ofs_y = 4},
|
||||
{.bitmap_index = 158, .adv_w = 192, .box_w = 10, .box_h = 8, .ofs_x = 1, .ofs_y = 2},
|
||||
{.bitmap_index = 178, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 203, .adv_w = 192, .box_w = 6, .box_h = 10, .ofs_x = 3, .ofs_y = 1},
|
||||
{.bitmap_index = 218, .adv_w = 192, .box_w = 8, .box_h = 10, .ofs_x = 2, .ofs_y = 1},
|
||||
{.bitmap_index = 238, .adv_w = 192, .box_w = 8, .box_h = 8, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 254, .adv_w = 192, .box_w = 8, .box_h = 8, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 270, .adv_w = 192, .box_w = 10, .box_h = 6, .ofs_x = 1, .ofs_y = 3},
|
||||
{.bitmap_index = 285, .adv_w = 192, .box_w = 2, .box_h = 8, .ofs_x = 5, .ofs_y = 2},
|
||||
{.bitmap_index = 289, .adv_w = 192, .box_w = 8, .box_h = 8, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 305, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 332, .adv_w = 192, .box_w = 8, .box_h = 6, .ofs_x = 2, .ofs_y = 3},
|
||||
{.bitmap_index = 344, .adv_w = 192, .box_w = 9, .box_h = 8, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 362, .adv_w = 192, .box_w = 10, .box_h = 9, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 385, .adv_w = 192, .box_w = 8, .box_h = 10, .ofs_x = 2, .ofs_y = 1},
|
||||
{.bitmap_index = 405, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 203, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 228, .adv_w = 192, .box_w = 6, .box_h = 10, .ofs_x = 3, .ofs_y = 1},
|
||||
{.bitmap_index = 243, .adv_w = 192, .box_w = 8, .box_h = 10, .ofs_x = 2, .ofs_y = 1},
|
||||
{.bitmap_index = 263, .adv_w = 192, .box_w = 8, .box_h = 8, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 279, .adv_w = 192, .box_w = 8, .box_h = 8, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 295, .adv_w = 192, .box_w = 10, .box_h = 6, .ofs_x = 1, .ofs_y = 3},
|
||||
{.bitmap_index = 310, .adv_w = 192, .box_w = 2, .box_h = 8, .ofs_x = 5, .ofs_y = 2},
|
||||
{.bitmap_index = 314, .adv_w = 192, .box_w = 8, .box_h = 8, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 330, .adv_w = 192, .box_w = 12, .box_h = 9, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 357, .adv_w = 192, .box_w = 8, .box_h = 6, .ofs_x = 2, .ofs_y = 3},
|
||||
{.bitmap_index = 369, .adv_w = 192, .box_w = 9, .box_h = 8, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 387, .adv_w = 192, .box_w = 10, .box_h = 9, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 410, .adv_w = 192, .box_w = 8, .box_h = 10, .ofs_x = 2, .ofs_y = 1},
|
||||
{.bitmap_index = 430, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 455, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 480, .adv_w = 192, .box_w = 8, .box_h = 10, .ofs_x = 2, .ofs_y = 1},
|
||||
{.bitmap_index = 500, .adv_w = 192, .box_w = 8, .box_h = 10, .ofs_x = 2, .ofs_y = 1},
|
||||
{.bitmap_index = 520, .adv_w = 192, .box_w = 10, .box_h = 8, .ofs_x = 1, .ofs_y = 2},
|
||||
{.bitmap_index = 540, .adv_w = 192, .box_w = 12, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 576, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 480, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 505, .adv_w = 192, .box_w = 8, .box_h = 10, .ofs_x = 2, .ofs_y = 1},
|
||||
{.bitmap_index = 525, .adv_w = 192, .box_w = 8, .box_h = 10, .ofs_x = 2, .ofs_y = 1},
|
||||
{.bitmap_index = 545, .adv_w = 192, .box_w = 10, .box_h = 8, .ofs_x = 1, .ofs_y = 2},
|
||||
{.bitmap_index = 565, .adv_w = 192, .box_w = 12, .box_h = 12, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 601, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 626, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 651, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 676, .adv_w = 192, .box_w = 8, .box_h = 10, .ofs_x = 2, .ofs_y = 1},
|
||||
{.bitmap_index = 696, .adv_w = 192, .box_w = 9, .box_h = 8, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 714, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 739, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 764, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 789, .adv_w = 192, .box_w = 12, .box_h = 8, .ofs_x = 0, .ofs_y = 2},
|
||||
{.bitmap_index = 813, .adv_w = 192, .box_w = 8, .box_h = 8, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 829, .adv_w = 192, .box_w = 12, .box_h = 8, .ofs_x = 0, .ofs_y = 2},
|
||||
{.bitmap_index = 853, .adv_w = 192, .box_w = 9, .box_h = 10, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 876, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1}
|
||||
{.bitmap_index = 676, .adv_w = 192, .box_w = 10, .box_h = 8, .ofs_x = 1, .ofs_y = 2},
|
||||
{.bitmap_index = 696, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 721, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 746, .adv_w = 192, .box_w = 8, .box_h = 10, .ofs_x = 2, .ofs_y = 1},
|
||||
{.bitmap_index = 766, .adv_w = 192, .box_w = 9, .box_h = 8, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 784, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 809, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 834, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 859, .adv_w = 192, .box_w = 12, .box_h = 8, .ofs_x = 0, .ofs_y = 2},
|
||||
{.bitmap_index = 883, .adv_w = 192, .box_w = 8, .box_h = 8, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 899, .adv_w = 192, .box_w = 12, .box_h = 8, .ofs_x = 0, .ofs_y = 2},
|
||||
{.bitmap_index = 923, .adv_w = 192, .box_w = 9, .box_h = 10, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 946, .adv_w = 192, .box_w = 10, .box_h = 10, .ofs_x = 1, .ofs_y = 1}
|
||||
};
|
||||
|
||||
/*---------------------
|
||||
@ -302,11 +322,11 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
|
||||
|
||||
static const uint16_t unicode_list_0[] = {
|
||||
0x0, 0x14, 0x62, 0x9b, 0x148, 0x182, 0x1ca, 0x1d1,
|
||||
0x1e1, 0x2af, 0x2c0, 0x418, 0x47e, 0x488, 0x48d, 0x48f,
|
||||
0x490, 0x4f9, 0x523, 0x600, 0x62b, 0x757, 0x76a, 0x773,
|
||||
0x7b8, 0x7ca, 0x7e9, 0x874, 0x8af, 0x8b2, 0x8c2, 0xa52,
|
||||
0xa87, 0xad7, 0xdfb, 0xe05, 0xe35, 0xea1, 0xee3, 0xf4b,
|
||||
0x1017, 0x15db, 0x1782
|
||||
0x1e1, 0x26a, 0x2af, 0x2c0, 0x418, 0x47e, 0x488, 0x48d,
|
||||
0x48f, 0x490, 0x4f9, 0x523, 0x600, 0x62b, 0x757, 0x76a,
|
||||
0x773, 0x7b8, 0x7ca, 0x7e9, 0x874, 0x8af, 0x8b2, 0x8c2,
|
||||
0x991, 0xa49, 0xa52, 0xa87, 0xad7, 0xdfb, 0xe05, 0xe35,
|
||||
0xea1, 0xee3, 0xf4b, 0x1017, 0x15db, 0x1782
|
||||
};
|
||||
|
||||
/*Collect the unicode lists and glyph_id offsets*/
|
||||
@ -314,7 +334,7 @@ static const lv_font_fmt_txt_cmap_t cmaps[] =
|
||||
{
|
||||
{
|
||||
.range_start = 57669, .range_length = 6019, .glyph_id_start = 1,
|
||||
.unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 43, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
||||
.unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 46, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/*******************************************************************************
|
||||
* Size: 16 px
|
||||
* Bpp: 2
|
||||
* Opts: --no-compress --no-prefilter --bpp 2 --size 16 --font MaterialSymbolsRounded.ttf -r 0xE145,0xE5C3,0xE770,0xEF40,0xEBCC,0xEFE6,0xEF4A,0xE5CD,0xF15C,0xE668,0xE92E,0xE326,0xEB97,0xE745,0xEC1C,0xE2C7,0xF720,0xF090,0xE8AF,0xE30F,0xE8FD,0xE9F4,0xE3F4,0xE316,0xE90F,0xEA07,0xE9B9,0xE159,0xE5D2,0xE28D,0xE5D4,0xE405,0xE89C,0xF8C7,0xE5D5,0xEF7A,0xE8B8,0xE9F7,0xE55D,0xF028,0xE1E0,0xE63E,0xE1A7 --format lvgl -o ../source-fonts/material_symbols_shared_16.c --force-fast-kern-format
|
||||
* Opts: --no-compress --no-prefilter --bpp 2 --size 16 --font MaterialSymbolsRounded.ttf -r 0xE145,0xE5C3,0xE770,0xEF40,0xEBCC,0xEFE6,0xEF4A,0xE5CD,0xF15C,0xE668,0xE92E,0xE326,0xEB97,0xE745,0xEC1C,0xE2C7,0xF720,0xF090,0xE8AF,0xE30F,0xE8FD,0xE9F4,0xE3F4,0xE316,0xE90F,0xEA07,0xE9B9,0xE159,0xE5D2,0xE28D,0xE5D4,0xE405,0xE89C,0xF8C7,0xE5D5,0xEF7A,0xE8B8,0xE9F7,0xE55D,0xF028,0xE1E0,0xE63E,0xE1A7,0xEB8E,0xEAD6,0xE3AF --format lvgl -o ../source-fonts/material_symbols_shared_16.c --force-fast-kern-format
|
||||
******************************************************************************/
|
||||
|
||||
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||
@ -88,6 +88,15 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
||||
0x55, 0xd, 0xd, 0xbf, 0xfc, 0xff, 0xd1, 0x55,
|
||||
0x1, 0x54,
|
||||
|
||||
/* U+E3AF "" */
|
||||
0x0, 0x15, 0x40, 0x0, 0x1f, 0xff, 0x40, 0xb,
|
||||
0x42, 0x2e, 0x2, 0xd0, 0x50, 0x34, 0x36, 0xc,
|
||||
0x1, 0xcb, 0x1a, 0xfe, 0xad, 0xa0, 0xbf, 0xc0,
|
||||
0xea, 0x3, 0xfd, 0xe, 0xba, 0xbf, 0x60, 0xd7,
|
||||
0x0, 0x30, 0x9c, 0x3c, 0x9, 0xb, 0x80, 0xf4,
|
||||
0x80, 0xf0, 0x3, 0xfa, 0xfc, 0x0, 0x6, 0xf9,
|
||||
0x0,
|
||||
|
||||
/* U+E3F4 "" */
|
||||
0xbf, 0xff, 0xfe, 0xe5, 0x55, 0x5b, 0xd0, 0x0,
|
||||
0x7, 0xd0, 0x0, 0x7, 0xd0, 0x0, 0x7, 0xd0,
|
||||
@ -245,6 +254,21 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
||||
0x5c, 0xf0, 0x3, 0xff, 0xfc, 0x0, 0x6, 0xf9,
|
||||
0x0,
|
||||
|
||||
/* U+EAD6 "" */
|
||||
0xbf, 0xff, 0xfe, 0xe5, 0x55, 0x5b, 0xd0, 0x0,
|
||||
0x7, 0xd0, 0x0, 0x7, 0xdf, 0x7a, 0x27, 0xdc,
|
||||
0xa1, 0x77, 0xdc, 0xa0, 0xe7, 0xdf, 0x78, 0xc7,
|
||||
0xd0, 0x0, 0x7, 0xd0, 0x0, 0x7, 0xe5, 0x55,
|
||||
0x5b, 0xbf, 0xff, 0xfe,
|
||||
|
||||
/* U+EB8E "" */
|
||||
0x2a, 0xaa, 0xaa, 0x4f, 0xff, 0xff, 0xfd, 0xff,
|
||||
0xff, 0xff, 0xde, 0x0, 0x0, 0xd, 0xd2, 0x40,
|
||||
0x0, 0xdd, 0x1d, 0x0, 0xd, 0xd0, 0xb0, 0x0,
|
||||
0xdd, 0x1e, 0x0, 0xd, 0xd2, 0x83, 0xf8, 0xdd,
|
||||
0x0, 0x15, 0xd, 0xbf, 0xff, 0xff, 0xd1, 0x55,
|
||||
0x55, 0x50,
|
||||
|
||||
/* U+EB97 "" */
|
||||
0x7f, 0xff, 0xff, 0xce, 0x55, 0x55, 0x5d, 0xd0,
|
||||
0x0, 0x0, 0xdd, 0x15, 0x53, 0x4d, 0xd1, 0x55,
|
||||
@ -356,40 +380,43 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
|
||||
{.bitmap_index = 240, .adv_w = 256, .box_w = 14, .box_h = 14, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 289, .adv_w = 256, .box_w = 8, .box_h = 5, .ofs_x = 4, .ofs_y = 6},
|
||||
{.bitmap_index = 299, .adv_w = 256, .box_w = 14, .box_h = 12, .ofs_x = 1, .ofs_y = 2},
|
||||
{.bitmap_index = 341, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 377, .adv_w = 256, .box_w = 8, .box_h = 12, .ofs_x = 4, .ofs_y = 2},
|
||||
{.bitmap_index = 401, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 437, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 473, .adv_w = 256, .box_w = 10, .box_h = 10, .ofs_x = 3, .ofs_y = 3},
|
||||
{.bitmap_index = 498, .adv_w = 256, .box_w = 12, .box_h = 8, .ofs_x = 2, .ofs_y = 4},
|
||||
{.bitmap_index = 522, .adv_w = 256, .box_w = 4, .box_h = 12, .ofs_x = 6, .ofs_y = 2},
|
||||
{.bitmap_index = 534, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 570, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 2},
|
||||
{.bitmap_index = 618, .adv_w = 256, .box_w = 12, .box_h = 8, .ofs_x = 2, .ofs_y = 4},
|
||||
{.bitmap_index = 642, .adv_w = 256, .box_w = 13, .box_h = 12, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 681, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 717, .adv_w = 256, .box_w = 12, .box_h = 14, .ofs_x = 2, .ofs_y = 1},
|
||||
{.bitmap_index = 759, .adv_w = 256, .box_w = 14, .box_h = 13, .ofs_x = 1, .ofs_y = 2},
|
||||
{.bitmap_index = 805, .adv_w = 256, .box_w = 14, .box_h = 14, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 341, .adv_w = 256, .box_w = 14, .box_h = 14, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 390, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 426, .adv_w = 256, .box_w = 8, .box_h = 12, .ofs_x = 4, .ofs_y = 2},
|
||||
{.bitmap_index = 450, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 486, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 522, .adv_w = 256, .box_w = 10, .box_h = 10, .ofs_x = 3, .ofs_y = 3},
|
||||
{.bitmap_index = 547, .adv_w = 256, .box_w = 12, .box_h = 8, .ofs_x = 2, .ofs_y = 4},
|
||||
{.bitmap_index = 571, .adv_w = 256, .box_w = 4, .box_h = 12, .ofs_x = 6, .ofs_y = 2},
|
||||
{.bitmap_index = 583, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 619, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 2},
|
||||
{.bitmap_index = 667, .adv_w = 256, .box_w = 12, .box_h = 8, .ofs_x = 2, .ofs_y = 4},
|
||||
{.bitmap_index = 691, .adv_w = 256, .box_w = 13, .box_h = 12, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 730, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 766, .adv_w = 256, .box_w = 12, .box_h = 14, .ofs_x = 2, .ofs_y = 1},
|
||||
{.bitmap_index = 808, .adv_w = 256, .box_w = 14, .box_h = 13, .ofs_x = 1, .ofs_y = 2},
|
||||
{.bitmap_index = 854, .adv_w = 256, .box_w = 14, .box_h = 14, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 903, .adv_w = 256, .box_w = 10, .box_h = 14, .ofs_x = 3, .ofs_y = 1},
|
||||
{.bitmap_index = 938, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 974, .adv_w = 256, .box_w = 14, .box_h = 12, .ofs_x = 1, .ofs_y = 2},
|
||||
{.bitmap_index = 1016, .adv_w = 256, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 1080, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 1116, .adv_w = 256, .box_w = 14, .box_h = 14, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 1165, .adv_w = 256, .box_w = 14, .box_h = 13, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 1211, .adv_w = 256, .box_w = 12, .box_h = 14, .ofs_x = 2, .ofs_y = 1},
|
||||
{.bitmap_index = 1253, .adv_w = 256, .box_w = 12, .box_h = 14, .ofs_x = 2, .ofs_y = 1},
|
||||
{.bitmap_index = 1295, .adv_w = 256, .box_w = 13, .box_h = 12, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 1334, .adv_w = 256, .box_w = 14, .box_h = 14, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 1383, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 1419, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 1455, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 2},
|
||||
{.bitmap_index = 1503, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 1539, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 2},
|
||||
{.bitmap_index = 1587, .adv_w = 256, .box_w = 12, .box_h = 14, .ofs_x = 2, .ofs_y = 1},
|
||||
{.bitmap_index = 1629, .adv_w = 256, .box_w = 14, .box_h = 14, .ofs_x = 1, .ofs_y = 1}
|
||||
{.bitmap_index = 903, .adv_w = 256, .box_w = 14, .box_h = 14, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 952, .adv_w = 256, .box_w = 10, .box_h = 14, .ofs_x = 3, .ofs_y = 1},
|
||||
{.bitmap_index = 987, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 1023, .adv_w = 256, .box_w = 14, .box_h = 12, .ofs_x = 1, .ofs_y = 2},
|
||||
{.bitmap_index = 1065, .adv_w = 256, .box_w = 16, .box_h = 16, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 1129, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 1165, .adv_w = 256, .box_w = 14, .box_h = 14, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 1214, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 1250, .adv_w = 256, .box_w = 14, .box_h = 12, .ofs_x = 1, .ofs_y = 2},
|
||||
{.bitmap_index = 1292, .adv_w = 256, .box_w = 14, .box_h = 13, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 1338, .adv_w = 256, .box_w = 12, .box_h = 14, .ofs_x = 2, .ofs_y = 1},
|
||||
{.bitmap_index = 1380, .adv_w = 256, .box_w = 12, .box_h = 14, .ofs_x = 2, .ofs_y = 1},
|
||||
{.bitmap_index = 1422, .adv_w = 256, .box_w = 13, .box_h = 12, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 1461, .adv_w = 256, .box_w = 14, .box_h = 14, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 1510, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 1546, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 1582, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 2},
|
||||
{.bitmap_index = 1630, .adv_w = 256, .box_w = 12, .box_h = 12, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 1666, .adv_w = 256, .box_w = 16, .box_h = 12, .ofs_x = 0, .ofs_y = 2},
|
||||
{.bitmap_index = 1714, .adv_w = 256, .box_w = 12, .box_h = 14, .ofs_x = 2, .ofs_y = 1},
|
||||
{.bitmap_index = 1756, .adv_w = 256, .box_w = 14, .box_h = 14, .ofs_x = 1, .ofs_y = 1}
|
||||
};
|
||||
|
||||
/*---------------------
|
||||
@ -398,11 +425,11 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
|
||||
|
||||
static const uint16_t unicode_list_0[] = {
|
||||
0x0, 0x14, 0x62, 0x9b, 0x148, 0x182, 0x1ca, 0x1d1,
|
||||
0x1e1, 0x2af, 0x2c0, 0x418, 0x47e, 0x488, 0x48d, 0x48f,
|
||||
0x490, 0x4f9, 0x523, 0x600, 0x62b, 0x757, 0x76a, 0x773,
|
||||
0x7b8, 0x7ca, 0x7e9, 0x874, 0x8af, 0x8b2, 0x8c2, 0xa52,
|
||||
0xa87, 0xad7, 0xdfb, 0xe05, 0xe35, 0xea1, 0xee3, 0xf4b,
|
||||
0x1017, 0x15db, 0x1782
|
||||
0x1e1, 0x26a, 0x2af, 0x2c0, 0x418, 0x47e, 0x488, 0x48d,
|
||||
0x48f, 0x490, 0x4f9, 0x523, 0x600, 0x62b, 0x757, 0x76a,
|
||||
0x773, 0x7b8, 0x7ca, 0x7e9, 0x874, 0x8af, 0x8b2, 0x8c2,
|
||||
0x991, 0xa49, 0xa52, 0xa87, 0xad7, 0xdfb, 0xe05, 0xe35,
|
||||
0xea1, 0xee3, 0xf4b, 0x1017, 0x15db, 0x1782
|
||||
};
|
||||
|
||||
/*Collect the unicode lists and glyph_id offsets*/
|
||||
@ -410,7 +437,7 @@ static const lv_font_fmt_txt_cmap_t cmaps[] =
|
||||
{
|
||||
{
|
||||
.range_start = 57669, .range_length = 6019, .glyph_id_start = 1,
|
||||
.unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 43, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
||||
.unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 46, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/*******************************************************************************
|
||||
* Size: 20 px
|
||||
* Bpp: 2
|
||||
* Opts: --no-compress --no-prefilter --bpp 2 --size 20 --font MaterialSymbolsRounded.ttf -r 0xE145,0xE5C3,0xE770,0xEF40,0xEBCC,0xEFE6,0xEF4A,0xE5CD,0xF15C,0xE668,0xE92E,0xE326,0xEB97,0xE745,0xEC1C,0xE2C7,0xF720,0xF090,0xE8AF,0xE30F,0xE8FD,0xE9F4,0xE3F4,0xE316,0xE90F,0xEA07,0xE9B9,0xE159,0xE5D2,0xE28D,0xE5D4,0xE405,0xE89C,0xF8C7,0xE5D5,0xEF7A,0xE8B8,0xE9F7,0xE55D,0xF028,0xE1E0,0xE63E,0xE1A7 --format lvgl -o ../source-fonts/material_symbols_shared_20.c --force-fast-kern-format
|
||||
* Opts: --no-compress --no-prefilter --bpp 2 --size 20 --font MaterialSymbolsRounded.ttf -r 0xE145,0xE5C3,0xE770,0xEF40,0xEBCC,0xEFE6,0xEF4A,0xE5CD,0xF15C,0xE668,0xE92E,0xE326,0xEB97,0xE745,0xEC1C,0xE2C7,0xF720,0xF090,0xE8AF,0xE30F,0xE8FD,0xE9F4,0xE3F4,0xE316,0xE90F,0xEA07,0xE9B9,0xE159,0xE5D2,0xE28D,0xE5D4,0xE405,0xE89C,0xF8C7,0xE5D5,0xEF7A,0xE8B8,0xE9F7,0xE55D,0xF028,0xE1E0,0xE63E,0xE1A7,0xEB8E,0xEAD6,0xE3AF --format lvgl -o ../source-fonts/material_symbols_shared_20.c --force-fast-kern-format
|
||||
******************************************************************************/
|
||||
|
||||
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||
@ -107,6 +107,19 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
||||
0x80, 0xe0, 0x0, 0x0, 0x38, 0xe, 0x3f, 0xff,
|
||||
0xc3, 0xff, 0xe2, 0xaa, 0xa4, 0x1a, 0xa8,
|
||||
|
||||
/* U+E3AF "" */
|
||||
0x0, 0x1, 0x54, 0x0, 0x0, 0x2, 0xff, 0xfc,
|
||||
0x0, 0x1, 0xf9, 0x1e, 0xf4, 0x0, 0x7c, 0x2,
|
||||
0x3, 0xd0, 0xf, 0x80, 0x20, 0xf, 0x2, 0xd8,
|
||||
0x8, 0x0, 0x38, 0x3c, 0x21, 0xea, 0xab, 0xc3,
|
||||
0x82, 0x7f, 0xd0, 0x1d, 0x34, 0xf, 0xff, 0x1,
|
||||
0xd3, 0x40, 0xbf, 0xf4, 0x1d, 0x38, 0x7, 0xfc,
|
||||
0xc1, 0xc3, 0xea, 0xab, 0x46, 0x3c, 0x1d, 0x0,
|
||||
0x20, 0x3b, 0x80, 0xb0, 0x5, 0x1, 0xf0, 0x3,
|
||||
0xc0, 0x80, 0x7c, 0x0, 0xb, 0xaa, 0xbf, 0x0,
|
||||
0x0, 0x1b, 0xfe, 0x40, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0,
|
||||
|
||||
/* U+E3F4 "" */
|
||||
0x1a, 0xaa, 0xaa, 0xa4, 0x7f, 0xff, 0xff, 0xfd,
|
||||
0xb0, 0x0, 0x0, 0xe, 0xb0, 0x0, 0x0, 0xe,
|
||||
@ -320,6 +333,26 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
||||
0x0, 0x1b, 0xfe, 0x40, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0,
|
||||
|
||||
/* U+EAD6 "" */
|
||||
0x1a, 0xaa, 0xaa, 0xa4, 0x7f, 0xff, 0xff, 0xfd,
|
||||
0x70, 0x0, 0x0, 0xe, 0xb0, 0x0, 0x0, 0xe,
|
||||
0xb0, 0x0, 0x0, 0xe, 0xb2, 0x92, 0x84, 0x4e,
|
||||
0xb3, 0xbb, 0x8c, 0xce, 0xb3, 0x3a, 0xc, 0xce,
|
||||
0xb3, 0x3b, 0x4a, 0x8e, 0xb3, 0x3a, 0x7, 0x4e,
|
||||
0xb2, 0x92, 0x82, 0xe, 0xb0, 0x0, 0x0, 0xe,
|
||||
0xb0, 0x0, 0x0, 0xe, 0x70, 0x0, 0x0, 0xe,
|
||||
0x7f, 0xff, 0xff, 0xfd, 0x1a, 0xaa, 0xaa, 0xa4,
|
||||
|
||||
/* U+EB8E "" */
|
||||
0x5, 0x55, 0x55, 0x55, 0x43, 0xff, 0xff, 0xff,
|
||||
0xfd, 0x3f, 0xff, 0xff, 0xff, 0xe3, 0xff, 0xff,
|
||||
0xff, 0xfe, 0x38, 0x0, 0x0, 0x0, 0xe3, 0x87,
|
||||
0x40, 0x0, 0xe, 0x38, 0x3d, 0x0, 0x0, 0xe3,
|
||||
0x80, 0xf4, 0x0, 0xe, 0x38, 0xf, 0x0, 0x0,
|
||||
0xe3, 0x83, 0xc0, 0x69, 0xe, 0x38, 0x20, 0x2f,
|
||||
0xf0, 0xe3, 0x80, 0x0, 0x0, 0xe, 0x3f, 0xff,
|
||||
0xff, 0xff, 0xd1, 0xaa, 0xaa, 0xaa, 0xa8,
|
||||
|
||||
/* U+EB97 "" */
|
||||
0xa, 0xaa, 0xaa, 0xaa, 0x43, 0xff, 0xff, 0xff,
|
||||
0xfd, 0x38, 0x0, 0x0, 0x0, 0xe3, 0x80, 0x0,
|
||||
@ -466,40 +499,43 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
|
||||
{.bitmap_index = 355, .adv_w = 320, .box_w = 18, .box_h = 18, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 436, .adv_w = 320, .box_w = 10, .box_h = 6, .ofs_x = 5, .ofs_y = 7},
|
||||
{.bitmap_index = 451, .adv_w = 320, .box_w = 18, .box_h = 14, .ofs_x = 1, .ofs_y = 3},
|
||||
{.bitmap_index = 514, .adv_w = 320, .box_w = 16, .box_h = 16, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 578, .adv_w = 320, .box_w = 10, .box_h = 16, .ofs_x = 5, .ofs_y = 2},
|
||||
{.bitmap_index = 618, .adv_w = 320, .box_w = 14, .box_h = 16, .ofs_x = 3, .ofs_y = 2},
|
||||
{.bitmap_index = 674, .adv_w = 320, .box_w = 14, .box_h = 14, .ofs_x = 3, .ofs_y = 3},
|
||||
{.bitmap_index = 723, .adv_w = 320, .box_w = 12, .box_h = 12, .ofs_x = 4, .ofs_y = 4},
|
||||
{.bitmap_index = 759, .adv_w = 320, .box_w = 16, .box_h = 10, .ofs_x = 2, .ofs_y = 5},
|
||||
{.bitmap_index = 799, .adv_w = 320, .box_w = 4, .box_h = 14, .ofs_x = 8, .ofs_y = 3},
|
||||
{.bitmap_index = 813, .adv_w = 320, .box_w = 14, .box_h = 14, .ofs_x = 3, .ofs_y = 3},
|
||||
{.bitmap_index = 862, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 2},
|
||||
{.bitmap_index = 937, .adv_w = 320, .box_w = 14, .box_h = 10, .ofs_x = 3, .ofs_y = 5},
|
||||
{.bitmap_index = 972, .adv_w = 320, .box_w = 16, .box_h = 14, .ofs_x = 3, .ofs_y = 3},
|
||||
{.bitmap_index = 1028, .adv_w = 320, .box_w = 16, .box_h = 14, .ofs_x = 2, .ofs_y = 3},
|
||||
{.bitmap_index = 1084, .adv_w = 320, .box_w = 14, .box_h = 18, .ofs_x = 3, .ofs_y = 1},
|
||||
{.bitmap_index = 1147, .adv_w = 320, .box_w = 18, .box_h = 17, .ofs_x = 1, .ofs_y = 2},
|
||||
{.bitmap_index = 1224, .adv_w = 320, .box_w = 17, .box_h = 18, .ofs_x = 2, .ofs_y = 1},
|
||||
{.bitmap_index = 1301, .adv_w = 320, .box_w = 18, .box_h = 18, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 1382, .adv_w = 320, .box_w = 14, .box_h = 18, .ofs_x = 3, .ofs_y = 1},
|
||||
{.bitmap_index = 1445, .adv_w = 320, .box_w = 14, .box_h = 16, .ofs_x = 3, .ofs_y = 2},
|
||||
{.bitmap_index = 1501, .adv_w = 320, .box_w = 18, .box_h = 14, .ofs_x = 1, .ofs_y = 3},
|
||||
{.bitmap_index = 1564, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 1664, .adv_w = 320, .box_w = 16, .box_h = 16, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 1728, .adv_w = 320, .box_w = 18, .box_h = 18, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 1809, .adv_w = 320, .box_w = 18, .box_h = 16, .ofs_x = 1, .ofs_y = 2},
|
||||
{.bitmap_index = 1881, .adv_w = 320, .box_w = 16, .box_h = 18, .ofs_x = 2, .ofs_y = 1},
|
||||
{.bitmap_index = 1953, .adv_w = 320, .box_w = 14, .box_h = 18, .ofs_x = 3, .ofs_y = 1},
|
||||
{.bitmap_index = 2016, .adv_w = 320, .box_w = 16, .box_h = 14, .ofs_x = 3, .ofs_y = 3},
|
||||
{.bitmap_index = 2072, .adv_w = 320, .box_w = 18, .box_h = 18, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 2153, .adv_w = 320, .box_w = 16, .box_h = 15, .ofs_x = 2, .ofs_y = 3},
|
||||
{.bitmap_index = 2213, .adv_w = 320, .box_w = 16, .box_h = 16, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 2277, .adv_w = 320, .box_w = 20, .box_h = 14, .ofs_x = 0, .ofs_y = 3},
|
||||
{.bitmap_index = 2347, .adv_w = 320, .box_w = 14, .box_h = 14, .ofs_x = 3, .ofs_y = 3},
|
||||
{.bitmap_index = 2396, .adv_w = 320, .box_w = 20, .box_h = 14, .ofs_x = 0, .ofs_y = 3},
|
||||
{.bitmap_index = 2466, .adv_w = 320, .box_w = 16, .box_h = 18, .ofs_x = 2, .ofs_y = 1},
|
||||
{.bitmap_index = 2538, .adv_w = 320, .box_w = 18, .box_h = 18, .ofs_x = 1, .ofs_y = 1}
|
||||
{.bitmap_index = 514, .adv_w = 320, .box_w = 18, .box_h = 18, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 595, .adv_w = 320, .box_w = 16, .box_h = 16, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 659, .adv_w = 320, .box_w = 10, .box_h = 16, .ofs_x = 5, .ofs_y = 2},
|
||||
{.bitmap_index = 699, .adv_w = 320, .box_w = 14, .box_h = 16, .ofs_x = 3, .ofs_y = 2},
|
||||
{.bitmap_index = 755, .adv_w = 320, .box_w = 14, .box_h = 14, .ofs_x = 3, .ofs_y = 3},
|
||||
{.bitmap_index = 804, .adv_w = 320, .box_w = 12, .box_h = 12, .ofs_x = 4, .ofs_y = 4},
|
||||
{.bitmap_index = 840, .adv_w = 320, .box_w = 16, .box_h = 10, .ofs_x = 2, .ofs_y = 5},
|
||||
{.bitmap_index = 880, .adv_w = 320, .box_w = 4, .box_h = 14, .ofs_x = 8, .ofs_y = 3},
|
||||
{.bitmap_index = 894, .adv_w = 320, .box_w = 14, .box_h = 14, .ofs_x = 3, .ofs_y = 3},
|
||||
{.bitmap_index = 943, .adv_w = 320, .box_w = 20, .box_h = 15, .ofs_x = 0, .ofs_y = 2},
|
||||
{.bitmap_index = 1018, .adv_w = 320, .box_w = 14, .box_h = 10, .ofs_x = 3, .ofs_y = 5},
|
||||
{.bitmap_index = 1053, .adv_w = 320, .box_w = 16, .box_h = 14, .ofs_x = 3, .ofs_y = 3},
|
||||
{.bitmap_index = 1109, .adv_w = 320, .box_w = 16, .box_h = 14, .ofs_x = 2, .ofs_y = 3},
|
||||
{.bitmap_index = 1165, .adv_w = 320, .box_w = 14, .box_h = 18, .ofs_x = 3, .ofs_y = 1},
|
||||
{.bitmap_index = 1228, .adv_w = 320, .box_w = 18, .box_h = 17, .ofs_x = 1, .ofs_y = 2},
|
||||
{.bitmap_index = 1305, .adv_w = 320, .box_w = 17, .box_h = 18, .ofs_x = 2, .ofs_y = 1},
|
||||
{.bitmap_index = 1382, .adv_w = 320, .box_w = 18, .box_h = 18, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 1463, .adv_w = 320, .box_w = 14, .box_h = 18, .ofs_x = 3, .ofs_y = 1},
|
||||
{.bitmap_index = 1526, .adv_w = 320, .box_w = 14, .box_h = 16, .ofs_x = 3, .ofs_y = 2},
|
||||
{.bitmap_index = 1582, .adv_w = 320, .box_w = 18, .box_h = 14, .ofs_x = 1, .ofs_y = 3},
|
||||
{.bitmap_index = 1645, .adv_w = 320, .box_w = 20, .box_h = 20, .ofs_x = 0, .ofs_y = 0},
|
||||
{.bitmap_index = 1745, .adv_w = 320, .box_w = 16, .box_h = 16, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 1809, .adv_w = 320, .box_w = 18, .box_h = 18, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 1890, .adv_w = 320, .box_w = 16, .box_h = 16, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 1954, .adv_w = 320, .box_w = 18, .box_h = 14, .ofs_x = 1, .ofs_y = 3},
|
||||
{.bitmap_index = 2017, .adv_w = 320, .box_w = 18, .box_h = 16, .ofs_x = 1, .ofs_y = 2},
|
||||
{.bitmap_index = 2089, .adv_w = 320, .box_w = 16, .box_h = 18, .ofs_x = 2, .ofs_y = 1},
|
||||
{.bitmap_index = 2161, .adv_w = 320, .box_w = 14, .box_h = 18, .ofs_x = 3, .ofs_y = 1},
|
||||
{.bitmap_index = 2224, .adv_w = 320, .box_w = 16, .box_h = 14, .ofs_x = 3, .ofs_y = 3},
|
||||
{.bitmap_index = 2280, .adv_w = 320, .box_w = 18, .box_h = 18, .ofs_x = 1, .ofs_y = 1},
|
||||
{.bitmap_index = 2361, .adv_w = 320, .box_w = 16, .box_h = 15, .ofs_x = 2, .ofs_y = 3},
|
||||
{.bitmap_index = 2421, .adv_w = 320, .box_w = 16, .box_h = 16, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 2485, .adv_w = 320, .box_w = 20, .box_h = 14, .ofs_x = 0, .ofs_y = 3},
|
||||
{.bitmap_index = 2555, .adv_w = 320, .box_w = 14, .box_h = 14, .ofs_x = 3, .ofs_y = 3},
|
||||
{.bitmap_index = 2604, .adv_w = 320, .box_w = 20, .box_h = 14, .ofs_x = 0, .ofs_y = 3},
|
||||
{.bitmap_index = 2674, .adv_w = 320, .box_w = 16, .box_h = 18, .ofs_x = 2, .ofs_y = 1},
|
||||
{.bitmap_index = 2746, .adv_w = 320, .box_w = 18, .box_h = 18, .ofs_x = 1, .ofs_y = 1}
|
||||
};
|
||||
|
||||
/*---------------------
|
||||
@ -508,11 +544,11 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
|
||||
|
||||
static const uint16_t unicode_list_0[] = {
|
||||
0x0, 0x14, 0x62, 0x9b, 0x148, 0x182, 0x1ca, 0x1d1,
|
||||
0x1e1, 0x2af, 0x2c0, 0x418, 0x47e, 0x488, 0x48d, 0x48f,
|
||||
0x490, 0x4f9, 0x523, 0x600, 0x62b, 0x757, 0x76a, 0x773,
|
||||
0x7b8, 0x7ca, 0x7e9, 0x874, 0x8af, 0x8b2, 0x8c2, 0xa52,
|
||||
0xa87, 0xad7, 0xdfb, 0xe05, 0xe35, 0xea1, 0xee3, 0xf4b,
|
||||
0x1017, 0x15db, 0x1782
|
||||
0x1e1, 0x26a, 0x2af, 0x2c0, 0x418, 0x47e, 0x488, 0x48d,
|
||||
0x48f, 0x490, 0x4f9, 0x523, 0x600, 0x62b, 0x757, 0x76a,
|
||||
0x773, 0x7b8, 0x7ca, 0x7e9, 0x874, 0x8af, 0x8b2, 0x8c2,
|
||||
0x991, 0xa49, 0xa52, 0xa87, 0xad7, 0xdfb, 0xe05, 0xe35,
|
||||
0xea1, 0xee3, 0xf4b, 0x1017, 0x15db, 0x1782
|
||||
};
|
||||
|
||||
/*Collect the unicode lists and glyph_id offsets*/
|
||||
@ -520,7 +556,7 @@ static const lv_font_fmt_txt_cmap_t cmaps[] =
|
||||
{
|
||||
{
|
||||
.range_start = 57669, .range_length = 6019, .glyph_id_start = 1,
|
||||
.unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 43, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
||||
.unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 46, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/*******************************************************************************
|
||||
* Size: 24 px
|
||||
* Bpp: 2
|
||||
* Opts: --no-compress --no-prefilter --bpp 2 --size 24 --font MaterialSymbolsRounded.ttf -r 0xE145,0xE5C3,0xE770,0xEF40,0xEBCC,0xEFE6,0xEF4A,0xE5CD,0xF15C,0xE668,0xE92E,0xE326,0xEB97,0xE745,0xEC1C,0xE2C7,0xF720,0xF090,0xE8AF,0xE30F,0xE8FD,0xE9F4,0xE3F4,0xE316,0xE90F,0xEA07,0xE9B9,0xE159,0xE5D2,0xE28D,0xE5D4,0xE405,0xE89C,0xF8C7,0xE5D5,0xEF7A,0xE8B8,0xE9F7,0xE55D,0xF028,0xE1E0,0xE63E,0xE1A7 --format lvgl -o ../source-fonts/material_symbols_shared_24.c --force-fast-kern-format
|
||||
* Opts: --no-compress --no-prefilter --bpp 2 --size 24 --font MaterialSymbolsRounded.ttf -r 0xE145,0xE5C3,0xE770,0xEF40,0xEBCC,0xEFE6,0xEF4A,0xE5CD,0xF15C,0xE668,0xE92E,0xE326,0xEB97,0xE745,0xEC1C,0xE2C7,0xF720,0xF090,0xE8AF,0xE30F,0xE8FD,0xE9F4,0xE3F4,0xE316,0xE90F,0xEA07,0xE9B9,0xE159,0xE5D2,0xE28D,0xE5D4,0xE405,0xE89C,0xF8C7,0xE5D5,0xEF7A,0xE8B8,0xE9F7,0xE55D,0xF028,0xE1E0,0xE63E,0xE1A7,0xEB8E,0xEAD6,0xE3AF --format lvgl -o ../source-fonts/material_symbols_shared_24.c --force-fast-kern-format
|
||||
******************************************************************************/
|
||||
|
||||
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||
@ -127,6 +127,21 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
||||
0xf, 0x0, 0x0, 0x0, 0xf0, 0xf, 0xff, 0xff,
|
||||
0xf0, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xbf, 0xfe,
|
||||
|
||||
/* U+E3AF "" */
|
||||
0x0, 0x6, 0xff, 0x90, 0x0, 0x0, 0x7f, 0xff,
|
||||
0xfd, 0x0, 0x2, 0xfd, 0x3, 0x7f, 0x80, 0xb,
|
||||
0xd0, 0x9, 0x7, 0xe0, 0x1f, 0x80, 0x1c, 0x1,
|
||||
0xf4, 0x3e, 0xc0, 0x34, 0x0, 0x7c, 0x7c, 0x60,
|
||||
0x70, 0x0, 0x3d, 0xb4, 0x30, 0xff, 0xff, 0xfe,
|
||||
0xf0, 0x1f, 0xff, 0xc0, 0xf, 0xf0, 0xb, 0xff,
|
||||
0xc0, 0xf, 0xf0, 0x3, 0xff, 0xe0, 0xf, 0xf0,
|
||||
0x3, 0xff, 0xf4, 0xf, 0xbf, 0xff, 0xff, 0xc,
|
||||
0x1e, 0x7c, 0x0, 0xd, 0x9, 0x3d, 0x3d, 0x0,
|
||||
0x1c, 0x3, 0xbc, 0x1f, 0x40, 0x34, 0x2, 0xf4,
|
||||
0xb, 0xd0, 0x60, 0x7, 0xe0, 0x2, 0xfd, 0xc0,
|
||||
0x7f, 0x80, 0x0, 0x7f, 0xff, 0xfd, 0x0, 0x0,
|
||||
0x6, 0xff, 0x90, 0x0,
|
||||
|
||||
/* U+E3F4 "" */
|
||||
0x7f, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff,
|
||||
0xff, 0xf0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0,
|
||||
@ -387,6 +402,31 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
||||
0xff, 0x80, 0x0, 0x7f, 0xff, 0xfd, 0x0, 0x0,
|
||||
0x6, 0xff, 0x90, 0x0,
|
||||
|
||||
/* U+EAD6 "" */
|
||||
0x7f, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff,
|
||||
0xff, 0xf0, 0x0, 0x0, 0x0, 0xff, 0x0, 0x0,
|
||||
0x0, 0xf, 0xf0, 0x0, 0x0, 0x0, 0xff, 0x0,
|
||||
0x0, 0x0, 0xf, 0xf3, 0xf3, 0xf3, 0xc, 0xff,
|
||||
0x32, 0x74, 0x35, 0xcf, 0xf3, 0x27, 0x82, 0xa8,
|
||||
0xff, 0x32, 0x78, 0x1f, 0x4f, 0xf3, 0x27, 0x40,
|
||||
0xf0, 0xff, 0x3f, 0x3f, 0xa, 0xf, 0xf0, 0x0,
|
||||
0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0xf, 0xf0,
|
||||
0x0, 0x0, 0x0, 0xff, 0x0, 0x0, 0x0, 0xf,
|
||||
0xff, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff, 0xff,
|
||||
0xfd,
|
||||
|
||||
/* U+EB8E "" */
|
||||
0x7f, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xf0, 0x0, 0x0, 0x0,
|
||||
0xf, 0xf0, 0x20, 0x0, 0x0, 0xf, 0xf0, 0x7c,
|
||||
0x0, 0x0, 0xf, 0xf0, 0x3f, 0x0, 0x0, 0xf,
|
||||
0xf0, 0xf, 0xc0, 0x0, 0xf, 0xf0, 0xf, 0xc0,
|
||||
0x0, 0xf, 0xf0, 0x3f, 0x0, 0x0, 0xf, 0xf0,
|
||||
0x7c, 0xf, 0xff, 0xf, 0xf0, 0x20, 0xf, 0xff,
|
||||
0xf, 0xf0, 0x0, 0x0, 0x0, 0xf, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xfd,
|
||||
|
||||
/* U+EB97 "" */
|
||||
0x7f, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xf0, 0x0, 0x0, 0x0, 0xf, 0xf0,
|
||||
@ -561,40 +601,43 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
|
||||
{.bitmap_index = 465, .adv_w = 384, .box_w = 20, .box_h = 20, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 565, .adv_w = 384, .box_w = 12, .box_h = 7, .ofs_x = 6, .ofs_y = 9},
|
||||
{.bitmap_index = 586, .adv_w = 384, .box_w = 20, .box_h = 16, .ofs_x = 2, .ofs_y = 4},
|
||||
{.bitmap_index = 666, .adv_w = 384, .box_w = 18, .box_h = 18, .ofs_x = 3, .ofs_y = 3},
|
||||
{.bitmap_index = 747, .adv_w = 384, .box_w = 12, .box_h = 18, .ofs_x = 6, .ofs_y = 3},
|
||||
{.bitmap_index = 801, .adv_w = 384, .box_w = 16, .box_h = 18, .ofs_x = 4, .ofs_y = 3},
|
||||
{.bitmap_index = 873, .adv_w = 384, .box_w = 16, .box_h = 16, .ofs_x = 4, .ofs_y = 4},
|
||||
{.bitmap_index = 937, .adv_w = 384, .box_w = 14, .box_h = 14, .ofs_x = 5, .ofs_y = 5},
|
||||
{.bitmap_index = 986, .adv_w = 384, .box_w = 18, .box_h = 12, .ofs_x = 3, .ofs_y = 6},
|
||||
{.bitmap_index = 1040, .adv_w = 384, .box_w = 4, .box_h = 16, .ofs_x = 10, .ofs_y = 4},
|
||||
{.bitmap_index = 1056, .adv_w = 384, .box_w = 16, .box_h = 16, .ofs_x = 4, .ofs_y = 4},
|
||||
{.bitmap_index = 1120, .adv_w = 384, .box_w = 24, .box_h = 17, .ofs_x = 0, .ofs_y = 3},
|
||||
{.bitmap_index = 1222, .adv_w = 384, .box_w = 16, .box_h = 12, .ofs_x = 4, .ofs_y = 6},
|
||||
{.bitmap_index = 1270, .adv_w = 384, .box_w = 18, .box_h = 16, .ofs_x = 4, .ofs_y = 4},
|
||||
{.bitmap_index = 1342, .adv_w = 384, .box_w = 18, .box_h = 17, .ofs_x = 3, .ofs_y = 4},
|
||||
{.bitmap_index = 1419, .adv_w = 384, .box_w = 16, .box_h = 20, .ofs_x = 4, .ofs_y = 2},
|
||||
{.bitmap_index = 1499, .adv_w = 384, .box_w = 20, .box_h = 19, .ofs_x = 2, .ofs_y = 3},
|
||||
{.bitmap_index = 1594, .adv_w = 384, .box_w = 20, .box_h = 20, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 666, .adv_w = 384, .box_w = 20, .box_h = 20, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 766, .adv_w = 384, .box_w = 18, .box_h = 18, .ofs_x = 3, .ofs_y = 3},
|
||||
{.bitmap_index = 847, .adv_w = 384, .box_w = 12, .box_h = 18, .ofs_x = 6, .ofs_y = 3},
|
||||
{.bitmap_index = 901, .adv_w = 384, .box_w = 16, .box_h = 18, .ofs_x = 4, .ofs_y = 3},
|
||||
{.bitmap_index = 973, .adv_w = 384, .box_w = 16, .box_h = 16, .ofs_x = 4, .ofs_y = 4},
|
||||
{.bitmap_index = 1037, .adv_w = 384, .box_w = 14, .box_h = 14, .ofs_x = 5, .ofs_y = 5},
|
||||
{.bitmap_index = 1086, .adv_w = 384, .box_w = 18, .box_h = 12, .ofs_x = 3, .ofs_y = 6},
|
||||
{.bitmap_index = 1140, .adv_w = 384, .box_w = 4, .box_h = 16, .ofs_x = 10, .ofs_y = 4},
|
||||
{.bitmap_index = 1156, .adv_w = 384, .box_w = 16, .box_h = 16, .ofs_x = 4, .ofs_y = 4},
|
||||
{.bitmap_index = 1220, .adv_w = 384, .box_w = 24, .box_h = 17, .ofs_x = 0, .ofs_y = 3},
|
||||
{.bitmap_index = 1322, .adv_w = 384, .box_w = 16, .box_h = 12, .ofs_x = 4, .ofs_y = 6},
|
||||
{.bitmap_index = 1370, .adv_w = 384, .box_w = 18, .box_h = 16, .ofs_x = 4, .ofs_y = 4},
|
||||
{.bitmap_index = 1442, .adv_w = 384, .box_w = 18, .box_h = 17, .ofs_x = 3, .ofs_y = 4},
|
||||
{.bitmap_index = 1519, .adv_w = 384, .box_w = 16, .box_h = 20, .ofs_x = 4, .ofs_y = 2},
|
||||
{.bitmap_index = 1599, .adv_w = 384, .box_w = 20, .box_h = 19, .ofs_x = 2, .ofs_y = 3},
|
||||
{.bitmap_index = 1694, .adv_w = 384, .box_w = 20, .box_h = 20, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 1794, .adv_w = 384, .box_w = 16, .box_h = 20, .ofs_x = 4, .ofs_y = 2},
|
||||
{.bitmap_index = 1874, .adv_w = 384, .box_w = 16, .box_h = 18, .ofs_x = 4, .ofs_y = 3},
|
||||
{.bitmap_index = 1946, .adv_w = 384, .box_w = 20, .box_h = 16, .ofs_x = 2, .ofs_y = 4},
|
||||
{.bitmap_index = 2026, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 2164, .adv_w = 384, .box_w = 18, .box_h = 18, .ofs_x = 3, .ofs_y = 3},
|
||||
{.bitmap_index = 2245, .adv_w = 384, .box_w = 20, .box_h = 20, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 2345, .adv_w = 384, .box_w = 20, .box_h = 18, .ofs_x = 2, .ofs_y = 3},
|
||||
{.bitmap_index = 2435, .adv_w = 384, .box_w = 18, .box_h = 20, .ofs_x = 3, .ofs_y = 2},
|
||||
{.bitmap_index = 2525, .adv_w = 384, .box_w = 16, .box_h = 20, .ofs_x = 4, .ofs_y = 2},
|
||||
{.bitmap_index = 2605, .adv_w = 384, .box_w = 18, .box_h = 16, .ofs_x = 4, .ofs_y = 4},
|
||||
{.bitmap_index = 2677, .adv_w = 384, .box_w = 20, .box_h = 20, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 2777, .adv_w = 384, .box_w = 18, .box_h = 18, .ofs_x = 3, .ofs_y = 3},
|
||||
{.bitmap_index = 2858, .adv_w = 384, .box_w = 18, .box_h = 18, .ofs_x = 3, .ofs_y = 3},
|
||||
{.bitmap_index = 2939, .adv_w = 384, .box_w = 22, .box_h = 16, .ofs_x = 1, .ofs_y = 4},
|
||||
{.bitmap_index = 3027, .adv_w = 384, .box_w = 16, .box_h = 16, .ofs_x = 4, .ofs_y = 4},
|
||||
{.bitmap_index = 3091, .adv_w = 384, .box_w = 22, .box_h = 16, .ofs_x = 1, .ofs_y = 4},
|
||||
{.bitmap_index = 3179, .adv_w = 384, .box_w = 18, .box_h = 20, .ofs_x = 3, .ofs_y = 2},
|
||||
{.bitmap_index = 3269, .adv_w = 384, .box_w = 20, .box_h = 20, .ofs_x = 2, .ofs_y = 2}
|
||||
{.bitmap_index = 1794, .adv_w = 384, .box_w = 20, .box_h = 20, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 1894, .adv_w = 384, .box_w = 16, .box_h = 20, .ofs_x = 4, .ofs_y = 2},
|
||||
{.bitmap_index = 1974, .adv_w = 384, .box_w = 16, .box_h = 18, .ofs_x = 4, .ofs_y = 3},
|
||||
{.bitmap_index = 2046, .adv_w = 384, .box_w = 20, .box_h = 16, .ofs_x = 2, .ofs_y = 4},
|
||||
{.bitmap_index = 2126, .adv_w = 384, .box_w = 24, .box_h = 23, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 2264, .adv_w = 384, .box_w = 18, .box_h = 18, .ofs_x = 3, .ofs_y = 3},
|
||||
{.bitmap_index = 2345, .adv_w = 384, .box_w = 20, .box_h = 20, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 2445, .adv_w = 384, .box_w = 18, .box_h = 18, .ofs_x = 3, .ofs_y = 3},
|
||||
{.bitmap_index = 2526, .adv_w = 384, .box_w = 20, .box_h = 16, .ofs_x = 2, .ofs_y = 4},
|
||||
{.bitmap_index = 2606, .adv_w = 384, .box_w = 20, .box_h = 18, .ofs_x = 2, .ofs_y = 3},
|
||||
{.bitmap_index = 2696, .adv_w = 384, .box_w = 18, .box_h = 20, .ofs_x = 3, .ofs_y = 2},
|
||||
{.bitmap_index = 2786, .adv_w = 384, .box_w = 16, .box_h = 20, .ofs_x = 4, .ofs_y = 2},
|
||||
{.bitmap_index = 2866, .adv_w = 384, .box_w = 18, .box_h = 16, .ofs_x = 4, .ofs_y = 4},
|
||||
{.bitmap_index = 2938, .adv_w = 384, .box_w = 20, .box_h = 20, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 3038, .adv_w = 384, .box_w = 18, .box_h = 18, .ofs_x = 3, .ofs_y = 3},
|
||||
{.bitmap_index = 3119, .adv_w = 384, .box_w = 18, .box_h = 18, .ofs_x = 3, .ofs_y = 3},
|
||||
{.bitmap_index = 3200, .adv_w = 384, .box_w = 22, .box_h = 16, .ofs_x = 1, .ofs_y = 4},
|
||||
{.bitmap_index = 3288, .adv_w = 384, .box_w = 16, .box_h = 16, .ofs_x = 4, .ofs_y = 4},
|
||||
{.bitmap_index = 3352, .adv_w = 384, .box_w = 22, .box_h = 16, .ofs_x = 1, .ofs_y = 4},
|
||||
{.bitmap_index = 3440, .adv_w = 384, .box_w = 18, .box_h = 20, .ofs_x = 3, .ofs_y = 2},
|
||||
{.bitmap_index = 3530, .adv_w = 384, .box_w = 20, .box_h = 20, .ofs_x = 2, .ofs_y = 2}
|
||||
};
|
||||
|
||||
/*---------------------
|
||||
@ -603,11 +646,11 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
|
||||
|
||||
static const uint16_t unicode_list_0[] = {
|
||||
0x0, 0x14, 0x62, 0x9b, 0x148, 0x182, 0x1ca, 0x1d1,
|
||||
0x1e1, 0x2af, 0x2c0, 0x418, 0x47e, 0x488, 0x48d, 0x48f,
|
||||
0x490, 0x4f9, 0x523, 0x600, 0x62b, 0x757, 0x76a, 0x773,
|
||||
0x7b8, 0x7ca, 0x7e9, 0x874, 0x8af, 0x8b2, 0x8c2, 0xa52,
|
||||
0xa87, 0xad7, 0xdfb, 0xe05, 0xe35, 0xea1, 0xee3, 0xf4b,
|
||||
0x1017, 0x15db, 0x1782
|
||||
0x1e1, 0x26a, 0x2af, 0x2c0, 0x418, 0x47e, 0x488, 0x48d,
|
||||
0x48f, 0x490, 0x4f9, 0x523, 0x600, 0x62b, 0x757, 0x76a,
|
||||
0x773, 0x7b8, 0x7ca, 0x7e9, 0x874, 0x8af, 0x8b2, 0x8c2,
|
||||
0x991, 0xa49, 0xa52, 0xa87, 0xad7, 0xdfb, 0xe05, 0xe35,
|
||||
0xea1, 0xee3, 0xf4b, 0x1017, 0x15db, 0x1782
|
||||
};
|
||||
|
||||
/*Collect the unicode lists and glyph_id offsets*/
|
||||
@ -615,7 +658,7 @@ static const lv_font_fmt_txt_cmap_t cmaps[] =
|
||||
{
|
||||
{
|
||||
.range_start = 57669, .range_length = 6019, .glyph_id_start = 1,
|
||||
.unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 43, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
||||
.unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 46, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
/*******************************************************************************
|
||||
* Size: 32 px
|
||||
* Bpp: 2
|
||||
* Opts: --no-compress --no-prefilter --bpp 2 --size 32 --font MaterialSymbolsRounded.ttf -r 0xE145,0xE5C3,0xE770,0xEF40,0xEBCC,0xEFE6,0xEF4A,0xE5CD,0xF15C,0xE668,0xE92E,0xE326,0xEB97,0xE745,0xEC1C,0xE2C7,0xF720,0xF090,0xE8AF,0xE30F,0xE8FD,0xE9F4,0xE3F4,0xE316,0xE90F,0xEA07,0xE9B9,0xE159,0xE5D2,0xE28D,0xE5D4,0xE405,0xE89C,0xF8C7,0xE5D5,0xEF7A,0xE8B8,0xE9F7,0xE55D,0xF028,0xE1E0,0xE63E,0xE1A7 --format lvgl -o ../source-fonts/material_symbols_shared_32.c --force-fast-kern-format
|
||||
* Opts: --no-compress --no-prefilter --bpp 2 --size 32 --font MaterialSymbolsRounded.ttf -r 0xE145,0xE5C3,0xE770,0xEF40,0xEBCC,0xEFE6,0xEF4A,0xE5CD,0xF15C,0xE668,0xE92E,0xE326,0xEB97,0xE745,0xEC1C,0xE2C7,0xF720,0xF090,0xE8AF,0xE30F,0xE8FD,0xE9F4,0xE3F4,0xE316,0xE90F,0xEA07,0xE9B9,0xE159,0xE5D2,0xE28D,0xE5D4,0xE405,0xE89C,0xF8C7,0xE5D5,0xEF7A,0xE8B8,0xE9F7,0xE55D,0xF028,0xE1E0,0xE63E,0xE1A7,0xEB8E,0xEAD6,0xE3AF --format lvgl -o ../source-fonts/material_symbols_shared_32.c --force-fast-kern-format
|
||||
******************************************************************************/
|
||||
|
||||
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
|
||||
@ -203,6 +203,33 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
||||
0x3f, 0xff, 0xfd, 0x2a, 0xaa, 0xaa, 0x90, 0xa,
|
||||
0xaa, 0xa4,
|
||||
|
||||
/* U+E3AF "" */
|
||||
0x0, 0x0, 0x1, 0x55, 0x40, 0x0, 0x0, 0x0,
|
||||
0x0, 0x2f, 0xff, 0xfd, 0x0, 0x0, 0x0, 0x2,
|
||||
0xff, 0xff, 0xff, 0xc0, 0x0, 0x0, 0x1f, 0xfe,
|
||||
0x42, 0xef, 0xf4, 0x0, 0x0, 0x7f, 0xd0, 0x3,
|
||||
0x42, 0xfe, 0x0, 0x1, 0xfe, 0x0, 0xb, 0x0,
|
||||
0x7f, 0x40, 0x3, 0xfc, 0x0, 0x1d, 0x0, 0x1f,
|
||||
0xc0, 0xb, 0xfd, 0x0, 0x38, 0x0, 0x7, 0xe0,
|
||||
0xf, 0xcb, 0x0, 0x70, 0x0, 0x3, 0xf4, 0x2f,
|
||||
0x43, 0x40, 0xf0, 0x0, 0x1, 0xf8, 0x3f, 0x2,
|
||||
0xc2, 0xff, 0xff, 0xff, 0xfc, 0x3e, 0x0, 0xe3,
|
||||
0xff, 0xf5, 0x55, 0xbc, 0x3e, 0x0, 0x7f, 0xff,
|
||||
0xf0, 0x0, 0x7d, 0x3d, 0x0, 0x3f, 0xff, 0xf4,
|
||||
0x0, 0x7d, 0x3d, 0x0, 0xf, 0xff, 0xfc, 0x0,
|
||||
0x7d, 0x3e, 0x0, 0xb, 0xff, 0xfe, 0x0, 0x7d,
|
||||
0x3f, 0x55, 0x5b, 0xff, 0xd7, 0x0, 0xbc, 0x2f,
|
||||
0xff, 0xff, 0xff, 0x83, 0xc0, 0xfc, 0x1f, 0x40,
|
||||
0x0, 0xf, 0x0, 0xd1, 0xf8, 0xf, 0xc0, 0x0,
|
||||
0xe, 0x0, 0xb3, 0xf0, 0x7, 0xe0, 0x0, 0x2c,
|
||||
0x0, 0x3f, 0xe0, 0x2, 0xf8, 0x0, 0x34, 0x0,
|
||||
0x2f, 0xc0, 0x0, 0xfe, 0x0, 0xe0, 0x0, 0xbf,
|
||||
0x0, 0x0, 0x3f, 0xd1, 0xc0, 0x7, 0xfc, 0x0,
|
||||
0x0, 0xb, 0xff, 0xea, 0xff, 0xf0, 0x0, 0x0,
|
||||
0x1, 0xff, 0xff, 0xff, 0x40, 0x0, 0x0, 0x0,
|
||||
0x1b, 0xff, 0xe4, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0,
|
||||
|
||||
/* U+E3F4 "" */
|
||||
0x2f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xbf, 0xff,
|
||||
0xff, 0xff, 0xff, 0xfe, 0xfe, 0xaa, 0xaa, 0xaa,
|
||||
@ -643,6 +670,48 @@ static LV_ATTRIBUTE_LARGE_CONST const uint8_t glyph_bitmap[] = {
|
||||
0x1b, 0xff, 0xe4, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0,
|
||||
|
||||
/* U+EAD6 "" */
|
||||
0x2f, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xbf, 0xff,
|
||||
0xff, 0xff, 0xff, 0xfe, 0xfe, 0xaa, 0xaa, 0xaa,
|
||||
0xaa, 0xbf, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f,
|
||||
0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xf8, 0x0,
|
||||
0x0, 0x0, 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x0,
|
||||
0x0, 0x2f, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f,
|
||||
0xf8, 0xff, 0x4f, 0xe7, 0x7, 0x2f, 0xf8, 0xe7,
|
||||
0xdd, 0x47, 0x4b, 0x2f, 0xf8, 0xd3, 0xdc, 0x3,
|
||||
0x8e, 0x2f, 0xf8, 0xd3, 0xdf, 0x82, 0xcd, 0x2f,
|
||||
0xf8, 0xd3, 0xde, 0x1, 0xec, 0x2f, 0xf8, 0xd3,
|
||||
0xdc, 0x0, 0xfc, 0x2f, 0xf8, 0xfb, 0xdf, 0x90,
|
||||
0xf8, 0x2f, 0xf8, 0xff, 0x4f, 0xe0, 0x70, 0x2f,
|
||||
0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xf8, 0x0,
|
||||
0x0, 0x0, 0x0, 0x2f, 0xf8, 0x0, 0x0, 0x0,
|
||||
0x0, 0x2f, 0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f,
|
||||
0xf8, 0x0, 0x0, 0x0, 0x0, 0x2f, 0xfe, 0xaa,
|
||||
0xaa, 0xaa, 0xaa, 0xbf, 0xbf, 0xff, 0xff, 0xff,
|
||||
0xff, 0xfe, 0x2f, 0xff, 0xff, 0xff, 0xff, 0xf8,
|
||||
|
||||
/* U+EB8E "" */
|
||||
0x1, 0x55, 0x55, 0x55, 0x55, 0x55, 0x50, 0x1f,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x3f, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xfd, 0x3f, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xfe, 0x3f, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xfe, 0x3e, 0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
0x3e, 0x3e, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3e,
|
||||
0x3e, 0x3, 0xe0, 0x0, 0x0, 0x0, 0x3e, 0x3e,
|
||||
0x3, 0xf8, 0x0, 0x0, 0x0, 0x3e, 0x3e, 0x0,
|
||||
0xfe, 0x0, 0x0, 0x0, 0x3e, 0x3e, 0x0, 0x3f,
|
||||
0x80, 0x0, 0x0, 0x3e, 0x3e, 0x0, 0x1f, 0xc0,
|
||||
0x0, 0x0, 0x3e, 0x3e, 0x0, 0x7f, 0x40, 0x0,
|
||||
0x0, 0x3e, 0x3e, 0x1, 0xfd, 0x0, 0x0, 0x0,
|
||||
0x3e, 0x3e, 0x3, 0xf4, 0x7, 0xff, 0xf0, 0x3e,
|
||||
0x3e, 0x3, 0xd0, 0xb, 0xff, 0xf0, 0x3e, 0x3e,
|
||||
0x0, 0x0, 0x2, 0xaa, 0x90, 0x3e, 0x3e, 0x0,
|
||||
0x0, 0x0, 0x0, 0x0, 0x3e, 0x3f, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xfd, 0x2f, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xfc, 0x6, 0xaa, 0xaa, 0xaa, 0xaa,
|
||||
0xaa, 0xa0,
|
||||
|
||||
/* U+EB97 "" */
|
||||
0xb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf4, 0x3f,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0x3f, 0xaa,
|
||||
@ -930,40 +999,43 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
|
||||
{.bitmap_index = 879, .adv_w = 512, .box_w = 28, .box_h = 28, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 1075, .adv_w = 512, .box_w = 16, .box_h = 9, .ofs_x = 8, .ofs_y = 12},
|
||||
{.bitmap_index = 1111, .adv_w = 512, .box_w = 28, .box_h = 22, .ofs_x = 2, .ofs_y = 5},
|
||||
{.bitmap_index = 1265, .adv_w = 512, .box_w = 24, .box_h = 24, .ofs_x = 4, .ofs_y = 4},
|
||||
{.bitmap_index = 1409, .adv_w = 512, .box_w = 16, .box_h = 24, .ofs_x = 8, .ofs_y = 4},
|
||||
{.bitmap_index = 1505, .adv_w = 512, .box_w = 22, .box_h = 24, .ofs_x = 5, .ofs_y = 4},
|
||||
{.bitmap_index = 1637, .adv_w = 512, .box_w = 22, .box_h = 22, .ofs_x = 5, .ofs_y = 5},
|
||||
{.bitmap_index = 1758, .adv_w = 512, .box_w = 18, .box_h = 18, .ofs_x = 7, .ofs_y = 7},
|
||||
{.bitmap_index = 1839, .adv_w = 512, .box_w = 24, .box_h = 16, .ofs_x = 4, .ofs_y = 8},
|
||||
{.bitmap_index = 1935, .adv_w = 512, .box_w = 6, .box_h = 22, .ofs_x = 13, .ofs_y = 5},
|
||||
{.bitmap_index = 1968, .adv_w = 512, .box_w = 22, .box_h = 22, .ofs_x = 5, .ofs_y = 5},
|
||||
{.bitmap_index = 2089, .adv_w = 512, .box_w = 32, .box_h = 23, .ofs_x = 0, .ofs_y = 4},
|
||||
{.bitmap_index = 2273, .adv_w = 512, .box_w = 22, .box_h = 16, .ofs_x = 5, .ofs_y = 8},
|
||||
{.bitmap_index = 2361, .adv_w = 512, .box_w = 25, .box_h = 22, .ofs_x = 5, .ofs_y = 5},
|
||||
{.bitmap_index = 2499, .adv_w = 512, .box_w = 24, .box_h = 22, .ofs_x = 4, .ofs_y = 5},
|
||||
{.bitmap_index = 2631, .adv_w = 512, .box_w = 22, .box_h = 28, .ofs_x = 5, .ofs_y = 2},
|
||||
{.bitmap_index = 2785, .adv_w = 512, .box_w = 28, .box_h = 26, .ofs_x = 2, .ofs_y = 4},
|
||||
{.bitmap_index = 2967, .adv_w = 512, .box_w = 26, .box_h = 28, .ofs_x = 3, .ofs_y = 2},
|
||||
{.bitmap_index = 3149, .adv_w = 512, .box_w = 28, .box_h = 28, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 3345, .adv_w = 512, .box_w = 20, .box_h = 28, .ofs_x = 6, .ofs_y = 2},
|
||||
{.bitmap_index = 3485, .adv_w = 512, .box_w = 22, .box_h = 24, .ofs_x = 5, .ofs_y = 4},
|
||||
{.bitmap_index = 3617, .adv_w = 512, .box_w = 28, .box_h = 22, .ofs_x = 2, .ofs_y = 5},
|
||||
{.bitmap_index = 3771, .adv_w = 512, .box_w = 32, .box_h = 31, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 4019, .adv_w = 512, .box_w = 24, .box_h = 24, .ofs_x = 4, .ofs_y = 4},
|
||||
{.bitmap_index = 4163, .adv_w = 512, .box_w = 28, .box_h = 28, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 4359, .adv_w = 512, .box_w = 28, .box_h = 24, .ofs_x = 2, .ofs_y = 4},
|
||||
{.bitmap_index = 4527, .adv_w = 512, .box_w = 24, .box_h = 28, .ofs_x = 4, .ofs_y = 2},
|
||||
{.bitmap_index = 4695, .adv_w = 512, .box_w = 22, .box_h = 28, .ofs_x = 5, .ofs_y = 2},
|
||||
{.bitmap_index = 4849, .adv_w = 512, .box_w = 25, .box_h = 22, .ofs_x = 5, .ofs_y = 5},
|
||||
{.bitmap_index = 4987, .adv_w = 512, .box_w = 28, .box_h = 28, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 5183, .adv_w = 512, .box_w = 24, .box_h = 24, .ofs_x = 4, .ofs_y = 4},
|
||||
{.bitmap_index = 5327, .adv_w = 512, .box_w = 24, .box_h = 24, .ofs_x = 4, .ofs_y = 4},
|
||||
{.bitmap_index = 5471, .adv_w = 512, .box_w = 30, .box_h = 22, .ofs_x = 1, .ofs_y = 5},
|
||||
{.bitmap_index = 5636, .adv_w = 512, .box_w = 22, .box_h = 22, .ofs_x = 5, .ofs_y = 5},
|
||||
{.bitmap_index = 5757, .adv_w = 512, .box_w = 30, .box_h = 22, .ofs_x = 1, .ofs_y = 5},
|
||||
{.bitmap_index = 5922, .adv_w = 512, .box_w = 25, .box_h = 28, .ofs_x = 4, .ofs_y = 2},
|
||||
{.bitmap_index = 6097, .adv_w = 512, .box_w = 28, .box_h = 28, .ofs_x = 2, .ofs_y = 2}
|
||||
{.bitmap_index = 1265, .adv_w = 512, .box_w = 28, .box_h = 28, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 1461, .adv_w = 512, .box_w = 24, .box_h = 24, .ofs_x = 4, .ofs_y = 4},
|
||||
{.bitmap_index = 1605, .adv_w = 512, .box_w = 16, .box_h = 24, .ofs_x = 8, .ofs_y = 4},
|
||||
{.bitmap_index = 1701, .adv_w = 512, .box_w = 22, .box_h = 24, .ofs_x = 5, .ofs_y = 4},
|
||||
{.bitmap_index = 1833, .adv_w = 512, .box_w = 22, .box_h = 22, .ofs_x = 5, .ofs_y = 5},
|
||||
{.bitmap_index = 1954, .adv_w = 512, .box_w = 18, .box_h = 18, .ofs_x = 7, .ofs_y = 7},
|
||||
{.bitmap_index = 2035, .adv_w = 512, .box_w = 24, .box_h = 16, .ofs_x = 4, .ofs_y = 8},
|
||||
{.bitmap_index = 2131, .adv_w = 512, .box_w = 6, .box_h = 22, .ofs_x = 13, .ofs_y = 5},
|
||||
{.bitmap_index = 2164, .adv_w = 512, .box_w = 22, .box_h = 22, .ofs_x = 5, .ofs_y = 5},
|
||||
{.bitmap_index = 2285, .adv_w = 512, .box_w = 32, .box_h = 23, .ofs_x = 0, .ofs_y = 4},
|
||||
{.bitmap_index = 2469, .adv_w = 512, .box_w = 22, .box_h = 16, .ofs_x = 5, .ofs_y = 8},
|
||||
{.bitmap_index = 2557, .adv_w = 512, .box_w = 25, .box_h = 22, .ofs_x = 5, .ofs_y = 5},
|
||||
{.bitmap_index = 2695, .adv_w = 512, .box_w = 24, .box_h = 22, .ofs_x = 4, .ofs_y = 5},
|
||||
{.bitmap_index = 2827, .adv_w = 512, .box_w = 22, .box_h = 28, .ofs_x = 5, .ofs_y = 2},
|
||||
{.bitmap_index = 2981, .adv_w = 512, .box_w = 28, .box_h = 26, .ofs_x = 2, .ofs_y = 4},
|
||||
{.bitmap_index = 3163, .adv_w = 512, .box_w = 26, .box_h = 28, .ofs_x = 3, .ofs_y = 2},
|
||||
{.bitmap_index = 3345, .adv_w = 512, .box_w = 28, .box_h = 28, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 3541, .adv_w = 512, .box_w = 20, .box_h = 28, .ofs_x = 6, .ofs_y = 2},
|
||||
{.bitmap_index = 3681, .adv_w = 512, .box_w = 22, .box_h = 24, .ofs_x = 5, .ofs_y = 4},
|
||||
{.bitmap_index = 3813, .adv_w = 512, .box_w = 28, .box_h = 22, .ofs_x = 2, .ofs_y = 5},
|
||||
{.bitmap_index = 3967, .adv_w = 512, .box_w = 32, .box_h = 31, .ofs_x = 0, .ofs_y = 1},
|
||||
{.bitmap_index = 4215, .adv_w = 512, .box_w = 24, .box_h = 24, .ofs_x = 4, .ofs_y = 4},
|
||||
{.bitmap_index = 4359, .adv_w = 512, .box_w = 28, .box_h = 28, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 4555, .adv_w = 512, .box_w = 24, .box_h = 24, .ofs_x = 4, .ofs_y = 4},
|
||||
{.bitmap_index = 4699, .adv_w = 512, .box_w = 28, .box_h = 22, .ofs_x = 2, .ofs_y = 5},
|
||||
{.bitmap_index = 4853, .adv_w = 512, .box_w = 28, .box_h = 24, .ofs_x = 2, .ofs_y = 4},
|
||||
{.bitmap_index = 5021, .adv_w = 512, .box_w = 24, .box_h = 28, .ofs_x = 4, .ofs_y = 2},
|
||||
{.bitmap_index = 5189, .adv_w = 512, .box_w = 22, .box_h = 28, .ofs_x = 5, .ofs_y = 2},
|
||||
{.bitmap_index = 5343, .adv_w = 512, .box_w = 25, .box_h = 22, .ofs_x = 5, .ofs_y = 5},
|
||||
{.bitmap_index = 5481, .adv_w = 512, .box_w = 28, .box_h = 28, .ofs_x = 2, .ofs_y = 2},
|
||||
{.bitmap_index = 5677, .adv_w = 512, .box_w = 24, .box_h = 24, .ofs_x = 4, .ofs_y = 4},
|
||||
{.bitmap_index = 5821, .adv_w = 512, .box_w = 24, .box_h = 24, .ofs_x = 4, .ofs_y = 4},
|
||||
{.bitmap_index = 5965, .adv_w = 512, .box_w = 30, .box_h = 22, .ofs_x = 1, .ofs_y = 5},
|
||||
{.bitmap_index = 6130, .adv_w = 512, .box_w = 22, .box_h = 22, .ofs_x = 5, .ofs_y = 5},
|
||||
{.bitmap_index = 6251, .adv_w = 512, .box_w = 30, .box_h = 22, .ofs_x = 1, .ofs_y = 5},
|
||||
{.bitmap_index = 6416, .adv_w = 512, .box_w = 25, .box_h = 28, .ofs_x = 4, .ofs_y = 2},
|
||||
{.bitmap_index = 6591, .adv_w = 512, .box_w = 28, .box_h = 28, .ofs_x = 2, .ofs_y = 2}
|
||||
};
|
||||
|
||||
/*---------------------
|
||||
@ -972,11 +1044,11 @@ static const lv_font_fmt_txt_glyph_dsc_t glyph_dsc[] = {
|
||||
|
||||
static const uint16_t unicode_list_0[] = {
|
||||
0x0, 0x14, 0x62, 0x9b, 0x148, 0x182, 0x1ca, 0x1d1,
|
||||
0x1e1, 0x2af, 0x2c0, 0x418, 0x47e, 0x488, 0x48d, 0x48f,
|
||||
0x490, 0x4f9, 0x523, 0x600, 0x62b, 0x757, 0x76a, 0x773,
|
||||
0x7b8, 0x7ca, 0x7e9, 0x874, 0x8af, 0x8b2, 0x8c2, 0xa52,
|
||||
0xa87, 0xad7, 0xdfb, 0xe05, 0xe35, 0xea1, 0xee3, 0xf4b,
|
||||
0x1017, 0x15db, 0x1782
|
||||
0x1e1, 0x26a, 0x2af, 0x2c0, 0x418, 0x47e, 0x488, 0x48d,
|
||||
0x48f, 0x490, 0x4f9, 0x523, 0x600, 0x62b, 0x757, 0x76a,
|
||||
0x773, 0x7b8, 0x7ca, 0x7e9, 0x874, 0x8af, 0x8b2, 0x8c2,
|
||||
0x991, 0xa49, 0xa52, 0xa87, 0xad7, 0xdfb, 0xe05, 0xe35,
|
||||
0xea1, 0xee3, 0xf4b, 0x1017, 0x15db, 0x1782
|
||||
};
|
||||
|
||||
/*Collect the unicode lists and glyph_id offsets*/
|
||||
@ -984,7 +1056,7 @@ static const lv_font_fmt_txt_cmap_t cmaps[] =
|
||||
{
|
||||
{
|
||||
.range_start = 57669, .range_length = 6019, .glyph_id_start = 1,
|
||||
.unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 43, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
||||
.unicode_list = unicode_list_0, .glyph_id_ofs_list = NULL, .list_length = 46, .type = LV_FONT_FMT_TXT_CMAP_SPARSE_TINY
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -82,6 +82,7 @@
|
||||
#include <tactility/concurrent/thread.h>
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/drivers/audio_stream.h>
|
||||
#include <tactility/drivers/camera.h>
|
||||
#include <tactility/drivers/display.h>
|
||||
|
||||
|
||||
@ -200,6 +201,7 @@ namespace app {
|
||||
namespace webserversettings { extern const ::AppManifest manifest; }
|
||||
#ifdef ESP_PLATFORM
|
||||
namespace apwebserver { extern const ::AppManifest manifest; }
|
||||
namespace camera { extern const ::AppManifest manifest; }
|
||||
namespace crashdiagnostics { extern const ::AppManifest manifest; }
|
||||
#if CONFIG_TT_TDECK_WORKAROUND == 1
|
||||
namespace keyboardsettings { extern const ::AppManifest manifest; } // T-Deck only for now
|
||||
@ -266,6 +268,9 @@ static void registerInternalApps() {
|
||||
app_manager_add(&app::webserversettings::manifest);
|
||||
#ifdef ESP_PLATFORM
|
||||
app_manager_add(&app::apwebserver::manifest);
|
||||
if (device_exists_of_type(&CAMERA_TYPE)) {
|
||||
app_manager_add(&app::camera::manifest);
|
||||
}
|
||||
app_manager_add(&app::crashdiagnostics::manifest);
|
||||
#if defined(CONFIG_TT_TDECK_WORKAROUND)
|
||||
app_manager_add(&app::keyboardsettings::manifest);
|
||||
|
||||
@ -32,6 +32,30 @@ struct Context {
|
||||
std::vector<::AppManifest> manifests;
|
||||
};
|
||||
|
||||
struct IconEntry {
|
||||
const char* id;
|
||||
const char* icon;
|
||||
};
|
||||
|
||||
constexpr IconEntry ICONS[] = {
|
||||
{"tactility.apphub", LVGL_ICON_SHARED_DOWNLOAD},
|
||||
{"tactility.camera", LVGL_ICON_SHARED_CAMERA},
|
||||
{"tactility.chat", LVGL_ICON_SHARED_FORUM},
|
||||
{"tactility.i2cscanner", LVGL_ICON_SHARED_CABLE},
|
||||
{"tactility.notes", LVGL_ICON_SHARED_EDIT_NOTE},
|
||||
{"tactility.screenshot", LVGL_ICON_SHARED_IMAGE},
|
||||
{"tactility.systeminfo", LVGL_ICON_SHARED_DEVICES},
|
||||
{"tactility.terminal", LVGL_ICON_SHARED_TERMINAL},
|
||||
{"tactility.webserversettings", LVGL_ICON_SHARED_CLOUD},
|
||||
};
|
||||
|
||||
const char* appIcon(const ::AppManifest* manifest) {
|
||||
for (const auto& entry : ICONS) {
|
||||
if (!strcmp(manifest->id, entry.id)) return entry.icon;
|
||||
}
|
||||
return LVGL_ICON_SHARED_DEPLOYED_CODE;
|
||||
}
|
||||
|
||||
void populateList(lv_obj_t* list);
|
||||
|
||||
// Named (not a lambda) so lv_async_call_cancel() below has a stable function pointer to match against.
|
||||
@ -96,7 +120,7 @@ void onHelpPressed(lv_event_t* event) {
|
||||
lv_obj_t* createAppWidget(const ::AppManifest* manifest, lv_obj_t* list, bool favourite) {
|
||||
// Plain "*" prefix, not an icon: shared Material Symbols font is subsetted and has no star glyph.
|
||||
const std::string label = favourite ? (std::string("* ") + manifest->name) : manifest->name;
|
||||
lv_obj_t* btn = lv_list_add_button(list, LVGL_ICON_SHARED_TOOLBAR, label.c_str());
|
||||
lv_obj_t* btn = lv_list_add_button(list, appIcon(manifest), label.c_str());
|
||||
lv_obj_t* image = lv_obj_get_child(btn, 0);
|
||||
lv_obj_set_style_text_font(image, lvgl_get_shared_icon_font(), LV_PART_MAIN);
|
||||
// Not read by any event here (those get the manifest via their own callback user data) - lets
|
||||
|
||||
@ -42,7 +42,7 @@ void onBackPressed(lv_event_t* event) {
|
||||
}
|
||||
|
||||
void createPackageWidget(const char* packageId, lv_obj_t* list) {
|
||||
lv_obj_t* btn = lv_list_add_button(list, LVGL_ICON_SHARED_TOOLBAR, packageId);
|
||||
lv_obj_t* btn = lv_list_add_button(list, LVGL_ICON_SHARED_DEPLOYED_CODE, packageId);
|
||||
lv_obj_t* image = lv_obj_get_child(btn, 0);
|
||||
lv_obj_set_style_text_font(image, lvgl_get_shared_icon_font(), LV_PART_MAIN);
|
||||
lv_obj_add_event_cb(btn, &onPackagePressed, LV_EVENT_SHORT_CLICKED, const_cast<char*>(packageId));
|
||||
|
||||
501
Tactility/Source/app/camera/Camera.cpp
Normal file
501
Tactility/Source/app/camera/Camera.cpp
Normal file
@ -0,0 +1,501 @@
|
||||
#ifdef ESP_PLATFORM
|
||||
#include <Tactility/Tactility.h>
|
||||
|
||||
#include <app/event.h>
|
||||
#include <app/manager.h>
|
||||
#include <app/manifest.h>
|
||||
#include <app/paths.h>
|
||||
#include <app/scheduler.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <ctime>
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/semphr.h>
|
||||
|
||||
#include <lvgl/fonts.h>
|
||||
#include <lvgl/lvgl.h>
|
||||
#include <lvgl/widgets/toolbar.h>
|
||||
#include <lvgl_window_manager/window_manager.h>
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/drivers/camera.h>
|
||||
#include <tactility/memory.h>
|
||||
|
||||
namespace tt::app::camera {
|
||||
|
||||
extern const ::AppManifest manifest;
|
||||
|
||||
constexpr uint32_t FRAME_TIMEOUT_MS = 200;
|
||||
|
||||
namespace {
|
||||
|
||||
struct Context {
|
||||
uint32_t appInstanceId;
|
||||
|
||||
CameraHandle camHandle = nullptr;
|
||||
|
||||
uint8_t* displayBuf[2] = {};
|
||||
int displayBufIdx = 0;
|
||||
int publishedDisplayBufIdx = -1;
|
||||
uint32_t frameWidth = 0;
|
||||
uint32_t frameHeight = 0;
|
||||
|
||||
TaskHandle_t camTask = nullptr;
|
||||
SemaphoreHandle_t stopSem = nullptr;
|
||||
SemaphoreHandle_t doneSem = nullptr;
|
||||
|
||||
SemaphoreHandle_t camHandleMutex = nullptr;
|
||||
|
||||
std::atomic<bool> captureNext {false};
|
||||
std::atomic<bool> stopping {false};
|
||||
|
||||
lv_display_rotation_t displayRotation = LV_DISPLAY_ROTATION_0;
|
||||
|
||||
lv_obj_t* previewContainer = nullptr;
|
||||
lv_obj_t* previewCanvas = nullptr;
|
||||
lv_obj_t* toastLabel = nullptr;
|
||||
lv_timer_t* toastTimer = nullptr;
|
||||
};
|
||||
|
||||
static void anim_opa_cb(void* var, int32_t v) {
|
||||
lv_obj_set_style_opa((lv_obj_t*)var, v, 0);
|
||||
}
|
||||
|
||||
static void toast_fade_out_ready_cb(lv_anim_t* a) {
|
||||
lv_obj_t* toast = (lv_obj_t*)a->var;
|
||||
lv_obj_add_flag(toast, LV_OBJ_FLAG_HIDDEN);
|
||||
}
|
||||
|
||||
static void toastTimerCb(lv_timer_t *timer) {
|
||||
auto* ctx = static_cast<Context*>(lv_timer_get_user_data(timer));
|
||||
lv_timer_delete(timer);
|
||||
if (ctx != nullptr) {
|
||||
ctx->toastTimer = nullptr;
|
||||
if (ctx->toastLabel != nullptr) {
|
||||
lv_anim_t a;
|
||||
lv_anim_init(&a);
|
||||
lv_anim_set_var(&a, ctx->toastLabel);
|
||||
lv_anim_set_values(&a, LV_OPA_90, LV_OPA_TRANSP);
|
||||
lv_anim_set_time(&a, 300);
|
||||
lv_anim_set_exec_cb(&a, anim_opa_cb);
|
||||
lv_anim_set_completed_cb(&a, toast_fade_out_ready_cb);
|
||||
lv_anim_start(&a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void showToast(Context* ctx, const char *text) {
|
||||
if (ctx == nullptr || ctx->toastLabel == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (!lvgl_try_lock(pdMS_TO_TICKS(100))) return;
|
||||
|
||||
lv_anim_delete(ctx->toastLabel, anim_opa_cb);
|
||||
|
||||
lv_label_set_text(ctx->toastLabel, text);
|
||||
lv_obj_remove_flag(ctx->toastLabel, LV_OBJ_FLAG_HIDDEN);
|
||||
lv_obj_move_foreground(ctx->toastLabel);
|
||||
|
||||
lv_anim_t a;
|
||||
lv_anim_init(&a);
|
||||
lv_anim_set_var(&a, ctx->toastLabel);
|
||||
lv_anim_set_values(&a, LV_OPA_TRANSP, LV_OPA_90);
|
||||
lv_anim_set_time(&a, 250);
|
||||
lv_anim_set_exec_cb(&a, anim_opa_cb);
|
||||
lv_anim_set_path_cb(&a, lv_anim_path_ease_out);
|
||||
lv_anim_start(&a);
|
||||
|
||||
if (ctx->toastTimer != nullptr) {
|
||||
lv_timer_del(ctx->toastTimer);
|
||||
}
|
||||
ctx->toastTimer = lv_timer_create(toastTimerCb, 3000, ctx);
|
||||
lvgl_unlock();
|
||||
}
|
||||
|
||||
void buildTimestampedPath(const char* suffix, char* out, size_t outLen) {
|
||||
char dir[200];
|
||||
if (app_paths_get_user_data_directory("tactility.camera", dir, sizeof(dir)) != ERROR_NONE) {
|
||||
LOG_E("Camera", "Failed to resolve user data directory");
|
||||
out[0] = '\0';
|
||||
return;
|
||||
}
|
||||
if (mkdir(dir, 0755) != 0 && errno != EEXIST) {
|
||||
LOG_E("Camera", "mkdir failed for %s: errno=%d", dir, errno);
|
||||
}
|
||||
|
||||
time_t now = time(nullptr);
|
||||
struct tm tm_info;
|
||||
localtime_r(&now, &tm_info);
|
||||
|
||||
static uint32_t sequence = 0;
|
||||
char fname[64];
|
||||
strftime(fname, sizeof(fname), "/%Y%m%d_%H%M%S", &tm_info);
|
||||
snprintf(out, outLen, "%s%s_%04u%s", dir, fname, static_cast<unsigned>(sequence++), suffix);
|
||||
}
|
||||
|
||||
bool saveJpeg(Context* ctx) {
|
||||
if (!ctx->camHandle) {
|
||||
showToast(ctx, "Capture failed: driver unavailable");
|
||||
return false;
|
||||
}
|
||||
|
||||
char path[256];
|
||||
buildTimestampedPath(".jpg", path, sizeof(path));
|
||||
|
||||
uint8_t* jpegBuf = nullptr;
|
||||
size_t jpegLen = 0;
|
||||
if (camera_capture_jpeg(ctx->camHandle, &jpegBuf, &jpegLen, 100) != ERROR_NONE || !jpegBuf) {
|
||||
showToast(ctx, "Capture failed: encode error");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
{
|
||||
FILE* f = fopen(path, "wbx");
|
||||
if (f) {
|
||||
const size_t written = fwrite(jpegBuf, 1, jpegLen, f);
|
||||
const int closeResult = fclose(f);
|
||||
ok = written == jpegLen && closeResult == 0;
|
||||
if (!ok) {
|
||||
unlink(path);
|
||||
}
|
||||
} else {
|
||||
LOG_E("Camera", "fopen failed for %s: errno=%d", path, errno);
|
||||
}
|
||||
}
|
||||
heap_caps_free(jpegBuf);
|
||||
|
||||
if (ok) {
|
||||
LOG_I("Camera", "Saved JPEG: %s (%zu bytes)", path, jpegLen);
|
||||
const char* basename = strrchr(path, '/');
|
||||
char msg[sizeof(path) + 8];
|
||||
snprintf(msg, sizeof(msg), "Saved: %s", basename ? basename + 1 : path);
|
||||
showToast(ctx, msg);
|
||||
} else {
|
||||
showToast(ctx, "Capture failed: cannot write file");
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
static void syncRotation(Context* ctx) {
|
||||
if (!ctx->camHandleMutex) return;
|
||||
xSemaphoreTake(ctx->camHandleMutex, portMAX_DELAY);
|
||||
|
||||
if (!ctx->camHandle) {
|
||||
xSemaphoreGive(ctx->camHandleMutex);
|
||||
return;
|
||||
}
|
||||
|
||||
CameraRotation rot;
|
||||
switch (ctx->displayRotation) {
|
||||
case LV_DISPLAY_ROTATION_90: rot = CAMERA_ROTATION_90; break;
|
||||
case LV_DISPLAY_ROTATION_180: rot = CAMERA_ROTATION_180; break;
|
||||
case LV_DISPLAY_ROTATION_270: rot = CAMERA_ROTATION_270; break;
|
||||
default: rot = CAMERA_ROTATION_0; break;
|
||||
}
|
||||
camera_set_rotation(ctx->camHandle, rot);
|
||||
|
||||
ctx->frameWidth = camera_get_width(ctx->camHandle);
|
||||
ctx->frameHeight = camera_get_height(ctx->camHandle);
|
||||
|
||||
xSemaphoreGive(ctx->camHandleMutex);
|
||||
}
|
||||
|
||||
void onDisplayRotation(lv_event_t* e) {
|
||||
auto* ctx = static_cast<Context*>(lv_event_get_user_data(e));
|
||||
if (!ctx) return;
|
||||
// Called on LVGL task - safe to read display rotation here
|
||||
lv_display_t* disp = static_cast<lv_display_t*>(lv_event_get_target(e));
|
||||
if (disp) ctx->displayRotation = lv_display_get_rotation(disp);
|
||||
syncRotation(ctx);
|
||||
}
|
||||
|
||||
void onCaptureBtn(lv_event_t* e) {
|
||||
auto* ctx = static_cast<Context*>(lv_event_get_user_data(e));
|
||||
if (ctx) {
|
||||
ctx->captureNext.store(true);
|
||||
showToast(ctx, "Capturing...");
|
||||
}
|
||||
}
|
||||
|
||||
void cameraTaskEntry(void* arg) {
|
||||
auto* ctx = static_cast<Context*>(arg);
|
||||
|
||||
Device* camDev = nullptr;
|
||||
if (device_get_first_active_by_type(&CAMERA_TYPE, &camDev) != ERROR_NONE) {
|
||||
LOG_E("Camera", "Camera device not found");
|
||||
xSemaphoreGive(ctx->doneSem);
|
||||
vTaskDelete(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
CameraHandle handle = nullptr;
|
||||
if (camera_open(camDev, &handle) != ERROR_NONE) {
|
||||
LOG_E("Camera", "camera_open failed");
|
||||
device_put(camDev);
|
||||
xSemaphoreGive(ctx->doneSem);
|
||||
vTaskDelete(nullptr);
|
||||
return;
|
||||
}
|
||||
device_put(camDev);
|
||||
|
||||
xSemaphoreTake(ctx->camHandleMutex, portMAX_DELAY);
|
||||
ctx->camHandle = handle;
|
||||
xSemaphoreGive(ctx->camHandleMutex);
|
||||
syncRotation(ctx);
|
||||
showToast(ctx, "Camera Started...");
|
||||
|
||||
size_t frameSz = (size_t)camera_get_width(handle) * camera_get_height(handle) * 2;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
const MemoryPolicy policy { .required = 0, .desired = MEMORY_CAPABILITY_EXTERNAL, .alignment = 0 };
|
||||
ctx->displayBuf[i] = static_cast<uint8_t*>(memory_alloc_with_policy(frameSz, &policy));
|
||||
if (!ctx->displayBuf[i]) {
|
||||
LOG_E("Camera", "Failed to alloc display buffer %d", i);
|
||||
xSemaphoreTake(ctx->camHandleMutex, portMAX_DELAY);
|
||||
camera_close(handle);
|
||||
ctx->camHandle = nullptr;
|
||||
xSemaphoreGive(ctx->camHandleMutex);
|
||||
for (int j = 0; j < 2; j++) {
|
||||
heap_caps_free(ctx->displayBuf[j]);
|
||||
ctx->displayBuf[j] = nullptr;
|
||||
}
|
||||
xSemaphoreGive(ctx->doneSem);
|
||||
vTaskDelete(nullptr);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t* frameBuf = nullptr;
|
||||
size_t frameLen = 0;
|
||||
|
||||
while (true) {
|
||||
if (xSemaphoreTake(ctx->stopSem, 0) == pdTRUE) break;
|
||||
|
||||
if (ctx->captureNext.load()) {
|
||||
ctx->captureNext.store(false);
|
||||
saveJpeg(ctx);
|
||||
continue;
|
||||
}
|
||||
|
||||
uint32_t frameWidth = 0;
|
||||
uint32_t frameHeight = 0;
|
||||
error_t err = camera_get_frame(handle, &frameBuf, &frameLen, FRAME_TIMEOUT_MS, &frameWidth, &frameHeight);
|
||||
if (err == ERROR_TIMEOUT) continue;
|
||||
if (err != ERROR_NONE) {
|
||||
LOG_E("Camera", "get_frame error: %d", (int)err);
|
||||
break;
|
||||
}
|
||||
|
||||
int idx = ctx->publishedDisplayBufIdx < 0 ? 0 : ctx->publishedDisplayBufIdx ^ 1;
|
||||
if (frameLen > frameSz || (size_t)frameWidth * frameHeight * 2 > frameSz) {
|
||||
LOG_E("Camera", "Frame too large: %zu bytes (%ux%u)", frameLen, (unsigned)frameWidth, (unsigned)frameHeight);
|
||||
camera_release_frame(handle);
|
||||
continue;
|
||||
}
|
||||
memcpy(ctx->displayBuf[idx], frameBuf, frameLen);
|
||||
camera_release_frame(handle);
|
||||
ctx->displayBufIdx = idx;
|
||||
|
||||
if (lvgl_try_lock(pdMS_TO_TICKS(50))) {
|
||||
lv_obj_t* previewCanvas = ctx->previewCanvas;
|
||||
const bool stopping = ctx->stopping.load();
|
||||
auto w = static_cast<int32_t>(frameWidth);
|
||||
auto h = static_cast<int32_t>(frameHeight);
|
||||
if (previewCanvas != nullptr && !stopping) {
|
||||
lv_canvas_set_buffer(previewCanvas, ctx->displayBuf[idx], w, h, LV_COLOR_FORMAT_RGB565);
|
||||
ctx->publishedDisplayBufIdx = idx;
|
||||
}
|
||||
lvgl_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
xSemaphoreTake(ctx->camHandleMutex, portMAX_DELAY);
|
||||
camera_close(handle);
|
||||
ctx->camHandle = nullptr;
|
||||
xSemaphoreGive(ctx->camHandleMutex);
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
heap_caps_free(ctx->displayBuf[i]);
|
||||
ctx->displayBuf[i] = nullptr;
|
||||
}
|
||||
|
||||
xSemaphoreGive(ctx->doneSem);
|
||||
vTaskDelete(nullptr);
|
||||
}
|
||||
|
||||
void startCamera(Context* ctx) {
|
||||
ctx->stopSem = xSemaphoreCreateBinary();
|
||||
ctx->doneSem = xSemaphoreCreateBinary();
|
||||
ctx->camHandleMutex = xSemaphoreCreateMutex();
|
||||
|
||||
xTaskCreatePinnedToCore(cameraTaskEntry, "cam", 8 * 1024, ctx, 5, &ctx->camTask, 0);
|
||||
}
|
||||
|
||||
void stopCamera(Context* ctx) {
|
||||
if (!ctx->camTask) return;
|
||||
|
||||
xSemaphoreGive(ctx->stopSem);
|
||||
while (xSemaphoreTake(ctx->doneSem, portMAX_DELAY) != pdTRUE) {
|
||||
}
|
||||
ctx->camTask = nullptr;
|
||||
|
||||
vSemaphoreDelete(ctx->stopSem); ctx->stopSem = nullptr;
|
||||
vSemaphoreDelete(ctx->doneSem); ctx->doneSem = nullptr;
|
||||
vSemaphoreDelete(ctx->camHandleMutex); ctx->camHandleMutex = nullptr;
|
||||
}
|
||||
|
||||
void onBackPressed(lv_event_t* event) {
|
||||
auto* ctx = static_cast<Context*>(lv_event_get_user_data(event));
|
||||
app_event_emit_close(ctx->appInstanceId);
|
||||
}
|
||||
|
||||
void createWidgets(lv_obj_t* parent, void* userData) {
|
||||
auto* ctx = static_cast<Context*>(userData);
|
||||
ctx->stopping.store(false);
|
||||
|
||||
lv_obj_remove_flag(parent, LV_OBJ_FLAG_SCROLLABLE);
|
||||
lv_obj_set_flex_flow(parent, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_style_pad_row(parent, 0, LV_STATE_DEFAULT);
|
||||
|
||||
auto* toolbar = lvgl_toolbar_create(parent, "Camera");
|
||||
// The global toolbar nav callback only knows how to stop old-model apps.
|
||||
lvgl_toolbar_set_nav_action(toolbar, LV_SYMBOL_CLOSE, onBackPressed, ctx);
|
||||
lvgl_toolbar_add_text_button_action(toolbar, LV_SYMBOL_EYE_OPEN, onCaptureBtn, ctx);
|
||||
|
||||
auto* main_wrapper = lv_obj_create(parent);
|
||||
lv_obj_set_flex_flow(main_wrapper, LV_FLEX_FLOW_COLUMN);
|
||||
lv_obj_set_flex_align(main_wrapper, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_START, LV_FLEX_ALIGN_START);
|
||||
lv_obj_set_flex_grow(main_wrapper, 1);
|
||||
lv_obj_set_width(main_wrapper, LV_PCT(100));
|
||||
lv_obj_set_height(main_wrapper, LV_PCT(100));
|
||||
lv_obj_set_style_pad_all(main_wrapper, 6, 0);
|
||||
lv_obj_set_style_border_width(main_wrapper, 0, 0);
|
||||
lv_obj_remove_flag(main_wrapper, LV_OBJ_FLAG_SCROLLABLE);
|
||||
|
||||
ctx->previewContainer = lv_obj_create(main_wrapper);
|
||||
lv_obj_set_size(ctx->previewContainer, LV_PCT(100), LV_PCT(100));
|
||||
lv_obj_set_style_bg_color(ctx->previewContainer, lv_color_black(), 0);
|
||||
lv_obj_set_style_border_width(ctx->previewContainer, 0, 0);
|
||||
lv_obj_set_style_pad_all(ctx->previewContainer, 0, 0);
|
||||
lv_obj_set_style_radius(ctx->previewContainer, 0, 0);
|
||||
lv_obj_remove_flag(ctx->previewContainer, LV_OBJ_FLAG_SCROLLABLE);
|
||||
|
||||
ctx->previewCanvas = lv_canvas_create(ctx->previewContainer);
|
||||
lv_obj_set_style_bg_color(ctx->previewCanvas, lv_color_black(), 0);
|
||||
lv_obj_set_style_bg_opa(ctx->previewCanvas, LV_OPA_COVER, 0);
|
||||
lv_obj_center(ctx->previewCanvas);
|
||||
|
||||
ctx->toastLabel = lv_label_create(lv_layer_top());
|
||||
lv_obj_align(ctx->toastLabel, LV_ALIGN_TOP_MID, 0, 52 * 2 + 24);
|
||||
lv_obj_set_style_radius(ctx->toastLabel, 16, 0);
|
||||
lv_obj_set_style_pad_hor(ctx->toastLabel, 24, 0);
|
||||
lv_obj_set_style_pad_ver(ctx->toastLabel, 12, 0);
|
||||
lv_obj_set_style_border_width(ctx->toastLabel, 2, 0);
|
||||
lv_obj_set_style_text_font(ctx->toastLabel, lvgl_get_text_font(FONT_SIZE_DEFAULT), 0);
|
||||
lv_obj_set_style_bg_opa(ctx->toastLabel, LV_OPA_90, 0);
|
||||
lv_obj_set_style_bg_color(ctx->toastLabel, lv_color_hex(0x181825), 0);
|
||||
lv_obj_set_style_text_color(ctx->toastLabel, lv_color_white(), 0);
|
||||
lv_obj_set_style_border_color(ctx->toastLabel, lv_color_hex(0x3B82F6), 0);
|
||||
lv_obj_set_style_shadow_width(ctx->toastLabel, 16, 0);
|
||||
lv_obj_set_style_shadow_color(ctx->toastLabel, lv_color_black(), 0);
|
||||
lv_obj_add_flag(ctx->toastLabel, LV_OBJ_FLAG_HIDDEN);
|
||||
|
||||
lv_display_t* disp = lv_display_get_default();
|
||||
if (disp) {
|
||||
ctx->displayRotation = lv_display_get_rotation(disp);
|
||||
lv_display_add_event_cb(disp, onDisplayRotation, LV_EVENT_RESOLUTION_CHANGED, ctx);
|
||||
}
|
||||
|
||||
startCamera(ctx);
|
||||
}
|
||||
|
||||
void destroyWidgets(void* userData) {
|
||||
auto* ctx = static_cast<Context*>(userData);
|
||||
|
||||
lv_display_t* disp = lv_display_get_default();
|
||||
if (disp) lv_display_remove_event_cb_with_user_data(disp, onDisplayRotation, ctx);
|
||||
|
||||
if (ctx->toastTimer != nullptr) {
|
||||
lv_timer_delete(ctx->toastTimer);
|
||||
ctx->toastTimer = nullptr;
|
||||
}
|
||||
|
||||
if (ctx->toastLabel != nullptr) {
|
||||
lv_anim_delete(ctx->toastLabel, nullptr);
|
||||
}
|
||||
|
||||
ctx->stopping.store(true);
|
||||
|
||||
if (ctx->previewCanvas != nullptr) {
|
||||
lv_obj_delete(ctx->previewCanvas);
|
||||
}
|
||||
ctx->previewCanvas = nullptr;
|
||||
|
||||
stopCamera(ctx);
|
||||
|
||||
ctx->previewContainer = nullptr;
|
||||
if (ctx->toastLabel != nullptr) {
|
||||
lv_obj_delete(ctx->toastLabel);
|
||||
ctx->toastLabel = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t appMain(int argc, char* argv[]) {
|
||||
uint32_t appInstanceId = app_scheduler_current_app_id();
|
||||
Context ctx {};
|
||||
ctx.appInstanceId = appInstanceId;
|
||||
|
||||
TaskEventGroup event_group {};
|
||||
task_event_group_construct(&event_group);
|
||||
|
||||
AppEventSubscription sub {};
|
||||
check(app_event_subscribe(&sub, &event_group) == ERROR_NONE);
|
||||
|
||||
WindowId window = window_manager_create_ext(appInstanceId, createWidgets, destroyWidgets, &ctx);
|
||||
|
||||
bool shouldClose = false;
|
||||
while (!shouldClose) {
|
||||
task_event_group_wait_any(&event_group, nullptr, portMAX_DELAY);
|
||||
|
||||
AppEvent event {};
|
||||
while (app_event_poll(&sub, &event) == ERROR_NONE) {
|
||||
switch (event.type) {
|
||||
case APP_EVENT_CLOSE:
|
||||
shouldClose = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (shouldClose) break;
|
||||
}
|
||||
}
|
||||
|
||||
window_manager_remove(window);
|
||||
check(app_event_unsubscribe(&sub) == ERROR_NONE);
|
||||
task_event_group_destruct(&event_group);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
extern const ::AppManifest manifest = {
|
||||
.id = "tactility.camera",
|
||||
.name = "Camera",
|
||||
.category = APP_CATEGORY_USER,
|
||||
.location = { APP_LOCATION_MEMORY, reinterpret_cast<void*>(appMain) },
|
||||
.flags = 0,
|
||||
.stack = {.depth = 4096, .desired_memory_capability = MEMORY_CAPABILITY_EXTERNAL }
|
||||
};
|
||||
|
||||
} // namespace tt::app::camera
|
||||
|
||||
#endif
|
||||
@ -29,6 +29,36 @@ struct Context {
|
||||
std::vector<::AppManifest> manifests;
|
||||
};
|
||||
|
||||
struct IconEntry {
|
||||
const char* id;
|
||||
const char* icon;
|
||||
};
|
||||
|
||||
constexpr IconEntry ICONS[] = {
|
||||
{"tactility.apppackagelist", LVGL_ICON_SHARED_DEPLOYED_CODE},
|
||||
{"tactility.audiosettings", LVGL_ICON_SHARED_MUSIC_NOTE},
|
||||
{"tactility.btmanage", LVGL_ICON_SHARED_BLUETOOTH},
|
||||
{"tactility.development", LVGL_ICON_SHARED_LOGO_DEV},
|
||||
{"tactility.display", LVGL_ICON_SHARED_DISPLAY_SETTINGS},
|
||||
{"tactility.gpssettings", LVGL_ICON_SHARED_NAVIGATION},
|
||||
{"tactility.grovesettings", LVGL_ICON_SHARED_CABLE},
|
||||
{"tactility.keyboardsettings", LVGL_ICON_SHARED_KEYBOARD_ALT},
|
||||
{"tactility.localesettings", LVGL_ICON_SHARED_LANGUAGE},
|
||||
{"tactility.power", LVGL_ICON_SHARED_POWER_SETTINGS_NEW},
|
||||
{"tactility.timedatesettings", LVGL_ICON_SHARED_CALENDAR_MONTH},
|
||||
{"tactility.touchcalibration", LVGL_ICON_SHARED_CIRCLE},
|
||||
{"tactility.trackballsettings", LVGL_ICON_SHARED_DEVICES},
|
||||
{"tactility.usbsettings", LVGL_ICON_SHARED_USB},
|
||||
{"tactility.wifimanage", LVGL_ICON_SHARED_WIFI},
|
||||
};
|
||||
|
||||
const char* appIcon(const ::AppManifest* manifest) {
|
||||
for (const auto& entry : ICONS) {
|
||||
if (!strcmp(manifest->id, entry.id)) return entry.icon;
|
||||
}
|
||||
return LVGL_ICON_SHARED_DEPLOYED_CODE;
|
||||
}
|
||||
|
||||
void onAppPressed(lv_event_t* e) {
|
||||
// Fire-and-forget top-level navigation, same as AppList's own app-launch buttons.
|
||||
const auto* manifest = static_cast<const ::AppManifest*>(lv_event_get_user_data(e));
|
||||
@ -49,9 +79,7 @@ void onBackPressed(lv_event_t* event) {
|
||||
|
||||
void createWidget(const ::AppManifest* manifest, lv_obj_t* list) {
|
||||
check(list);
|
||||
// The new AppManifest has no per-app icon - use a shared generic one for every entry,
|
||||
// same fallback the old model used for apps that didn't provide one.
|
||||
auto* btn = lv_list_add_button(list, LVGL_ICON_SHARED_TOOLBAR, manifest->name);
|
||||
auto* btn = lv_list_add_button(list, appIcon(manifest), manifest->name);
|
||||
lv_obj_t* image = lv_obj_get_child(btn, 0);
|
||||
lv_obj_set_style_text_font(image, lvgl_get_shared_icon_font(), LV_PART_MAIN);
|
||||
lv_obj_add_event_cb(btn, &onAppPressed, LV_EVENT_SHORT_CLICKED, const_cast<::AppManifest*>(manifest));
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#include <tactility/check.h>
|
||||
#include <tactility/device.h>
|
||||
#include <tactility/drivers/bluetooth.h>
|
||||
#include <tactility/drivers/bluetooth_hid_device.h>
|
||||
#include <tactility/drivers/bluetooth_midi.h>
|
||||
#include <tactility/drivers/bluetooth_serial.h>
|
||||
#include <tactility/drivers/power_supply.h>
|
||||
@ -180,14 +181,19 @@ class StatusbarService final : public Service {
|
||||
|
||||
Device* serial_dev = bluetooth_serial_get();
|
||||
Device* midi_dev = bluetooth_midi_get();
|
||||
Device* hid_dev = bluetooth_hid_device_get();
|
||||
bool connected = (serial_dev && bluetooth_serial_is_connected(serial_dev)) ||
|
||||
(midi_dev && bluetooth_midi_is_connected(midi_dev));
|
||||
(midi_dev && bluetooth_midi_is_connected(midi_dev)) ||
|
||||
(hid_dev && bluetooth_hid_device_is_connected(hid_dev));
|
||||
if (serial_dev) {
|
||||
device_put(serial_dev);
|
||||
}
|
||||
if (midi_dev) {
|
||||
device_put(midi_dev);
|
||||
}
|
||||
if (hid_dev) {
|
||||
device_put(hid_dev);
|
||||
}
|
||||
const char* desired_icon = getBluetoothStatusIcon(radio_state, scanning, connected);
|
||||
if (bt_last_icon != desired_icon) {
|
||||
if (desired_icon != nullptr) {
|
||||
|
||||
@ -228,14 +228,8 @@ bool save(const DisplaySettings& settings) {
|
||||
|
||||
static bool isOriginallyLandscape() {
|
||||
auto* lvgl_display = lv_display_get_default();
|
||||
auto rotation = lv_display_get_rotation(lvgl_display);
|
||||
// The lvgl resolution code compensates for rotation. We have to revert the compensation to get the real display resolution
|
||||
// TODO: Use info from display driver
|
||||
if (rotation == LV_DISPLAY_ROTATION_0 || rotation == LV_DISPLAY_ROTATION_180) {
|
||||
return lv_display_get_physical_horizontal_resolution(lvgl_display) > lv_display_get_physical_vertical_resolution(lvgl_display);
|
||||
} else {
|
||||
return lv_display_get_physical_horizontal_resolution(lvgl_display) < lv_display_get_physical_vertical_resolution(lvgl_display);
|
||||
}
|
||||
return lv_display_get_original_horizontal_resolution(lvgl_display) >
|
||||
lv_display_get_original_vertical_resolution(lvgl_display);
|
||||
}
|
||||
|
||||
lv_display_rotation_t toLvglDisplayRotation(Orientation orientation) {
|
||||
|
||||
@ -1,11 +1,15 @@
|
||||
dependencies:
|
||||
espressif/cjson: "^1.7.19"
|
||||
espressif/esp_codec_dev: "1.5.10"
|
||||
espressif/esp_audio_codec: "2.4.0"
|
||||
espressif/esp_audio_codec: "2.5.0"
|
||||
espressif/esp_video:
|
||||
version: "2.2.0"
|
||||
rules:
|
||||
- if: "target in [esp32s3, esp32c6, esp32p4]"
|
||||
espressif/esp_new_jpeg:
|
||||
version: "^1.0.2"
|
||||
rules:
|
||||
- if: "target in [esp32, esp32s3]"
|
||||
espressif/esp_hosted:
|
||||
version: "2.12.11"
|
||||
rules:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user