Compare commits

...

68 Commits

Author SHA1 Message Date
alex 281c3b6e18
merge zig: upgrade from 0.11 to 0.12.0
ci/woodpecker/push/woodpecker Pipeline was successful Details
7 months ago
alex 729af48569
zig: upgrade from 0.11 to 0.12.0
ci/woodpecker/push/woodpecker Pipeline was successful Details
mostly lots of language improvements and bugfixes, leading to better
code here, from the programming language point of view.

zig v0.12.0 release notes:
https://ziglang.org/download/0.12.0/release-notes.html
7 months ago
alex e07b1557c7
lib/ini: sync with upstream at 19e1210
exact command:

    git subtree --prefix=lib/ini --squash pull \
      https://github.com/ziglibs/ini \
      19e1210063882ab7db73a8aaa60e733d4aaafe9f
7 months ago
alex e0851a5057 Squashed 'lib/ini/' changes from 2b11e8fef..19e121006
19e121006 FIX: local variable is never mutated
91775fd5c UPDATE: updated Build.zig to zig master

git-subtree-dir: lib/ini
git-subtree-split: 19e1210063882ab7db73a8aaa60e733d4aaafe9f
7 months ago
alex 285cff1d51
ui: increase keyboard buttons font size
ci/woodpecker/push/woodpecker Pipeline was successful Details
ci/woodpecker/tag/woodpecker Pipeline was successful Details
simply make the keyboard buttons text larger.
makes it easier to type.
7 months ago
alex e55471e48c
ngui,nd: screenlock feature implementation
ci/woodpecker/push/woodpecker Pipeline was successful Details
ci/woodpecker/tag/woodpecker Pipeline was successful Details
the screenlock use case is a way to restrict access to the touchscreen,
for example from children. it is in no way a security measure against
theft or prolonged physical access.

however, nd daemon will refuse to connect to a wifi, switch sysupdates
channel, set a new nodename or init lnd wallet during active screenlock

screenlock pin code can be enabled and disabled from the settings screen.
upon loss of the code, the only way to disable screenlock is to set
slock field to null in the nd daemon conf file.
8 months ago
alex a080e1ac79
nd,ui: add a new facility to be able to change node name
ci/woodpecker/push/woodpecker Pipeline was successful Details
ci/woodpecker/tag/woodpecker Pipeline was successful Details
the "nodename" encompasses lnd alias and OS hostname.
while the former may be seen by lightning node peers as a node name, the
latter is how the device is seen on a local network such as WiFi.

upon receiving a comm message set_nodename, nd sets both lightning node
alias and hostname to that new name while applying restrictions such as
RFC 1123 for hostnames.

the lightning alias is written to lnd config file, regenerated and
persistent, after which the lnd daemon is restarted to pick up the
changes. network host name is changed by writing the name to
/etc/hostname and issuing "hostname <newname>" shell command.

while persisting operations are atomic, the whole sequence isn't.
in the latter case an inconsistency can be eliminated by sending a
set_nodename msg again.

the nd daemon also includes the OS hostname in the settings message when
sending it to ngui.
9 months ago
alex 836f196a44
ui: add zig wrapper funcs for keyboard on/off
ci/woodpecker/push/woodpecker Pipeline was successful Details
this is still someone limiting in that tabview invariance is assumed.
so, it'll require some more to make it work for a screen pop over in the
future.
9 months ago
alex 0212f11d47
test: reinstate lndhc playground build
it broke after last commit where lnd client got moved into the lightning
module, preventing lndhc from importing it.

also, add lndhc to CI build to catch regressions like this early on.
9 months ago
alex d217adffba
ui/driver: add Xlib support when dev-building on a linux host
ci/woodpecker/push/woodpecker Pipeline was successful Details
something broken in recent SDL2 or Xorg releases, or a combination of
plus LVGL usage of their APIs. the result was that the main window
stopped drawing altogether. Downgrading SDL2 and other parts didn't seem
to help at all.

this commit adds support for SDL2-alternative when compiling and running
the GUI on a dev linux machine with Xorg.

there's a small patch to the original lv_drivers/x11/x11.c since clang
in C11 mode refuses to compile otherwise, giving a "initializer element
is not a compile-time constant" error.

release builds remain as is. this is only for development.
9 months ago
alex 8b837e783c
merge lvgl8.3.11 and lv_drivers updates into master 9 months ago
alex be9cb613de
lib/lv_drivers: update to latest 0091dc6 (2024-02-14)
git subtree --prefix=lib/lv_drivers --squash pull \
      https://github.com/lvgl/lv_drivers \
      0091dc612facc94dce1061a9b78d641c77f1791a
9 months ago
alex 20ee2f8220 Squashed 'lib/lv_drivers/' changes from 718302577..0091dc612
0091dc612 fix(wayland): fix compile error wrt LV_WAYLAND_CLIENT_SIDE_DECORATIONS (#307)
451e659cf Add pkgconfig file (#301)
5a5b4a1a3 added x11 display driver port (#300)
4391dbf32 perf(drm): use wait_cb for direct double-buffered rendering (#299)
7e18481ce fix(drm): backport drm driver fixes from lvgl 9 (#298)
f5b58b947 feat(evdev): backport multi device support from lvgl 9 (#296)
ad66ff155 add return value to drm_init
c239cc465 Removed clamp from Calibrate section as it has map in it
e44e7f043 fix(build): Update xpt2046_read to match signature required by lv_indev_drv_t's read callback. (#290)
7b9dee11c Fix crash during startup in certain conditions (#286)
9d153fb65 Add USE_WAYLAND to smm.c (#285)
8669c6fc8 libInput: Add POINTER_MOTION_ABSOLUTE support (#284)
c71e5f84b drm: Default to XRGB8888 framebuffer (#282)
57494ff8e Add a way to set SDL window title from lv_drv_conf.h (#277)
b03c9dac9 fix(xkb): Fix memory leak by avoiding double reference (#276)
ec0ad8296 feature(libinput): Expose function for querying capability (#275)
0d5de84e2 feature(libinput): Add function to reset driver states (#274)
94dc4ce06 Use win32 singly linked list instead of LVGL linked list for fixing memory access conflict issues for win32drv. (#273)
1792ab20a feature(wayland): add a shared memory manager, allowing backing buffers to be allocated on demand. (#270)
f7935569f use SDL_RES instead of LV_RES for touch events (#268)
ba9c3cc4f Update README.md (#261)
f261225d9 follow lvgl changes
ab5e30ccb Add the multiple display support for win32drv. (#259)
820341ea1 Improve the keyboard support for win32drv. (#258)
b13361a1f fix: The mouse moves outside the screen area (#251)
829e0ffc3 chore(wayland) : accelerate damage updates, reduce unnecessary cycles (#249)
5523f9974 fix(wayland-protocols): minimum version (#246)
fe9de86e9 Wayland api fixes (#243)
59e698ce1 fix(wayland) : fix possible memory leak (#238)
2ed01feab fix(drm): Fix compiler warnings (#237)
cf4e6d75a make windows.h lower case (#236)
dc0d71a3a chore(sdl): fix warning (#232)
c68b59e42 fix(fbdev): Fix rendering for 24 bits per pixel (#231)
4f98fddd2 hide the SDL2 include from public LVGL functions (#227)
ff01834db fix(fbdev): Gracefully handle FBIOBLANK errors (#229)
73219786a bump version number to v9.0.0-dev

git-subtree-dir: lib/lv_drivers
git-subtree-split: 0091dc612facc94dce1061a9b78d641c77f1791a
9 months ago
alex bc87a57de2
lib/lvgl: update from v8.3.1 to latest v8.3.11
git subtree --prefix=lib/lvgl --squash pull \
      https://github.com/lvgl/lvgl v8.3.11

v8.3 release notes: https://docs.lvgl.io/8.3/CHANGELOG.html
9 months ago
alex 752e2c61ad Squashed 'lib/lvgl/' changes from 9024b72b4..74d0a816a
74d0a816a release v8.3.11
8194d8322 chore(cmsis-pack): prepare for v8.3.11 (#4936)
1840decb4 fix(qrcode): use LV_ASSERT instead of assert
ef76206c7 fix(disp): fix infinite recursive SCREEN_LOADED events
4fdc4c20b fix(obj): readjust scroll after layout when child removed (#4921)
85776aeec fix(rt-thread): fix create lvgl thread problem (#4862)
d20bd1ca3 fix(keyboard): add '&' character
c16bfdc22 fix(obj): fix arduino compile warnings (#4807)
3b6f98a93 fix(table):fix issue with abnormal string output of 'lv_table_set_cell_value_fmt' (#4804)
6c86969ee fix(table) user data API functions renamed (#4769)
fdfff5c0b feat(table): add user_data to table cells (#4767)
2791d5739 feat(tiny_ttf): backport Tiny TTF to lvgl 8 (#4727)
68d380eb9 fix(ime_pinyin): keep cursor in the textarea when a candidate is pressed (#4731)
20b6199ba fix(arc): fix setting value by click
7efcea6d0 chore(cmake): add support for user-specified lv_conf.h path (#4689)
7f894cf75 fix(draw_needles): changed needle line draw start point from scale ce… (#4682)
fa40b0519 feat(littlefs): add lv_fs_littlefs system as a driver (#4677)
17c580fad fix(arc): handle click outside background angle range (#4586) (#4667)
454e45429 fix(meter):  fix minor issues (#4657)
9fbac7570 docs: fix typo
1e381f11b STM32U5 DMA2D support (8.3) (#4643)
d22cda3cd fix: fix warning in lv_draw_sw_letter.c
869cc6300 backport: fix(lv_disp): fix lv_scr_load_anim being called twice quickly (#4629)
73fa50afa docs(obj): fix wording (#4625)
7a8fcbfd3 fix(draw): fix scaling rectangle parts with opa
7568df77d chore: fix compile error
9a673e447 chore(lv_draw_sw_letter.c): Fix print format (#4615)
3b2d75be0 fix(draw): fix compiler error in lv_draw_sw_transform.c #2 (#4612)
87ff746e2 docs(label): update text for recoloring (#4606)
14e21d27f fix(dropdown): avoid partial match in lv_dropdown_get_option_index (#4598)
ff4f3f976 fix(dropdown): reset char_i = 0, avoid access overflow (#4589)
a7a9d278c fix(btnmatrix): set LV_BTNMATRIX_BTN_NONE when clicking of disabled button (#4571) (#4578)
06e229cc7 release v8.3.10
9e388055e chore(cmsis-pack): create cmsis-pack for v8.3.10 (#4572)
eb87767cc chore: code formatting
01cd1fed9 fix(vglite): be sure end_angle > start_angle in arc drawing
28094404a fix(refr): fix single buffered direct mode
e2b19eb4a fix: build on Windows (MinGW environment) (#4538)
bff1f2297 fix(docs): dropdown: fix function name in description of static options (#4535)
9787d47d0 fix: do not copy invalid areas if not double buffered mode (#4526)
6548ea0f2 feat(style): backport opa_layered
1375ea85a Update screen object opacity function documentation (#4505)
a29645659 docs(calendar): update according to v8.2 changes
336f24127 feat(disp): add double buffered direct-mode efficient sync algorithm (v8.3) (#4497)
1c5df6c66 demo(sress): fix issues when the stress test is opened/clsoed multiple times
7d314aab6 fix(sdl): add missing parameter in lv_draw_sdl_composite_texture_obtain (#4490)
fd21ed0eb ci: update screenshot compare from v9 to automatically create missing reference images
5fc488a08 ci(dropdown): fix test
f17458924 fix(dropdown): position to the selected item in lv_dropdown_set_selected
bcebafe4f docs(simulator): remove SDL support from the Visual Studio project
8063fac79 fix(btnmatrix): fix tapping just outside a button in a buttonmatrix
9ec3b8706 docs: update changelog
bdf5bfb88 chore(cmsis-pack): prepare for release v8.3.9 (#4424)
4f102d7b6 fix: use const lv_img_dsc_t * dsc function parameter in lv_img_buf.h/
810852b41 docs(disp): metined that rotation rotates the touch coordinates too
21e95bc1b fix(decoder): fix LV_IMG_CF_ALPHA_8BIT bin file decoder (#4406)
dbcf56288 fix(config): fix typo in LV_USE_PERF_MONITOR and LV_USE_MEM_MONITOR (#4403)
eee2dd186 fix(attr): refactor LV_ATTRIBUTE_* for function attributes (#4404)
141f4b8ab fix(font): fix optimizer issue in  lv_font_fmt_txt.c (#4385)
f9ffcc9d8 fix(chart): fix lv_chart_get_point_pos_by_id
385d999a4 fix(imgbtn): support LV_OBJ_FLAG_CHECKABLE
29ed7c571 fix(btnmatrix): Fix typo in previous commit!
65f1c9305 fix(btnmatrix): Hide button matrix when all buttons hidden
b1bbb95ce chore: format code
223dc1cf9 fix(tabview): fix warning
416b26771 chore(music demo) fix formatting
645006e35 fix(indev): fix warnings when loggin coordinates is enabled
375b3b5d3 fix(obj) prevent hidden objects keeping focus
1c5d4b02d Merge branch 'demo-close' into release/v8.3
e6d7be00b docs: update changelog
15433d69b chore(cmsis-pack): update cmsis-pack for v8.3.8 (#4340)
91038a99e demos: add lv_demo_..._close() functions for each demo
9491c3ff6 example(tabview): fix tabview disable scrollig example
3de61c76a fix(tabview): remove the animation if the tab is selected by clicking the button on the header
09cc0de57 docs: mention incompatibility between software rotation and `direct_mode` or `full_refresh` (#4308)
227ac0234 docs(faq): don't say 24 bit is support as LVGL can't render in RGB888 directly
8b83fe7ea feat(rt-thread): make the rt-thread env recursively glob the UI files
edd5ad28a fix(btnmatrix): fix array out of bounds addressing with groups and no buttons
07bce7466 fix:(BtnMatrix) Backport https://github.com/lvgl/lvgl/pull/4185
1713cd3fd Revert "fix:(BtnMatrix) Backport https://github.com/lvgl/lvgl/pull/4185"
cb602ea77 fix:(BtnMatrix) Backport https://github.com/lvgl/lvgl/pull/4185
caf29ef0c add(docs): add renesas-ra6m3 get-started document (#4278)
a3199514a fix(stm32): static function prototypes moved from .h to .c (#4276)
78cbdfc15 add(gpu): add renesas-ra6m3 gpu adaptation (#4270)
75e6ef4e1 fix(btnmatrix): fix using > 7 as button width
2376c5786 fix(png): fix decode image size and some warnings (#4248)
e3659c46b fix(arduino): fix messed up variable types
df96b57f4 fix(bidi): add more Hebrew checks to RTL characters set (#4171) (#4239)
67b3011f8 fix(chart): fix division by zero if there are no ticks
d87737612 perf(pxp, vglite): improve performance and add more features (#4222)
6a89bd2d7 fix(msgbox): fix typo
6843c191b fix(msgbox): add missing lv_obj_class_init_obj
1caafc55d fix(disp): fix memory leak lv_scr_load_anim with auto_del and time=0
5ba90a5c4 fix(flex): register LV_STYLE_FLEX_GROW
630da9c6c fix(img): fix getting the image type on big endian systems (#4215)
ee95e7dc2 fix(sdl): destroy texture after use if not stored in cache (#4173)
45b13c378 fix(draw): typo with LV_COLOR_DEPTH 8
2b56e0420 chore(cmsis-pack): update cmsis-pack for v8.3.7 (#4203)
177900b03 docs(changelog): update changelog for v8.3.7
203e7fc97 fix (spinbox):  doubling characters entered from the keyboard (#4190)
7345e6235 fix(arm-2d): fix transform-chrome-keying issue (#4178)
48d7878ba fix(style): fix trasition on bg_grad color fixes: #4174
a0795b49e fix(indev): fix integer overflow in recursive zoom calculation
a150b15e4 feat(btnmatrix): review ctrl map and allow width values to be max 15
a95714ba7 fix(menu): prevent setting the current page again (#4136)
8536152d8 fix(esp): fix ESP-IDF pedantic builds (backport v8.3) (#4135)
631444183 fix: color mixing with LV_COLOR_SWAP == 1 (#4101)
88c51b22a docs: udpate changelog
6b0092c0d chore(cmsis-pack): update cmsis-pack for v8.3.6 (#4108)
aa313806d fix(bar): delete running animations when a new value is set without animation
5e0e1c8c4 chore: code formatting
d0e19eb2d fix(arc): fix knob area invalidation
fd20fabfd fix(group): fix default_group becomes wild pointer when deleted (#4076)
399069b4a Update build_html_examples.sh
501230e0f docs: use a fixed commit of lv_web_emscripten
adcf16638 fix(fs_posix): allow creating new file and set permission. (#3976)
2f294aa76 docs(arduino): add note to not use lv_examles library
9a870b34a format code
0b7777f27 fix(slider): consider animations on pressing
e8d8f399e fix(img): support negative angles (#3846)
0df09db23 fix(gif): synchronize with master (#4003)
e2386fd46 fix(gpu): fix STM GPU drivers for some variants (#4004)
2944277f0 fix(img): possible divide by 0 exception (lvgl#3988) (#3990)
6af01798d feat(msg): add lv_msg_unsubcribe_obj
77670fb1a chore: update the version numbers to v8.3.5-dev
f29514aa5 docs: update changelog
e7e8cf846 feat(cmsis-pack): update cmsis-pack for v8.3.5 (#3972)
8b1270347 fix(monkey): remove executable permissions from source files (#3971)
e6cd7063b fix(ci): set Ubuntu version for MicroPython test (#3865)
34c545ef1 docs(indev): fix the name of long_press_repeat_time (was long_press_rep_time)
361ee7961 feat(gpu): improve NXP's PXP and VGLite accelerators (#3952)
39f424767 fix(roller): consider the recolor setting of the label
1853cc514 perf(dam2d): rework stm32 dma2d  (#3904)
9faca8a8d Update layer.md
8ea6f03fc fix(Kconfig): Fix wrong type of LV_FS_STDIO_CACHE_SIZE (v8.3) (#3906)
c6c1b0b3d chore: add an option to "LV_TICK_CUSTOM" (#3879)
e529230f4 ci(esp): fix push to the component registry on tag
dbb15bb3e feat(cmsis-pack): update for v8.3.4 (#3896)
47c8f8f98 bump version numbers to v8.3.5-dev
2c0162b45 release v8.3.4
dec580b9f fix(rt-thread): sync rt-thread v5.0.0 rt_align (#3864)
ad56dfaf7 fix(gridnav): fix stucking in pressed state with encoder
c8e584f87 fix(style): add the missing support for pct pivot in tranasform style properties
d2d886aae fix(draw): SDL2 gradient support  #3848 (#3856)
1e3ca25fe fix(example): fix warnings
84cf05d8b fix(indev): fix scrolling on transformed obejcts
2c17b28ac fix(darw): add back the disappeared antialising=0 support
1ed026ca7 fix(benchmark): fix warnings
ae3825871 demo(benchmark): fix lv_label_set_text_fmt format strings
ae300acb2 [v8.3.x][rt-thread][squareline] fix compiler cannot find the lvgl/lvg… (#3834)
41fa41613 fix(msg): fix typos in API by adding wrappers fixes #3822
68f6190f8 chore: format code
1173dcba9 demo(benchmark): fix warning
716e5e2c8 fix(meter): fix setting part_draw_dsc.id in needle img drawing
bb2c2ac34 fix(chart): fix very dense bar charts
c4c400716 fix(flex): be sure obj->w_layout and h_layout can't be set at the same time
6825d4bd1 chore(table): remove extra spaces (#3805)
39d03a80f feat(table): scroll to the selected cell with key navigation
340a1cb60 fix(esp.cmake): add demos and examples (#3784)
e06f03db7 fix(draw): fix transformation accuracy
bd11ad854 fix(draw): handle LV_COLOR_DEPTH == 1 too in lv_draw_sw_transform
e050f5ca1 fix(draw): fix text color with sub pixel rendering and BGR order
903e94b71 fix(style): remove the reduntant define of LV_GRADIENT_MAX_STOPS
0732400e7 Revert "feat(keyboard): ported arabic keyboard from release 7.10.0 (#3728)"
483b2a432 feat(keyboard): ported arabic keyboard from release 7.10.0 (#3728)
5545ffc92 release v8.3.3
c8bee4041 fix: version number in lvgl.h
755d363ec release v8.3.2
dfd14fa77 fix(slider): find the nearest value on click instead of floor
1ab9aa531 fix(fragment): fixed child fragment event dispatch (#3683)
4d69cd865 fix(sdl): clear streaming/target texture with FillRect (#3682)
832bef434 fix(sdl): transformation with alpha (#3576) (#3678)
d5b2a9b25 fix(draw): fix border drawing with thick borders
764095021 chore: fix warnings
8b605cc48 fix(refr): fix true double double buffering logic with transparent screens
ece349500 fix(draw): allow drawing outline with LV_DRAW_COMPLEX == 0 too
f6655c2aa fix(draw_sw): fix image cache to access the freed stack space (#3584)
cba2aa95c fix(style): use compile time prop_cnt for const styles (#3609)
660464c97 chore(rt-thread) backport fixes from v9 (#3604)
5156ee058 fix(group): be sure obj is removed from its current group in lv_group_add_obj
a0515ba30 fix(style): add missing invalidation in lv_obj_remove_local_style_prop
1a4603091 docs(draw) remove reference to old lv_fs_add_drv function (#3564)
f58dcd94f docs(disp): LV_COLOR_SCREEN_TRANSP remove dependency on LV_COLOR_DEPTH_32 as transparency is supported across all color depths (#3556)
d59bba12d fix(colorwheel): fix updating color when using lv_colorwheel_set_hsv
5022476ed remove accidentally added code
b884abae2 fix(canvas): fix clipéping on transformation
aa45d5985 fix(demo): can not found lvgl.h file (#3477)
55e95ed35 fix(ci) checkout lv_micropython release/v8 branch (#3524)
be485d760 ci: protect test.c with #if LV_BUILD_TEST

git-subtree-dir: lib/lvgl
git-subtree-split: 74d0a816a440eea53e030c4f1af842a94f7ce3d3
9 months ago
alex 0a74bf2c3a
nd/conf: add lnd config (de)serializer and use it conf gen
ci/woodpecker/push/woodpecker Pipeline was successful Details
the change is based on the previously added ini parser.
this makes lnd config gen more robust and allows to presist config
modifications in the future, such as changing node alias.
10 months ago
alex 55531668eb
lib: add simple ini file format parser library
will be used to parse lnd and bitcoind config files.

    git subtree add --prefix=lib/ini --squash \
      https://github.com/ziglibs/ini \
      2b11e8fef86d0eefb225156e695be1c1d5c35cbc
12 months ago
alex 15a2b6d823 Squashed 'lib/ini/' content from commit 2b11e8fe
git-subtree-dir: lib/ini
git-subtree-split: 2b11e8fef86d0eefb225156e695be1c1d5c35cbc
12 months ago
alex b57ebacd4a
nd,ngui: add lightning setup process, phone pairing and reset
ci/woodpecker/pr/woodpecker Pipeline failed Details
ci/woodpecker/push/woodpecker Pipeline was successful Details
ci/woodpecker/tag/woodpecker Pipeline was successful Details
the daemon can now identify which state lnd is in and report to the GUI
which displays different elements on the lighting tab, based on the
reported lnd state:

- startup in progress: displays spinner
- no lightning wallet: displays a "setup" button and guides the user
  through a simple workflow
- reset an operational node

this means, the UI has now minimal but functional elements for any user
equipped with a smart phone to set up the lightning node without SSHing
in or using command line in general.
1 year ago
alex 9f9e4aa171
nd: ignore RpcInWarmup bitcoind RPC error
ci/woodpecker/push/woodpecker Pipeline was successful Details
the daemon now pretends the report is sent over to ngui on such errors.
this is a stop-gap to avoid writing errors on tty. see linked issue.

part of #30
1 year ago
alex e618fee65c
comm: rename bitcoin report to onchain
ci/woodpecker/push/woodpecker Pipeline was successful Details
the "bitcoin" name is overloaded: everything's about bitcoin here.
a less confusing name is onchain to emphasize the difference w.r.t.
lightning or any other future L2 networks.
1 year ago
alex 29f6975601
nd,ngui: remove memleaks and deadlocks mostly from v0.4.0
ci/woodpecker/push/woodpecker Pipeline was successful Details
ci/woodpecker/tag/woodpecker Pipeline was successful Details
the offending memleak printed out at program exit was introduced in
116fb3b5, specifically line 140 in src/bitcoindrpc.zig using incorrect
allocator.

while there, improved a bit overall memory handling by making sure
heap-alloc'ed messages are always deinit'ed.

another source of trouble was logging from within a sighandler: the
logger uses a thread mutex which may deadlock when the handler is
invoked by the OS.
1 year ago
alex 280bea40df
nd/conf: link to sysupdates repo in doc comments
it is important the constants in Config.zig match those in sysupdates.
somehow should've made it into 664c75a9 but never did.
1 year ago
alex c82848d186
nd,ngui: let users switch sysupdates channel from the UI
ci/woodpecker/pr/woodpecker Pipeline was successful Details
ci/woodpecker/push/woodpecker Pipeline was successful Details
ci/woodpecker/tag/woodpecker Pipeline was successful Details
at the moment, there are two channels: edge and stable.

this builds up on few previous commits, most notably the persistent
configuration storage.
1 year ago
alex 1d8d67a987
ui/lvgl: add a dropdown widget 1 year ago
alex e8838b3eaf
ui/lvgl: add an optional spinner to card widget
some cards will need to show a nondeterministic progress.
the spinner in the top right corner does exactly that, controlled
via the new spin function.

the default is no spinner.
1 year ago
alex 094f6406e3
ui/lvgl: add a couple convenience methods for next commits
small things like show/hide and enable/disable. also, the text of the
button can now be set directly using its label field.
1 year ago
alex 664c75a9c9
nd: add a persistent configuration support
the config will be used by the daemon to store user choices across
reboots.

closes #6
1 year ago
alex aca7eb1165
comm: introduce a simpler way to read/write
this builds on top of the main read and write fn, setting up a global
structure to allow module users imply comm.pipeWrite(msg)
and comm.pipeRead() without providing an allocator or reader/writer
on each call.

the advantage is simplification in the gui functions because they don't
have access to an allocator or the nd process read/write pipe.

disadvantage is in testing because it requires a global,
"before all tests" setup.

at the moment, only ngui is modified to use the new pipeRead/Write. the
daemon would suffer too many changes, especially in tests, due to the
global state.
1 year ago
alex a18a2a5435
lndhttp: remove nonexistent field from pending chan list
funding_expiry_blocks is present in lightning.proto but a REST API call
shows no such field, at least in lnd v0.16.4, leading to json parsing error.

the field is unused at the moment anyway.
1 year ago
alex 116fb3b59c
nd,ngui: display on-chain balance in bitcoin tab
ci/woodpecker/pr/woodpecker Pipeline was successful Details
ci/woodpecker/tag/woodpecker Pipeline was successful Details
ci/woodpecker/push/woodpecker Pipeline was successful Details
a previous commit added some lightning tab implementation which
including balance details but only for lightning channels.

this commit queries lnd for a wallet balance and displays it on the
bitcoin tab since "wallet" funds are on-chain and it doesn't feel like
it belongs to the lightning tab in the UI.

while there, also improved some daemon backend code style, alightning
with the lightning implementation structures.
1 year ago
alex 05c89bbd1c
ui: visualize lnd lightning report on the tab panel
ci/woodpecker/pr/woodpecker Pipeline was successful Details
ci/woodpecker/push/woodpecker Pipeline was successful Details
similarly to 0260d477, the lightning tab has now some basic info
including channels list.

the gui playground is updated to send some stub data via comms
periodically.
1 year ago
alex 52a8c1fb1a
nd: add lnd lightning report sent to UI every min
similarly to 2642a554, this adds an lnd HTTP client able to make some
queries like getinfo. the daemon then uses the client to compose a
lightning status report and sends it over to ngui through comms,
periodically.

there's also a client playground built on demand with
"zig build lndhc".
1 year ago
alex 328df67c5d
zig: upgrade from 0.10.x to 0.11.0
ci/woodpecker/push/woodpecker Pipeline was successful Details
while there's lots of changes and new features in zig v0.11.0, the most
important for this project at the moment is the HTTP client.
the client is most likely what will connect to lnd lightning node to
fetch stats and info for the UI to then visualize it on "lightning" tab,
similar to the bitcoind RPC client.

see all zig 0.11 release notes here:
https://ziglang.org/download/0.11.0/release-notes.html
1 year ago
alex e84489c345
ui: keep last comm reports to update on wakeup
ci/woodpecker/push/woodpecker Pipeline was successful Details
ci/woodpecker/tag/woodpecker Pipeline was successful Details
a previous commit a06a4757 stopped updating the UI while in standby
mode. unfortunately, this makes the UI data become stale on wakeup.
for example, bitcoin chain height and its timestamp.

this commit keeps the last report received from daemon comm during
standby and uses it to update the UI immediately on wakeup.
1 year ago
alex a06a4757b2
ngui: clarify and handle concurrency during screen sleep/standby
ci/woodpecker/pr/woodpecker Pipeline was successful Details
ci/woodpecker/push/woodpecker Pipeline was successful Details
ci/woodpecker/tag/woodpecker Pipeline was successful Details
the screen.sleep fn was actually called in concurrent-unsafe mode,
i.e without acquiring UI mutex. in conjuction with commThreadLoopCycle
this would have eventually led to LVGL primitives concurrent access.

so, screen.sleep now takes UI mutex to hold during LVGL calls.
a bit ugly but certainly better than relying on luck.
1 year ago
alex 0260d47747
ui: visualize bitcoind status report on the tab panel
the bitcoin tab has now some basic status and stats: parts of blockchain
info, network info and mempool. this is far from complete but makes a
good start for an initial version.

the gui playground is also updated to sent some stub info via comms
periodically.
1 year ago
alex 2642a55477
nd: add bitcoin core report sent to UI every min
this adds a very simple bitcoind RPC client able to make a few queries
like the blockchain and network status. the daemon uses the client
to get the bitcoind status and sends a report through comms periodically.

there's also a little playground program which simply dumps a query
result to stderr. built on demand with "zig build btcrpc".
1 year ago
alex c1a809c567
ui/lvgl: fix a bug where a top container didn't have its object created
ci/woodpecker/push/woodpecker Pipeline was successful Details
a previous commit 7d1ab5cb rewrote toplayer objects creation as
Container.newTop except the new code was using the top layer object
obtained from lv_disp_get_layer_top as is. this obviously led to all
sorts of UB and illegal memory access when screen.sleep'ing.
1 year ago
alex 7d1ab5cb78
ui/lvgl: improve UI element types in zig
ci/woodpecker/push/woodpecker Pipeline was successful Details
this commit improves on the LVGL API wrapping interface in zig by
defining different types where each is associated with either a
particular lv_xxx_t object in C or a logically different UI element.

this makes programming much more pleasant, allows compartmentalizing
different UI concepts and elements, and reduces chances of making a
thanks to stricter type enforcement.

no visual changes in the UI.
1 year ago
alex 746b179478
ui: force alignment of modal callback function
ci/woodpecker/push/woodpecker Pipeline was successful Details
ci/woodpecker/tag/woodpecker Pipeline was successful Details
fullscreen modal dialog was added in 4297c139. the callback function to
that modal *must* be aligned according to the target architecture.
failing to do so may result in "incorrect alignment" panic.

this somehow worked in 4297c139 but sometimes panic. i suspect this may
be due to PIE-enabled build, possibly in conjuction with some zig v0.10
compiler bugs.

ref #20
ref #5
1 year ago
alex 63eb27bf18
nd,ngui: make program termination reliable on SIGTERM
ci/woodpecker/pr/woodpecker Pipeline was successful Details
ci/woodpecker/push/woodpecker Pipeline was successful Details
most troubles were due to blocking nature of child process pipe
descriptions which made comm.read loops hang in various places
under certain conditions.

this commit moves all read/writes in separate threads to be able to
always watch for sig TERM and INT, and ensures child process pipes
are closed early allowing comm.read loops to terminate.
1 year ago
alex 532581a246
ngui: display poweroff progress during system shutdown
ci/woodpecker/pr/woodpecker Pipeline was successful Details
ci/woodpecker/push/woodpecker Pipeline was successful Details
this greatly improves UX during shutdown: no need to guess at which
point it's ok to unplug the power cord.

the commit also includes a GUI playground. a sort of a fake daemon which
sends hardcoded messages to ngui. useful for manual debugging and trying
different UX scenarious.
1 year ago
alex 78df4ad7ee
nd: poweroff with progress report to ngui
the daemon now sends info about the system shutdown progress: a list of
important services which may require up to several minutes to stop such
as lnd lightning daemon and bitcoin core.

see next commit for how this info is displayed and used by the GUI.
1 year ago
alex a7c560e92a
build: switch LVGL default logging from info to warn
ci/woodpecker/push/woodpecker Pipeline was successful Details
this hides all LVGL info messages about UI interactions like events,
making the log output more useful during development.

it is still possible to increase verbosity to the original level using
the lvgl_loglevel build flag.
1 year ago
alex ec5e15e8e9
build-time semantic versioning support
ci/woodpecker/push/woodpecker Pipeline was successful Details
1 year ago
alex 517f9d4056
ui: display ngui semver on a new info panel tab
ci/woodpecker/push/woodpecker Pipeline was successful Details
ci/woodpecker/pr/woodpecker Pipeline was successful Details
this adds the 4th tab, an info-icon button, and shows the value of
the release version recorded at build time - a feature added in a
previous commit.
1 year ago
alex 7dc1f6329e
build: add semantic versioning support
both nd and ngui now acquire semantic versioning recorded at the build
time. they also report the version at startup and -v flag.
this is useful for a release process and to avoid potential
compatibility issues in the future.

in a regular build flow, the version is taken from a git tag using the
following command:

    git -C . describe --match 'v*.*.*' --tags --abbrev=8

in a non-standard scenario where git isn't available, the version can
be provided on the command line during build like so:

    zig build -Dversion=1.2.3

if both git and command line supplied versions are available, they must
match.
1 year ago
alex 53812cbd37
build: make release builds for aarch64 reproducible
ci/woodpecker/push/woodpecker Pipeline was successful Details
part of #2
1 year ago
alex 706a62a08e
build: strip C source file paths from resulting binary
ci/woodpecker/push/woodpecker Pipeline was successful Details
helps with reproducible builds, especially for releases.
1 year ago
alex 81db4aaa71
ci: add sha256sum output for aarch64 build
ci/woodpecker/push/woodpecker Pipeline was successful Details
the goal is reproducible builds.
1 year ago
alex f1784cb39d
ngui: add a way to limit LVGL logging verbosity
ci/woodpecker/push/woodpecker Pipeline was successful Details
the commit adds a build option lvgl_loglevel and sets a default similar
to that of std.log.default_level so the two are aligned more or less.
1 year ago
alex 4297c139a1
ngui: port some LVGL-based UI code from C to zig
ci/woodpecker/push/woodpecker Pipeline was successful Details
ci/woodpecker/pr/woodpecker Pipeline was successful Details
this commit includes lots of new code in ui/lvgl.zig and ui/widget.zig
to work with LVGL directly from zig. in fact, some C code is moved from
ui/c/ui.c to ui/xxx.zig.

in addition, a new module ui/widget.zig is where all custom UI elements
will reside. at the moment it comprises of the ported topdrop and a new
modal func. the latter is an alternative to LVGL's lv_msgbox popup.

as a practical example, the commit replaces the power off confirmation
popup with the new modal window.
1 year ago
alex c73867ea4d
ngui: get rid of the ambiguous ui header file
functions declared in ui.h were actually used by ui.c, the opposite of
what such a header is expected to contain. these functions are defined
in zig code and declarations are better off in the same ui.c file.

this is just a quick clean up before porting some C code to zig.
2 years ago
alex cb229d5a26
nd: ping ngui at start as an in-process pipe test
ci/woodpecker/push/woodpecker Pipeline was successful Details
ci/woodpecker/tag/woodpecker Pipeline was successful Details
this is an attempt at identifying the underlying problem.
unclear whether this normal behaviour on a linux kernel or something to
do with zig implementation.

either way, pinging the UI makes CommReadInvalidTag error disappear on startup.

updates #16
2 years ago
alex ad8cdf727b
ngui: yield CPU during standby mode
ci/woodpecker/push/woodpecker Pipeline was successful Details
when the screen turns off, the idle loop never gave a chance CPU to
do other work and pegged at 100%. adding a short sleep each cycle
yields CPU to the OS.

closes #15
2 years ago
alex fd49235f9e
ui: implement a screen timeout after a period of user inactivity
ci/woodpecker/push/woodpecker Pipeline was successful Details
ci/woodpecker/tag/woodpecker Pipeline was successful Details
passed 60 sec of no touch screen activity, daemon turns off backlight
and gui places a black "topdrop", opposite of backdrop. simply touching
the screen reactivates it immediately.

there seem to be no way to turn screen power off, so backlight plus
black topdrop is the next best.

there's no user settings to change 60 sec timeout at the moment because it
is unclear whether it's worth adding UI elements. can always do so later.

the implementation also provides means to reactivate the screen in
an event of an alert from the daemon in the future.

closes #3
2 years ago
alex 021c810dc7
ui: move all C lvgl/zig code into lvgl.zig and drv.zig
the idea is for all zig code to use C LVGL only via this
new module lvgl.zig, all display and input driver/devices is handled
by drv.zig.

this makes C/zig nicely compartmentalized in just a handful places.
2 years ago
alex 5c60b92f85
ci: run lint, tests and build for each commit
ci/woodpecker/push/woodpecker Pipeline was successful Details
the CI uses a custom image produced by tools/ci-containerfile.
see instructions in the readme.

CI logs are at https://woodpecker.qcode.ch/nakamochi/ndg
2 years ago
alex fe68ae96d6
comm: format protocol header manually and eliminate a potential footgun
the nd/ngui protocol is a simple TLV: message tag, length and
a json-encoded payload. the issue is with the (tag, length) header which
was written/read by using raw memory pointers, such as
Writer.writeStruct. in addition, tag ordinal values were auto-generated
by the compiler.

all those deficiencies may potentially lead to bugs hard to find or
serious data leaks.

serializing and deserializing the (tag, length) header manually
makes it more robust and eliminates the footgun.
2 years ago
alex ae7c3b2db8
tools: be silent when checking c code formatting
no news is good news. and either way, clang-format verbose mode is
inconsistent with zig fmt. the latter outputs only malformatted files.
2 years ago
alex 3f6c0aef44
git: add 2ecd44a7 to blame-ignore list 2 years ago
alex 2ecd44a7db
ui/c: workaround clang-format's pointer alignment in a define
it is actually multiplication, not a pointer. reads nicer this way.
2 years ago
alex 6a93ba9a30
zig: switch from stage1 to the new stage2 compiler
stage2 has been merged and set as default around end of aug 2022 in
https://github.com/ziglang/zig/pull/12368. since then the main focus has
been on this new stage2 compiler.

with the release of 0.10.1 the stage2 is fairly useable now and it is
the way forward, towards zig 0.11 or 1.0. read more about difference in
https://github.com/ziglang/zig/wiki/Self-Hosted-Compiler-Upgrade-Guide

another good read on the relevant topic is
https://ziglang.org/news/goodbye-cpp/
2 years ago
alex c08ded524e
docs: a quick local dev setup and contributing sections
while there, made test filter actually work with

    zig build test -Dtest-filter=xxx

a previous invocation with `--test-filter` never worked.
2 years ago
alex 698e5b6f76
src,lib: zig fmt and clang-format all code
C style is now fixed by .clang-format.
a handy script to check all source code formatting is in
tools/fmt-check.sh.
2 years ago
alex 161a2b965b
license: add qeles AG to copyright holders
qeles AG is now a significant contributor, too.
https://qeles.ch
2 years ago
alex 5332d00290 ngui: make it work with zig release v0.10.0
only one tiny change: @maximum -> @max.
nothing to do for nd.
2 years ago

@ -0,0 +1,15 @@
# https://clang.llvm.org/docs/ClangFormat.html
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
---
IndentWidth: 4
ContinuationIndentWidth: 4
UseTab: Never
ColumnLimit: 102
PointerAlignment: Right
BreakBeforeBraces: Linux
AlignAfterOpenBracket: DontAlign
BinPackArguments: false
BinPackParameters: false
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortFunctionsOnASingleLine: Empty

@ -0,0 +1,3 @@
# zig fmt and clang-format all lib/ and src/
698e5b6f76f4cec712e147e86f6c373f811e28d0
2ecd44a7dbd03645de71a76ef5763ebc2bbe707e

@ -0,0 +1,35 @@
clone:
git:
image: woodpeckerci/plugin-git
# https://woodpecker-ci.org/plugins/Git%20Clone
settings:
# tags are required for aarch64 release builds for semver
tags: true
lfs: false
recursive: false
pipeline:
lint:
image: git.qcode.ch/nakamochi/ci-zig0.12.0:v1
commands:
- ./tools/fmt-check.sh
test:
image: git.qcode.ch/nakamochi/ci-zig0.12.0:v1
commands:
- zig build test
sdl2:
image: git.qcode.ch/nakamochi/ci-zig0.12.0:v1
commands:
- zig build -Ddriver=sdl2
x11:
image: git.qcode.ch/nakamochi/ci-zig0.12.0:v1
commands:
- zig build -Ddriver=x11
aarch64:
image: git.qcode.ch/nakamochi/ci-zig0.12.0:v1
commands:
- zig build -Ddriver=fbev -Dtarget=aarch64-linux-musl -Doptimize=ReleaseSafe -Dstrip
- sha256sum zig-out/bin/nd zig-out/bin/ngui
playground:
image: git.qcode.ch/nakamochi/ci-zig0.12.0:v1
commands:
- zig build guiplay btcrpc lndhc

@ -1,5 +1,6 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2023 qeles AG
Copyright (c) 2022 alex@cloudware.io Copyright (c) 2022 alex@cloudware.io
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

@ -1,5 +1,102 @@
build for rpi: # nakamochi daemon and gui (ndg)
zig build -Dtarget=aarch64-linux-musl -Ddriver=fbev -Drelease-safe -Dstrip release build for linux/aarch64, a raspberry pi 4:
otherwise just `zig build` on dev host zig build -Dtarget=aarch64-linux-musl -Ddriver=fbev -Doptimize=ReleaseSafe -Dstrip
a dev build for a native arch linux host running Xorg can be compiled simply
with `zig build`. otherwise, for macOS or non-X11 platforms use SDL2:
zig build -Ddriver=sdl2
## local development
you'll need [zig v0.11.x](https://ziglang.org/download/).
if working on the gui, also [SDL2](https://www.libsdl.org/).
note that compiling the daemon on macOS is currently unsupported since
it requires some linux primitives.
compiling is expected to be as easy as
# only gui
zig build ngui
# only daemon
zig build nd
# everything at once
zig build
the output is placed in `./zig-out/bin` directory. for example, to run the gui,
simply execute `./zig-out/bin/ngui`.
the build script has a few project-specific options. list them all with
a `zig build --help` command. for instance, to reduce LVGL logging verbosity in
debug build mode, one can set this extra build flag:
zig build ngui -Dlvgl_loglevel=warn
run all tests with
zig build test
or a filtered subset using `test-filter`:
zig build test -Dtest-filter=xxx
significant contributors may find adding [.git-blame-ignore-revs](.git-blame-ignore-revs)
file to their git config useful, to skip very likely irrelevant commits
when browsing `git blame`:
git config blame.ignoreRevsFile .git-blame-ignore-revs
see also the [contributing](#contributing) section.
## CI automated checks
the CI runs code format checks, tests and builds for fbdev+evdev on aarch64
and SDL2. it requires a container image with zig and clang tools such as
clang-format.
to make a new image and switch the CI to use it, first modify the
[ci-containerfile](tools/ci-containerfile) and produce the image locally:
podman build --rm -t ndg-ci -f ./tools/ci-containerfile \
--build-arg ZIGURL=https://ziglang.org/download/0.12.0/zig-linux-x86_64-0.12.0.tar.xz
then tag it with the target URL, for example:
podman tag localhost/ndg-ci git.qcode.ch/nakamochi/ci-zig0.12.0:v1
generate an [access token](https://git.qcode.ch/user/settings/applications),
login to the container registry and push the image to remote:
podman login git.qcode.ch
podman push git.qcode.ch/nakamochi/ci-zig0.12.0:v1
the image will be available at
https://git.qcode.ch/nakamochi/-/packages/
finally, delete the access token from
https://git.qcode.ch/user/settings/applications
what's left is to update the CI [build pipeline](.woodpecker.yml) and delete
the older version of the image.
## contributing
to contribute, create a pull request or send a patch with
[git send-mail](https://git-scm.com/docs/git-send-email) to alex-dot-cloudware.io.
before sending a change, please make sure tests pass:
zig build test
and all code is formatted: zig code with `zig fmt` and C according to the
style described by [.clang-format](.clang-format) file. if `clang-format` tool
is installed, all formatting can be checked with:
./tools/fmt-check.sh
note that only C files in `src/` are formatted.
leave third party libraries as is - it is easier to update and upgrade when
the original style is preserved, even if it doesn't match this project.

@ -1,123 +1,202 @@
const std = @import("std"); const std = @import("std");
const nifbuild = @import("lib/nif/build.zig");
pub fn build(b: *std.build.Builder) void {
b.use_stage1 = true;
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{}); const target = b.standardTargetOptions(.{});
const mode = b.standardReleaseOptions(); const optimize = b.standardOptimizeOption(.{});
const strip = b.option(bool, "strip", "strip output binary; default: false") orelse false; const strip = b.option(bool, "strip", "strip output binary; default: false") orelse false;
const drv = b.option(DriverTarget, "driver", "display and input drivers combo; default: sdl2") orelse .sdl2; const drv = b.option(DriverTarget, "driver", "display and input drivers combo; default: x11") orelse .x11;
const disp_horiz = b.option(u32, "horiz", "display horizontal pixels count; default: 800") orelse 800; const disp_horiz = b.option(u32, "horiz", "display horizontal pixels count; default: 800") orelse 800;
const disp_vert = b.option(u32, "vert", "display vertical pixels count; default: 480") orelse 480; const disp_vert = b.option(u32, "vert", "display vertical pixels count; default: 480") orelse 480;
const lvgl_loglevel = b.option(LVGLLogLevel, "lvgl_loglevel", "LVGL lib logging level") orelse LVGLLogLevel.default(optimize);
const inver = b.option([]const u8, "version", "semantic version of the build; must match git tag when available");
const buildopts = b.addOptions();
const buildopts_mod = buildopts.createModule();
buildopts.addOption(DriverTarget, "driver", drv);
const semver_step = VersionStep.create(b, buildopts, inver);
buildopts.step.dependOn(semver_step);
// network interface (nif) standalone library used by the daemon and tests.
const libnif_dep = b.lazyDependency("nif", .{ .target = target, .optimize = optimize }) orelse return;
const libnif = libnif_dep.artifact("nif");
// ini file format parser
const libini_dep = b.lazyDependency("ini", .{ .target = target, .optimize = optimize }) orelse return;
const common_cflags = .{
"-Wall",
"-Wextra",
"-Wundef",
// strip source file paths for repro builds
b.fmt("-ffile-prefix-map={s}/=/", .{b.pathFromRoot("")}),
};
// gui build // gui build
const ngui = b.addExecutable("ngui", "src/ngui.zig"); const ngui = b.addExecutable(.{
ngui.setTarget(target); .name = "ngui",
ngui.setBuildMode(mode); .root_source_file = b.path("src/ngui.zig"),
.target = target,
.optimize = optimize,
.link_libc = true,
.strip = strip,
});
ngui.pie = true; ngui.pie = true;
ngui.strip = strip; ngui.root_module.addImport("build_options", buildopts_mod);
ngui.addIncludePath(b.path("lib"));
ngui.addIncludePath("lib"); ngui.addIncludePath(b.path("src/ui/c"));
ngui.addIncludePath("src/ui/c");
ngui.linkLibC();
const lvgl_flags = &.{ const lvgl_flags = .{
"-std=c11", "-std=c11",
"-fstack-protector", "-fstack-protector",
"-Wall",
"-Wextra",
"-Wformat", "-Wformat",
"-Wformat-security", "-Wformat-security",
"-Wundef", } ++ common_cflags;
}; ngui.addCSourceFiles(.{ .files = lvgl_generic_src, .flags = &lvgl_flags });
ngui.addCSourceFiles(lvgl_generic_src, lvgl_flags);
const ngui_cflags: []const []const u8 = &.{ const ngui_cflags = .{
"-std=c11", "-std=c11",
"-Wall",
"-Wextra",
"-Wshadow", "-Wshadow",
"-Wundef",
"-Wunused-parameter", "-Wunused-parameter",
"-Werror", "-Werror",
}; } ++ common_cflags;
ngui.addCSourceFiles(&.{ ngui.addCSourceFiles(.{
"src/ui/c/ui.c", .root = b.path("src/ui/c"),
"src/ui/c/lv_font_courierprimecode_14.c", .files = &.{
"src/ui/c/lv_font_courierprimecode_16.c", "ui.c",
"src/ui/c/lv_font_courierprimecode_24.c", "lv_font_courierprimecode_14.c",
}, ngui_cflags); "lv_font_courierprimecode_16.c",
"lv_font_courierprimecode_24.c",
ngui.defineCMacroRaw(b.fmt("NM_DISP_HOR={}", .{disp_horiz})); },
ngui.defineCMacroRaw(b.fmt("NM_DISP_VER={}", .{disp_vert})); .flags = &ngui_cflags,
ngui.defineCMacro("LV_CONF_INCLUDE_SIMPLE", null); });
ngui.root_module.addCMacro("NM_DISP_HOR", b.fmt("{d}", .{disp_horiz}));
ngui.root_module.addCMacro("NM_DISP_VER", b.fmt("{d}", .{disp_vert}));
ngui.defineCMacro("LV_CONF_INCLUDE_SIMPLE", "1");
ngui.defineCMacro("LV_LOG_LEVEL", lvgl_loglevel.text());
ngui.defineCMacro("LV_TICK_CUSTOM", "1"); ngui.defineCMacro("LV_TICK_CUSTOM", "1");
ngui.defineCMacro("LV_TICK_CUSTOM_INCLUDE", "\"ui.h\""); ngui.defineCMacro("LV_TICK_CUSTOM_INCLUDE", "\"lv_custom_tick.h\"");
ngui.defineCMacro("LV_TICK_CUSTOM_SYS_TIME_EXPR", "(nm_get_curr_tick())"); ngui.defineCMacro("LV_TICK_CUSTOM_SYS_TIME_EXPR", "(nm_get_curr_tick())");
switch (drv) { switch (drv) {
.sdl2 => { .sdl2 => {
ngui.addCSourceFiles(lvgl_sdl2_src, lvgl_flags); ngui.addCSourceFiles(.{ .files = lvgl_sdl2_src, .flags = &lvgl_flags });
ngui.addCSourceFile("src/ui/c/drv_sdl2.c", ngui_cflags); ngui.addCSourceFile(.{ .file = b.path("src/ui/c/drv_sdl2.c"), .flags = &ngui_cflags });
ngui.defineCMacro("NM_DRV_SDL2", null); ngui.defineCMacro("USE_SDL", "1");
ngui.defineCMacro("USE_SDL", null);
ngui.linkSystemLibrary("SDL2"); ngui.linkSystemLibrary("SDL2");
}, },
.x11 => {
ngui.addCSourceFiles(.{ .files = lvgl_x11_src, .flags = &lvgl_flags });
ngui.addCSourceFiles(.{
.files = &.{
"src/ui/c/drv_x11.c",
"src/ui/c/mouse_cursor_icon.c",
},
.flags = &ngui_cflags,
});
ngui.defineCMacro("USE_X11", "1");
ngui.linkSystemLibrary("X11");
},
.fbev => { .fbev => {
ngui.addCSourceFiles(lvgl_fbev_src, lvgl_flags); ngui.addCSourceFiles(.{ .files = lvgl_fbev_src, .flags = &lvgl_flags });
ngui.addCSourceFile("src/ui/c/drv_fbev.c", ngui_cflags); ngui.addCSourceFile(.{ .file = b.path("src/ui/c/drv_fbev.c"), .flags = &ngui_cflags });
ngui.defineCMacro("NM_DRV_FBEV", null); ngui.defineCMacro("USE_FBDEV", "1");
ngui.defineCMacro("USE_FBDEV", null); ngui.defineCMacro("USE_EVDEV", "1");
ngui.defineCMacro("USE_EVDEV", null);
}, },
} }
const ngui_build_step = b.step("ngui", "build ngui (nakamochi gui)"); const ngui_build_step = b.step("ngui", "build ngui (nakamochi gui)");
ngui_build_step.dependOn(&b.addInstallArtifact(ngui).step); ngui_build_step.dependOn(&b.addInstallArtifact(ngui, .{}).step);
// daemon build // daemon build
const nd = b.addExecutable("nd", "src/nd.zig"); const nd = b.addExecutable(.{
nd.setTarget(target); .name = "nd",
nd.setBuildMode(mode); .root_source_file = b.path("src/nd.zig"),
.target = target,
.optimize = optimize,
.strip = strip,
});
nd.pie = true; nd.pie = true;
nd.strip = strip; nd.root_module.addImport("build_options", buildopts_mod);
nd.root_module.addImport("nif", libnif_dep.module("nif"));
nifbuild.addPkg(b, nd, "lib/nif"); nd.root_module.addImport("ini", libini_dep.module("ini"));
const niflib = nifbuild.library(b, "lib/nif"); nd.linkLibrary(libnif);
niflib.setTarget(target);
niflib.setBuildMode(mode);
nd.linkLibrary(niflib);
const nd_build_step = b.step("nd", "build nd (nakamochi daemon)"); const nd_build_step = b.step("nd", "build nd (nakamochi daemon)");
nd_build_step.dependOn(&b.addInstallArtifact(nd).step); nd_build_step.dependOn(&b.addInstallArtifact(nd, .{}).step);
// default build
const build_all_step = b.step("all", "build everything");
build_all_step.dependOn(ngui_build_step);
build_all_step.dependOn(nd_build_step);
b.default_step.dependOn(build_all_step);
// automated tests
{ {
const tests = b.addTest("src/test.zig"); const tests = b.addTest(.{
tests.setTarget(target); .root_source_file = b.path("src/test.zig"),
tests.setBuildMode(mode); .target = target,
tests.linkLibC(); .optimize = optimize,
if (b.args) |args| { .link_libc = true,
for (args) |a, i| { .filter = b.option([]const u8, "test-filter", "run tests matching the filter"),
if (std.mem.eql(u8, a, "--test-filter")) { });
tests.setFilter(args[i + 1]); // don't care about OOB tests.root_module.addImport("build_options", buildopts_mod);
break; tests.root_module.addImport("nif", libnif_dep.module("nif"));
tests.root_module.addImport("ini", libini_dep.module("ini"));
tests.linkLibrary(libnif);
const run_tests = b.addRunArtifact(tests);
const test_step = b.step("test", "run tests");
test_step.dependOn(&run_tests.step);
} }
// GUI playground
{
const guiplay = b.addExecutable(.{
.name = "guiplay",
.root_source_file = b.path("src/test/guiplay.zig"),
.target = target,
.optimize = optimize,
});
guiplay.root_module.addImport("comm", b.createModule(.{ .root_source_file = b.path("src/comm.zig") }));
const guiplay_build_step = b.step("guiplay", "build GUI playground");
guiplay_build_step.dependOn(&b.addInstallArtifact(guiplay, .{}).step);
guiplay_build_step.dependOn(ngui_build_step);
} }
// bitcoind RPC client playground
{
const btcrpc = b.addExecutable(.{
.name = "btcrpc",
.root_source_file = b.path("src/test/btcrpc.zig"),
.target = target,
.optimize = optimize,
.strip = strip,
});
btcrpc.root_module.addImport("bitcoindrpc", b.createModule(.{ .root_source_file = b.path("src/bitcoindrpc.zig") }));
const btcrpc_build_step = b.step("btcrpc", "bitcoind RPC client playground");
btcrpc_build_step.dependOn(&b.addInstallArtifact(btcrpc, .{}).step);
} }
const test_step = b.step("test", "run tests"); // lnd HTTP API client playground
test_step.dependOn(&tests.step); {
const lndhc = b.addExecutable(.{
.name = "lndhc",
.root_source_file = b.path("src/test/lndhc.zig"),
.target = target,
.optimize = optimize,
.strip = strip,
});
lndhc.root_module.addImport("lightning", b.createModule(.{ .root_source_file = b.path("src/lightning.zig") }));
const lndhc_build_step = b.step("lndhc", "lnd HTTP API client playground");
lndhc_build_step.dependOn(&b.addInstallArtifact(lndhc, .{}).step);
} }
// default build step
const build_all_step = b.step("all", "build nd and ngui (default step)");
build_all_step.dependOn(ngui_build_step);
build_all_step.dependOn(nd_build_step);
b.default_step.dependOn(build_all_step);
} }
const DriverTarget = enum { const DriverTarget = enum {
sdl2, sdl2,
x11,
fbev, // framebuffer + evdev fbev, // framebuffer + evdev
}; };
@ -126,6 +205,10 @@ const lvgl_sdl2_src: []const []const u8 = &.{
"lib/lv_drivers/sdl/sdl_common.c", "lib/lv_drivers/sdl/sdl_common.c",
}; };
const lvgl_x11_src: []const []const u8 = &.{
"lib/lv_drivers/x11/x11.c",
};
const lvgl_fbev_src: []const []const u8 = &.{ const lvgl_fbev_src: []const []const u8 = &.{
"lib/lv_drivers/display/fbdev.c", "lib/lv_drivers/display/fbdev.c",
"lib/lv_drivers/indev/evdev.c", "lib/lv_drivers/indev/evdev.c",
@ -281,3 +364,112 @@ const lvgl_generic_src: []const []const u8 = &.{
"lib/lvgl/src/widgets/lv_table.c", "lib/lvgl/src/widgets/lv_table.c",
"lib/lvgl/src/widgets/lv_textarea.c", "lib/lvgl/src/widgets/lv_textarea.c",
}; };
/// LVGL log levels based on LV_LOG_LEVEL_xxx.
/// note that the messages are printed from a zig fn callback, always with .info std.log.Level.
const LVGLLogLevel = enum {
trace,
info,
warn,
err,
user,
none,
/// returns default mode based on the compiler optimization flags.
fn default(mode: std.builtin.Mode) @This() {
return switch (mode) {
.Debug => .warn,
.ReleaseSafe => .warn,
.ReleaseFast, .ReleaseSmall => .err,
};
}
/// returns a C #define value for LVGL config.
fn text(self: @This()) []const u8 {
return switch (self) {
.trace => "LV_LOG_LEVEL_TRACE",
.info => "LV_LOG_LEVEL_INFO",
.warn => "LV_LOG_LEVEL_WARN",
.err => "LV_LOG_LEVEL_ERROR",
.user => "LV_LOG_LEVEL_USER",
.none => "LV_LOG_LEVEL_NONE",
};
}
};
/// VersionStep injects a release build semantic version into buildopts as "semver".
/// the make step fails if the inver input version and the one found in a git tag mismatch.
///
/// while git-tagged versions are expected to be in v<semver>format, input version
/// to match against is any format supported by std.SemanticVersion.parse.
/// input version is optional; if unset, make fn succeeds given a correctly formatted
/// git tag is found.
const VersionStep = struct {
inver: ?[]const u8, // input version in std.SemanticVersion.parse format
buildopts: *std.Build.Step.Options, // where to store the build version
b: *std.Build,
step: std.Build.Step,
fn create(b: *std.Build, o: *std.Build.Step.Options, inver: ?[]const u8) *std.Build.Step {
const vstep = b.allocator.create(VersionStep) catch unreachable;
vstep.* = VersionStep{
.inver = inver,
.buildopts = o,
.b = b,
.step = std.Build.Step.init(.{
.id = .custom,
.name = "VersionStep: ndg semver",
.owner = b,
.makeFn = make,
}),
};
return &vstep.step;
}
fn make(step: *std.Build.Step, _: *std.Progress.Node) anyerror!void {
const self: *@This() = @fieldParentPtr("step", step);
const semver = try self.eval();
std.log.info("build version: {any}", .{semver});
self.buildopts.addOption(std.SemanticVersion, "semver", semver);
}
fn eval(self: *VersionStep) !std.SemanticVersion {
const repover = try self.gitver();
if (self.inver) |v| {
const insem = std.SemanticVersion.parse(v) catch |err| {
std.log.err("invalid input semver '{s}': {any}", .{ v, err });
return err;
};
if (repover != null and insem.order(repover.?) != .eq) {
std.log.err("input and repo semver mismatch: {any} vs {any}", .{ insem, repover });
return error.VersionMismatch;
}
return insem;
}
if (repover == null) {
std.log.err("must supply build semver from command line.", .{});
return error.MissingVersion;
}
return repover.?;
}
fn gitver(self: *VersionStep) !?std.SemanticVersion {
if (!std.process.can_spawn) {
return null;
}
const git = self.b.findProgram(&[_][]const u8{"git"}, &[_][]const u8{}) catch return null;
const prefix = "v"; // git tag prefix
const matchTag = self.b.fmt("{s}*.*.*", .{prefix});
const cmd = [_][]const u8{ git, "-C", self.b.pathFromRoot("."), "describe", "--match", matchTag, "--tags", "--abbrev=8" };
var code: u8 = undefined;
const git_describe = self.b.runAllowFail(&cmd, &code, .Ignore) catch return null;
const repotag = std.mem.trim(u8, git_describe, " \n\r")[prefix.len..];
return std.SemanticVersion.parse(repotag) catch |err| ret: {
std.log.err("unparsable git tag semver '{s}': {any}", .{ repotag, err });
break :ret err;
};
}
};

@ -0,0 +1,17 @@
.{
.name = "ndg",
.version = "0.8.1",
.dependencies = .{
.nif = .{
.path = "lib/nif",
},
.ini = .{
.path = "lib/ini",
},
},
.paths = .{
"build.zig",
"build.zig.zon",
"src",
},
}

@ -0,0 +1,2 @@
*.zig text=auto eol=lf
*.zig text=auto eol=lf

@ -0,0 +1 @@
github: MasterQ32

@ -0,0 +1,2 @@
zig-cache/
zig-out/

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

@ -0,0 +1,81 @@
# INI parser library
This is a very simple ini-parser library that provides:
- Raw record reading
- Leading/trailing whitespace removal
- comments based on `;` and `#`
- Zig API
- C API
## Usage example
### Zig
```zig
const std = @import("std");
const ini = @import("ini");
pub fn main() !void {
const file = try std.fs.cwd().openFile("example.ini", .{});
defer file.close();
var parser = ini.parse(std.testing.allocator, file.reader());
defer parser.deinit();
var writer = std.io.getStdOut().writer();
while (try parser.next()) |record| {
switch (record) {
.section => |heading| try writer.print("[{s}]\n", .{heading}),
.property => |kv| try writer.print("{s} = {s}\n", .{ kv.key, kv.value }),
.enumeration => |value| try writer.print("{s}\n", .{value}),
}
}
}
```
### C
```c
#include <ini.h>
#include <stdio.h>
#include <stdbool.h>
int main() {
FILE * f = fopen("example.ini", "rb");
if(!f)
return 1;
struct ini_Parser parser;
ini_create_file(&parser, f);
struct ini_Record record;
while(true)
{
enum ini_Error error = ini_next(&parser, &record);
if(error != INI_SUCCESS)
goto cleanup;
switch(record.type) {
case INI_RECORD_NUL: goto done;
case INI_RECORD_SECTION:
printf("[%s]\n", record.section);
break;
case INI_RECORD_PROPERTY:
printf("%s = %s\n", record.property.key, record.property.value);
break;
case INI_RECORD_ENUMERATION:
printf("%s\n", record.enumeration);
break;
}
}
done:
cleanup:
ini_destroy(&parser);
fclose(f);
return 0;
}
```

@ -0,0 +1,73 @@
const std = @import("std");
pub fn build(b: *std.Build) void {
const optimize = b.standardOptimizeOption(.{});
const target = b.standardTargetOptions(.{});
_ = b.addModule("ini", .{
.root_source_file = .{
.path = "src/ini.zig",
},
});
const lib = b.addStaticLibrary(.{
.name = "ini",
.root_source_file = .{ .path = "src/lib.zig" },
.target = target,
.optimize = optimize,
});
lib.bundle_compiler_rt = true;
lib.addIncludePath(.{ .path = "src" });
lib.linkLibC();
b.installArtifact(lib);
const example_c = b.addExecutable(.{
.name = "example-c",
.optimize = optimize,
.target = target,
});
example_c.addCSourceFile(.{
.file = .{
.path = "example/example.c",
},
.flags = &.{
"-Wall",
"-Wextra",
"-pedantic",
},
});
example_c.addIncludePath(.{ .path = "src" });
example_c.linkLibrary(lib);
example_c.linkLibC();
b.installArtifact(example_c);
const example_zig = b.addExecutable(.{
.name = "example-zig",
.root_source_file = .{ .path = "example/example.zig" },
.optimize = optimize,
.target = target,
});
example_zig.root_module.addImport("ini", b.modules.get("ini").?);
b.installArtifact(example_zig);
var main_tests = b.addTest(.{
.root_source_file = .{ .path = "src/test.zig" },
.optimize = optimize,
});
var binding_tests = b.addTest(.{
.root_source_file = .{ .path = "src/lib-test.zig" },
.optimize = optimize,
});
binding_tests.addIncludePath(.{ .path = "src" });
binding_tests.linkLibrary(lib);
binding_tests.linkLibC();
const test_step = b.step("test", "Run library tests");
test_step.dependOn(&main_tests.step);
test_step.dependOn(&binding_tests.step);
}

@ -0,0 +1,10 @@
.{
.name = "libini",
.version = "0.0.0",
.dependencies = .{},
.paths = .{
"build.zig",
"build.zig.zon",
"src",
},
}

@ -0,0 +1,41 @@
#include <ini.h>
#include <stdio.h>
#include <stdbool.h>
int main() {
FILE * f = fopen("example.ini", "rb");
if(!f)
return 1;
struct ini_Parser parser;
ini_create_file(&parser, f);
struct ini_Record record;
while(true)
{
enum ini_Error error = ini_next(&parser, &record);
if(error != INI_SUCCESS)
goto cleanup;
switch(record.type) {
case INI_RECORD_NUL: goto done;
case INI_RECORD_SECTION:
printf("[%s]\n", record.section);
break;
case INI_RECORD_PROPERTY:
printf("%s = %s\n", record.property.key, record.property.value);
break;
case INI_RECORD_ENUMERATION:
printf("%s\n", record.enumeration);
break;
}
}
done:
cleanup:
ini_destroy(&parser);
fclose(f);
return 0;
}

@ -0,0 +1,9 @@
[Meta]
author = xq
library = ini
[Albums]
Thriller
Back in Black
Bat Out of Hell
The Dark Side of the Moon

@ -0,0 +1,22 @@
const std = @import("std");
const ini = @import("ini");
pub fn main() !void {
const file = try std.fs.cwd().openFile("example.ini", .{});
defer file.close();
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer if (gpa.deinit() != .ok) @panic("memory leaked");
var parser = ini.parse(gpa.allocator(), file.reader());
defer parser.deinit();
var writer = std.io.getStdOut().writer();
while (try parser.next()) |record| {
switch (record) {
.section => |heading| try writer.print("[{s}]\n", .{heading}),
.property => |kv| try writer.print("{s} = {s}\n", .{ kv.key, kv.value }),
.enumeration => |value| try writer.print("{s}\n", .{value}),
}
}
}

@ -0,0 +1,64 @@
#ifndef ZIG_INI_H
#define ZIG_INI_H
#include <stddef.h>
#include <stdio.h>
#include <stdalign.h>
/// Opaque parser type. Consider the bytes in this struct
/// as "implementation defined".
/// This must also be fixed memory and must not be copied
/// after being initialized with `ini_create_*`!
struct ini_Parser
{
alignas(16) char opaque[128];
};
enum ini_RecordType : int
{
INI_RECORD_NUL = 0,
INI_RECORD_SECTION = 1,
INI_RECORD_PROPERTY = 2,
INI_RECORD_ENUMERATION = 3,
};
struct ini_KeyValuePair
{
char const * key;
char const * value;
};
struct ini_Record
{
enum ini_RecordType type;
union {
char const * section;
struct ini_KeyValuePair property;
char const * enumeration;
};
};
enum ini_Error
{
INI_SUCCESS = 0,
INI_ERR_OUT_OF_MEMORY = 1,
INI_ERR_IO = 2,
INI_ERR_INVALID_DATA = 3,
};
extern void ini_create_buffer(
struct ini_Parser * parser,
char const * data,
size_t length
);
extern void ini_create_file(
struct ini_Parser * parser,
FILE * file
);
extern void ini_destroy(struct ini_Parser * parser);
extern enum ini_Error ini_next(struct ini_Parser * parser, struct ini_Record * record);
#endif

@ -0,0 +1,93 @@
const std = @import("std");
/// An entry in a ini file. Each line that contains non-whitespace text can
/// be categorized into a record type.
pub const Record = union(enum) {
/// A section heading enclosed in `[` and `]`. The brackets are not included.
section: [:0]const u8,
/// A line that contains a key-value pair separated by `=`.
/// Both key and value have the excess whitespace trimmed.
/// Both key and value allow escaping with C string syntax.
property: KeyValue,
/// A line that is either escaped as a C string or contains no `=`
enumeration: [:0]const u8,
};
pub const KeyValue = struct {
key: [:0]const u8,
value: [:0]const u8,
};
const whitespace = " \r\t\x00";
/// WARNING:
/// This function is not a general purpose function but
/// requires to be executed on slices of the line_buffer *after*
/// the NUL terminator appendix.
/// This function will override the character after the slice end,
/// so make sure there is one available!
fn insertNulTerminator(slice: []const u8) [:0]const u8 {
const mut_ptr = @as([*]u8, @ptrFromInt(@intFromPtr(slice.ptr)));
mut_ptr[slice.len] = 0;
return mut_ptr[0..slice.len :0];
}
pub fn Parser(comptime Reader: type) type {
return struct {
const Self = @This();
line_buffer: std.ArrayList(u8),
reader: Reader,
pub fn deinit(self: *Self) void {
self.line_buffer.deinit();
self.* = undefined;
}
pub fn next(self: *Self) !?Record {
while (true) {
self.reader.readUntilDelimiterArrayList(&self.line_buffer, '\n', 4096) catch |err| switch (err) {
error.EndOfStream => {
if (self.line_buffer.items.len == 0)
return null;
},
else => |e| return e,
};
try self.line_buffer.append(0); // append guaranteed space for sentinel
const line = if (std.mem.indexOfAny(u8, self.line_buffer.items, ";#")) |index|
std.mem.trim(u8, self.line_buffer.items[0..index], whitespace)
else
std.mem.trim(u8, self.line_buffer.items, whitespace);
if (line.len == 0)
continue;
if (std.mem.startsWith(u8, line, "[") and std.mem.endsWith(u8, line, "]")) {
return Record{ .section = insertNulTerminator(line[1 .. line.len - 1]) };
}
if (std.mem.indexOfScalar(u8, line, '=')) |index| {
return Record{
.property = KeyValue{
// note: the key *might* replace the '=' in the slice with 0!
.key = insertNulTerminator(std.mem.trim(u8, line[0..index], whitespace)),
.value = insertNulTerminator(std.mem.trim(u8, line[index + 1 ..], whitespace)),
},
};
}
return Record{ .enumeration = insertNulTerminator(line) };
}
}
};
}
/// Returns a new parser that can read the ini structure
pub fn parse(allocator: std.mem.Allocator, reader: anytype) Parser(@TypeOf(reader)) {
return Parser(@TypeOf(reader)){
.line_buffer = std.ArrayList(u8).init(allocator),
.reader = reader,
};
}

@ -0,0 +1,89 @@
const std = @import("std");
const c = @cImport({
@cInclude("ini.h");
});
test "parser create/destroy" {
var buffer: c.ini_Parser = undefined;
c.ini_create_buffer(&buffer, "", 0);
c.ini_destroy(&buffer);
}
fn expectNull(record: c.ini_Record) !void {
try std.testing.expectEqual(c.INI_RECORD_NUL, record.type);
}
fn expectSection(heading: []const u8, record: c.ini_Record) !void {
try std.testing.expectEqual(c.INI_RECORD_SECTION, record.type);
try std.testing.expectEqualStrings(heading, std.mem.span(record.unnamed_0.section));
}
fn expectKeyValue(key: []const u8, value: []const u8, record: c.ini_Record) !void {
try std.testing.expectEqual(c.INI_RECORD_PROPERTY, record.type);
try std.testing.expectEqualStrings(key, std.mem.span(record.unnamed_0.property.key));
try std.testing.expectEqualStrings(value, std.mem.span(record.unnamed_0.property.value));
}
fn expectEnumeration(enumeration: []const u8, record: c.ini_Record) !void {
try std.testing.expectEqual(c.INI_RECORD_ENUMERATION, record.type);
try std.testing.expectEqualStrings(enumeration, std.mem.span(record.unnamed_0.enumeration));
}
fn parseNext(parser: *c.ini_Parser) !c.ini_Record {
var record: c.ini_Record = undefined;
const err = c.ini_next(parser, &record);
switch (err) {
c.INI_SUCCESS => return record,
c.INI_ERR_OUT_OF_MEMORY => return error.OutOfMemory,
c.INI_ERR_IO => return error.InputOutput,
c.INI_ERR_INVALID_DATA => return error.InvalidData,
else => unreachable,
}
}
fn commonTest(parser: *c.ini_Parser) !void {
try expectSection("Meta", try parseNext(parser));
try expectKeyValue("author", "xq", try parseNext(parser));
try expectKeyValue("library", "ini", try parseNext(parser));
try expectSection("Albums", try parseNext(parser));
try expectEnumeration("Thriller", try parseNext(parser));
try expectEnumeration("Back in Black", try parseNext(parser));
try expectEnumeration("Bat Out of Hell", try parseNext(parser));
try expectEnumeration("The Dark Side of the Moon", try parseNext(parser));
try expectNull(try parseNext(parser));
}
test "buffer parser" {
const slice =
\\[Meta]
\\author = xq
\\library = ini
\\
\\[Albums]
\\Thriller
\\Back in Black
\\Bat Out of Hell
\\The Dark Side of the Moon
;
var parser: c.ini_Parser = undefined;
c.ini_create_buffer(&parser, slice, slice.len);
defer c.ini_destroy(&parser);
try commonTest(&parser);
}
test "file parser" {
const file = c.fopen("example/example.ini", "rb") orelse unreachable;
defer _ = c.fclose(file);
var parser: c.ini_Parser = undefined;
c.ini_create_file(&parser, file);
defer c.ini_destroy(&parser);
try commonTest(&parser);
}

@ -0,0 +1,158 @@
const std = @import("std");
const ini = @import("ini.zig");
const c = @cImport({
@cInclude("ini.h");
});
const Record = extern struct {
type: Type,
value: Data,
const Type = enum(c.ini_RecordType) {
nul = 0,
section = 1,
property = 2,
enumeration = 3,
};
const Data = extern union {
section: [*:0]const u8,
property: KeyValuePair,
enumeration: [*:0]const u8,
};
const KeyValuePair = extern struct {
key: [*:0]const u8,
value: [*:0]const u8,
};
};
const BufferParser = struct {
stream: std.io.FixedBufferStream([]const u8),
parser: ini.Parser(std.io.FixedBufferStream([]const u8).Reader),
};
const IniParser = union(enum) {
buffer: BufferParser,
file: ini.Parser(CReader),
};
const IniError = enum(c.ini_Error) {
success = 0,
out_of_memory = 1,
io = 2,
invalid_data = 3,
};
comptime {
if (@sizeOf(c.ini_Parser) < @sizeOf(IniParser))
@compileError(std.fmt.comptimePrint("ini_Parser struct in header is too small. Please set the char array to at least {d} chars!", .{@sizeOf(IniParser)}));
if (@alignOf(c.ini_Parser) < @alignOf(IniParser))
@compileError("align mismatch: ini_Parser struct does not match IniParser");
if (@sizeOf(c.ini_Record) != @sizeOf(Record))
@compileError("size mismatch: ini_Record struct does not match Record!");
if (@alignOf(c.ini_Record) != @alignOf(Record))
@compileError("align mismatch: ini_Record struct does not match Record!");
if (@sizeOf(c.ini_KeyValuePair) != @sizeOf(Record.KeyValuePair))
@compileError("size mismatch: ini_KeyValuePair struct does not match Record.KeyValuePair!");
if (@alignOf(c.ini_KeyValuePair) != @alignOf(Record.KeyValuePair))
@compileError("align mismatch: ini_KeyValuePair struct does not match Record.KeyValuePair!");
}
export fn ini_create_buffer(parser: *IniParser, data: [*]const u8, length: usize) void {
parser.* = IniParser{
.buffer = .{
.stream = std.io.fixedBufferStream(data[0..length]),
.parser = undefined,
},
};
// this is required to have the parser store a pointer to the stream.
parser.buffer.parser = ini.parse(std.heap.c_allocator, parser.buffer.stream.reader());
}
export fn ini_create_file(parser: *IniParser, file: *std.c.FILE) void {
parser.* = IniParser{
.file = ini.parse(std.heap.c_allocator, cReader(file)),
};
}
export fn ini_destroy(parser: *IniParser) void {
switch (parser.*) {
.buffer => |*p| p.parser.deinit(),
.file => |*p| p.deinit(),
}
parser.* = undefined;
}
const ParseError = error{ OutOfMemory, StreamTooLong } || CReader.Error;
fn mapError(err: ParseError) IniError {
return switch (err) {
error.OutOfMemory => IniError.out_of_memory,
error.StreamTooLong => IniError.invalid_data,
else => IniError.io,
};
}
export fn ini_next(parser: *IniParser, record: *Record) IniError {
const src_record_or_null: ?ini.Record = switch (parser.*) {
.buffer => |*p| p.parser.next() catch |e| return mapError(e),
.file => |*p| p.next() catch |e| return mapError(e),
};
if (src_record_or_null) |src_record| {
record.* = switch (src_record) {
.section => |heading| Record{
.type = .section,
.value = .{ .section = heading.ptr },
},
.enumeration => |enumeration| Record{
.type = .enumeration,
.value = .{ .enumeration = enumeration.ptr },
},
.property => |property| Record{
.type = .property,
.value = .{ .property = .{
.key = property.key.ptr,
.value = property.value.ptr,
} },
},
};
} else {
record.* = Record{
.type = .nul,
.value = undefined,
};
}
return .success;
}
const CReader = std.io.Reader(*std.c.FILE, std.fs.File.ReadError, cReaderRead);
fn cReader(c_file: *std.c.FILE) CReader {
return .{ .context = c_file };
}
fn cReaderRead(c_file: *std.c.FILE, bytes: []u8) std.fs.File.ReadError!usize {
const amt_read = std.c.fread(bytes.ptr, 1, bytes.len, c_file);
if (amt_read >= 0) return amt_read;
switch (@as(std.os.E, @enumFromInt(std.c._errno().*))) {
.SUCCESS => unreachable,
.INVAL => unreachable,
.FAULT => unreachable,
.AGAIN => unreachable, // this is a blocking API
.BADF => unreachable, // always a race condition
.DESTADDRREQ => unreachable, // connect was never called
.DQUOT => return error.DiskQuota,
.FBIG => return error.FileTooBig,
.IO => return error.InputOutput,
.NOSPC => return error.NoSpaceLeft,
.PERM => return error.AccessDenied,
.PIPE => return error.BrokenPipe,
else => |err| return std.os.unexpectedErrno(err),
}
}

@ -0,0 +1,183 @@
const std = @import("std");
const ini = @import("ini.zig");
const parse = ini.parse;
const Record = ini.Record;
fn expectNull(record: ?Record) !void {
try std.testing.expectEqual(@as(?Record, null), record);
}
fn expectSection(heading: []const u8, record: ?Record) !void {
try std.testing.expectEqualStrings(heading, record.?.section);
}
fn expectKeyValue(key: []const u8, value: []const u8, record: ?Record) !void {
try std.testing.expectEqualStrings(key, record.?.property.key);
try std.testing.expectEqualStrings(value, record.?.property.value);
}
fn expectEnumeration(enumeration: []const u8, record: ?Record) !void {
try std.testing.expectEqualStrings(enumeration, record.?.enumeration);
}
test "empty file" {
var stream = std.io.fixedBufferStream("");
var parser = parse(std.testing.allocator, stream.reader());
defer parser.deinit();
try expectNull(try parser.next());
try expectNull(try parser.next());
try expectNull(try parser.next());
try expectNull(try parser.next());
}
test "section" {
var stream = std.io.fixedBufferStream("[Hello]");
var parser = parse(std.testing.allocator, stream.reader());
defer parser.deinit();
try expectSection("Hello", try parser.next());
try expectNull(try parser.next());
}
test "key-value-pair" {
for (&[_][]const u8{
"key=value",
" key=value",
"key=value ",
" key=value ",
"key =value",
" key =value",
"key =value ",
" key =value ",
"key= value",
" key= value",
"key= value ",
" key= value ",
"key = value",
" key = value",
"key = value ",
" key = value ",
}) |pattern| {
var stream = std.io.fixedBufferStream(pattern);
var parser = parse(std.testing.allocator, stream.reader());
defer parser.deinit();
try expectKeyValue("key", "value", try parser.next());
try expectNull(try parser.next());
}
}
test "enumeration" {
var stream = std.io.fixedBufferStream("enum");
var parser = parse(std.testing.allocator, stream.reader());
defer parser.deinit();
try expectEnumeration("enum", try parser.next());
try expectNull(try parser.next());
}
test "empty line skipping" {
var stream = std.io.fixedBufferStream("item a\r\n\r\n\r\nitem b");
var parser = parse(std.testing.allocator, stream.reader());
defer parser.deinit();
try expectEnumeration("item a", try parser.next());
try expectEnumeration("item b", try parser.next());
try expectNull(try parser.next());
}
test "multiple sections" {
var stream = std.io.fixedBufferStream(" [Hello] \r\n[Foo Bar]\n[Hello!]\n");
var parser = parse(std.testing.allocator, stream.reader());
defer parser.deinit();
try expectSection("Hello", try parser.next());
try expectSection("Foo Bar", try parser.next());
try expectSection("Hello!", try parser.next());
try expectNull(try parser.next());
}
test "multiple properties" {
var stream = std.io.fixedBufferStream("a = b\r\nc =\r\nkey value = core property");
var parser = parse(std.testing.allocator, stream.reader());
defer parser.deinit();
try expectKeyValue("a", "b", try parser.next());
try expectKeyValue("c", "", try parser.next());
try expectKeyValue("key value", "core property", try parser.next());
try expectNull(try parser.next());
}
test "multiple enumeration" {
var stream = std.io.fixedBufferStream(" a \n b \r\n c ");
var parser = parse(std.testing.allocator, stream.reader());
defer parser.deinit();
try expectEnumeration("a", try parser.next());
try expectEnumeration("b", try parser.next());
try expectEnumeration("c", try parser.next());
try expectNull(try parser.next());
}
test "mixed data" {
var stream = std.io.fixedBufferStream(
\\[Meta]
\\author = xq
\\library = ini
\\
\\[Albums]
\\Thriller
\\Back in Black
\\Bat Out of Hell
\\The Dark Side of the Moon
);
var parser = parse(std.testing.allocator, stream.reader());
defer parser.deinit();
try expectSection("Meta", try parser.next());
try expectKeyValue("author", "xq", try parser.next());
try expectKeyValue("library", "ini", try parser.next());
try expectSection("Albums", try parser.next());
try expectEnumeration("Thriller", try parser.next());
try expectEnumeration("Back in Black", try parser.next());
try expectEnumeration("Bat Out of Hell", try parser.next());
try expectEnumeration("The Dark Side of the Moon", try parser.next());
try expectNull(try parser.next());
}
test "# comments" {
var stream = std.io.fixedBufferStream(
\\[section] # comment
\\key = value # comment
\\enum # comment
);
var parser = parse(std.testing.allocator, stream.reader());
defer parser.deinit();
try expectSection("section", try parser.next());
try expectKeyValue("key", "value", try parser.next());
try expectEnumeration("enum", try parser.next());
try expectNull(try parser.next());
}
test "; comments" {
var stream = std.io.fixedBufferStream(
\\[section] ; comment
\\key = value ; comment
\\enum ; comment
);
var parser = parse(std.testing.allocator, stream.reader());
defer parser.deinit();
try expectSection("section", try parser.next());
try expectKeyValue("key", "value", try parser.next());
try expectEnumeration("enum", try parser.next());
try expectNull(try parser.next());
}

@ -1,2 +1,3 @@
**/*.o **/*.o
**/*.d **/*.d
build/*

@ -20,6 +20,7 @@ target_include_directories(lv_drivers SYSTEM PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
find_package(PkgConfig) find_package(PkgConfig)
pkg_check_modules(PKG_WAYLAND wayland-client wayland-cursor wayland-protocols xkbcommon) pkg_check_modules(PKG_WAYLAND wayland-client wayland-cursor wayland-protocols xkbcommon)
pkg_check_modules(PKG_LVGL lvgl)
target_link_libraries(lv_drivers PUBLIC lvgl ${PKG_WAYLAND_LIBRARIES}) target_link_libraries(lv_drivers PUBLIC lvgl ${PKG_WAYLAND_LIBRARIES})
if("${LIB_INSTALL_DIR}" STREQUAL "") if("${LIB_INSTALL_DIR}" STREQUAL "")
@ -38,7 +39,16 @@ install(
PATTERN ".git*" EXCLUDE PATTERN ".git*" EXCLUDE
PATTERN "CMakeFiles" EXCLUDE PATTERN "CMakeFiles" EXCLUDE
PATTERN "docs" EXCLUDE PATTERN "docs" EXCLUDE
PATTERN "lib" EXCLUDE) PATTERN "lib" EXCLUDE
PATTERN "*.pc.in" EXCLUDE)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${PKG_LVGL_CFLAGS}")
configure_file("${CMAKE_SOURCE_DIR}/lv-drivers.pc.in" lv-drivers.pc @ONLY)
install(
FILES "${CMAKE_BINARY_DIR}/lv-drivers.pc"
DESTINATION "${LIB_INSTALL_DIR}/pkgconfig/")
file(GLOB LV_DRIVERS_PUBLIC_HEADERS "${CMAKE_SOURCE_DIR}/lv_drv_conf.h") file(GLOB LV_DRIVERS_PUBLIC_HEADERS "${CMAKE_SOURCE_DIR}/lv_drv_conf.h")

@ -1,6 +1,6 @@
# Display and Touch pad drivers # Display and Touch pad drivers
Display controller and touchpad driver to can be directly used with [LittlevGL](https://littlevgl.com). Display controller and touchpad driver to can be directly used with [LVGL](https://lvgl.io/).
To learn more about using drivers in LittlevGL visit the [Porting guide](https://docs.lvgl.io/latest/en/html/porting/index.html). To learn more about using drivers in LittlevGL visit the [Porting guide](https://docs.lvgl.io/latest/en/html/porting/index.html).

@ -9,19 +9,14 @@
#include "drm.h" #include "drm.h"
#if USE_DRM #if USE_DRM
#include <unistd.h> #include <errno.h>
#include <pthread.h> #include <fcntl.h>
#include <time.h> #include <poll.h>
#include <sys/time.h> #include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <inttypes.h> #include <unistd.h>
#include <xf86drm.h> #include <xf86drm.h>
#include <xf86drmMode.h> #include <xf86drmMode.h>
@ -41,7 +36,7 @@ struct drm_buffer {
uint32_t pitch; uint32_t pitch;
uint32_t offset; uint32_t offset;
unsigned long int size; unsigned long int size;
void * map; uint8_t * map;
uint32_t fb_handle; uint32_t fb_handle;
}; };
@ -65,8 +60,9 @@ struct drm_dev {
drmModePropertyPtr plane_props[128]; drmModePropertyPtr plane_props[128];
drmModePropertyPtr crtc_props[128]; drmModePropertyPtr crtc_props[128];
drmModePropertyPtr conn_props[128]; drmModePropertyPtr conn_props[128];
struct drm_buffer drm_bufs[2]; /* DUMB buffers */ struct drm_buffer drm_bufs[2]; /*DUMB buffers*/
struct drm_buffer *cur_bufs[2]; /* double buffering handling */ uint8_t active_drm_buf_idx; /*Double buffering handling*/
lv_disp_draw_buf_t draw_buf;
} drm_dev; } drm_dev;
static uint32_t get_plane_property_id(const char *name) static uint32_t get_plane_property_id(const char *name)
@ -117,7 +113,18 @@ static uint32_t get_conn_property_id(const char *name)
static void page_flip_handler(int fd, unsigned int sequence, unsigned int tv_sec, static void page_flip_handler(int fd, unsigned int sequence, unsigned int tv_sec,
unsigned int tv_usec, void *user_data) unsigned int tv_usec, void *user_data)
{ {
LV_UNUSED(fd);
LV_UNUSED(sequence);
LV_UNUSED(tv_sec);
LV_UNUSED(tv_usec);
LV_UNUSED(user_data);
dbg("flip"); dbg("flip");
if(drm_dev.req) {
drmModeAtomicFree(drm_dev.req);
drm_dev.req = NULL;
}
} }
static int drm_get_plane_props(void) static int drm_get_plane_props(void)
@ -244,7 +251,7 @@ static int drm_dmabuf_set_plane(struct drm_buffer *buf)
{ {
int ret; int ret;
static int first = 1; static int first = 1;
uint32_t flags = DRM_MODE_PAGE_FLIP_EVENT; uint32_t flags = DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_ATOMIC_NONBLOCK;
drm_dev.req = drmModeAtomicAlloc(); drm_dev.req = drmModeAtomicAlloc();
@ -283,6 +290,7 @@ static int drm_dmabuf_set_plane(struct drm_buffer *buf)
static int find_plane(unsigned int fourcc, uint32_t *plane_id, uint32_t crtc_id, uint32_t crtc_idx) static int find_plane(unsigned int fourcc, uint32_t *plane_id, uint32_t crtc_id, uint32_t crtc_idx)
{ {
LV_UNUSED(crtc_id);
drmModePlaneResPtr planes; drmModePlaneResPtr planes;
drmModePlanePtr plane; drmModePlanePtr plane;
unsigned int i; unsigned int i;
@ -393,7 +401,7 @@ static int drm_find_connector(void)
drm_dev.mmWidth = conn->mmWidth; drm_dev.mmWidth = conn->mmWidth;
drm_dev.mmHeight = conn->mmHeight; drm_dev.mmHeight = conn->mmHeight;
memcpy(&drm_dev.mode, &conn->modes[0], sizeof(drmModeModeInfo)); lv_memcpy(&drm_dev.mode, &conn->modes[0], sizeof(drmModeModeInfo));
if (drmModeCreatePropertyBlob(drm_dev.fd, &drm_dev.mode, sizeof(drm_dev.mode), if (drmModeCreatePropertyBlob(drm_dev.fd, &drm_dev.mode, sizeof(drm_dev.mode),
&drm_dev.blob_id)) { &drm_dev.blob_id)) {
@ -464,7 +472,7 @@ static int drm_find_connector(void)
drmModeFreeEncoder(enc); drmModeFreeEncoder(enc);
} }
drm_dev.crtc_idx = -1; drm_dev.crtc_idx = UINT32_MAX;
for (i = 0; i < res->count_crtcs; ++i) { for (i = 0; i < res->count_crtcs; ++i) {
if (drm_dev.crtc_id == res->crtcs[i]) { if (drm_dev.crtc_id == res->crtcs[i]) {
@ -473,7 +481,7 @@ static int drm_find_connector(void)
} }
} }
if (drm_dev.crtc_idx == -1) { if (drm_dev.crtc_idx == UINT32_MAX) {
err("drm: CRTC not found"); err("drm: CRTC not found");
goto free_res; goto free_res;
} }
@ -614,7 +622,7 @@ static int drm_allocate_dumb(struct drm_buffer *buf)
int ret; int ret;
/* create dumb buffer */ /* create dumb buffer */
memset(&creq, 0, sizeof(creq)); lv_memset(&creq, 0, sizeof(creq));
creq.width = drm_dev.width; creq.width = drm_dev.width;
creq.height = drm_dev.height; creq.height = drm_dev.height;
creq.bpp = LV_COLOR_DEPTH; creq.bpp = LV_COLOR_DEPTH;
@ -626,12 +634,10 @@ static int drm_allocate_dumb(struct drm_buffer *buf)
buf->handle = creq.handle; buf->handle = creq.handle;
buf->pitch = creq.pitch; buf->pitch = creq.pitch;
dbg("pitch %d", buf->pitch);
buf->size = creq.size; buf->size = creq.size;
dbg("size %d", buf->size);
/* prepare buffer for memory mapping */ /* prepare buffer for memory mapping */
memset(&mreq, 0, sizeof(mreq)); lv_memset(&mreq, 0, sizeof(mreq));
mreq.handle = creq.handle; mreq.handle = creq.handle;
ret = drmIoctl(drm_dev.fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq); ret = drmIoctl(drm_dev.fd, DRM_IOCTL_MODE_MAP_DUMB, &mreq);
if (ret) { if (ret) {
@ -640,6 +646,7 @@ static int drm_allocate_dumb(struct drm_buffer *buf)
} }
buf->offset = mreq.offset; buf->offset = mreq.offset;
info("size %lu pitch %u offset %u", buf->size, buf->pitch, buf->offset);
/* perform actual memory mapping */ /* perform actual memory mapping */
buf->map = mmap(0, creq.size, PROT_READ | PROT_WRITE, MAP_SHARED, drm_dev.fd, mreq.offset); buf->map = mmap(0, creq.size, PROT_READ | PROT_WRITE, MAP_SHARED, drm_dev.fd, mreq.offset);
@ -649,7 +656,7 @@ static int drm_allocate_dumb(struct drm_buffer *buf)
} }
/* clear the framebuffer to 0 (= full transparency in ARGB8888) */ /* clear the framebuffer to 0 (= full transparency in ARGB8888) */
memset(buf->map, 0, creq.size); lv_memset(buf->map, 0, creq.size);
/* create framebuffer object for the dumb-buffer */ /* create framebuffer object for the dumb-buffer */
handles[0] = creq.handle; handles[0] = creq.handle;
@ -669,7 +676,7 @@ static int drm_setup_buffers(void)
{ {
int ret; int ret;
/* Allocate DUMB buffers */ /*Allocate DUMB buffers*/
ret = drm_allocate_dumb(&drm_dev.drm_bufs[0]); ret = drm_allocate_dumb(&drm_dev.drm_bufs[0]);
if (ret) if (ret)
return ret; return ret;
@ -678,80 +685,61 @@ static int drm_setup_buffers(void)
if (ret) if (ret)
return ret; return ret;
/* Set buffering handling */
drm_dev.cur_bufs[0] = NULL;
drm_dev.cur_bufs[1] = &drm_dev.drm_bufs[0];
return 0; return 0;
} }
void drm_wait_vsync(lv_disp_drv_t *disp_drv) void drm_wait_vsync(lv_disp_drv_t * disp_drv)
{ {
int ret; while(drm_dev.req) {
fd_set fds; struct pollfd pfd;
FD_ZERO(&fds); pfd.fd = drm_dev.fd;
FD_SET(drm_dev.fd, &fds); pfd.events = POLLIN;
int ret;
do { do {
ret = select(drm_dev.fd + 1, &fds, NULL, NULL, NULL); ret = poll(&pfd, 1, -1);
} while (ret == -1 && errno == EINTR); } while (ret == -1 && errno == EINTR);
if (ret < 0) { if(ret > 0)
err("select failed: %s", strerror(errno)); drmHandleEvent(drm_dev.fd, &drm_dev.drm_event_ctx);
drmModeAtomicFree(drm_dev.req); else {
drm_dev.req = NULL; err("poll failed: %s", strerror(errno));
return; return;
} }
}
if (FD_ISSET(drm_dev.fd, &fds)) lv_disp_flush_ready(disp_drv);
drmHandleEvent(drm_dev.fd, &drm_dev.drm_event_ctx);
drmModeAtomicFree(drm_dev.req);
drm_dev.req = NULL;
} }
void drm_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p) void drm_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{ {
struct drm_buffer *fbuf = drm_dev.cur_bufs[1]; struct drm_buffer *fbuf = &drm_dev.drm_bufs[drm_dev.active_drm_buf_idx ^ 1];
lv_coord_t w = (area->x2 - area->x1 + 1);
lv_coord_t h = (area->y2 - area->y1 + 1);
int i, y;
dbg("x %d:%d y %d:%d w %d h %d", area->x1, area->x2, area->y1, area->y2, w, h); if(!disp_drv->direct_mode) {
/*Backwards compatibility: Non-direct flush */
/* Partial update */ uint32_t w = (area->x2 - area->x1) + 1;
if ((w != drm_dev.width || h != drm_dev.height) && drm_dev.cur_bufs[0]) for (int y = 0, i = area->y1; i <= area->y2 ; ++i, ++y) {
memcpy(fbuf->map, drm_dev.cur_bufs[0]->map, fbuf->size); lv_memcpy(fbuf->map + (area->x1 * (LV_COLOR_SIZE / 8)) + (fbuf->pitch * i),
(uint8_t *)color_p + (w * (LV_COLOR_SIZE / 8) * y),
for (y = 0, i = area->y1 ; i <= area->y2 ; ++i, ++y) { w * (LV_COLOR_SIZE / 8));
memcpy((uint8_t *)fbuf->map + (area->x1 * (LV_COLOR_SIZE/8)) + (fbuf->pitch * i), }
(uint8_t *)color_p + (w * (LV_COLOR_SIZE/8) * y),
w * (LV_COLOR_SIZE/8));
} }
if (drm_dev.req) if(lv_disp_flush_is_last(disp_drv)) {
drm_wait_vsync(disp_drv); /*Request buffer swap*/
if(drm_dmabuf_set_plane(fbuf)) {
/* show fbuf plane */
if (drm_dmabuf_set_plane(fbuf)) {
err("Flush fail"); err("Flush fail");
return; return;
} }
else else
dbg("Flush done"); dbg("Flush done");
if (!drm_dev.cur_bufs[0]) drm_dev.active_drm_buf_idx ^= 1;
drm_dev.cur_bufs[1] = &drm_dev.drm_bufs[1]; }
else
drm_dev.cur_bufs[1] = drm_dev.cur_bufs[0];
drm_dev.cur_bufs[0] = fbuf;
lv_disp_flush_ready(disp_drv);
} }
#if LV_COLOR_DEPTH == 32 #if LV_COLOR_DEPTH == 32
#define DRM_FOURCC DRM_FORMAT_ARGB8888 #define DRM_FOURCC DRM_FORMAT_XRGB8888
#elif LV_COLOR_DEPTH == 16 #elif LV_COLOR_DEPTH == 16
#define DRM_FOURCC DRM_FORMAT_RGB565 #define DRM_FOURCC DRM_FORMAT_RGB565
#else #else
@ -770,7 +758,7 @@ void drm_get_sizes(lv_coord_t *width, lv_coord_t *height, uint32_t *dpi)
*dpi = DIV_ROUND_UP(drm_dev.width * 25400, drm_dev.mmWidth * 1000); *dpi = DIV_ROUND_UP(drm_dev.width * 25400, drm_dev.mmWidth * 1000);
} }
void drm_init(void) int drm_init(void)
{ {
int ret; int ret;
@ -778,7 +766,7 @@ void drm_init(void)
if (ret) { if (ret) {
close(drm_dev.fd); close(drm_dev.fd);
drm_dev.fd = -1; drm_dev.fd = -1;
return; return -1;
} }
ret = drm_setup_buffers(); ret = drm_setup_buffers();
@ -786,10 +774,28 @@ void drm_init(void)
err("DRM buffer allocation failed"); err("DRM buffer allocation failed");
close(drm_dev.fd); close(drm_dev.fd);
drm_dev.fd = -1; drm_dev.fd = -1;
return; return -1;
} }
info("DRM subsystem and buffer mapped successfully"); info("DRM subsystem and buffer mapped successfully");
return 0;
}
int drm_disp_drv_init(lv_disp_drv_t * disp_drv)
{
lv_disp_drv_init(disp_drv);
int ret = drm_init();
if(ret) return ret;
lv_disp_draw_buf_init(&drm_dev.draw_buf, drm_dev.drm_bufs[1].map, drm_dev.drm_bufs[0].map, drm_dev.width * drm_dev.height);
disp_drv->draw_buf = &drm_dev.draw_buf;
disp_drv->direct_mode = true;
disp_drv->hor_res = drm_dev.width;
disp_drv->ver_res = drm_dev.height;
disp_drv->flush_cb = drm_flush;
disp_drv->wait_cb = drm_wait_vsync;
return 0;
} }
void drm_exit(void) void drm_exit(void)

@ -40,13 +40,14 @@ extern "C" {
/********************** /**********************
* GLOBAL PROTOTYPES * GLOBAL PROTOTYPES
**********************/ **********************/
void drm_init(void);
void drm_get_sizes(lv_coord_t *width, lv_coord_t *height, uint32_t *dpi); int drm_init(void); /*Deprecated: Use drm_disp_drv_init instead*/
int drm_disp_drv_init(lv_disp_drv_t * disp_drv);
void drm_get_sizes(lv_coord_t * width, lv_coord_t * height, uint32_t * dpi);
void drm_exit(void); void drm_exit(void);
void drm_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p); void drm_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color_p);
void drm_wait_vsync(lv_disp_drv_t * drv); void drm_wait_vsync(lv_disp_drv_t * drv);
/********************** /**********************
* MACROS * MACROS
**********************/ **********************/

@ -101,7 +101,7 @@ void fbdev_init(void)
// Make sure that the display is on. // Make sure that the display is on.
if (ioctl(fbfd, FBIOBLANK, FB_BLANK_UNBLANK) != 0) { if (ioctl(fbfd, FBIOBLANK, FB_BLANK_UNBLANK) != 0) {
perror("ioctl(FBIOBLANK)"); perror("ioctl(FBIOBLANK)");
return; // Don't return. Some framebuffer drivers like efifb or simplefb don't implement FBIOBLANK.
} }
#if USE_BSD_FBDEV #if USE_BSD_FBDEV
@ -195,8 +195,8 @@ void fbdev_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color
long int byte_location = 0; long int byte_location = 0;
unsigned char bit_location = 0; unsigned char bit_location = 0;
/*32 or 24 bit per pixel*/ /*32 bit per pixel*/
if(vinfo.bits_per_pixel == 32 || vinfo.bits_per_pixel == 24) { if(vinfo.bits_per_pixel == 32) {
uint32_t * fbp32 = (uint32_t *)fbp; uint32_t * fbp32 = (uint32_t *)fbp;
int32_t y; int32_t y;
for(y = act_y1; y <= act_y2; y++) { for(y = act_y1; y <= act_y2; y++) {
@ -205,6 +205,23 @@ void fbdev_flush(lv_disp_drv_t * drv, const lv_area_t * area, lv_color_t * color
color_p += w; color_p += w;
} }
} }
/*24 bit per pixel*/
else if(vinfo.bits_per_pixel == 24 && LV_COLOR_DEPTH == 32) {
uint8_t * fbp8 = (uint8_t *)fbp;
lv_coord_t x;
int32_t y;
uint8_t *pixel;
for(y = act_y1; y <= act_y2; y++) {
location = (act_x1 + vinfo.xoffset) + (y + vinfo.yoffset) * finfo.line_length / 3;
for (x = 0; x < w; ++x) {
pixel = (uint8_t *)(&color_p[x]);
fbp8[3 * (location + x)] = pixel[0];
fbp8[3 * (location + x) + 1] = pixel[1];
fbp8[3 * (location + x) + 2] = pixel[2];
}
color_p += w;
}
}
/*16 bit per pixel*/ /*16 bit per pixel*/
else if(vinfo.bits_per_pixel == 16) { else if(vinfo.bits_per_pixel == 16) {
uint16_t * fbp16 = (uint16_t *)fbp; uint16_t * fbp16 = (uint16_t *)fbp;

@ -55,9 +55,9 @@ void xpt2046_init(void)
/** /**
* Get the current position and state of the touchpad * Get the current position and state of the touchpad
* @param data store the read data here * @param data store the read data here
* @return false: because no ore data to be read * @return void
*/ */
bool xpt2046_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data) void xpt2046_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{ {
static int16_t last_x = 0; static int16_t last_x = 0;
static int16_t last_y = 0; static int16_t last_y = 0;
@ -105,7 +105,7 @@ bool xpt2046_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
data->point.x = x; data->point.x = x;
data->point.y = y; data->point.y = y;
return false; data->continue_reading = false; /* No more data to be read */
} }
/********************** /**********************

@ -41,7 +41,7 @@ extern "C" {
* GLOBAL PROTOTYPES * GLOBAL PROTOTYPES
**********************/ **********************/
void xpt2046_init(void); void xpt2046_init(void);
bool xpt2046_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); void xpt2046_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
/********************** /**********************
* MACROS * MACROS

@ -12,6 +12,7 @@
#include <stdio.h> #include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <errno.h>
#if USE_BSD_EVDEV #if USE_BSD_EVDEV
#include <dev/evdev/input.h> #include <dev/evdev/input.h>
#else #else
@ -22,230 +23,202 @@
#include "xkb.h" #include "xkb.h"
#endif /* USE_XKB */ #endif /* USE_XKB */
/*********************
* DEFINES
*********************/
/********************** /**********************
* TYPEDEFS * STATIC VARIABLES
**********************/ **********************/
/********************** evdev_device_t global_dsc;
* STATIC PROTOTYPES
**********************/
int map(int x, int in_min, int in_max, int out_min, int out_max);
/********************** /**********************
* STATIC VARIABLES * STATIC FUNCTIONS
**********************/ **********************/
int evdev_fd = -1;
int evdev_root_x;
int evdev_root_y;
int evdev_button;
int evdev_key_val; static int _evdev_process_key(uint16_t code, bool pressed)
{
#if USE_XKB
return xkb_process_key(code, pressed);
#else
LV_UNUSED(pressed);
switch(code) {
case KEY_UP:
return LV_KEY_UP;
case KEY_DOWN:
return LV_KEY_DOWN;
case KEY_RIGHT:
return LV_KEY_RIGHT;
case KEY_LEFT:
return LV_KEY_LEFT;
case KEY_ESC:
return LV_KEY_ESC;
case KEY_DELETE:
return LV_KEY_DEL;
case KEY_BACKSPACE:
return LV_KEY_BACKSPACE;
case KEY_ENTER:
return LV_KEY_ENTER;
case KEY_NEXT:
case KEY_TAB:
return LV_KEY_NEXT;
case KEY_PREVIOUS:
return LV_KEY_PREV;
case KEY_HOME:
return LV_KEY_HOME;
case KEY_END:
return LV_KEY_END;
default:
return 0;
}
#endif /*USE_XKB*/
}
/********************** static int _evdev_calibrate(int v, int in_min, int in_max, int out_min, int out_max)
* MACROS {
**********************/ if(in_min != in_max) v = (v - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
return LV_CLAMP(out_min, v, out_max);
}
static lv_point_t _evdev_process_pointer(lv_indev_drv_t * drv, int x, int y)
{
evdev_device_t * dsc = drv->user_data ? drv->user_data : &global_dsc;
int swapped_x = dsc->swap_axes ? y : x;
int swapped_y = dsc->swap_axes ? x : y;
int offset_x = 0; /*Not lv_disp_get_offset_x(drv->disp) for bc*/
int offset_y = 0; /*Not lv_disp_get_offset_y(drv->disp) for bc*/
int width = lv_disp_get_hor_res(drv->disp);
int height = lv_disp_get_ver_res(drv->disp);
lv_point_t p;
p.x = _evdev_calibrate(swapped_x, dsc->hor_min, dsc->hor_max, offset_x, offset_x + width - 1);
p.y = _evdev_calibrate(swapped_y, dsc->ver_min, dsc->ver_max, offset_y, offset_y + height - 1);
return p;
}
/********************** /**********************
* GLOBAL FUNCTIONS * GLOBAL FUNCTIONS
**********************/ **********************/
/** void evdev_init()
* Initialize the evdev interface
*/
void evdev_init(void)
{ {
if (!evdev_set_file(EVDEV_NAME)) { evdev_device_init(&global_dsc);
return; #ifdef EVDEV_SWAP_AXES
} evdev_device_set_swap_axes(&global_dsc, EVDEV_SWAP_AXES);
#endif
#if EVDEV_CALIBRATE
evdev_device_set_calibration(&global_dsc, EVDEV_HOR_MIN, EVDEV_VER_MIN, EVDEV_HOR_MAX, EVDEV_VER_MAX);
#endif
evdev_device_set_file(&global_dsc, EVDEV_NAME);
}
void evdev_device_init(evdev_device_t * dsc)
{
lv_memset(dsc, 0, sizeof(evdev_device_t));
dsc->fd = -1;
#if USE_XKB #if USE_XKB
xkb_init(); xkb_init();
#endif #endif
} }
/**
* reconfigure the device file for evdev bool evdev_set_file(const char * dev_path)
* @param dev_name set the evdev device filename
* @return true: the device file set complete
* false: the device file doesn't exist current system
*/
bool evdev_set_file(char* dev_name)
{ {
if(evdev_fd != -1) { return evdev_device_set_file(&global_dsc, dev_path);
close(evdev_fd); }
bool evdev_device_set_file(evdev_device_t * dsc, const char * dev_path)
{
/*Reset state*/
dsc->root_x = 0;
dsc->root_y = 0;
dsc->key = 0;
dsc->state = LV_INDEV_STATE_RELEASED;
/*Close previous*/
if(dsc->fd >= 0) {
close(dsc->fd);
dsc->fd = -1;
} }
#if USE_BSD_EVDEV if(!dev_path) return false;
evdev_fd = open(dev_name, O_RDWR | O_NOCTTY);
#else
evdev_fd = open(dev_name, O_RDWR | O_NOCTTY | O_NDELAY);
#endif
if(evdev_fd == -1) { /*Open new*/
perror("unable to open evdev interface:"); dsc->fd = open(dev_path, O_RDONLY | O_NOCTTY | O_CLOEXEC);
if(dsc->fd < 0) {
LV_LOG_ERROR("open failed: %s", strerror(errno));
return false;
}
if(fcntl(dsc->fd, F_SETFL, O_NONBLOCK) < 0) {
LV_LOG_ERROR("fcntl failed: %s", strerror(errno));
close(dsc->fd);
dsc->fd = -1;
return false; return false;
} }
#if USE_BSD_EVDEV return true;
fcntl(evdev_fd, F_SETFL, O_NONBLOCK); }
#else
fcntl(evdev_fd, F_SETFL, O_ASYNC | O_NONBLOCK);
#endif
evdev_root_x = 0; void evdev_device_set_swap_axes(evdev_device_t * dsc, bool swap_axes)
evdev_root_y = 0; {
evdev_key_val = 0; dsc->swap_axes = swap_axes;
evdev_button = LV_INDEV_STATE_REL; }
return true; void evdev_device_set_calibration(evdev_device_t * dsc, int ver_min, int hor_min, int ver_max, int hor_max)
{
dsc->ver_min = ver_min;
dsc->hor_min = hor_min;
dsc->ver_max = ver_max;
dsc->hor_max = hor_max;
} }
/**
* Get the current position and state of the evdev
* @param data store the evdev data here
*/
void evdev_read(lv_indev_drv_t * drv, lv_indev_data_t * data) void evdev_read(lv_indev_drv_t * drv, lv_indev_data_t * data)
{ {
struct input_event in; evdev_device_t * dsc = drv->user_data ? drv->user_data : &global_dsc;
if(dsc->fd < 0) return;
while(read(evdev_fd, &in, sizeof(struct input_event)) > 0) { /*Update dsc with buffered events*/
struct input_event in = { 0 };
while(read(dsc->fd, &in, sizeof(in)) > 0) {
if(in.type == EV_REL) { if(in.type == EV_REL) {
if(in.code == REL_X) if(in.code == REL_X) dsc->root_x += in.value;
#if EVDEV_SWAP_AXES else if(in.code == REL_Y) dsc->root_y += in.value;
evdev_root_y += in.value; }
#else else if(in.type == EV_ABS) {
evdev_root_x += in.value; if(in.code == ABS_X || in.code == ABS_MT_POSITION_X) dsc->root_x = in.value;
#endif else if(in.code == ABS_Y || in.code == ABS_MT_POSITION_Y) dsc->root_y = in.value;
else if(in.code == REL_Y)
#if EVDEV_SWAP_AXES
evdev_root_x += in.value;
#else
evdev_root_y += in.value;
#endif
} else if(in.type == EV_ABS) {
if(in.code == ABS_X)
#if EVDEV_SWAP_AXES
evdev_root_y = in.value;
#else
evdev_root_x = in.value;
#endif
else if(in.code == ABS_Y)
#if EVDEV_SWAP_AXES
evdev_root_x = in.value;
#else
evdev_root_y = in.value;
#endif
else if(in.code == ABS_MT_POSITION_X)
#if EVDEV_SWAP_AXES
evdev_root_y = in.value;
#else
evdev_root_x = in.value;
#endif
else if(in.code == ABS_MT_POSITION_Y)
#if EVDEV_SWAP_AXES
evdev_root_x = in.value;
#else
evdev_root_y = in.value;
#endif
else if(in.code == ABS_MT_TRACKING_ID) { else if(in.code == ABS_MT_TRACKING_ID) {
if(in.value == -1) if(in.value == -1) dsc->state = LV_INDEV_STATE_RELEASED;
evdev_button = LV_INDEV_STATE_REL; else if(in.value == 0) dsc->state = LV_INDEV_STATE_PRESSED;
else if(in.value == 0)
evdev_button = LV_INDEV_STATE_PR;
} }
} else if(in.type == EV_KEY) { }
else if(in.type == EV_KEY) {
if(in.code == BTN_MOUSE || in.code == BTN_TOUCH) { if(in.code == BTN_MOUSE || in.code == BTN_TOUCH) {
if(in.value == 0) if(in.value == 0) dsc->state = LV_INDEV_STATE_RELEASED;
evdev_button = LV_INDEV_STATE_REL; else if(in.value == 1) dsc->state = LV_INDEV_STATE_PRESSED;
else if(in.value == 1)
evdev_button = LV_INDEV_STATE_PR;
} else if(drv->type == LV_INDEV_TYPE_KEYPAD) {
#if USE_XKB
data->key = xkb_process_key(in.code, in.value != 0);
#else
switch(in.code) {
case KEY_BACKSPACE:
data->key = LV_KEY_BACKSPACE;
break;
case KEY_ENTER:
data->key = LV_KEY_ENTER;
break;
case KEY_PREVIOUS:
data->key = LV_KEY_PREV;
break;
case KEY_NEXT:
data->key = LV_KEY_NEXT;
break;
case KEY_UP:
data->key = LV_KEY_UP;
break;
case KEY_LEFT:
data->key = LV_KEY_LEFT;
break;
case KEY_RIGHT:
data->key = LV_KEY_RIGHT;
break;
case KEY_DOWN:
data->key = LV_KEY_DOWN;
break;
case KEY_TAB:
data->key = LV_KEY_NEXT;
break;
default:
data->key = 0;
break;
} }
#endif /* USE_XKB */ else {
if (data->key != 0) { dsc->key = _evdev_process_key(in.code, in.value != 0);
/* Only record button state when actual output is produced to prevent widgets from refreshing */ if(dsc->key) {
data->state = (in.value) ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL; dsc->state = in.value ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
data->continue_reading = true; /*Keep following events in buffer for now*/
break;
} }
evdev_key_val = data->key;
evdev_button = data->state;
return;
} }
} }
} }
if(drv->type == LV_INDEV_TYPE_KEYPAD) { /*Process and store in data*/
/* No data retrieved */ switch(drv->type) {
data->key = evdev_key_val; case LV_INDEV_TYPE_KEYPAD:
data->state = evdev_button; data->state = dsc->state;
return; data->key = dsc->key;
break;
case LV_INDEV_TYPE_POINTER:
data->state = dsc->state;
data->point = _evdev_process_pointer(drv, dsc->root_x, dsc->root_y);
break;
default:
break;
} }
if(drv->type != LV_INDEV_TYPE_POINTER)
return ;
/*Store the collected data*/
#if EVDEV_CALIBRATE
data->point.x = map(evdev_root_x, EVDEV_HOR_MIN, EVDEV_HOR_MAX, 0, drv->disp->driver->hor_res);
data->point.y = map(evdev_root_y, EVDEV_VER_MIN, EVDEV_VER_MAX, 0, drv->disp->driver->ver_res);
#else
data->point.x = evdev_root_x;
data->point.y = evdev_root_y;
#endif
data->state = evdev_button;
if(data->point.x < 0)
data->point.x = 0;
if(data->point.y < 0)
data->point.y = 0;
if(data->point.x >= drv->disp->driver->hor_res)
data->point.x = drv->disp->driver->hor_res - 1;
if(data->point.y >= drv->disp->driver->ver_res)
data->point.y = drv->disp->driver->ver_res - 1;
return ;
} }
/********************** #endif /*USE_EVDEV*/
* STATIC FUNCTIONS
**********************/
int map(int x, int in_min, int in_max, int out_min, int out_max)
{
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
#endif

@ -29,39 +29,81 @@ extern "C" {
#include "lvgl/lvgl.h" #include "lvgl/lvgl.h"
#endif #endif
/*********************
* DEFINES
*********************/
/********************** /**********************
* TYPEDEFS * TYPEDEFS
**********************/ **********************/
typedef struct {
/*Device*/
int fd;
/*Config*/
bool swap_axes;
int ver_min;
int hor_min;
int ver_max;
int hor_max;
/*State*/
int root_x;
int root_y;
int key;
lv_indev_state_t state;
} evdev_device_t;
/********************** /**********************
* GLOBAL PROTOTYPES * GLOBAL PROTOTYPES
**********************/ **********************/
/** /**
* Initialize the evdev * Initialize the global evdev device, as configured with EVDEV_NAME,
* EVDEV_SWAP_AXES, and EVDEV_CALIBRATE.
*/ */
void evdev_init(void); void evdev_init();
/** /**
* reconfigure the device file for evdev * Initialize an evdev device.
* @param dev_name set the evdev device filename * @param dsc evdev device
* @return true: the device file set complete
* false: the device file doesn't exist current system
*/ */
bool evdev_set_file(char* dev_name); void evdev_device_init(evdev_device_t * dsc);
/** /**
* Get the current position and state of the evdev * Reconfigure the path for the global evdev device.
* @param data store the evdev data here * @param dev_path device path, e.g., /dev/input/event0, or NULL to close
* @return whether the device was successfully opened
*/ */
void evdev_read(lv_indev_drv_t * drv, lv_indev_data_t * data); bool evdev_set_file(const char * dev_path);
/**
* Configure or reconfigure the path for an evdev device.
* @param dsc evdev device
* @param dev_path device path, e.g., /dev/input/event0, or NULL to close
* @return whether the device was successfully opened
*/
bool evdev_device_set_file(evdev_device_t * dsc, const char * dev_path);
/**
* Configure whether pointer coordinates of an evdev device sould be swapped.
* Default to false.
* @param dsc evdev device
* @param swap_axes whether to swap x and y axes
*/
void evdev_device_set_swap_axes(evdev_device_t * dsc, bool swap_axes);
/**
* Configure a coordinate transformation for an evdev device. Applied after
* axis swap, if any. Defaults to no transformation.
* @param dsc evdev device
* @param hor_min horizontal pointer coordinate mapped to 0
* @param ver_min vertical pointer coordinate mapped to 0
* @param ver_min pointer coordinate mapped to horizontal max of display
* @param ver_max pointer coordinate mapped to vertical max of display
*/
void evdev_device_set_calibration(evdev_device_t * dsc, int hor_min, int ver_min, int hor_max, int ver_max);
/********************** /**
* MACROS * Read callback for the input driver.
**********************/ * @param drv input driver where drv->user_data is NULL for the global evdev
* device or an evdev_device_t pointer.
* @param data destination for input events
*/
void evdev_read(lv_indev_drv_t * drv, lv_indev_data_t * data);
#endif /* USE_EVDEV */ #endif /* USE_EVDEV */

@ -74,7 +74,28 @@ static const struct libinput_interface interface = {
**********************/ **********************/
/** /**
* find connected input device with specific capabilities * Determine the capabilities of a specific libinput device.
* @param device the libinput device to query
* @return the supported input capabilities
*/
libinput_capability libinput_query_capability(struct libinput_device *device) {
libinput_capability capability = LIBINPUT_CAPABILITY_NONE;
if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_KEYBOARD)
&& (libinput_device_keyboard_has_key(device, KEY_ENTER) || libinput_device_keyboard_has_key(device, KEY_KPENTER)))
{
capability |= LIBINPUT_CAPABILITY_KEYBOARD;
}
if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_POINTER)) {
capability |= LIBINPUT_CAPABILITY_POINTER;
}
if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_TOUCH)) {
capability |= LIBINPUT_CAPABILITY_TOUCH;
}
return capability;
}
/**
* Find connected input device with specific capabilities
* @param capabilities required device capabilities * @param capabilities required device capabilities
* @param force_rescan erase the device cache (if any) and rescan the file system for available devices * @param force_rescan erase the device cache (if any) and rescan the file system for available devices
* @return device node path (e.g. /dev/input/event0) for the first matching device or NULL if no device was found. * @return device node path (e.g. /dev/input/event0) for the first matching device or NULL if no device was found.
@ -87,7 +108,7 @@ char *libinput_find_dev(libinput_capability capabilities, bool force_rescan) {
} }
/** /**
* find connected input devices with specific capabilities * Find connected input devices with specific capabilities
* @param capabilities required device capabilities * @param capabilities required device capabilities
* @param devices pre-allocated array to store the found device node paths (e.g. /dev/input/event0). The pointers are * @param devices pre-allocated array to store the found device node paths (e.g. /dev/input/event0). The pointers are
* safe to use until the next forceful device search. * safe to use until the next forceful device search.
@ -138,8 +159,8 @@ bool libinput_set_file_state(libinput_drv_state_t *state, char* dev_name)
// citing libinput.h:libinput_path_remove_device: // citing libinput.h:libinput_path_remove_device:
// > If no matching device exists, this function does nothing. // > If no matching device exists, this function does nothing.
if (state->libinput_device) { if (state->libinput_device) {
state->libinput_device = libinput_device_unref(state->libinput_device);
libinput_path_remove_device(state->libinput_device); libinput_path_remove_device(state->libinput_device);
state->libinput_device = libinput_device_unref(state->libinput_device);
} }
state->libinput_device = libinput_path_add_device(state->libinput_context, dev_name); state->libinput_device = libinput_path_add_device(state->libinput_context, dev_name);
@ -195,6 +216,29 @@ void libinput_init_state(libinput_drv_state_t *state, char* path)
#endif #endif
} }
/**
* De-initialise a previously initialised driver state and free any dynamically allocated memory. Use this function if you want to
* reuse an existing driver state.
* @param state driver state to de-initialize
*/
void libinput_deinit_state(libinput_drv_state_t *state)
{
if (state->libinput_device) {
libinput_path_remove_device(state->libinput_device);
libinput_device_unref(state->libinput_device);
}
if (state->libinput_context) {
libinput_unref(state->libinput_context);
}
#if USE_XKB
xkb_deinit_state(&(state->xkb_state));
#endif
lv_memzero(state, sizeof(libinput_drv_state_t));
}
/** /**
* Read available input events via libinput using the default driver state. Use this function if you only want * Read available input events via libinput using the default driver state. Use this function if you only want
* to connect a single device. * to connect a single device.
@ -296,18 +340,7 @@ static bool rescan_devices(void) {
* as part of this function, we don't have to increase its reference count to keep it alive. * as part of this function, we don't have to increase its reference count to keep it alive.
* https://wayland.freedesktop.org/libinput/doc/latest/api/group__base.html#gaa797496f0150b482a4e01376bd33a47b */ * https://wayland.freedesktop.org/libinput/doc/latest/api/group__base.html#gaa797496f0150b482a4e01376bd33a47b */
libinput_capability capabilities = LIBINPUT_CAPABILITY_NONE; libinput_capability capabilities = libinput_query_capability(device);
if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_KEYBOARD)
&& (libinput_device_keyboard_has_key(device, KEY_ENTER) || libinput_device_keyboard_has_key(device, KEY_KPENTER)))
{
capabilities |= LIBINPUT_CAPABILITY_KEYBOARD;
}
if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_POINTER)) {
capabilities |= LIBINPUT_CAPABILITY_POINTER;
}
if (libinput_device_has_capability(device, LIBINPUT_DEVICE_CAP_TOUCH)) {
capabilities |= LIBINPUT_CAPABILITY_TOUCH;
}
libinput_path_remove_device(device); libinput_path_remove_device(device);
@ -387,13 +420,13 @@ static void read_pointer(libinput_drv_state_t *state, struct libinput_event *eve
case LIBINPUT_EVENT_TOUCH_MOTION: case LIBINPUT_EVENT_TOUCH_MOTION:
case LIBINPUT_EVENT_TOUCH_DOWN: case LIBINPUT_EVENT_TOUCH_DOWN:
touch_event = libinput_event_get_touch_event(event); touch_event = libinput_event_get_touch_event(event);
lv_coord_t x = libinput_event_touch_get_x_transformed(touch_event, drv->physical_hor_res > 0 ? drv->physical_hor_res : drv->hor_res) - drv->offset_x; lv_coord_t x_touch = libinput_event_touch_get_x_transformed(touch_event, drv->physical_hor_res > 0 ? drv->physical_hor_res : drv->hor_res) - drv->offset_x;
lv_coord_t y = libinput_event_touch_get_y_transformed(touch_event, drv->physical_ver_res > 0 ? drv->physical_ver_res : drv->ver_res) - drv->offset_y; lv_coord_t y_touch = libinput_event_touch_get_y_transformed(touch_event, drv->physical_ver_res > 0 ? drv->physical_ver_res : drv->ver_res) - drv->offset_y;
if (x < 0 || x > drv->hor_res || y < 0 || y > drv->ver_res) { if (x_touch < 0 || x_touch > drv->hor_res || y_touch < 0 || y_touch > drv->ver_res) {
break; /* ignore touches that are out of bounds */ break; /* ignore touches that are out of bounds */
} }
state->most_recent_touch_point.x = x; state->most_recent_touch_point.x = x_touch;
state->most_recent_touch_point.y = y; state->most_recent_touch_point.y = y_touch;
state->button = LV_INDEV_STATE_PR; state->button = LV_INDEV_STATE_PR;
break; break;
case LIBINPUT_EVENT_TOUCH_UP: case LIBINPUT_EVENT_TOUCH_UP:
@ -406,6 +439,16 @@ static void read_pointer(libinput_drv_state_t *state, struct libinput_event *eve
state->most_recent_touch_point.x = LV_CLAMP(0, state->most_recent_touch_point.x, drv->hor_res - 1); state->most_recent_touch_point.x = LV_CLAMP(0, state->most_recent_touch_point.x, drv->hor_res - 1);
state->most_recent_touch_point.y = LV_CLAMP(0, state->most_recent_touch_point.y, drv->ver_res - 1); state->most_recent_touch_point.y = LV_CLAMP(0, state->most_recent_touch_point.y, drv->ver_res - 1);
break; break;
case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
pointer_event = libinput_event_get_pointer_event(event);
lv_coord_t x_pointer = libinput_event_pointer_get_absolute_x_transformed(pointer_event, drv->physical_hor_res > 0 ? drv->physical_hor_res : drv->hor_res) - drv->offset_x;
lv_coord_t y_pointer = libinput_event_pointer_get_absolute_y_transformed(pointer_event, drv->physical_ver_res > 0 ? drv->physical_ver_res : drv->ver_res) - drv->offset_y;
if (x_pointer < 0 || x_pointer > drv->hor_res || y_pointer < 0 || y_pointer > drv->ver_res) {
break; /* ignore pointer events that are out of bounds */
}
state->most_recent_touch_point.x = x_pointer;
state->most_recent_touch_point.y = y_pointer;
break;
case LIBINPUT_EVENT_POINTER_BUTTON: case LIBINPUT_EVENT_POINTER_BUTTON:
pointer_event = libinput_event_get_pointer_event(event); pointer_event = libinput_event_get_pointer_event(event);
enum libinput_button_state button_state = libinput_event_pointer_get_button_state(pointer_event); enum libinput_button_state button_state = libinput_event_pointer_get_button_state(pointer_event);

@ -70,7 +70,13 @@ typedef struct {
**********************/ **********************/
/** /**
* find connected input device with specific capabilities * Determine the capabilities of a specific libinput device.
* @param device the libinput device to query
* @return the supported input capabilities
*/
libinput_capability libinput_query_capability(struct libinput_device *device);
/**
* Find connected input device with specific capabilities
* @param capabilities required device capabilities * @param capabilities required device capabilities
* @param force_rescan erase the device cache (if any) and rescan the file system for available devices * @param force_rescan erase the device cache (if any) and rescan the file system for available devices
* @return device node path (e.g. /dev/input/event0) for the first matching device or NULL if no device was found. * @return device node path (e.g. /dev/input/event0) for the first matching device or NULL if no device was found.
@ -78,7 +84,7 @@ typedef struct {
*/ */
char *libinput_find_dev(libinput_capability capabilities, bool force_rescan); char *libinput_find_dev(libinput_capability capabilities, bool force_rescan);
/** /**
* find connected input devices with specific capabilities * Find connected input devices with specific capabilities
* @param capabilities required device capabilities * @param capabilities required device capabilities
* @param devices pre-allocated array to store the found device node paths (e.g. /dev/input/event0). The pointers are * @param devices pre-allocated array to store the found device node paths (e.g. /dev/input/event0). The pointers are
* safe to use until the next forceful device search. * safe to use until the next forceful device search.
@ -99,6 +105,12 @@ void libinput_init(void);
* @param path input device node path (e.g. /dev/input/event0) * @param path input device node path (e.g. /dev/input/event0)
*/ */
void libinput_init_state(libinput_drv_state_t *state, char* path); void libinput_init_state(libinput_drv_state_t *state, char* path);
/**
* De-initialise a previously initialised driver state and free any dynamically allocated memory. Use this function if you want to
* reuse an existing driver state.
* @param state driver state to de-initialize
*/
void libinput_deinit_state(libinput_drv_state_t *state);
/** /**
* Reconfigure the device file for libinput using the default driver state. Use this function if you only want * Reconfigure the device file for libinput using the default driver state. Use this function if you only want
* to connect a single device. * to connect a single device.

@ -73,6 +73,23 @@ bool xkb_init_state(xkb_drv_state_t *state) {
#endif #endif
} }
/**
* De-initialise a previously initialised driver state and free any dynamically allocated memory. Use this function if you want to
* reuse an existing driver state.
* @param state XKB driver state to use
*/
void xkb_deinit_state(xkb_drv_state_t *state) {
if (state->state) {
xkb_state_unref(state->state);
state->state = NULL;
}
if (state->keymap) {
xkb_keymap_unref(state->keymap);
state->keymap = NULL;
}
}
/** /**
* Set a new keymap to be used for processing future key events using the default driver state. Use * Set a new keymap to be used for processing future key events using the default driver state. Use
* this function if you only want to connect a single device. * this function if you only want to connect a single device.
@ -102,12 +119,6 @@ bool xkb_set_keymap_state(xkb_drv_state_t *state, struct xkb_rule_names names) {
return false; return false;
} }
state->keymap = xkb_keymap_ref(state->keymap);
if (!state->keymap) {
perror("could not reference XKB keymap");
return false;
}
if (state->state) { if (state->state) {
xkb_state_unref(state->state); xkb_state_unref(state->state);
state->state = NULL; state->state = NULL;
@ -119,12 +130,6 @@ bool xkb_set_keymap_state(xkb_drv_state_t *state, struct xkb_rule_names names) {
return false; return false;
} }
state->state = xkb_state_ref(state->state);
if (!state->state) {
perror("could not reference XKB state");
return false;
}
return true; return true;
} }

@ -60,6 +60,12 @@ bool xkb_init(void);
* @return true if the initialisation was successful * @return true if the initialisation was successful
*/ */
bool xkb_init_state(xkb_drv_state_t *state); bool xkb_init_state(xkb_drv_state_t *state);
/**
* De-initialise a previously initialised driver state and free any dynamically allocated memory. Use this function if you want to
* reuse an existing driver state.
* @param state XKB driver state to use
*/
void xkb_deinit_state(xkb_drv_state_t *state);
/** /**
* Set a new keymap to be used for processing future key events using the default driver state. Use * Set a new keymap to be used for processing future key events using the default driver state. Use
* this function if you only want to connect a single device. * this function if you only want to connect a single device.

@ -1,6 +1,6 @@
{ {
"name": "lv_drivers", "name": "lv_drivers",
"version": "8.3.0", "version": "9.0.0-dev",
"keywords": "littlevgl, lvgl, driver, display, touchpad", "keywords": "littlevgl, lvgl, driver, display, touchpad",
"description": "Drivers for LittlevGL graphics library.", "description": "Drivers for LittlevGL graphics library.",
"repository": { "repository": {

@ -0,0 +1,11 @@
prefix="@CMAKE_INSTALL_PREFIX@"
includedir="${prefix}/@INC_INSTALL_DIR@"
libdir=${prefix}/lib
Name: lv-drivers
Description: Display controller and touchpad driver that can be directly used with LVGL
URL: https://lvgl.io/
Version: 9.0.0
Cflags: -I${includedir}
Libs: -L${libdir} -llv_drivers
Requires: lvgl

@ -1,10 +1,5 @@
LV_DRIVERS_DIR_NAME ?= lv_drivers LV_DRIVERS_PATH ?= ${shell pwd}/lv_drivers
override CFLAGS := -I$(LVGL_DIR) $(CFLAGS) CSRCS += $(shell find $(LV_DRIVERS_PATH) -type f -name '*.c')
CFLAGS += "-I$(LV_DRIVERS_PATH)"
CSRCS += $(wildcard $(LVGL_DIR)/$(LV_DRIVERS_DIR_NAME)/*.c)
CSRCS += $(wildcard $(LVGL_DIR)/$(LV_DRIVERS_DIR_NAME)/wayland/*.c)
CSRCS += $(wildcard $(LVGL_DIR)/$(LV_DRIVERS_DIR_NAME)/indev/*.c)
CSRCS += $(wildcard $(LVGL_DIR)/$(LV_DRIVERS_DIR_NAME)/gtkdrv/*.c)
CSRCS += $(wildcard $(LVGL_DIR)/$(LV_DRIVERS_DIR_NAME)/display/*.c)
CSRCS += $(wildcard $(LVGL_DIR)/$(LV_DRIVERS_DIR_NAME)/sdl/*.c)

@ -1,6 +1,6 @@
/** /**
* @file lv_drv_conf.h * @file lv_drv_conf.h
* Configuration file for v8.3.0 * Configuration file for v9.0.0-dev
*/ */
/* /*
@ -110,6 +110,9 @@
/*Open two windows to test multi display support*/ /*Open two windows to test multi display support*/
# define SDL_DUAL_DISPLAY 0 # define SDL_DUAL_DISPLAY 0
/* Window Title */
# define SDL_WINDOW_TITLE "TFT Simulator"
#endif #endif
/*------------------- /*-------------------
@ -192,6 +195,13 @@
# endif # endif
#endif #endif
/*----------------------------------------
* X11 drivers (monitor, mouse, keyboard)
*---------------------------------------*/
#ifndef USE_X11
# define USE_X11 0
#endif
/*---------------- /*----------------
* SSD1963 * SSD1963
*--------------*/ *--------------*/

@ -9,8 +9,8 @@
#include "sdl.h" #include "sdl.h"
#if USE_MONITOR || USE_SDL #if USE_MONITOR || USE_SDL
#if LV_USE_GPU_SDL #if LV_USE_DRAW_SDL
# error "LV_USE_GPU_SDL must not be enabled" # error "LV_USE_DRAW_SDL must not be enabled"
#endif #endif
#if USE_MONITOR #if USE_MONITOR
@ -47,6 +47,7 @@
# define SDL_FULLSCREEN 0 # define SDL_FULLSCREEN 0
#endif #endif
#include "sdl_common_internal.h"
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <string.h> #include <string.h>
@ -59,6 +60,9 @@
#define KEYBOARD_BUFFER_SIZE SDL_TEXTINPUTEVENT_TEXT_SIZE #define KEYBOARD_BUFFER_SIZE SDL_TEXTINPUTEVENT_TEXT_SIZE
#endif #endif
#ifndef SDL_WINDOW_TITLE
#define SDL_WINDOW_TITLE "TFT Simulator"
#endif
/********************** /**********************
* TYPEDEFS * TYPEDEFS
**********************/ **********************/
@ -96,17 +100,6 @@ monitor_t monitor;
monitor_t monitor2; monitor_t monitor2;
#endif #endif
static volatile bool sdl_inited = false;
static bool left_button_down = false;
static int16_t last_x = 0;
static int16_t last_y = 0;
static int16_t wheel_diff = 0;
static lv_indev_state_t wheel_state = LV_INDEV_STATE_RELEASED;
static char buf[KEYBOARD_BUFFER_SIZE];
/********************** /**********************
* MACROS * MACROS
**********************/ **********************/
@ -344,7 +337,7 @@ static void window_create(monitor_t * m)
flag |= SDL_WINDOW_FULLSCREEN; flag |= SDL_WINDOW_FULLSCREEN;
#endif #endif
m->window = SDL_CreateWindow("TFT Simulator", m->window = SDL_CreateWindow(SDL_WINDOW_TITLE,
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
SDL_HOR_RES * SDL_ZOOM, SDL_VER_RES * SDL_ZOOM, flag); /*last param. SDL_WINDOW_BORDERLESS to hide borders*/ SDL_HOR_RES * SDL_ZOOM, SDL_VER_RES * SDL_ZOOM, flag); /*last param. SDL_WINDOW_BORDERLESS to hide borders*/
@ -375,7 +368,7 @@ static void window_update(monitor_t * m)
#endif #endif
SDL_RenderClear(m->renderer); SDL_RenderClear(m->renderer);
lv_disp_t * d = _lv_refr_get_disp_refreshing(); lv_disp_t * d = _lv_refr_get_disp_refreshing();
if(d->driver->screen_transp) { if(d && d->driver->screen_transp) {
SDL_SetRenderDrawColor(m->renderer, 0xff, 0, 0, 0xff); SDL_SetRenderDrawColor(m->renderer, 0xff, 0, 0, 0xff);
SDL_Rect r; SDL_Rect r;
r.x = 0; r.y = 0; r.w = SDL_HOR_RES; r.h = SDL_VER_RES; r.x = 0; r.y = 0; r.w = SDL_HOR_RES; r.h = SDL_VER_RES;

@ -5,6 +5,8 @@
#include "sdl_common.h" #include "sdl_common.h"
#if USE_SDL || USE_SDL_GPU #if USE_SDL || USE_SDL_GPU
#include "sdl_common_internal.h"
/********************* /*********************
* DEFINES * DEFINES
*********************/ *********************/
@ -130,17 +132,17 @@ void mouse_handler(SDL_Event * event)
case SDL_FINGERUP: case SDL_FINGERUP:
left_button_down = false; left_button_down = false;
last_x = LV_HOR_RES * event->tfinger.x / SDL_ZOOM; last_x = SDL_HOR_RES * event->tfinger.x / SDL_ZOOM;
last_y = LV_VER_RES * event->tfinger.y / SDL_ZOOM; last_y = SDL_VER_RES * event->tfinger.y / SDL_ZOOM;
break; break;
case SDL_FINGERDOWN: case SDL_FINGERDOWN:
left_button_down = true; left_button_down = true;
last_x = LV_HOR_RES * event->tfinger.x / SDL_ZOOM; last_x = SDL_HOR_RES * event->tfinger.x / SDL_ZOOM;
last_y = LV_VER_RES * event->tfinger.y / SDL_ZOOM; last_y = SDL_VER_RES * event->tfinger.y / SDL_ZOOM;
break; break;
case SDL_FINGERMOTION: case SDL_FINGERMOTION:
last_x = LV_HOR_RES * event->tfinger.x / SDL_ZOOM; last_x = SDL_HOR_RES * event->tfinger.x / SDL_ZOOM;
last_y = LV_VER_RES * event->tfinger.y / SDL_ZOOM; last_y = SDL_VER_RES * event->tfinger.y / SDL_ZOOM;
break; break;
} }

@ -32,7 +32,6 @@ extern "C" {
#ifndef SDL_INCLUDE_PATH #ifndef SDL_INCLUDE_PATH
#define SDL_INCLUDE_PATH MONITOR_SDL_INCLUDE_PATH #define SDL_INCLUDE_PATH MONITOR_SDL_INCLUDE_PATH
#endif #endif
#include SDL_INCLUDE_PATH
#ifndef SDL_ZOOM #ifndef SDL_ZOOM
#define SDL_ZOOM MONITOR_ZOOM #define SDL_ZOOM MONITOR_ZOOM
@ -85,16 +84,6 @@ void sdl_mousewheel_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
*/ */
void sdl_keyboard_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data); void sdl_keyboard_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data);
int quit_filter(void * userdata, SDL_Event * event);
void mouse_handler(SDL_Event * event);
void mousewheel_handler(SDL_Event * event);
uint32_t keycode_to_ctrl_key(SDL_Keycode sdl_key);
void keyboard_handler(SDL_Event * event);
/**********************
* MACROS
**********************/
#endif /* USE_SDL || USE_SDL_GPU */ #endif /* USE_SDL || USE_SDL_GPU */
#ifdef __cplusplus #ifdef __cplusplus

@ -0,0 +1,39 @@
/**
* @file sdl_common_internal.h
* Provides SDL related functions which are only used internal.
*
*/
#ifndef SDL_COMMON_INTERNAL_H
#define SDL_COMMON_INTERNAL_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "sdl_common.h"
#if USE_SDL || USE_SDL_GPU
#include SDL_INCLUDE_PATH
/**********************
* GLOBAL PROTOTYPES
**********************/
int quit_filter(void * userdata, SDL_Event * event);
void mouse_handler(SDL_Event * event);
void mousewheel_handler(SDL_Event * event);
uint32_t keycode_to_ctrl_key(SDL_Keycode sdl_key);
void keyboard_handler(SDL_Event * event);
#endif /* USE_SDL || USE_SDL_GPU */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* SDL_COMMON_INTERNAL_H */

@ -9,7 +9,7 @@
#include "sdl_gpu.h" #include "sdl_gpu.h"
#if USE_SDL_GPU #if USE_SDL_GPU
#if LV_USE_GPU_SDL == 0 #if LV_USE_DRAW_SDL == 0
# error "LV_USE_DRAW_SDL must be enabled" # error "LV_USE_DRAW_SDL must be enabled"
#endif #endif
@ -29,6 +29,7 @@
# error "Cannot enable both MONITOR and SDL at the same time. " # error "Cannot enable both MONITOR and SDL at the same time. "
#endif #endif
#include "sdl_common_internal.h"
#include <stdlib.h> #include <stdlib.h>
#include <stdbool.h> #include <stdbool.h>
#include <string.h> #include <string.h>
@ -90,14 +91,14 @@ void sdl_init(void)
void sdl_disp_drv_init(lv_disp_drv_t * disp_drv, lv_coord_t hor_res, lv_coord_t ver_res) void sdl_disp_drv_init(lv_disp_drv_t * disp_drv, lv_coord_t hor_res, lv_coord_t ver_res)
{ {
monitor_t *m = lv_mem_alloc(sizeof(monitor_t)); monitor_t *m = lv_malloc(sizeof(monitor_t));
window_create(m); window_create(m);
lv_disp_drv_init(disp_drv); lv_disp_drv_init(disp_drv);
disp_drv->direct_mode = 1; disp_drv->direct_mode = 1;
disp_drv->flush_cb = monitor_flush; disp_drv->flush_cb = monitor_flush;
disp_drv->hor_res = hor_res; disp_drv->hor_res = hor_res;
disp_drv->ver_res = ver_res; disp_drv->ver_res = ver_res;
lv_disp_draw_buf_t *disp_buf = lv_mem_alloc(sizeof(lv_disp_draw_buf_t)); lv_disp_draw_buf_t *disp_buf = lv_malloc(sizeof(lv_disp_draw_buf_t));
lv_disp_draw_buf_init(disp_buf, m->texture, NULL, hor_res * ver_res); lv_disp_draw_buf_init(disp_buf, m->texture, NULL, hor_res * ver_res);
disp_drv->draw_buf = disp_buf; disp_drv->draw_buf = disp_buf;
disp_drv->antialiasing = 1; disp_drv->antialiasing = 1;

@ -8,7 +8,7 @@ pkg_check_modules(xkbcommon REQUIRED xkbcommon)
# Wayland protocols # Wayland protocols
find_program(WAYLAND_SCANNER_EXECUTABLE NAMES wayland-scanner) find_program(WAYLAND_SCANNER_EXECUTABLE NAMES wayland-scanner)
pkg_check_modules(WAYLAND_PROTOCOLS REQUIRED wayland-protocols>=1.15) pkg_check_modules(WAYLAND_PROTOCOLS REQUIRED wayland-protocols>=1.25)
pkg_get_variable(WAYLAND_PROTOCOLS_BASE wayland-protocols pkgdatadir) pkg_get_variable(WAYLAND_PROTOCOLS_BASE wayland-protocols pkgdatadir)
macro(wayland_generate protocol_xml_file output_dir target) macro(wayland_generate protocol_xml_file output_dir target)

@ -0,0 +1,652 @@
/**
* @file smm.c
*
*/
#if USE_WAYLAND
#include <stddef.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <time.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "smm.h"
#define MAX_NAME_ATTEMPTS (5)
#define PREFER_NUM_BUFFERS (3)
#define ROUND_UP(n, b) (((((n) ? (n) : 1) + (b) - 1) / (b)) * (b))
#define LLHEAD(type) \
struct { \
struct type *first; \
struct type *last; \
}
#define LLLINK(type) \
struct { \
struct type *next; \
struct type *prev; \
}
#define LL_FIRST(head) ((head)->first)
#define LL_LAST(head) ((head)->last)
#define LL_IS_EMPTY(head) (LL_FIRST(head) == NULL)
#define LL_NEXT(src, member) ((src)->member.next)
#define LL_PREV(src, member) ((src)->member.prev)
#define LL_INIT(head) do { \
(head)->first = NULL; \
(head)->last = NULL; \
} while (0)
#define LL_ENQUEUE(head, src, member) do { \
(src)->member.next = NULL; \
(src)->member.prev = (head)->last; \
if ((head)->last == NULL) { \
(head)->first = (src); \
} else { \
(head)->last->member.next = (src); \
} \
(head)->last = (src); \
} while (0)
#define LL_DEQUEUE(entry, head, member) do { \
(entry) = LL_FIRST(head); \
LL_REMOVE(head, entry, member); \
} while (0)
#define LL_INSERT_AFTER(head, dest, src, member) do { \
(src)->member.prev = (dest); \
(src)->member.next = (dest)->member.next; \
if ((dest)->member.next != NULL) { \
(dest)->member.next->member.prev = (src); \
} else { \
(head)->last = (src); \
} \
(dest)->member.next = (src); \
} while (0)
#define LL_REMOVE(head, src, member) do { \
if ((src)->member.prev != NULL) { \
(src)->member.prev->member.next = (src)->member.next; \
} else { \
(head)->first = (src)->member.next; \
} \
if ((src)->member.next != NULL) { \
(src)->member.next->member.prev = (src)->member.prev; \
} else { \
(head)->last = (src)->member.prev; \
} \
} while (0)
#define LL_FOREACH(entry, head, member) \
for ((entry) = LL_FIRST(head); \
(entry) != NULL; \
(entry) = LL_NEXT(entry, member))
struct smm_pool {
struct smm_pool_properties props;
LLHEAD(smm_buffer) allocd;
void *map;
size_t map_size;
bool map_outdated;
};
struct smm_buffer {
struct smm_buffer_properties props;
bool group_resized;
LLLINK(smm_buffer) pool;
LLLINK(smm_buffer) use;
LLLINK(smm_buffer) age;
};
struct smm_group {
struct smm_group_properties props;
size_t size;
unsigned char num_buffers;
LLHEAD(smm_buffer) unused;
LLHEAD(smm_buffer) inuse;
LLHEAD(smm_buffer) history;
LLLINK(smm_group) link;
};
static size_t calc_buffer_size(struct smm_buffer *buf);
static void purge_history(struct smm_buffer *buf);
static struct smm_buffer *get_from_pool(struct smm_group *grp);
static void return_to_pool(struct smm_buffer *buf);
static struct smm_pool *alloc_pool(void);
static void free_pool(struct smm_pool *pool);
static struct smm_buffer *alloc_buffer(struct smm_buffer *last, size_t offset);
static void free_buffer(struct smm_buffer *buf);
static struct {
unsigned long page_sz;
struct smm_events cbs;
struct smm_pool *active;
LLHEAD(smm_group) groups;
struct {
size_t active_used;
} statistics;
} smm_instance;
void smm_init(struct smm_events *evs)
{
memcpy(&smm_instance.cbs, evs, sizeof(struct smm_events));
srand((unsigned int)clock());
smm_instance.page_sz = (unsigned long)sysconf(_SC_PAGESIZE);
LL_INIT(&smm_instance.groups);
}
void smm_deinit(void)
{
struct smm_group *grp;
/* Destroy all buffer groups */
while (!LL_IS_EMPTY(&smm_instance.groups)) {
LL_DEQUEUE(grp, &smm_instance.groups, link);
smm_destroy(grp);
}
}
void smm_setctx(void *ctx)
{
smm_instance.cbs.ctx = ctx;
}
smm_group_t *smm_create(void)
{
struct smm_group *grp;
/* Allocate and intialize a new buffer group */
grp = malloc(sizeof(struct smm_group));
if (grp != NULL) {
grp->size = smm_instance.page_sz;
grp->num_buffers = 0;
LL_INIT(&grp->unused);
LL_INIT(&grp->inuse);
LL_INIT(&grp->history);
/* Add to instance groups queue */
LL_ENQUEUE(&smm_instance.groups, grp, link);
}
return grp;
}
void smm_resize(smm_group_t *grp, size_t sz)
{
struct smm_buffer *buf;
struct smm_group *rgrp = grp;
/* Round allocation size up to a sysconf(_SC_PAGE_SIZE) boundary */
rgrp->size = ROUND_UP(sz, smm_instance.page_sz);
/* Return all unused buffers to pool (to be re-allocated at the new size) */
while (!LL_IS_EMPTY(&rgrp->unused)) {
LL_DEQUEUE(buf, &rgrp->unused, use);
return_to_pool(buf);
}
/* Mark all buffers in use to be freed to pool when possible */
LL_FOREACH(buf, &rgrp->inuse, use) {
buf->group_resized = true;
purge_history(buf);
}
}
void smm_destroy(smm_group_t *grp)
{
struct smm_buffer *buf;
struct smm_group *dgrp = grp;
/* Return unused buffers */
while (!LL_IS_EMPTY(&dgrp->unused)) {
LL_DEQUEUE(buf, &dgrp->unused, use);
return_to_pool(buf);
}
/* Return buffers that are still in use (ideally this queue should be empty
* at this time)
*/
while (!LL_IS_EMPTY(&dgrp->inuse)) {
LL_DEQUEUE(buf, &dgrp->inuse, use);
return_to_pool(buf);
}
/* Remove from instance groups queue */
LL_REMOVE(&smm_instance.groups, dgrp, link);
free(dgrp);
}
smm_buffer_t *smm_acquire(smm_group_t *grp)
{
struct smm_buffer *buf;
struct smm_group *agrp = grp;
if (LL_IS_EMPTY(&agrp->unused)) {
/* No unused buffer available, so get a new one from pool */
buf = get_from_pool(agrp);
} else {
/* Otherwise, reuse an unused buffer */
LL_DEQUEUE(buf, &agrp->unused, use);
}
if (buf != NULL) {
/* Add buffer to in-use queue */
LL_ENQUEUE(&agrp->inuse, buf, use);
/* Emit 'init buffer' event */
if (smm_instance.cbs.init_buffer != NULL) {
if (smm_instance.cbs.init_buffer(smm_instance.cbs.ctx, &buf->props)) {
smm_release(buf);
buf = NULL;
}
}
if (buf != NULL) {
/* Remove from history */
purge_history(buf);
/* Add to history a-new */
LL_ENQUEUE(&agrp->history, buf, age);
}
}
return buf;
}
void *smm_map(smm_buffer_t *buf)
{
struct smm_buffer *mbuf = buf;
struct smm_pool *pool = mbuf->props.pool;
void *map = pool->map;
if (pool->map_outdated) {
/* Update mapping to current pool size */
if (pool->map != NULL) {
munmap(pool->map, pool->map_size);
}
map = mmap(NULL,
pool->props.size,
PROT_READ | PROT_WRITE,
MAP_SHARED,
pool->props.fd,
0);
if (map == MAP_FAILED) {
map = NULL;
pool->map = NULL;
} else {
pool->map = map;
pool->map_size = pool->props.size;
pool->map_outdated = false;
}
}
/* Calculate buffer mapping (from offset in pool) */
if (map != NULL) {
map = (((char *)map) + mbuf->props.offset);
}
return map;
}
void smm_release(smm_buffer_t *buf)
{
struct smm_buffer *rbuf = buf;
struct smm_group *grp = rbuf->props.group;
/* Remove from in-use queue */
LL_REMOVE(&grp->inuse, rbuf, use);
if (rbuf->group_resized) {
/* Buffer group was resized while this buffer was in-use, thus it must be
* returned to it's pool
*/
rbuf->group_resized = false;
return_to_pool(rbuf);
} else {
/* Move to unused queue */
LL_ENQUEUE(&grp->unused, rbuf, use);
/* Try to limit total number of buffers to preferred number */
while ((grp->num_buffers > PREFER_NUM_BUFFERS) &&
(!LL_IS_EMPTY(&grp->unused))) {
LL_DEQUEUE(rbuf, &grp->unused, use);
return_to_pool(rbuf);
}
}
}
smm_buffer_t *smm_latest(smm_group_t *grp)
{
struct smm_group *lgrp = grp;
return LL_LAST(&lgrp->history);
}
smm_buffer_t *smm_next(smm_buffer_t *buf)
{
struct smm_buffer *ibuf;
struct smm_buffer *nbuf = buf;
struct smm_group *grp = nbuf->props.group;
LL_FOREACH(ibuf, &grp->history, age) {
if (ibuf == nbuf) {
ibuf = LL_NEXT(ibuf, age);
break;
}
}
return ibuf;
}
void purge_history(struct smm_buffer *buf)
{
struct smm_buffer *ibuf;
struct smm_group *grp = buf->props.group;
/* Remove from history (and any older) */
LL_FOREACH(ibuf, &grp->history, age) {
if (ibuf == buf) {
do {
LL_DEQUEUE(ibuf, &grp->history, age);
} while (ibuf != buf);
break;
}
}
}
size_t calc_buffer_size(struct smm_buffer *buf)
{
size_t buf_sz;
struct smm_pool *buf_pool = buf->props.pool;
if (buf == LL_LAST(&buf_pool->allocd)) {
buf_sz = (buf_pool->props.size - buf->props.offset);
} else {
buf_sz = (LL_NEXT(buf, pool)->props.offset - buf->props.offset);
}
return buf_sz;
}
struct smm_buffer *get_from_pool(struct smm_group *grp)
{
int ret;
size_t buf_sz;
struct smm_buffer *buf;
struct smm_buffer *last = NULL;
/* TODO: Determine when to allocate a new active pool (i.e. memory shrink) */
if (smm_instance.active == NULL) {
/* Allocate a new active pool */
smm_instance.active = alloc_pool();
smm_instance.statistics.active_used = 0;
}
if (smm_instance.active == NULL) {
buf = NULL;
} else {
/* Search for a free buffer large enough for allocation */
LL_FOREACH(buf, &smm_instance.active->allocd, pool) {
last = buf;
if (buf->props.group == NULL) {
buf_sz = calc_buffer_size(buf);
if (buf_sz == grp->size) {
break;
} else if (buf_sz > grp->size) {
if ((buf != LL_LAST(&smm_instance.active->allocd)) &&
(LL_NEXT(buf, pool)->props.group == NULL)) {
/* Pull back next buffer to use unallocated size */
LL_NEXT(buf, pool)->props.offset -= (buf_sz - grp->size);
} else {
/* Allocate another buffer to hold unallocated size */
alloc_buffer(buf, buf->props.offset + grp->size);
}
break;
}
}
}
if (buf == NULL) {
/* No buffer found to meet allocation size, expand pool */
if ((last != NULL) &&
(last->props.group == NULL)) {
/* Use last free buffer */
buf_sz = (grp->size - buf_sz);
} else {
/* Allocate new buffer */
buf_sz = grp->size;
if (last == NULL) {
buf = alloc_buffer(NULL, 0);
} else {
buf = alloc_buffer(last, smm_instance.active->props.size);
}
last = buf;
}
if (last != NULL) {
/* Expand pool backing memory */
ret = ftruncate(smm_instance.active->props.fd,
smm_instance.active->props.size + buf_sz);
if (ret) {
if (buf != NULL) {
free_buffer(buf);
buf = NULL;
}
} else {
smm_instance.active->props.size += buf_sz;
smm_instance.active->map_outdated = true;
buf = last;
if (!(smm_instance.active->props.size - buf_sz)) {
/* Emit 'new pool' event */
if ((smm_instance.cbs.new_pool != NULL) &&
(smm_instance.cbs.new_pool(smm_instance.cbs.ctx,
&smm_instance.active->props))) {
free_buffer(buf);
free_pool(smm_instance.active);
smm_instance.active = NULL;
buf = NULL;
}
} else {
/* Emit 'expand pool' event */
if (smm_instance.cbs.expand_pool != NULL) {
smm_instance.cbs.expand_pool(smm_instance.cbs.ctx,
&smm_instance.active->props);
}
}
}
}
}
}
if (buf != NULL) {
/* Set buffer group */
memcpy((void *)&buf->props.group, &grp, sizeof(struct smm_group *));
/* Emit 'new buffer' event */
if (smm_instance.cbs.new_buffer != NULL) {
if (smm_instance.cbs.new_buffer(smm_instance.cbs.ctx, &buf->props)) {
grp = NULL;
memcpy((void *)&buf->props.group, &grp, sizeof(struct smm_group *));
buf = NULL;
}
}
if (buf != NULL) {
/* Update active pool usage statistic */
smm_instance.statistics.active_used += grp->size;
grp->num_buffers++;
}
}
return buf;
}
void return_to_pool(struct smm_buffer *buf)
{
struct smm_group *grp = buf->props.group;
struct smm_pool *pool = buf->props.pool;
/* Emit 'free buffer' event */
if (smm_instance.cbs.free_buffer != NULL) {
smm_instance.cbs.free_buffer(smm_instance.cbs.ctx, &buf->props);
}
/* Buffer is no longer part of history */
purge_history(buf);
/* Buffer is no longer part of group */
grp->num_buffers--;
grp = NULL;
memcpy((void *)&buf->props.group, &grp, sizeof(struct smm_group *));
/* Update active pool usage statistic */
if (smm_instance.active == pool) {
smm_instance.statistics.active_used -= calc_buffer_size(buf);
}
/* Coalesce with ungrouped buffers beside this one */
if ((buf != LL_LAST(&pool->allocd)) &&
(LL_NEXT(buf, pool)->props.group == NULL)) {
free_buffer(LL_NEXT(buf, pool));
}
if ((buf != LL_FIRST(&pool->allocd)) &&
(LL_PREV(buf, pool)->props.group == NULL)) {
buf = LL_PREV(buf, pool);
pool = buf->props.pool;
free_buffer(LL_NEXT(buf, pool));
}
/* Free buffer (and pool), if only remaining buffer in pool */
if ((buf == LL_FIRST(&pool->allocd)) &&
(buf == LL_LAST(&pool->allocd))) {
free_buffer(buf);
/* Emit 'free pool' event */
if (smm_instance.cbs.free_pool != NULL) {
smm_instance.cbs.free_pool(smm_instance.cbs.ctx, &pool->props);
}
free_pool(pool);
if (smm_instance.active == pool) {
smm_instance.active = NULL;
}
}
}
struct smm_pool *alloc_pool(void)
{
struct smm_pool *pool;
char name[] = ("/" SMM_FD_NAME "-XXXXX");
unsigned char attempts = 0;
bool opened = false;
pool = malloc(sizeof(struct smm_pool));
if (pool != NULL) {
do {
/* A randomized pool name should help reduce collisions */
sprintf(name + sizeof(SMM_FD_NAME) + 1, "%05X", rand() & 0xFFFF);
pool->props.fd = shm_open(name,
O_RDWR | O_CREAT | O_EXCL,
S_IRUSR | S_IWUSR);
if (pool->props.fd >= 0) {
shm_unlink(name);
pool->props.size = 0;
pool->map = NULL;
pool->map_size = 0;
pool->map_outdated = false;
LL_INIT(&pool->allocd);
opened = true;
break;
} else {
if (errno != EEXIST) {
break;
}
attempts++;
}
} while (attempts < MAX_NAME_ATTEMPTS);
if (!opened) {
free(pool);
pool = NULL;
}
}
return pool;
}
void free_pool(struct smm_pool *pool)
{
if (pool->map != NULL) {
munmap(pool->map, pool->map_size);
}
close(pool->props.fd);
free(pool);
}
struct smm_buffer *alloc_buffer(struct smm_buffer *last, size_t offset)
{
struct smm_buffer *buf;
struct smm_buffer_properties initial_props = {
{NULL},
NULL,
smm_instance.active,
offset
};
/* Allocate and intialize a new buffer (including linking in to pool) */
buf = malloc(sizeof(struct smm_buffer));
if (buf != NULL) {
memcpy(&buf->props, &initial_props, sizeof(struct smm_buffer_properties));
buf->group_resized = false;
if (last == NULL) {
LL_ENQUEUE(&smm_instance.active->allocd, buf, pool);
} else {
LL_INSERT_AFTER(&smm_instance.active->allocd, last, buf, pool);
}
}
return buf;
}
void free_buffer(struct smm_buffer *buf)
{
struct smm_pool *buf_pool = buf->props.pool;
/* Remove from pool */
LL_REMOVE(&buf_pool->allocd, buf, pool);
free(buf);
}
#endif

@ -0,0 +1,67 @@
/**
* @file smm.h
*
*/
#ifndef SMM_H
#define SMM_H
#include <stddef.h>
#include <stdbool.h>
#define SMM_FD_NAME "lvgl-wayland"
#define SMM_POOL_TAGS (1)
#define SMM_BUFFER_TAGS (2)
#define SMM_GROUP_TAGS (1)
#define SMM_POOL_PROPERTIES(p) ((const struct smm_pool_properties *)(p))
#define SMM_BUFFER_PROPERTIES(b) ((const struct smm_buffer_properties *)(b))
#define SMM_GROUP_PROPERTIES(g) ((const struct smm_group_properties *)(g))
#define SMM_TAG(o, n, v) \
do { \
void **smm_tag = (void **)((char *)o + (n * sizeof(void *))); \
*smm_tag = (v); \
} while(0)
typedef void smm_pool_t;
typedef void smm_buffer_t;
typedef void smm_group_t;
struct smm_events {
void *ctx;
bool (*new_pool)(void *ctx, smm_pool_t *pool);
void (*expand_pool)(void *ctx, smm_pool_t *pool);
void (*free_pool)(void *ctx, smm_pool_t *pool);
bool (*new_buffer)(void *ctx, smm_buffer_t *buf);
bool (*init_buffer)(void *ctx, smm_buffer_t *buf);
void (*free_buffer)(void *ctx, smm_buffer_t *buf);
};
struct smm_pool_properties {
void *tag[SMM_POOL_TAGS];
size_t size;
int fd;
};
struct smm_buffer_properties {
void *tag[SMM_BUFFER_TAGS];
smm_group_t *const group;
smm_pool_t *const pool;
size_t offset;
};
struct smm_group_properties {
void *tag[SMM_GROUP_TAGS];
};
void smm_init(struct smm_events *evs);
void smm_setctx(void *ctx);
void smm_deinit(void);
smm_group_t *smm_create(void);
void smm_resize(smm_group_t *grp, size_t sz);
void smm_destroy(smm_group_t *grp);
smm_buffer_t *smm_acquire(smm_group_t *grp);
void *smm_map(smm_buffer_t *buf);
void smm_release(smm_buffer_t *buf);
smm_buffer_t *smm_latest(smm_group_t *grp);
smm_buffer_t *smm_next(smm_buffer_t *buf);
#endif

File diff suppressed because it is too large Load Diff

@ -54,7 +54,6 @@ lv_disp_t * lv_wayland_create_window(lv_coord_t hor_res, lv_coord_t ver_res, cha
lv_wayland_display_close_f_t close_cb); lv_wayland_display_close_f_t close_cb);
void lv_wayland_close_window(lv_disp_t * disp); void lv_wayland_close_window(lv_disp_t * disp);
bool lv_wayland_window_is_open(lv_disp_t * disp); bool lv_wayland_window_is_open(lv_disp_t * disp);
bool lv_wayland_window_is_flush_pending(lv_disp_t * disp);
void lv_wayland_window_set_fullscreen(lv_disp_t * disp, bool fullscreen); void lv_wayland_window_set_fullscreen(lv_disp_t * disp, bool fullscreen);
lv_indev_t * lv_wayland_get_pointer(lv_disp_t * disp); lv_indev_t * lv_wayland_get_pointer(lv_disp_t * disp);
lv_indev_t * lv_wayland_get_pointeraxis(lv_disp_t * disp); lv_indev_t * lv_wayland_get_pointeraxis(lv_disp_t * disp);

File diff suppressed because it is too large Load Diff

@ -20,7 +20,11 @@
#if USE_WIN32DRV #if USE_WIN32DRV
#include <Windows.h> #if LV_USE_USER_DATA == 0
#error "Support for user data is required by new Win32 driver. Set LV_USE_USER_DATA to 1 in lv_conf.h"
#endif
#include <windows.h>
#if _MSC_VER >= 1200 #if _MSC_VER >= 1200
// Disable compilation warnings. // Disable compilation warnings.
@ -46,10 +50,50 @@
* DEFINES * DEFINES
*********************/ *********************/
#define LVGL_SIMULATOR_WINDOW_CLASS L"LVGL.SimulatorWindow"
/********************** /**********************
* TYPEDEFS * TYPEDEFS
**********************/ **********************/
typedef struct _lv_win32_keyboard_queue_item_t
{
SLIST_ENTRY ItemEntry;
uint32_t key;
lv_indev_state_t state;
} lv_win32_keyboard_queue_item_t;
typedef struct _lv_win32_window_context_t
{
lv_disp_t* display_device_object;
lv_indev_t* mouse_device_object;
lv_indev_t* mousewheel_device_object;
lv_indev_t* keyboard_device_object;
lv_coord_t display_hor_res;
lv_coord_t display_ver_res;
uint32_t display_dpi;
HDC display_framebuffer_context_handle;
uint32_t* display_framebuffer_base;
size_t display_framebuffer_size;
lv_disp_draw_buf_t display_buffer;
lv_disp_drv_t display_driver;
lv_indev_state_t mouse_state;
lv_point_t mouse_point;
lv_indev_drv_t mouse_driver;
lv_indev_state_t mousewheel_state;
int16_t mousewheel_enc_diff;
lv_indev_drv_t mousewheel_driver;
CRITICAL_SECTION keyboard_mutex;
PSLIST_HEADER keyboard_queue;
uint16_t keyboard_utf16_high_surrogate;
uint16_t keyboard_utf16_low_surrogate;
lv_indev_drv_t keyboard_driver;
} lv_win32_window_context_t;
/********************** /**********************
* GLOBAL PROTOTYPES * GLOBAL PROTOTYPES
**********************/ **********************/
@ -63,6 +107,19 @@ EXTERN_C lv_indev_t* lv_win32_encoder_device_object;
EXTERN_C void lv_win32_add_all_input_devices_to_group( EXTERN_C void lv_win32_add_all_input_devices_to_group(
lv_group_t* group); lv_group_t* group);
EXTERN_C lv_win32_window_context_t* lv_win32_get_window_context(
HWND window_handle);
EXTERN_C bool lv_win32_init_window_class();
EXTERN_C HWND lv_win32_create_display_window(
const wchar_t* window_title,
lv_coord_t hor_res,
lv_coord_t ver_res,
HINSTANCE instance_handle,
HICON icon_handle,
int show_window_mode);
EXTERN_C bool lv_win32_init( EXTERN_C bool lv_win32_init(
HINSTANCE instance_handle, HINSTANCE instance_handle,
int show_window_mode, int show_window_mode,

@ -0,0 +1,284 @@
/**
* @file x11.c
*
*/
/*********************
* INCLUDES
*********************/
#include "x11.h"
#if USE_X11
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
/*********************
* DEFINES
*********************/
#ifndef KEYBOARD_BUFFER_SIZE
#define KEYBOARD_BUFFER_SIZE 64
#endif
#define MIN(A, B) ((A) < (B) ? (A) : (B))
#define MAX(A, B) ((A) > (B) ? (A) : (B))
#ifndef X11_OPTIMIZED_SCREEN_UPDATE
#define X11_OPTIMIZED_SCREEN_UPDATE 1
#endif
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC VARIABLES
**********************/
static Display* display = NULL;
static Window window = (XID)-1;
static GC gc = NULL;
static XImage* ximage = NULL;
static lv_timer_t* timer = NULL;
static char kb_buffer[KEYBOARD_BUFFER_SIZE];
static lv_point_t mouse_pos = { 0, 0 };
static bool left_mouse_btn = false;
static bool right_mouse_btn = false;
static bool wheel_mouse_btn = false;
static int16_t wheel_cnt = 0;
/**********************
* MACROS
**********************/
/**********************
* STATIC FUNCTIONS
**********************/
static int predicate(Display* disp, XEvent* evt, XPointer arg) { return 1; }
static void x11_event_handler(lv_timer_t * t)
{
XEvent myevent;
KeySym mykey;
int n;
/* handle all outstanding X events */
while (XCheckIfEvent(display, &myevent, predicate, NULL)) {
switch(myevent.type)
{
case Expose:
if(myevent.xexpose.count==0)
{
XPutImage(display, window, gc, ximage, 0, 0, 0, 0, LV_HOR_RES, LV_VER_RES);
}
break;
case MotionNotify:
mouse_pos.x = myevent.xmotion.x;
mouse_pos.y = myevent.xmotion.y;
break;
case ButtonPress:
switch (myevent.xbutton.button)
{
case Button1:
left_mouse_btn = true;
break;
case Button2:
wheel_mouse_btn = true;
break;
case Button3:
right_mouse_btn = true;
break;
case Button4:
wheel_cnt--; // Scrolled up
break;
case Button5:
wheel_cnt++; // Scrolled down
break;
default:
LV_LOG_WARN("unhandled button press : %d", myevent.xbutton.button);
}
break;
case ButtonRelease:
switch (myevent.xbutton.button)
{
case Button1:
left_mouse_btn = false;
break;
case Button2:
wheel_mouse_btn = false;
break;
case Button3:
right_mouse_btn = false;
break;
}
break;
case KeyPress:
n = XLookupString(&myevent.xkey, &kb_buffer[0], sizeof(kb_buffer), &mykey, NULL);
kb_buffer[n] = '\0';
break;
case KeyRelease:
break;
default:
LV_LOG_WARN("unhandled x11 event: %d", myevent.type);
}
}
}
static void lv_x11_hide_cursor()
{
XColor black = { .red = 0, .green = 0, .blue = 0 };
char empty_data[] = { 0 };
Pixmap empty_bitmap = XCreateBitmapFromData(display, window, empty_data, 1, 1);
Cursor inv_cursor = XCreatePixmapCursor(display, empty_bitmap, empty_bitmap, &black, &black, 0, 0);
XDefineCursor(display, window, inv_cursor);
XFreeCursor(display, inv_cursor);
XFreePixmap(display, empty_bitmap);
}
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_x11_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p)
{
#if X11_OPTIMIZED_SCREEN_UPDATE
static lv_area_t upd_area = {
.x1 = 0xFFFF,
.x2 = 0,
.y1 = 0xFFFF,
.y2 = 0
};
/* build display update area until lv_disp_flush_is_last */
upd_area.x1 = MIN(upd_area.x1, area->x1);
upd_area.x2 = MAX(upd_area.x2, area->x2);
upd_area.y1 = MIN(upd_area.y1, area->y1);
upd_area.y2 = MAX(upd_area.y2, area->y2);
#endif // X11_OPTIMIZED_SCREEN_UPDATE
for (lv_coord_t y = area->y1; y <= area->y2; y++)
{
uint32_t dst_offs = area->x1 + y * LV_HOR_RES;
uint32_t* dst_data = &((uint32_t*)ximage->data)[dst_offs];
for (lv_coord_t x = area->x1; x <= area->x2; x++, color_p++, dst_data++)
{
*dst_data = lv_color_to32(*color_p);
}
}
if (lv_disp_flush_is_last(disp_drv))
{
#if X11_OPTIMIZED_SCREEN_UPDATE
/* refresh collected display update area only */
lv_coord_t upd_w = upd_area.x2 - upd_area.x1 + 1;
lv_coord_t upd_h = upd_area.y2 - upd_area.y1 + 1;
XPutImage(display, window, gc, ximage, upd_area.x1, upd_area.y1, upd_area.x1, upd_area.y1, upd_w, upd_h);
/* invalidate collected area */
upd_area.x1 = 0xFFFF;
upd_area.x2 = 0;
upd_area.y1 = 0xFFFF;
upd_area.y2 = 0;
#else
/* refresh full display */
XPutImage(display, window, gc, ximage, 0, 0, 0, 0, LV_HOR_RES, LV_VER_RES);
#endif
}
lv_disp_flush_ready(disp_drv);
}
void lv_x11_get_pointer(lv_indev_drv_t *indev_drv, lv_indev_data_t *data)
{
(void) indev_drv; // Unused
data->point = mouse_pos;
data->state = left_mouse_btn ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
}
void lv_x11_get_mousewheel(lv_indev_drv_t *indev_drv, lv_indev_data_t *data)
{
(void) indev_drv; // Unused
data->state = wheel_mouse_btn ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
data->enc_diff = wheel_cnt;
wheel_cnt = 0;
}
void lv_x11_get_keyboard(lv_indev_drv_t *indev_drv, lv_indev_data_t *data)
{
(void) indev_drv; // Unused
size_t len = strlen(kb_buffer);
if (len > 0)
{
data->state = LV_INDEV_STATE_PRESSED;
data->key = kb_buffer[0];
memmove(kb_buffer, kb_buffer + 1, len);
data->continue_reading = (len > 0);
}
else
{
data->state = LV_INDEV_STATE_RELEASED;
}
}
void lv_x11_init(char const* title, lv_coord_t width, lv_coord_t height)
{
/* setup display/screen */
display = XOpenDisplay(NULL);
int screen = DefaultScreen(display);
/* drawing contexts for an window */
unsigned long myforeground = BlackPixel(display, screen);
unsigned long mybackground = WhitePixel(display, screen);
/* create window */
window = XCreateSimpleWindow(display, DefaultRootWindow(display),
0, 0, width, height,
0, myforeground, mybackground);
/* window manager properties (yes, use of StdProp is obsolete) */
XSetStandardProperties(display, window, title, NULL, None, NULL, 0, NULL);
/* allow receiving mouse and keyboard events */
XSelectInput(display, window, PointerMotionMask|ButtonPressMask|ButtonReleaseMask|KeyPressMask|KeyReleaseMask|ExposureMask);
/* graphics context */
gc = XCreateGC(display, window, 0, 0);
lv_x11_hide_cursor();
/* create cache XImage */
Visual* visual = XDefaultVisual(display, screen);
int dplanes = DisplayPlanes(display, screen);
ximage = XCreateImage(display, visual, dplanes, ZPixmap, 0,
malloc(width * height * sizeof(uint32_t)), width, height, 32, 0);
timer = lv_timer_create(x11_event_handler, 10, NULL);
/* finally bring window on top of the other windows */
XMapRaised(display, window);
}
void lv_x11_deinit(void)
{
lv_timer_del(timer);
free(ximage->data);
XDestroyImage(ximage);
ximage = NULL;
XFreeGC(display, gc);
gc = NULL;
XDestroyWindow(display, window);
window = (XID)-1;
XCloseDisplay(display);
display = NULL;
}
#endif // USE_X11

@ -0,0 +1,60 @@
/**
* @file x11.h
*
*/
#ifndef X11_H
#define X11_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#ifndef LV_DRV_NO_CONF
#ifdef LV_CONF_INCLUDE_SIMPLE
#include "lv_drv_conf.h"
#else
#include "../../lv_drv_conf.h"
#endif
#endif
#if USE_X11
#ifdef LV_LVGL_H_INCLUDE_SIMPLE
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
void lv_x11_init(char const* title, lv_coord_t width, lv_coord_t height);
void lv_x11_deinit(void);
void lv_x11_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p);
void lv_x11_get_pointer(lv_indev_drv_t *indev_drv, lv_indev_data_t *data);
void lv_x11_get_mousewheel(lv_indev_drv_t *indev_drv, lv_indev_data_t *data);
void lv_x11_get_keyboard(lv_indev_drv_t *indev_drv, lv_indev_data_t *data);
/**********************
* MACROS
**********************/
#endif /* USE_X11 */
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* X11_H */

@ -8,7 +8,7 @@ jobs:
build: build:
if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }} if: ${{ github.event_name != 'pull_request' || github.repository != github.event.pull_request.head.repo.full_name }}
name: Build ${{ matrix.port }} port name: Build ${{ matrix.port }} port
runs-on: ubuntu-latest runs-on: ubuntu-20.04
continue-on-error: true continue-on-error: true
strategy: strategy:
matrix: matrix:
@ -23,7 +23,7 @@ jobs:
- name: Clone lv_micropython - name: Clone lv_micropython
run: | run: |
git clone https://github.com/lvgl/lv_micropython.git . git clone https://github.com/lvgl/lv_micropython.git .
git checkout master git checkout release/v8
- name: Initialize lv_bindings submodule - name: Initialize lv_bindings submodule
run: git submodule update --init --recursive lib/lv_bindings run: git submodule update --init --recursive lib/lv_bindings
- name: Update ${{ matrix.port }} port submodules - name: Update ${{ matrix.port }} port submodules

@ -3,21 +3,21 @@ name: Push LVGL release to Espressif Component Service
# If the commit is tagged, it will be uploaded. Other scenario silently fail. # If the commit is tagged, it will be uploaded. Other scenario silently fail.
on: on:
push: push:
branches: tags:
- master - v*
jobs: jobs:
upload_components: upload_components:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@master - uses: actions/checkout@v2
with: with:
submodules: "recursive" submodules: "recursive"
- name: Upload component to component registry - name: Upload component to component registry
uses: espressif/github-actions/upload_components@master uses: espressif/upload-components-ci-action@v1
with: with:
name: "lvgl" name: "lvgl"
version: "git" version: ${{ github.ref_name }}
namespace: "lvgl" namespace: "lvgl"
api_token: ${{ secrets.ESP_IDF_COMPONENT_API_TOKEN }} api_token: ${{ secrets.ESP_IDF_COMPONENT_API_TOKEN }}

@ -42,11 +42,9 @@ menu "LVGL configuration"
config LV_COLOR_SCREEN_TRANSP config LV_COLOR_SCREEN_TRANSP
bool "Enable more complex drawing routines to manage screens transparency." bool "Enable more complex drawing routines to manage screens transparency."
depends on LV_COLOR_DEPTH_32
help help
Can be used if the UI is above another layer, e.g. an OSD menu or video player. Can be used if the UI is above another layer, e.g. an OSD menu or video player.
Requires `LV_COLOR_DEPTH = 32` colors and the screen's `bg_opa` should be set to The screen's `bg_opa` should be set to non LV_OPA_COVER value
non LV_OPA_COVER value
config LV_COLOR_MIX_ROUND_OFS config LV_COLOR_MIX_ROUND_OFS
int "Adjust color mix functions rounding" int "Adjust color mix functions rounding"
@ -230,6 +228,16 @@ menu "LVGL configuration"
Must be defined to include path of CMSIS header of target processor Must be defined to include path of CMSIS header of target processor
e.g. "stm32f769xx.h" or "stm32f429xx.h" e.g. "stm32f769xx.h" or "stm32f429xx.h"
config LV_USE_GPU_RA6M3_G2D
bool "Enable RA6M3 G2D GPU."
config LV_GPU_RA6M3_G2D_INCLUDE
string "include path of target processor"
depends on LV_USE_GPU_RA6M3_G2D
default "hal_data.h"
help
Must be defined to include path of target processor
e.g. "hal_data.h"
config LV_USE_GPU_SWM341_DMA2D config LV_USE_GPU_SWM341_DMA2D
bool "Enable SWM341 DMA2D GPU." bool "Enable SWM341 DMA2D GPU."
config LV_GPU_SWM341_DMA2D_INCLUDE config LV_GPU_SWM341_DMA2D_INCLUDE
@ -913,7 +921,8 @@ menu "LVGL configuration"
string "Set the working directory" string "Set the working directory"
depends on LV_USE_FS_STDIO depends on LV_USE_FS_STDIO
config LV_FS_STDIO_CACHE_SIZE config LV_FS_STDIO_CACHE_SIZE
string ">0 to cache this number of bytes in lv_fs_read()" int ">0 to cache this number of bytes in lv_fs_read()"
default 0
depends on LV_USE_FS_STDIO depends on LV_USE_FS_STDIO
config LV_USE_FS_POSIX config LV_USE_FS_POSIX
@ -955,6 +964,17 @@ menu "LVGL configuration"
default 0 default 0
depends on LV_USE_FS_FATFS depends on LV_USE_FS_FATFS
config LV_USE_FS_LITTLEFS
bool "File system on top of LittleFS"
config LV_FS_LITTLEFS_LETTER
int "Set an upper cased letter on which the drive will accessible (e.g. 'A' i.e. 65)"
default 0
depends on LV_USE_FS_LITTLEFS
config LV_FS_LITTLEFS_CACHE_SIZE
int ">0 to cache this number of bytes in lv_fs_read()"
default 0
depends on LV_USE_FS_LITTLEFS
config LV_USE_PNG config LV_USE_PNG
bool "PNG decoder library" bool "PNG decoder library"
@ -991,6 +1011,13 @@ menu "LVGL configuration"
endmenu endmenu
endif endif
config LV_USE_TINY_TTF
bool "Tiny TTF library"
config LV_TINY_TTF_FILE_SUPPORT
bool "Load TTF data from files"
depends on LV_USE_TINY_TTF
default n
config LV_USE_RLOTTIE config LV_USE_RLOTTIE
bool "Lottie library" bool "Lottie library"

@ -1,9 +1,4 @@
#if defined(LV_LVGL_H_INCLUDE_SIMPLE) #include "../../../lvgl.h"
#include "lvgl.h"
#else
#include "lvgl/lvgl.h"
#endif
#ifndef LV_ATTRIBUTE_MEM_ALIGN #ifndef LV_ATTRIBUTE_MEM_ALIGN
#define LV_ATTRIBUTE_MEM_ALIGN #define LV_ATTRIBUTE_MEM_ALIGN

@ -89,7 +89,7 @@ LV_FONT_DECLARE(lv_font_benchmark_montserrat_16_compr_az);
LV_FONT_DECLARE(lv_font_benchmark_montserrat_28_compr_az); LV_FONT_DECLARE(lv_font_benchmark_montserrat_28_compr_az);
static void monitor_cb(lv_disp_drv_t * drv, uint32_t time, uint32_t px); static void monitor_cb(lv_disp_drv_t * drv, uint32_t time, uint32_t px);
static void scene_next_task_cb(lv_timer_t * timer); static void next_scene_timer_cb(lv_timer_t * timer);
static void rect_create(lv_style_t * style); static void rect_create(lv_style_t * style);
static void img_create(lv_style_t * style, const void * src, bool rotate, bool zoom, bool aa); static void img_create(lv_style_t * style, const void * src, bool rotate, bool zoom, bool aa);
static void txt_create(lv_style_t * style); static void txt_create(lv_style_t * style);
@ -636,7 +636,7 @@ static lv_obj_t * scene_bg;
static lv_obj_t * title; static lv_obj_t * title;
static lv_obj_t * subtitle; static lv_obj_t * subtitle;
static uint32_t rnd_act; static uint32_t rnd_act;
static lv_timer_t * next_scene_timer;
static const uint32_t rnd_map[] = { static const uint32_t rnd_map[] = {
0xbd13204f, 0x67d8167f, 0x20211c99, 0xb0a7cc05, 0xbd13204f, 0x67d8167f, 0x20211c99, 0xb0a7cc05,
@ -708,9 +708,21 @@ void lv_demo_benchmark(void)
benchmark_init(); benchmark_init();
/*Manually start scenes*/ /*Manually start scenes*/
scene_next_task_cb(NULL); next_scene_timer_cb(NULL);
} }
void lv_demo_benchmark_close(void)
{
if(next_scene_timer) lv_timer_del(next_scene_timer);
next_scene_timer = NULL;
lv_anim_del(NULL, NULL);
lv_style_reset(&style_common);
lv_obj_clean(lv_scr_act());
}
void lv_demo_benchmark_run_scene(int_fast16_t scene_no) void lv_demo_benchmark_run_scene(int_fast16_t scene_no)
{ {
@ -725,7 +737,8 @@ void lv_demo_benchmark_run_scene(int_fast16_t scene_no)
scene_act = scene_no >> 1; scene_act = scene_no >> 1;
if(scenes[scene_act].create_cb) { if(scenes[scene_act].create_cb) {
lv_label_set_text_fmt(title, "%"LV_PRId32"/%d: %s%s", scene_act * 2 + (opa_mode ? 1 : 0), (int)(dimof(scenes) * 2) - 2, lv_label_set_text_fmt(title, "%"LV_PRId32"/%"LV_PRId32": %s%s", scene_act * 2 + (opa_mode ? 1 : 0),
(int32_t)(dimof(scenes) * 2) - 2,
scenes[scene_act].name, opa_mode ? " + opa" : ""); scenes[scene_act].name, opa_mode ? " + opa" : "");
lv_label_set_text(subtitle, ""); lv_label_set_text(subtitle, "");
@ -972,11 +985,13 @@ static void report_cb(lv_timer_t * timer)
} }
} }
static void scene_next_task_cb(lv_timer_t * timer) static void next_scene_timer_cb(lv_timer_t * timer)
{ {
LV_UNUSED(timer); LV_UNUSED(timer);
lv_obj_clean(scene_bg); lv_obj_clean(scene_bg);
next_scene_timer = NULL;
if(opa_mode) { if(opa_mode) {
if(scene_act >= 0) { if(scene_act >= 0) {
if(scenes[scene_act].time_sum_opa == 0) scenes[scene_act].time_sum_opa = 1; if(scenes[scene_act].time_sum_opa == 0) scenes[scene_act].time_sum_opa = 1;
@ -995,8 +1010,8 @@ static void scene_next_task_cb(lv_timer_t * timer)
} }
if(scenes[scene_act].create_cb) { if(scenes[scene_act].create_cb) {
lv_label_set_text_fmt(title, "%"LV_PRId32"/%d: %s%s", scene_act * 2 + (opa_mode ? 1 : 0), lv_label_set_text_fmt(title, "%"LV_PRId32"/%"LV_PRId32": %s%s", scene_act * 2 + (opa_mode ? 1 : 0),
(int)(dimof(scenes) * 2) - 2, scenes[scene_act].name, opa_mode ? " + opa" : ""); (int32_t)(dimof(scenes) * 2) - 2, scenes[scene_act].name, opa_mode ? " + opa" : "");
if(opa_mode) { if(opa_mode) {
lv_label_set_text_fmt(subtitle, "Result of \"%s\": %"LV_PRId32" FPS", scenes[scene_act].name, lv_label_set_text_fmt(subtitle, "Result of \"%s\": %"LV_PRId32" FPS", scenes[scene_act].name,
scenes[scene_act].fps_normal); scenes[scene_act].fps_normal);
@ -1013,8 +1028,8 @@ static void scene_next_task_cb(lv_timer_t * timer)
rnd_reset(); rnd_reset();
scenes[scene_act].create_cb(); scenes[scene_act].create_cb();
lv_timer_t * t = lv_timer_create(scene_next_task_cb, SCENE_TIME, NULL); next_scene_timer = lv_timer_create(next_scene_timer_cb, SCENE_TIME, NULL);
lv_timer_set_repeat_count(t, 1); lv_timer_set_repeat_count(next_scene_timer, 1);
} }
/*Ready*/ /*Ready*/

@ -30,6 +30,8 @@ typedef void finished_cb_t(void);
**********************/ **********************/
void lv_demo_benchmark(void); void lv_demo_benchmark(void);
void lv_demo_benchmark_close(void);
void lv_demo_benchmark_run_scene(int_fast16_t scene_no); void lv_demo_benchmark_run_scene(int_fast16_t scene_no);
void lv_demo_benchmark_set_finished_cb(finished_cb_t * finished_cb); void lv_demo_benchmark_set_finished_cb(finished_cb_t * finished_cb);

@ -46,8 +46,11 @@ static lv_obj_t * t2;
void lv_demo_keypad_encoder(void) void lv_demo_keypad_encoder(void)
{ {
g = lv_group_get_default();
if(g == NULL) {
g = lv_group_create(); g = lv_group_create();
lv_group_set_default(g); lv_group_set_default(g);
}
lv_indev_t * cur_drv = NULL; lv_indev_t * cur_drv = NULL;
for(;;) { for(;;) {
@ -76,6 +79,12 @@ void lv_demo_keypad_encoder(void)
msgbox_create(); msgbox_create();
} }
void lv_demo_keypad_encoder_close(void)
{
lv_obj_clean(lv_scr_act());
lv_obj_clean(lv_layer_top());
}
/********************** /**********************
* STATIC FUNCTIONS * STATIC FUNCTIONS
**********************/ **********************/

@ -27,6 +27,7 @@ extern "C" {
* GLOBAL PROTOTYPES * GLOBAL PROTOTYPES
**********************/ **********************/
void lv_demo_keypad_encoder(void); void lv_demo_keypad_encoder(void);
void lv_demo_keypad_encoder_close(void);
/********************** /**********************
* MACROS * MACROS

@ -103,6 +103,12 @@ static const uint32_t time_list[] = {
2 * 60 + 19, 2 * 60 + 19,
}; };
#if LV_DEMO_MUSIC_AUTO_PLAY
static lv_timer_t * auto_step_timer;
#endif
static lv_color_t original_screen_bg_color;
/********************** /**********************
* MACROS * MACROS
**********************/ **********************/
@ -113,14 +119,31 @@ static const uint32_t time_list[] = {
void lv_demo_music(void) void lv_demo_music(void)
{ {
original_screen_bg_color = lv_obj_get_style_bg_color(lv_scr_act(), 0);
lv_obj_set_style_bg_color(lv_scr_act(), lv_color_hex(0x343247), 0); lv_obj_set_style_bg_color(lv_scr_act(), lv_color_hex(0x343247), 0);
list = _lv_demo_music_list_create(lv_scr_act()); list = _lv_demo_music_list_create(lv_scr_act());
ctrl = _lv_demo_music_main_create(lv_scr_act()); ctrl = _lv_demo_music_main_create(lv_scr_act());
#if LV_DEMO_MUSIC_AUTO_PLAY #if LV_DEMO_MUSIC_AUTO_PLAY
lv_timer_create(auto_step_cb, 1000, NULL); auto_step_timer = lv_timer_create(auto_step_cb, 1000, NULL);
#endif
}
void lv_demo_music_close(void)
{
/*Delete all aniamtions*/
lv_anim_del(NULL, NULL);
#if LV_DEMO_MUSIC_AUTO_PLAY
lv_timer_del(auto_step_timer);
#endif #endif
_lv_demo_music_list_close();
_lv_demo_music_main_close();
lv_obj_clean(lv_scr_act());
lv_obj_set_style_bg_color(lv_scr_act(), original_screen_bg_color, 0);
} }
const char * _lv_demo_music_get_title(uint32_t track_id) const char * _lv_demo_music_get_title(uint32_t track_id)

@ -36,6 +36,8 @@ extern "C" {
**********************/ **********************/
void lv_demo_music(void); void lv_demo_music(void);
void lv_demo_music_close(void);
const char * _lv_demo_music_get_title(uint32_t track_id); const char * _lv_demo_music_get_title(uint32_t track_id);
const char * _lv_demo_music_get_artist(uint32_t track_id); const char * _lv_demo_music_get_artist(uint32_t track_id);
const char * _lv_demo_music_get_genre(uint32_t track_id); const char * _lv_demo_music_get_genre(uint32_t track_id);

@ -130,6 +130,19 @@ lv_obj_t * _lv_demo_music_list_create(lv_obj_t * parent)
return list; return list;
} }
void _lv_demo_music_list_close(void)
{
lv_style_reset(&style_scrollbar);
lv_style_reset(&style_btn);
lv_style_reset(&style_btn_pr);
lv_style_reset(&style_btn_chk);
lv_style_reset(&style_btn_dis);
lv_style_reset(&style_title);
lv_style_reset(&style_artist);
lv_style_reset(&style_time);
}
void _lv_demo_music_list_btn_check(uint32_t track_id, bool state) void _lv_demo_music_list_btn_check(uint32_t track_id, bool state)
{ {
lv_obj_t * btn = lv_obj_get_child(list, track_id); lv_obj_t * btn = lv_obj_get_child(list, track_id);

@ -28,6 +28,8 @@ extern "C" {
* GLOBAL PROTOTYPES * GLOBAL PROTOTYPES
**********************/ **********************/
lv_obj_t * _lv_demo_music_list_create(lv_obj_t * parent); lv_obj_t * _lv_demo_music_list_create(lv_obj_t * parent);
void _lv_demo_music_list_close(void);
void _lv_demo_music_list_btn_check(uint32_t track_id, bool state); void _lv_demo_music_list_btn_check(uint32_t track_id, bool state);
/********************** /**********************

@ -60,7 +60,7 @@ static void prev_click_event_cb(lv_event_t * e);
static void next_click_event_cb(lv_event_t * e); static void next_click_event_cb(lv_event_t * e);
static void timer_cb(lv_timer_t * t); static void timer_cb(lv_timer_t * t);
static void track_load(uint32_t id); static void track_load(uint32_t id);
static void stop_start_anim(lv_timer_t * t); static void stop_start_anim_timer_cb(lv_timer_t * t);
static void spectrum_end_cb(lv_anim_t * a); static void spectrum_end_cb(lv_anim_t * a);
static void album_fade_anim_cb(void * var, int32_t v); static void album_fade_anim_cb(void * var, int32_t v);
static int32_t get_cos(int32_t deg, int32_t a); static int32_t get_cos(int32_t deg, int32_t a);
@ -84,6 +84,7 @@ static uint32_t spectrum_lane_ofs_start = 0;
static uint32_t bar_rot = 0; static uint32_t bar_rot = 0;
static uint32_t time_act; static uint32_t time_act;
static lv_timer_t * sec_counter_timer; static lv_timer_t * sec_counter_timer;
static lv_timer_t * stop_start_anim_timer;
static const lv_font_t * font_small; static const lv_font_t * font_small;
static const lv_font_t * font_large; static const lv_font_t * font_large;
static uint32_t track_id; static uint32_t track_id;
@ -232,8 +233,8 @@ lv_obj_t * _lv_demo_music_main_create(lv_obj_t * parent)
start_anim = true; start_anim = true;
lv_timer_t * timer = lv_timer_create(stop_start_anim, INTRO_TIME + 6000, NULL); stop_start_anim_timer = lv_timer_create(stop_start_anim_timer_cb, INTRO_TIME + 6000, NULL);
lv_timer_set_repeat_count(timer, 1); lv_timer_set_repeat_count(stop_start_anim_timer, 1);
lv_anim_init(&a); lv_anim_init(&a);
lv_anim_set_path_cb(&a, lv_anim_path_bounce); lv_anim_set_path_cb(&a, lv_anim_path_bounce);
@ -292,6 +293,12 @@ lv_obj_t * _lv_demo_music_main_create(lv_obj_t * parent)
return main_cont; return main_cont;
} }
void _lv_demo_music_main_close(void)
{
if(stop_start_anim_timer) lv_timer_del(stop_start_anim_timer);
lv_timer_del(sec_counter_timer);
}
void _lv_demo_music_album_next(bool next) void _lv_demo_music_album_next(bool next)
{ {
uint32_t id = track_id; uint32_t id = track_id;
@ -762,7 +769,7 @@ static void spectrum_draw_event_cb(lv_event_t * e)
lv_obj_t * obj = lv_event_get_target(e); lv_obj_t * obj = lv_event_get_target(e);
lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e); lv_draw_ctx_t * draw_ctx = lv_event_get_draw_ctx(e);
lv_opa_t opa = lv_obj_get_style_opa(obj, LV_PART_MAIN); lv_opa_t opa = lv_obj_get_style_opa_recursive(obj, LV_PART_MAIN);
if(opa < LV_OPA_MIN) return; if(opa < LV_OPA_MIN) return;
lv_point_t poly[4]; lv_point_t poly[4];
@ -990,10 +997,11 @@ static void spectrum_end_cb(lv_anim_t * a)
} }
static void stop_start_anim(lv_timer_t * t) static void stop_start_anim_timer_cb(lv_timer_t * t)
{ {
LV_UNUSED(t); LV_UNUSED(t);
start_anim = false; start_anim = false;
stop_start_anim_timer = NULL;
lv_obj_refresh_ext_draw_size(spectrum_obj); lv_obj_refresh_ext_draw_size(spectrum_obj);
} }

@ -28,6 +28,8 @@ extern "C" {
* GLOBAL PROTOTYPES * GLOBAL PROTOTYPES
**********************/ **********************/
lv_obj_t * _lv_demo_music_main_create(lv_obj_t * parent); lv_obj_t * _lv_demo_music_main_create(lv_obj_t * parent);
void _lv_demo_music_main_close(void);
void _lv_demo_music_play(uint32_t id); void _lv_demo_music_play(uint32_t id);
void _lv_demo_music_resume(void); void _lv_demo_music_resume(void);
void _lv_demo_music_pause(void); void _lv_demo_music_pause(void);

@ -25,7 +25,7 @@ static void msgbox_del(lv_timer_t * tmr);
static void set_y_anim(void * obj, int32_t v); static void set_y_anim(void * obj, int32_t v);
static void set_width_anim(void * obj, int32_t v); static void set_width_anim(void * obj, int32_t v);
static void arc_set_end_angle_anim(void * obj, int32_t v); static void arc_set_end_angle_anim(void * obj, int32_t v);
static void obj_test_task_cb(lv_timer_t * tmr); static void obj_test_timer_cb(lv_timer_t * tmr);
/********************** /**********************
* STATIC VARIABLES * STATIC VARIABLES
@ -34,6 +34,10 @@ static lv_obj_t * main_page;
static lv_obj_t * ta; static lv_obj_t * ta;
static const char * mbox_btns[] = {"Ok", "Cancel", ""}; static const char * mbox_btns[] = {"Ok", "Cancel", ""};
static uint32_t mem_free_start = 0; static uint32_t mem_free_start = 0;
static lv_timer_t * obj_test_timer;
static int16_t state;
static lv_timer_t * msgbox_tmr;
/********************** /**********************
* MACROS * MACROS
**********************/ **********************/
@ -45,23 +49,34 @@ static uint32_t mem_free_start = 0;
void lv_demo_stress(void) void lv_demo_stress(void)
{ {
LV_LOG_USER("Starting stress test. (< 100 bytes permanent memory leak is normal due to fragmentation)"); LV_LOG_USER("Starting stress test. (< 100 bytes permanent memory leak is normal due to fragmentation)");
lv_timer_create(obj_test_task_cb, LV_DEMO_STRESS_TIME_STEP, NULL); obj_test_timer = lv_timer_create(obj_test_timer_cb, LV_DEMO_STRESS_TIME_STEP, NULL);
state = -1;
}
void lv_demo_stress_close(void)
{
lv_timer_del(obj_test_timer);
obj_test_timer = NULL;
if(msgbox_tmr) {
lv_timer_del(msgbox_tmr);
msgbox_tmr = NULL;
}
lv_obj_clean(lv_scr_act());
lv_obj_clean(lv_layer_top());
} }
/********************** /**********************
* STATIC FUNCTIONS * STATIC FUNCTIONS
**********************/ **********************/
static void obj_test_task_cb(lv_timer_t * tmr) static void obj_test_timer_cb(lv_timer_t * tmr)
{ {
(void) tmr; /*Unused*/ (void) tmr; /*Unused*/
static int16_t state = -1;
lv_anim_t a; lv_anim_t a;
lv_obj_t * obj; lv_obj_t * obj;
// printf("step start: %d\n", state);
switch(state) { switch(state) {
case -1: { case -1: {
lv_res_t res = lv_mem_test(); lv_res_t res = lv_mem_test();
@ -246,8 +261,7 @@ static void obj_test_task_cb(lv_timer_t * tmr)
case 14: case 14:
obj = lv_msgbox_create(NULL, "Title", "Some text on the message box with average length", mbox_btns, true); obj = lv_msgbox_create(NULL, "Title", "Some text on the message box with average length", mbox_btns, true);
msgbox_tmr = lv_timer_create(msgbox_del, LV_DEMO_STRESS_TIME_STEP * 5 + 30, obj);
lv_timer_t * msgbox_tmr = lv_timer_create(msgbox_del, LV_DEMO_STRESS_TIME_STEP * 5 + 30, obj);
lv_timer_set_repeat_count(msgbox_tmr, 1); lv_timer_set_repeat_count(msgbox_tmr, 1);
lv_obj_align(obj, LV_ALIGN_RIGHT_MID, -10, 0); lv_obj_align(obj, LV_ALIGN_RIGHT_MID, -10, 0);
break; break;
@ -439,6 +453,7 @@ static void auto_del(lv_obj_t * obj, uint32_t delay)
static void msgbox_del(lv_timer_t * tmr) static void msgbox_del(lv_timer_t * tmr)
{ {
msgbox_tmr = NULL;
lv_msgbox_close(tmr->user_data); lv_msgbox_close(tmr->user_data);
} }

@ -30,6 +30,8 @@ extern "C" {
**********************/ **********************/
void lv_demo_stress(void); void lv_demo_stress(void);
void lv_demo_stress_close(void);
/********************** /**********************
* MACROS * MACROS
**********************/ **********************/

@ -86,6 +86,8 @@ static uint32_t session_desktop = 1000;
static uint32_t session_tablet = 1000; static uint32_t session_tablet = 1000;
static uint32_t session_mobile = 1000; static uint32_t session_mobile = 1000;
static lv_timer_t * meter2_timer;
/********************** /**********************
* MACROS * MACROS
**********************/ **********************/
@ -196,6 +198,22 @@ void lv_demo_widgets(void)
color_changer_create(tv); color_changer_create(tv);
} }
void lv_demo_widgets_close(void)
{
/*Delete all animation*/
lv_anim_del(NULL, NULL);
lv_timer_del(meter2_timer);
meter2_timer = NULL;
lv_obj_clean(lv_scr_act());
lv_style_reset(&style_text_muted);
lv_style_reset(&style_title);
lv_style_reset(&style_icon);
lv_style_reset(&style_bullet);
}
/********************** /**********************
* STATIC FUNCTIONS * STATIC FUNCTIONS
**********************/ **********************/
@ -205,6 +223,7 @@ static void profile_create(lv_obj_t * parent)
lv_obj_t * panel1 = lv_obj_create(parent); lv_obj_t * panel1 = lv_obj_create(parent);
lv_obj_set_height(panel1, LV_SIZE_CONTENT); lv_obj_set_height(panel1, LV_SIZE_CONTENT);
LV_IMG_DECLARE(img_demo_widgets_avatar); LV_IMG_DECLARE(img_demo_widgets_avatar);
lv_obj_t * avatar = lv_img_create(panel1); lv_obj_t * avatar = lv_img_create(panel1);
lv_img_set_src(avatar, &img_demo_widgets_avatar); lv_img_set_src(avatar, &img_demo_widgets_avatar);
@ -698,7 +717,7 @@ static void analytics_create(lv_obj_t * parent)
lv_meter_set_indicator_start_value(meter2, meter2_indic[2], 70); lv_meter_set_indicator_start_value(meter2, meter2_indic[2], 70);
lv_meter_set_indicator_end_value(meter2, meter2_indic[2], 99); lv_meter_set_indicator_end_value(meter2, meter2_indic[2], 99);
lv_timer_create(meter2_timer_cb, 100, meter2_indic); meter2_timer = lv_timer_create(meter2_timer_cb, 100, meter2_indic);
meter3 = create_meter_box(parent, "Network Speed", "Low speed", "Normal Speed", "High Speed"); meter3 = create_meter_box(parent, "Network Speed", "Low speed", "Normal Speed", "High Speed");
if(disp_size < DISP_LARGE) lv_obj_add_flag(lv_obj_get_parent(meter3), LV_OBJ_FLAG_FLEX_IN_NEW_TRACK); if(disp_size < DISP_LARGE) lv_obj_add_flag(lv_obj_get_parent(meter3), LV_OBJ_FLAG_FLEX_IN_NEW_TRACK);

@ -27,6 +27,7 @@ extern "C" {
* GLOBAL PROTOTYPES * GLOBAL PROTOTYPES
**********************/ **********************/
void lv_demo_widgets(void); void lv_demo_widgets(void);
void lv_demo_widgets_close(void);
/********************** /**********************
* MACROS * MACROS

@ -1,5 +1,328 @@
# Changelog # Changelog
## [v8.3.11](https://github.com/lvgl/lvgl/compare/v8.3.11...v8.3.10) 6 December 2023
### New Features
- feat(table): add user_data to table cells [`4767`](https://github.com/lvgl/lvgl/pull/4767)
- feat(tiny_ttf): backport Tiny TTF to lvgl 8 [`4727`](https://github.com/lvgl/lvgl/pull/4727)
- feat(littlefs): add lv_fs_littlefs system as a driver [`4677`](https://github.com/lvgl/lvgl/pull/4677)
### Fixes
- fix(obj): readjust scroll after layout when child removed [`4921`](https://github.com/lvgl/lvgl/pull/4921)
- fix(rt-thread): fix create lvgl thread problem [`4862`](https://github.com/lvgl/lvgl/pull/4862)
- fix(obj): fix arduino compile warnings [`4807`](https://github.com/lvgl/lvgl/pull/4807)
- fix(table):fix issue with abnormal string output of 'lv_table_set_cell_value_fmt' [`4804`](https://github.com/lvgl/lvgl/pull/4804)
- fix(table) user data API functions renamed [`4769`](https://github.com/lvgl/lvgl/pull/4769)
- fix(ime_pinyin): keep cursor in the textarea when a candidate is pressed [`4731`](https://github.com/lvgl/lvgl/pull/4731)
- fix(draw_needles): changed needle line draw start point from scale ce… [`4682`](https://github.com/lvgl/lvgl/pull/4682)
- fix(arc): handle click outside background angle range (#4586) [`4667`](https://github.com/lvgl/lvgl/pull/4667)
- fix(meter): fix minor issues [`4657`](https://github.com/lvgl/lvgl/pull/4657)
- fix(draw): fix compiler error in lv_draw_sw_transform.c #2 [`4612`](https://github.com/lvgl/lvgl/pull/4612)
- fix(dropdown): avoid partial match in lv_dropdown_get_option_index [`4598`](https://github.com/lvgl/lvgl/pull/4598)
- fix(dropdown): reset char_i = 0, avoid access overflow [`4589`](https://github.com/lvgl/lvgl/pull/4589)
- fix(btnmatrix): set LV_BTNMATRIX_BTN_NONE when clicking of disabled button (#4571) [`4578`](https://github.com/lvgl/lvgl/pull/4578)
- fix(qrcode): use LV_ASSERT instead of assert [`1840dec`](https://github.com/lvgl/lvgl/commit/1840decb4136ba01552fcb7cedb0ff759824e2fd)
- fix: fix warning in lv_draw_sw_letter.c [`d22cda3`](https://github.com/lvgl/lvgl/commit/d22cda3cdb15cee95763491db95753980846d9f9)
- fix(arc): fix setting value by click [`20b6199`](https://github.com/lvgl/lvgl/commit/20b6199ba90319942c3cd91f2c727da6cd40cd2d)
- fix(disp): fix infinite recursive SCREEN_LOADED events [`ef76206`](https://github.com/lvgl/lvgl/commit/ef76206c75ea9de26407534a9ce1079dc8e750e3)
- fix(keyboard): add '&' character [`d20bd1c`](https://github.com/lvgl/lvgl/commit/d20bd1ca397ff954167dd496cf1a78da8814f602)
- fix(draw): fix scaling rectangle parts with opa [`7a8fcbf`](https://github.com/lvgl/lvgl/commit/7a8fcbfd3458739cbe64b29767a969ece9542039)
### Docs
- docs(obj): fix wording [`4625`](https://github.com/lvgl/lvgl/pull/4625)
- docs(label): update text for recoloring [`4606`](https://github.com/lvgl/lvgl/pull/4606)
- docs: fix typo [`9fbac75`](https://github.com/lvgl/lvgl/commit/9fbac7570bdec18ddbb157b59f5e26a2ebdf5daf)
### Others
- chore(cmsis-pack): prepare for v8.3.11 [`4936`](https://github.com/lvgl/lvgl/pull/4936)
- chore(cmake): add support for user-specified lv_conf.h path [`4689`](https://github.com/lvgl/lvgl/pull/4689)
- STM32U5 DMA2D support (8.3) [`4643`](https://github.com/lvgl/lvgl/pull/4643)
- backport: fix(lv_disp): fix lv_scr_load_anim being called twice quickly [`4629`](https://github.com/lvgl/lvgl/pull/4629)
- chore(lv_draw_sw_letter.c): Fix print format [`4615`](https://github.com/lvgl/lvgl/pull/4615)
- chore: fix compile error [`7568df7`](https://github.com/lvgl/lvgl/commit/7568df77d16ecbf2242b2bc290dc8fc0eb29cf5a)
## [v8.3.10](https://github.com/lvgl/lvgl/compare/v8.3.10...v8.3.9) 20 September 2023
### New Features
- feat(disp): add double buffered direct-mode efficient sync algorithm (v8.3) [`4497`](https://github.com/lvgl/lvgl/pull/4497)
- feat(style): backport opa_layered [`6548ea0`](https://github.com/lvgl/lvgl/commit/6548ea0f291be8a97afb3c4d7dcabbe465ae5a04)
### Fixes
- fix: build on Windows (MinGW environment) [`4538`](https://github.com/lvgl/lvgl/pull/4538)
- fix(docs): dropdown: fix function name in description of static options [`4535`](https://github.com/lvgl/lvgl/pull/4535)
- fix: do not copy invalid areas if not double buffered mode [`4526`](https://github.com/lvgl/lvgl/pull/4526)
- fix(sdl): add missing parameter in lv_draw_sdl_composite_texture_obtain [`4490`](https://github.com/lvgl/lvgl/pull/4490)
- fix(dropdown): position to the selected item in lv_dropdown_set_selected [`f174589`](https://github.com/lvgl/lvgl/commit/f174589240b099a349e54ba09aa9b39c2b347341)
- fix(vglite): be sure end_angle > start_angle in arc drawing [`01cd1fe`](https://github.com/lvgl/lvgl/commit/01cd1fed9db974aa616a6289a29171b7a971cd89)
- fix(btnmatrix): fix tapping just outside a button in a buttonmatrix [`8063fac`](https://github.com/lvgl/lvgl/commit/8063fac793b0a09add1e57c1115b734659274e6f)
### Docs
- docs(calendar): update according to v8.2 changes [`a296456`](https://github.com/lvgl/lvgl/commit/a296456591f6ff0e3b3ae6cdcdd9ec5b1711c357)
- docs(simulator): remove SDL support from the Visual Studio project [`bcebafe`](https://github.com/lvgl/lvgl/commit/bcebafe4fb72e336b7dedca89c07e334427eef8d)
### CI and tests
- ci: update screenshot compare from v9 to automatically create missing reference images [`fd21ed0`](https://github.com/lvgl/lvgl/commit/fd21ed0eb82bacb1e482180ab0aaed6a667f000d)
- ci(dropdown): fix test [`5fc488a`](https://github.com/lvgl/lvgl/commit/5fc488a088639dbfb5eb44f65b05e13b6ba881bf)
### Others
- chore(cmsis-pack): create cmsis-pack for v8.3.10 [`4572`](https://github.com/lvgl/lvgl/pull/4572)
- Update screen object opacity function documentation [`4505`](https://github.com/lvgl/lvgl/pull/4505)
- demo(sress): fix issues when the stress test is opened/clsoed multiple times [`1c5df6c`](https://github.com/lvgl/lvgl/commit/1c5df6c665b0d5f6f346d45b13109ff1f6ea78a6)
- chore: code formatting [`eb87767`](https://github.com/lvgl/lvgl/commit/eb87767cc65fec93f9cc4f87a1f8fb5b32f7e41d)
## [v8.3.9](https://github.com/lvgl/lvgl/compare/v8.3.9...v8.3.8) 6 August 2023
### Fixes
- fix(decoder): fix LV_IMG_CF_ALPHA_8BIT bin file decoder [`4406`](https://github.com/lvgl/lvgl/pull/4406)
- fix(config): fix typo in LV_USE_PERF_MONITOR and LV_USE_MEM_MONITOR [`4403`](https://github.com/lvgl/lvgl/pull/4403)
- fix(attr): refactor LV_ATTRIBUTE_* for function attributes [`4404`](https://github.com/lvgl/lvgl/pull/4404)
- fix(font): fix optimizer issue in lv_font_fmt_txt.c [`4385`](https://github.com/lvgl/lvgl/pull/4385)
- fix(btnmatrix): Hide button matrix when all buttons hidden [`65f1c93`](https://github.com/lvgl/lvgl/commit/65f1c9305e1b13356010524da4764fe20fe93030)
- fix(obj) prevent hidden objects keeping focus [`375b3b5`](https://github.com/lvgl/lvgl/commit/375b3b5d3ef2ea8c52f971a1bf20998be7940d5e)
- fix(btnmatrix): Fix typo in previous commit! [`29ed7c5`](https://github.com/lvgl/lvgl/commit/29ed7c5717f6cfbca5ce888bf4497221525aae85)
- fix(tabview): fix warning [`223dc1c`](https://github.com/lvgl/lvgl/commit/223dc1cf9d1cad0f40caf244eb435af0871f4153)
- fix(indev): fix warnings when loggin coordinates is enabled [`645006e`](https://github.com/lvgl/lvgl/commit/645006e35195cab3354f34a1a8cbc8c5ed0fdfad)
- fix: use const lv_img_dsc_t * dsc function parameter in lv_img_buf.h/ [`4f102d7`](https://github.com/lvgl/lvgl/commit/4f102d7b6b2e9f9fa68ab7b976d93762107549a4)
- fix(chart): fix lv_chart_get_point_pos_by_id [`f9ffcc9`](https://github.com/lvgl/lvgl/commit/f9ffcc9d8e11beb369dcbab0945ca85eab8f77b2)
- fix(imgbtn): support LV_OBJ_FLAG_CHECKABLE [`385d999`](https://github.com/lvgl/lvgl/commit/385d999a4a8164fcde6ae05f6a5daa5d5c209dd3)
### Docs
- docs(disp): metined that rotation rotates the touch coordinates too [`810852b`](https://github.com/lvgl/lvgl/commit/810852b41be5df66fd7b80f8af69f8b579d142ea)
### Others
- demos: add lv_demo_..._close() functions for each demo [`91038a9`](https://github.com/lvgl/lvgl/commit/91038a99e82a2522f693c7cdc77e9e7a672ee9ed)
## [v8.3.8](https://github.com/lvgl/lvgl/compare/v8.3.8...v8.3.7) 5 July 2023
### New Features
- feat(rt-thread): make the rt-thread env recursively glob the UI files [`8b83fe7`](https://github.com/lvgl/lvgl/commit/8b83fe7ea53a597cdbae8204d0aa9be8ad3d2b89)
### Performance
- perf(pxp, vglite): improve performance and add more features [`4222`](https://github.com/lvgl/lvgl/pull/4222)
### Fixes
- fix(stm32): static function prototypes moved from .h to .c [`4276`](https://github.com/lvgl/lvgl/pull/4276)
- fix(png): fix decode image size and some warnings [`4248`](https://github.com/lvgl/lvgl/pull/4248)
- fix(bidi): add more Hebrew checks to RTL characters set (#4171) [`4239`](https://github.com/lvgl/lvgl/pull/4239)
- fix(img): fix getting the image type on big endian systems [`4215`](https://github.com/lvgl/lvgl/pull/4215)
- fix(sdl): destroy texture after use if not stored in cache [`4173`](https://github.com/lvgl/lvgl/pull/4173)
- fix:(BtnMatrix) Backport https://github.com/lvgl/lvgl/pull/4185 [`cb602ea`](https://github.com/lvgl/lvgl/commit/cb602ea7785de21a187ef5ee5f7de4e3aa3f7e0e)
- fix(arduino): fix messed up variable types [`e3659c4`](https://github.com/lvgl/lvgl/commit/e3659c46b128b2b715b196c3ccfb94b3de4c89f8)
- fix:(BtnMatrix) Backport https://github.com/lvgl/lvgl/pull/4185 [`07bce74`](https://github.com/lvgl/lvgl/commit/07bce7466d471a15ba241a9db3239f7a116b0b46)
- fix(chart): fix division by zero if there are no ticks [`67b3011`](https://github.com/lvgl/lvgl/commit/67b3011f835b08c77ff60ae2d1e6592a710ca2b1)
- fix(msgbox): fix typo [`6a89bd2`](https://github.com/lvgl/lvgl/commit/6a89bd2d7409ac4d49ad32da73ba50a84f7c8990)
- fix(tabview): remove the animation if the tab is selected by clicking the button on the header [`3de61c7`](https://github.com/lvgl/lvgl/commit/3de61c76af0aed1665e9d61e47b4dd50b9e8bdf1)
- fix(btnmatrix): fix array out of bounds addressing with groups and no buttons [`edd5ad2`](https://github.com/lvgl/lvgl/commit/edd5ad28ad74d1025db0b442cfa390d8c01ae006)
- fix(btnmatrix): fix using &gt; 7 as button width [`75e6ef4`](https://github.com/lvgl/lvgl/commit/75e6ef4e1d66a85d68160b97ef931b0717e77212)
- fix(draw): typo with LV_COLOR_DEPTH 8 [`45b13c3`](https://github.com/lvgl/lvgl/commit/45b13c378f6fc1728ddf1547c25daa61d62c9f76)
- fix(disp): fix memory leak lv_scr_load_anim with auto_del and time=0 [`1caafc5`](https://github.com/lvgl/lvgl/commit/1caafc55dde46e1b7e3d17d8c5349fbf7cccba9f)
- fix(msgbox): add missing lv_obj_class_init_obj [`6843c19`](https://github.com/lvgl/lvgl/commit/6843c191b792f66829477827279adbbc763541c1)
- fix(flex): register LV_STYLE_FLEX_GROW [`5ba90a5`](https://github.com/lvgl/lvgl/commit/5ba90a5c41f584a8eb3a4fc8e2f466729652ddb3)
### Examples
- example(tabview): fix tabview disable scrollig example [`9491c3f`](https://github.com/lvgl/lvgl/commit/9491c3ff6d2f8e56b13d8fb493d4b3ee98ef1a4b)
### Docs
- docs: mention incompatibility between software rotation and `direct_mode` or `full_refresh` [`4308`](https://github.com/lvgl/lvgl/pull/4308)
- docs(faq): don't say 24 bit is support as LVGL can't render in RGB888 directly [`227ac02`](https://github.com/lvgl/lvgl/commit/227ac023419eeb253892b1c36113059f12b1f9f2)
### CI and tests
### Others
- chore(cmsis-pack): update cmsis-pack for v8.3.8 [`4340`](https://github.com/lvgl/lvgl/pull/4340)
- add(docs): add renesas-ra6m3 get-started document [`4278`](https://github.com/lvgl/lvgl/pull/4278)
- add(gpu): add renesas-ra6m3 gpu adaptation [`4270`](https://github.com/lvgl/lvgl/pull/4270)
- Revert "fix:(BtnMatrix) Backport https://github.com/lvgl/lvgl/pull/4185" [`1713cd3`](https://github.com/lvgl/lvgl/commit/1713cd3fd8f93aa575fbcf0e34b8626b6ee69ded)
## [v8.3.7](https://github.com/lvgl/lvgl/compare/v8.3.7...v8.3.6) 3 May 2023
### New Features
- feat(btnmatrix): review ctrl map and allow width values to be max 15 [`a150b15`](https://github.com/lvgl/lvgl/commit/a150b15e45a922eb5497fe5a31a480e1cd689246)
### Fixes
- fix (spinbox): doubling characters entered from the keyboard [`4190`](https://github.com/lvgl/lvgl/pull/4190)
- fix(arm-2d): fix transform-chrome-keying issue [`4178`](https://github.com/lvgl/lvgl/pull/4178)
- fix(menu): prevent setting the current page again [`4136`](https://github.com/lvgl/lvgl/pull/4136)
- fix(esp): fix ESP-IDF pedantic builds (backport v8.3) [`4135`](https://github.com/lvgl/lvgl/pull/4135)
- fix: color mixing with LV_COLOR_SWAP == 1 [`4101`](https://github.com/lvgl/lvgl/pull/4101)
- fix(indev): fix integer overflow in recursive zoom calculation [`a0795b4`](https://github.com/lvgl/lvgl/commit/a0795b49e82102ad68a27c86c36c37fffbe66d3c)
- fix(style): fix trasition on bg_grad color [`48d7878`](https://github.com/lvgl/lvgl/commit/48d7878bac3f607322957ed6f710d6615d5e72e0)
## [v8.3.6](https://github.com/lvgl/lvgl/compare/v8.3.6...v8.3.5) 3 April 2023
### New Features
- feat(msg): add lv_msg_unsubcribe_obj [`6af0179`](https://github.com/lvgl/lvgl/commit/6af01798d82f90f0c2ba6a9da39c4f10fb427df7)
### Performance
### Fixes
- fix(group): fix default_group becomes wild pointer when deleted [`4076`](https://github.com/lvgl/lvgl/pull/4076)
- fix(fs_posix): allow creating new file and set permission. [`3976`](https://github.com/lvgl/lvgl/pull/3976)
- fix(img): support negative angles [`3846`](https://github.com/lvgl/lvgl/pull/3846)
- fix(gif): synchronize with master [`4003`](https://github.com/lvgl/lvgl/pull/4003)
- fix(gpu): fix STM GPU drivers for some variants [`4004`](https://github.com/lvgl/lvgl/pull/4004)
- fix(img): possible divide by 0 exception (lvgl#3988) [`3990`](https://github.com/lvgl/lvgl/pull/3990)
- fix(arc): fix knob area invalidation [`d0e19eb`](https://github.com/lvgl/lvgl/commit/d0e19eb2d38ba8a500399b0496d7a8363be4003e)
- fix(slider): consider animations on pressing [`0b7777f`](https://github.com/lvgl/lvgl/commit/0b7777f27a7932efe3d594be426e1beb59d80ae3)
- fix(bar): delete running animations when a new value is set without animation [`aa31380`](https://github.com/lvgl/lvgl/commit/aa313806d0ebde475fc2bc360a15172cc1b658a7)
- docs: use a fixed commit of lv_web_emscripten [`501230e`](https://github.com/lvgl/lvgl/commit/501230e0fc95936199b3187d350873c3bb4a94e4)
### Examples
### Docs
- docs(arduino): add note to not use lv_examles library [`2f294aa`](https://github.com/lvgl/lvgl/commit/2f294aa76c8fece98a4fa72304bc6f267ed2a228)
- docs: use a fixed commit of lv_web_emscripten [`501230e`](https://github.com/lvgl/lvgl/commit/501230e0fc95936199b3187d350873c3bb4a94e4)
### CI and tests
### Others
- chore(cmsis-pack): update cmsis-pack for v8.3.6 [`4108`](https://github.com/lvgl/lvgl/pull/4108)
- chore: update the version numbers to v8.3.5-dev [`77670fb`](https://github.com/lvgl/lvgl/commit/77670fb1a55e0f2012ff7a057e535830e7253e22)
- Update build_html_examples.sh [`399069b`](https://github.com/lvgl/lvgl/commit/399069b4a2423c11823581668fe71ce9a7c88e7d)
## [v8.3.5](https://github.com/lvgl/lvgl/compare/v8.3.4...v8.3.5) 7 February 2023
### Performance
- perf(gpu): improve NXP's PXP and VGLite accelerators [`3952`](https://github.com/lvgl/lvgl/pull/3952)
- perf(dam2d): rework stm32 dma2d [`3904`](https://github.com/lvgl/lvgl/pull/3904)
### Fixes
- fix(monkey): remove executable permissions from source files [`3971`](https://github.com/lvgl/lvgl/pull/3971)
- fix(ci): set Ubuntu version for MicroPython test [`3865`](https://github.com/lvgl/lvgl/pull/3865)
- fix(Kconfig): fix wrong type of LV_FS_STDIO_CACHE_SIZE (v8.3) [`3906`](https://github.com/lvgl/lvgl/pull/3906)
- docs(indev): fix the name of long_press_repeat_time (was long_press_rep_time) [`34c545e`](https://github.com/lvgl/lvgl/commit/34c545ef19dc97c8952a412e533a4cd3924b9fbc)
- fix(roller): consider the recolor setting of the label [`39f4247`](https://github.com/lvgl/lvgl/commit/39f424767fa57376c4cb08cf22951fd56d854fd6)
### Examples
### Docs
- docs(indev): fix the name of long_press_repeat_time (was long_press_rep_time) [`34c545e`](https://github.com/lvgl/lvgl/commit/34c545ef19dc97c8952a412e533a4cd3924b9fbc)
### CI and tests
- ci(esp): fix push to the component registry on tag [`e529230`](https://github.com/lvgl/lvgl/commit/e529230f4bb97b4506c430aac96d5ddaef685dc4)
### Others
- chore(cmsis-pack): update cmsis-pack for v8.3.5 [`3972`](https://github.com/lvgl/lvgl/pull/3972)
- chore: add an option to "LV_TICK_CUSTOM" [`3879`](https://github.com/lvgl/lvgl/pull/3879)
- bump version numbers to v8.3.5-dev [`47c8f8f`](https://github.com/lvgl/lvgl/commit/47c8f8f9822f4c0c0ffbe2f12b380bddefcec475)
- Update layer.md [`9faca8a`](https://github.com/lvgl/lvgl/commit/9faca8a8d4125e21dedbf6e46aa1586a6b57e5b8)
## [v8.3.4](https://github.com/lvgl/lvgl/compare/v8.3.4...v8.3.3) 15 December 2022
### New Features
- feat(keyboard): ported arabic keyboard from release 7.10.0 [`3728`](https://github.com/lvgl/lvgl/pull/3728)
- feat(table): scroll to the selected cell with key navigation [`39d03a8`](https://github.com/lvgl/lvgl/commit/39d03a80f45847a1977cfe9cc6a509b1613d0aca)
### Fixes
- fix(rt-thread): sync rt-thread v5.0.0 rt_align [`3864`](https://github.com/lvgl/lvgl/pull/3864)
- fix(draw): SDL2 gradient support #3848 [`3856`](https://github.com/lvgl/lvgl/pull/3856)
- fix(esp.cmake): add demos and examples [`3784`](https://github.com/lvgl/lvgl/pull/3784)
- fix(indev): fix scrolling on transformed obejcts [`84cf05d`](https://github.com/lvgl/lvgl/commit/84cf05d8b23b31e000db757a278545e58fcbcbe8)
- fix(style): add the missing support for pct pivot in tranasform style properties [`c8e584f`](https://github.com/lvgl/lvgl/commit/c8e584f879a1e1427e7a8f5ff496af39f17df41d)
- fix(flex): be sure obj-&gt;w_layout and h_layout can't be set at the same time [`c4c4007`](https://github.com/lvgl/lvgl/commit/c4c400716e80a279e7b3d43b8992915fe94441eb)
- fix(chart): fix very dense bar charts [`bb2c2ac`](https://github.com/lvgl/lvgl/commit/bb2c2ac34ac943978513c7ed51885078979b1c10)
- fix(draw): handle LV_COLOR_DEPTH == 1 too in lv_draw_sw_transform [`bd11ad8`](https://github.com/lvgl/lvgl/commit/bd11ad8542eac9ff51420e5afb80f7e6fcf36a5c)
- fix(example): fix warnings [`1e3ca25`](https://github.com/lvgl/lvgl/commit/1e3ca25fed13bbf85c32a60d4b7041cf8bd525ab)
- fix(benchmark): fix warnings [`1ed026c`](https://github.com/lvgl/lvgl/commit/1ed026ca7307957568fe419f1ff39a15b2535b3e)
- fix(draw): fix text color with sub pixel rendering and BGR order [`e050f5c`](https://github.com/lvgl/lvgl/commit/e050f5ca156f79d752894f38f0a437c946205cb4)
- fix(meter): fix setting part_draw_dsc.id in needle img drawing [`716e5e2`](https://github.com/lvgl/lvgl/commit/716e5e2c8bd2a22e7d56e8d7ca33054a11a1f4ed)
- fix(gridnav): fix stucking in pressed state with encoder [`ad56dfa`](https://github.com/lvgl/lvgl/commit/ad56dfaf7046a9bb8c05e877a8c8852cd14a59af)
- fix(darw): add back the disappeared antialising=0 support [`2c17b28`](https://github.com/lvgl/lvgl/commit/2c17b28ac476c95a4153ab6cabb77b1c7208bb74)
- fix(msg): fix typos in API by adding wrappers [`41fa416`](https://github.com/lvgl/lvgl/commit/41fa41613455260ccdeb87ecb890ce026ff0a435)
- fix(draw): fix transformation accuracy [`e06f03d`](https://github.com/lvgl/lvgl/commit/e06f03db72f98439078118518158f52439dd7bf8)
- fix(style): remove the reduntant define of LV_GRADIENT_MAX_STOPS [`903e94b`](https://github.com/lvgl/lvgl/commit/903e94b716ca1b32cdb51de11df679953699e53b)
- demo(benchmark): fix lv_label_set_text_fmt format strings [`ae38258`](https://github.com/lvgl/lvgl/commit/ae3825871e31cd42cad2f310bdfc605150670511)
- demo(benchmark): fix warning [`1173dcb`](https://github.com/lvgl/lvgl/commit/1173dcba96621e20c9a7240c8572bd6573bce6a0)
## [v8.3.3](https://github.com/lvgl/lvgl/compare/v8.3.2...v8.3.3) 06 October 2022
v8.3.3 is the same as v8.3.2. It was released only because the version number was set incorrectly in lvgl.h.
## [v8.3.2](https://github.com/lvgl/lvgl/compare/v8.3.1...v8.3.2) 27 September 2022
### Fixes
- fix(fragment): fixed child fragment event dispatch [`3683`](https://github.com/lvgl/lvgl/pull/3683)
- fix(sdl): clear streaming/target texture with FillRect [`3682`](https://github.com/lvgl/lvgl/pull/3682)
- fix(sdl): transformation with alpha (#3576) [`3678`](https://github.com/lvgl/lvgl/pull/3678)
- fix(draw_sw): fix image cache to access the freed stack space [`3584`](https://github.com/lvgl/lvgl/pull/3584)
- fix(style): use compile time prop_cnt for const styles [`3609`](https://github.com/lvgl/lvgl/pull/3609)
- fix(demo): can not found lvgl.h file [`3477`](https://github.com/lvgl/lvgl/pull/3477)
- fix(ci) checkout lv_micropython release/v8 branch [`3524`](https://github.com/lvgl/lvgl/pull/3524)
- fix(canvas): fix clipéping on transformation [`b884aba`](https://github.com/lvgl/lvgl/commit/b884abae26f3824b27783a85d18ed51e550347c1)
- fix(draw): allow drawing outline with LV_DRAW_COMPLEX == 0 too [`ece3495`](https://github.com/lvgl/lvgl/commit/ece34950040e218fc73605a4e88f1060c2a274f8)
- fix(colorwheel): fix updating color when using lv_colorwheel_set_hsv [`d59bba1`](https://github.com/lvgl/lvgl/commit/d59bba12db115afb4b6aa53eed2625221dfff2fd)
- fix(slider): find the nearest value on click instead of floor [`dfd14fa`](https://github.com/lvgl/lvgl/commit/dfd14fa778aef25d0db61748a58aa9989ce5e2c8)
- fix(draw): fix border drawing with thick borders [`d5b2a9b`](https://github.com/lvgl/lvgl/commit/d5b2a9b2562cbfa327bf0ec03c11d28576037a14)
- fix(refr): fix true double double buffering logic with transparent screens [`8b605cc`](https://github.com/lvgl/lvgl/commit/8b605cc48224d0497cdd936fa77229e0c3d606d2)
- fix(group): be sure obj is removed from its current group in lv_group_add_obj [`5156ee0`](https://github.com/lvgl/lvgl/commit/5156ee058d5de674a00ffd84d15d460de7f0e53b)
- fix(style): add missing invalidation in lv_obj_remove_local_style_prop [`a0515ba`](https://github.com/lvgl/lvgl/commit/a0515ba30dd74b8b22a6709d334eb03782ee1a4d)
### Docs
- docs(draw) remove reference to old lv_fs_add_drv function [`3564`](https://github.com/lvgl/lvgl/pull/3564)
- docs(disp): LV_COLOR_SCREEN_TRANSP remove dependency on LV_COLOR_DEPTH_32 as transparency is supported across all color depths [`3556`](https://github.com/lvgl/lvgl/pull/3556)
### CI and tests
- ci: protect test.c with #if LV_BUILD_TEST [`be485d7`](https://github.com/lvgl/lvgl/commit/be485d7605136d2a5d6a633c7cb5b7c525cae7ee)
### Others
- chore(rt-thread) backport fixes from v9 [`3604`](https://github.com/lvgl/lvgl/pull/3604)
- chore: fix warnings [`7640950`](https://github.com/lvgl/lvgl/commit/76409502163ffe67cfbab9c7f24f2226cc8a5941)
- remove accidentally added code [`5022476`](https://github.com/lvgl/lvgl/commit/5022476edc8676f2a6ef7b919d3578159edeef7c)
## [v8.3.1](https://github.com/lvgl/lvgl/compare/v8.3.0...v8.3.1) 25 July 2022 ## [v8.3.1](https://github.com/lvgl/lvgl/compare/v8.3.0...v8.3.1) 25 July 2022
### Fixes ### Fixes

@ -52,9 +52,14 @@ In the INO file you can see how to register a display and a touchpad for LVGL an
Note that, there is no dedicated INO file for every example. Instead, you can load an example by calling an `lv_example_...` function. For example `lv_example_btn_1()`. Note that, there is no dedicated INO file for every example. Instead, you can load an example by calling an `lv_example_...` function. For example `lv_example_btn_1()`.
**IMPORTANT** **IMPORTANT NOTE 1**
Due to some the limitations of Arduino's build system you need to copy `lvgl/examples` to `lvgl/src/examples`. Similarly for the demos `lvgl/demos` to `lvgl/src/demos`. Due to some the limitations of Arduino's build system you need to copy `lvgl/examples` to `lvgl/src/examples`. Similarly for the demos `lvgl/demos` to `lvgl/src/demos`.
**IMPORTANT NOTE 2**
Note that the `lv_examples` library is for LVGL v7 and you shouldn't install it for this version (since LVGL v8)
as the examples and demos are now part of the main LVGL library.
## Debugging and logging ## Debugging and logging
LVGL can display debug information in case of trouble. LVGL can display debug information in case of trouble.

@ -9,6 +9,7 @@
nxp nxp
stm32 stm32
espressif espressif
renesas
arduino arduino
tasmota-berry tasmota-berry
cmake cmake

@ -1,6 +1,6 @@
# NXP # NXP
NXP has integrated LVGL into the MCUXpresso SDK packages for several of their general purpose and crossover NXP has integrated LVGL into the MCUXpresso SDK packages for general purpose and crossover microcontrollers, allowing
microcontrollers, allowing easy evaluation and migration into your product design. easy evaluation and migration into your product design.
[Download an SDK for a supported board](https://www.nxp.com/design/software/embedded-software/littlevgl-open-source-graphics-library:LITTLEVGL-OPEN-SOURCE-GRAPHICS-LIBRARY?&tid=vanLITTLEVGL-OPEN-SOURCE-GRAPHICS-LIBRARY) [Download an SDK for a supported board](https://www.nxp.com/design/software/embedded-software/littlevgl-open-source-graphics-library:LITTLEVGL-OPEN-SOURCE-GRAPHICS-LIBRARY?&tid=vanLITTLEVGL-OPEN-SOURCE-GRAPHICS-LIBRARY)
today and get started with your next GUI application. today and get started with your next GUI application.
@ -10,42 +10,40 @@ with PXP/VGLite support if the modules are present), no additional integration w
## HW acceleration for NXP iMX RT platforms ## HW acceleration for NXP iMX RT platforms
Depending on the RT platform used, the acceleration can be done by NXP PXP (PiXel Pipeline) and/or the Verisilicon GPU Depending on the RT platform used, the acceleration can be done by NXP PXP (PiXel Pipeline) and/or the Verisilicon GPU
through an API named VGLite. There is a single NXP draw context that covers both GPUs allowing to have enabled either through an API named VGLite. Each accelerator has its own context that allows them to be used individually as well
one or even both at the same time. While enableing both 2D accelerators, the VGLite can be used to accelerate widget simultaneously (in LVGL multithreading mode).
drawing while the PXP accelerated blit and fill operations.
Supported draw callbacks are available in "src/draw/nxp/lv_gpu_nxp.c": ### PXP accelerator
Several drawing features in LVGL can be offloaded to the PXP engine. The CPU is available for other operations while the
PXP is running. RTOS is required to block the LVGL drawing thread and switch to another task or suspend the CPU for
power savings.
Supported draw callbacks are available in "src/draw/nxp/pxp/lv_draw_pxp.c":
```c ```c
nxp_draw_ctx->base_draw.draw_arc = lv_draw_nxp_arc; pxp_draw_ctx->base_draw.draw_img_decoded = lv_draw_pxp_img_decoded;
nxp_draw_ctx->base_draw.draw_rect = lv_draw_nxp_rect; pxp_draw_ctx->blend = lv_draw_pxp_blend;
nxp_draw_ctx->base_draw.draw_img_decoded = lv_draw_nxp_img_decoded; pxp_draw_ctx->base_draw.wait_for_finish = lv_draw_pxp_wait_for_finish;
nxp_draw_ctx->blend = lv_draw_nxp_blend; pxp_draw_ctx->base_draw.buffer_copy = lv_draw_pxp_buffer_copy;
``` ```
If enabled both GPUs, the PXP is the preffered one to be used for drawing operation. A fallback mechanism is
implemented so that if the feature is not supported by PXP (or if PXP fails), the VGLite will take over to handle the
task. At the end, the CPU will assure that every widget drawing is fully covered (if not already done by GPU).
### PXP accelerator
Several drawing features in LVGL can be offloaded to the PXP engine. The VGLite (if supported) and CPU are available for
other operations while the PXP is running. An RTOS is required to block the LVGL drawing thread and switch to another
task or suspend the CPU for power savings.
#### Features supported: #### Features supported:
All operations can be used in conjunction with optional transparency.
- RGB565 and ARGB8888 color formats - RGB565 and ARGB8888 color formats
- Area fill + optional transparency - Area fill with color
- BLIT (BLock Image Transfer) + optional transparency - BLIT (BLock Image Transfer)
- Color keying + optional transparency
- Recoloring (color tint) + optional transparency
- Image Rotation (90, 180, 270 degree) + optional transparency
- Recoloring (color tint) + Image Rotation (90, 180, 270 degree) + optional transparency
- Screen Rotation (90, 180, 270 degree) - Screen Rotation (90, 180, 270 degree)
- Color keying
- Recoloring (color tint)
- Image Rotation (90, 180, 270 degree)
- Buffer copy
- RTOS integration layer - RTOS integration layer
- Default FreeRTOS and bare metal code provided - Default FreeRTOS and bare metal code provided
- Combination of recolor and/or rotation + color key/alpha blend/transparency is supported but PXP needs two steps. - Combination of recolor and/or rotation + color key/alpha blend/transparency is supported.
First step is to recolor/rotate the image to a temporarly buffer (please check LV_MEM_SIZE value for allocation limit) That is achieved by PXP in two steps:
and another step is required to handle color keying, alpha chanel or to apply transparency. - First step is to recolor/rotate the image to a temporary buffer (statically allocated)
- Second step is required to handle color keying, alpha channel or to apply transparency
#### Known limitations: #### Known limitations:
- Rotation is not supported for images unaligned to blocks of 16x16 pixels. - Rotation is not supported for images unaligned to blocks of 16x16 pixels.
@ -78,51 +76,71 @@ and the final output image can look shifted.
#### Project setup: #### Project setup:
- Add PXP related files to project: - Add PXP related files to project:
- src/draw/nxp/pxp/lv_gpu_nxp_pxp.c, src/draw/nxp/pxp/lv_gpu_nxp_pxp.h: init, uninit, run/wait PXP device, log/trace - src/draw/nxp/pxp/lv_draw_pxp.c[.h]: draw context callbacks
- src/draw/nxp/pxp/lv_draw_pxp_blend.c, src/draw/nxp/pxp/lv_draw_pxp_blend.h: fill and blit (w/o transformation) - src/draw/nxp/pxp/lv_draw_pxp_blend.c[.h]: fill and blit (with optional transformation)
- src/draw/nxp/pxp/lv_gpu_nxp_osa.c, src/draw/nxp/pxp/lv_gpu_osa.h: default implementation of OS-specific functions - src/draw/nxp/pxp/lv_gpu_nxp_pxp.c[.h]: init, uninit, run/wait PXP device
(bare metal and FreeRTOS only) - src/draw/nxp/pxp/lv_gpu_nxp_pxp_osa.c[.h]: OS abstraction (FreeRTOS or bare metal)
- optional, required only if `LV_USE_GPU_NXP_PXP_AUTO_INIT` is set to 1 - optional, required only if `LV_USE_GPU_NXP_PXP_AUTO_INIT` is set to 1
- PXP related code depends on two drivers provided by MCU SDK. These drivers need to be added to project: - PXP related code depends on two drivers provided by MCU SDK. These drivers need to be added to project:
- fsl_pxp.c, fsl_pxp.h: PXP driver - fsl_pxp.c[.h]: PXP driver
- fsl_cache.c, fsl_cache.h: CPU cache handling functions - fsl_cache.c[.h]: CPU cache handling functions
#### Logging: #### Logging:
- By default, LV_GPU_NXP_PXP_LOG_ERRORS is enabled so that any PXP error will be seen on LVGL output - By default, `LV_GPU_NXP_PXP_LOG_ERRORS` is enabled so that any PXP error will be seen on SDK debug console
- For tracing logs about the PXP limitations or size thresholds, the user can enable LV_GPU_NXP_PXP_LOG_TRACES - By default, `LV_GPU_NXP_PXP_LOG_TRACES` is disabled. Enable it for tracing logs (like PXP limitations)
#### Advanced configuration: #### Advanced configuration:
- Implementation depends on multiple OS-specific functions. The struct `lv_nxp_pxp_cfg_t` with callback pointers is - Implementation depends on multiple OS-specific functions. The struct `lv_nxp_pxp_cfg_t` with callback pointers is
used as a parameter for the `lv_gpu_nxp_pxp_init()` function. Default implementation for FreeRTOS and baremetal is used as a parameter for the `lv_gpu_nxp_pxp_init()` function. Default implementation for FreeRTOS and bare metal is
provided in lv_gpu_nxp_osa.c provided in lv_gpu_nxp_pxp_osa.c
- `pxp_interrupt_init()`: Initialize PXP interrupt (HW setup, OS setup) - `pxp_interrupt_init()`: Initialize PXP interrupt (HW setup, OS setup)
- `pxp_interrupt_deinit()`: Deinitialize PXP interrupt (HW setup, OS setup) - `pxp_interrupt_deinit()`: Deinitialize PXP interrupt (HW setup, OS setup)
- `pxp_run()`: Start PXP job. Use OS-specific mechanism to block drawing thread. PXP must finish drawing before - `pxp_run()`: Start PXP job. Use OS-specific mechanism to block drawing thread. PXP must finish drawing before
leaving this function. leaving this function.
- There are configurable area thresholds which are used to decide whether the area will be processed by CPU or by PXP. - Area threshold (size limit) is configurable and used to decide whether the area will be processed by PXP or not.
Areas smaller than a defined value will be processed by CPU and those bigger than the threshold will be processed by Areas smaller than the defined value will be processed by CPU and those bigger than the threshold will be processed by
PXP. These thresholds may be defined as preprocessor variables. Default values are defined in lv_draw_pxp_blend.h PXP. The threshold is defined as a macro in lv_draw_pxp.c
- `LV_GPU_NXP_PXP_BLIT_SIZE_LIMIT`: size threshold for image BLIT, BLIT with color keying, BLIT with recolor and - `LV_GPU_NXP_PXP_SIZE_LIMIT`: size threshold for fill/blit (with optional transformation)
BLIT with rotation (OPA >= LV_OPA_MAX)
- `LV_GPU_NXP_PXP_BLIT_OPA_SIZE_LIMIT`: size threshold for image BLIT, BLIT with color keying, BLIT with recolor
and BLIT with rotation and transparency (OPA < LV_OPA_MAX)
- `LV_GPU_NXP_PXP_FILL_SIZE_LIMIT`: size threshold for fill operation (OPA >= LV_OPA_MAX)
- `LV_GPU_NXP_PXP_FILL_OPA_SIZE_LIMIT`: size threshold for fill operation with transparency (OPA < LV_OPA_MAX)
### VGLite accelerator ### VGLite accelerator
Extra drawing features in LVGL can be handled by the VGLite engine. The PXP (if supported) and CPU are available for Extra drawing features in LVGL can be handled by the VGLite engine. The CPU is available for other operations while the
other operations while the VGLite is running. An RTOS is required to block the LVGL drawing thread and switch to another VGLite is running. An RTOS is required to block the LVGL drawing thread and switch to another task or suspend the CPU
task or suspend the CPU for power savings. for power savings.
Supported draw callbacks are available in "src/draw/nxp/vglite/lv_draw_vglite.c":
```c
vglite_draw_ctx->base_draw.init_buf = lv_draw_vglite_init_buf;
vglite_draw_ctx->base_draw.draw_line = lv_draw_vglite_line;
vglite_draw_ctx->base_draw.draw_arc = lv_draw_vglite_arc;
vglite_draw_ctx->base_draw.draw_rect = lv_draw_vglite_rect;
vglite_draw_ctx->base_draw.draw_img_decoded = lv_draw_vglite_img_decoded;
vglite_draw_ctx->blend = lv_draw_vglite_blend;
vglite_draw_ctx->base_draw.wait_for_finish = lv_draw_vglite_wait_for_finish;
vglite_draw_ctx->base_draw.buffer_copy = lv_draw_vglite_buffer_copy;
```
#### Features supported: #### Features supported:
All operations can be used in conjunction with optional transparency.
- RGB565 and ARGB8888 color formats - RGB565 and ARGB8888 color formats
- Area fill + optional transparency - Area fill with color
- BLIT (BLock Image Transfer) + optional transparency - BLIT (BLock Image Transfer)
- Image Rotation (any degree with decimal) + optional transparency - Image Rotation (any degree with decimal)
- Image Scale + optional transparency - Image Scale
- Draw background rectangle with radius or gradient - Draw rectangle background with optional radius or gradient
- Draw arc - Blit rectangle background image
- RTOS integration layer - Draw rectangle border/outline with optional rounded corners
- Draw arc with optional rounded ending
- Draw line or dashed line with optional rounded ending
- Buffer copy
#### Known limitations:
- Source image alignment:
The byte alignment requirement for a pixel depends on the specific pixel format. Both buffer address and buffer stride
must be aligned. As general rule, the alignment is set to 16 pixels. This makes the buffer address alignment to be
32 bytes for RGB565 and 64 bytes for ARGB8888.
- For pixel engine (PE) destination, the alignment should be 64 bytes for all tiled (4x4) buffer layouts.
The pixel engine has no additional alignment requirement for linear buffer layouts (`VG_LITE_LINEAR`).
#### Basic configuration: #### Basic configuration:
- Select NXP VGLite engine in lv_conf.h: Set `LV_USE_GPU_NXP_VG_LITE` to 1 - Select NXP VGLite engine in lv_conf.h: Set `LV_USE_GPU_NXP_VG_LITE` to 1
@ -130,8 +148,8 @@ task or suspend the CPU for power savings.
#### Basic initialization: #### Basic initialization:
- Initialize VGLite before calling `lv_init()` by specifying the width/height of tessellation window. Value should be - Initialize VGLite before calling `lv_init()` by specifying the width/height of tessellation window. Value should be
a multiple of 16; minimum value is 16 pixels, maximum cannot be greater than frame width. If less than or equal to 0, a multiple of 16; minimum value is 16 pixels, maximum cannot be greater than the frame width. If less than or equal
then no tessellation buffer is created, in which case the function is used for a blit init. to 0, then no tessellation buffer is created, in which case VGLite is initialized only for blitting.
```c ```c
#if LV_USE_GPU_NXP_VG_LITE #if LV_USE_GPU_NXP_VG_LITE
#include "vg_lite.h" #include "vg_lite.h"
@ -144,25 +162,21 @@ task or suspend the CPU for power savings.
#### Project setup: #### Project setup:
- Add VGLite related files to project: - Add VGLite related files to project:
- src/draw/nxp/vglite/lv_gpu_nxp_vglite.c, src/draw/nxp/vglite/lv_gpu_nxp_vglite.h: buffer init, log/trace - src/draw/nxp/vglite/lv_draw_vglite.c[.h]: draw context callbacks
- src/draw/nxp/vglite/lv_draw_vglite_blend.c, src/draw/nxp/vglite/lv_draw_vglite_blend.h: fill and blit - src/draw/nxp/vglite/lv_draw_vglite_blend.c[.h]: fill and blit (with optional transformation)
(w/o transformation) - src/draw/nxp/vglite/lv_draw_vglite_rect.c[.h]: draw rectangle
- src/draw/nxp/vglite/lv_draw_vglite_rect.c, src/draw/nxp/vglite/lv_draw_vglite_rect.h: rectangle draw - src/draw/nxp/vglite/lv_draw_vglite_arc.c[.h]: draw arc
- src/draw/nxp/vglite/lv_draw_vglite_arc.c, src/draw/nxp/vglite/lv_draw_vglite_arc.h: arc draw - src/draw/nxp/vglite/lv_draw_vglite_line.c[.h]: draw line
- src/draw/nxp/vglite/lv_vglite_buf.c[.h]: init/get vglite buffer
- src/draw/nxp/vglite/lv_vglite_utils.c[.h]: function helpers
#### Logging: #### Logging:
- By default, LV_GPU_NXP_VG_LITE_LOG_ERRORS is enabled so that any VGLite error will be seen on LVGL output - By default, `LV_GPU_NXP_VG_LITE_LOG_ERRORS` is enabled so that any VGLite error will be seen on SDK debug console
- For tracing logs about the VGLite limitations, size thresholds or stride alignment, the user can enable - By default, `LV_GPU_NXP_VG_LITE_LOG_TRACES` is disabled. Enable it for tracing logs (like blit split workaround or
LV_GPU_NXP_VG_LITE_LOG_TRACES VGLite fallback to CPU due to any error on the driver)
#### Advanced configuration: #### Advanced configuration:
- There are configurable area thresholds which are used to decide whether the area will be processed by CPU or by - Area threshold (size limit) is configurable and used to decide whether the area will be processed by VGLite or not.
VGLite. Areas smaller than a defined value will be processed by CPU and those bigger than the threshold will be Areas smaller than the defined value will be processed by CPU and those bigger than the threshold will be processed by
processed by VGLite. These thresholds may be defined as preprocessor variables. Default values are defined in VGLite. The threshold is defined as a macro in lv_draw_vglite.c
lv_draw_vglite_blend.h - `LV_GPU_NXP_VG_LITE_SIZE_LIMIT`: size threshold for fill/blit (with optional transformation)
- `LV_GPU_NXP_VG_LITE_BLIT_SIZE_LIMIT`: size threshold for image BLIT, BLIT with scale and BLIT with rotation
(OPA >= LV_OPA_MAX)
- `LV_GPU_NXP_VG_LITE_BLIT_OPA_SIZE_LIMIT`: size threshold for image BLIT, BLIT with scale and BLIT with rotation
and transparency (OPA < LV_OPA_MAX)
- `LV_GPU_NXP_VG_LITE_FILL_SIZE_LIMIT`: size threshold for fill operation (OPA >= LV_OPA_MAX)
- `LV_GPU_NXP_VG_LITE_FILL_OPA_SIZE_LIMIT`: size threshold for fill operation with transparency (OPA < LV_OPA_MAX)

@ -15,7 +15,7 @@ The simulator is ported to various IDEs (Integrated Development Environments). C
- [Eclipse with SDL driver](https://github.com/lvgl/lv_sim_eclipse_sdl): Recommended on Linux and Mac - [Eclipse with SDL driver](https://github.com/lvgl/lv_sim_eclipse_sdl): Recommended on Linux and Mac
- [CodeBlocks](https://github.com/lvgl/lv_sim_codeblocks_win): Recommended on Windows - [CodeBlocks](https://github.com/lvgl/lv_sim_codeblocks_win): Recommended on Windows
- [VisualStudio with SDL driver](https://github.com/lvgl/lv_sim_visual_studio_sdl): For Windows - [VisualStudio](https://github.com/lvgl/lv_sim_visual_studio_sdl): For Windows
- [VSCode with SDL driver](https://github.com/lvgl/lv_sim_vscode_sdl): Recommended on Linux and Mac - [VSCode with SDL driver](https://github.com/lvgl/lv_sim_vscode_sdl): Recommended on Linux and Mac
- [PlatformIO with SDL driver](https://github.com/lvgl/lv_platformio): Recommended on Linux and Mac - [PlatformIO with SDL driver](https://github.com/lvgl/lv_platformio): Recommended on Linux and Mac
- [MDK with FastModel](https://github.com/lvgl/lv_port_an547_cm55_sim): For Windows - [MDK with FastModel](https://github.com/lvgl/lv_port_an547_cm55_sim): For Windows

@ -0,0 +1,129 @@
# Renesas
The [HMI-Board](https://bit.ly/3I9nfUo) development board SDK now comes with LVGL integration for quick evaluation. Simply download the [SDK](https://github.com/RT-Thread-Studio/sdk-bsp-ra6m3-hmi-board/tree/main/projects/hmi-board-lvgl) for the supported motherboard and youll be on your way to creating your next GUI application in no time. For more information, check out the [Software design description](https://github.com/RT-Thread-Studio/sdk-bsp-ra6m3-hmi-board/blob/main/projects/hmi-board-lvgl/README.md).
## Creating new project with LVGL
It is recommended to start your project by downloading the HMI-Board SDK example project. It comes fully equipped with LVGL and dave-2d support (if the modules are present), so you wont need to do any additional integration work.
## HW acceleration for Renesas RA6M3 platforms
For RA6M3 platforms, hardware acceleration can be achieved using the dave-2d GPU, depending on the platform used. Each accelerator has its own context, allowing them to be used individually or simultaneously in LVGLs multithreading mode.
### Dave-2d accelerator
LVGL can offload several drawing features to the dave-2d engine, freeing up the CPU for other operations while dave-2d runs. An RTOS is required to block the LVGL drawing thread and switch to another task or suspend the CPU for power savings. Supported draw callbacks can be found in “src/draw/renesas/lv_gpu_d2_ra6m3.c”.
LVGL can offload several drawing features to the dave-2d engine, freeing up the CPU for other operations while dave-2d runs. An RTOS is required to block the LVGL drawing thread and switch to another task or suspend the CPU for power savings. Supported draw callbacks can be found in “src/draw/renesas/lv_gpu_d2_ra6m3.c”.
```c
ra_2d_draw_ctx->blend = lv_draw_ra6m3_2d_blend;
ra_2d_draw_ctx->base_draw.draw_img_decoded = lv_port_gpu_img_decoded;
ra_2d_draw_ctx->base_draw.wait_for_finish = lv_port_gpu_wait;
ra_2d_draw_ctx->base_draw.draw_letter = lv_draw_gpu_letter;
```
### Features supported:
All operations can be used in conjunction with optional transparency.
- RGB565 and ARGB8888 color formats
- Area fill with color
- BLIT (BLock Image Transfer)
- Color conversion
- Rotate and scale
- Alpha blending
- Bilinear filtering
- RTOS integration layer
- Default RT-Thread code provided
- Subpixel exact placement
### Basic configuration:
- Select Renesas dave-2d engine in lv_conf.h: Set `LV_USE_GPU_RA6M3_G2D` to 1
- Set referenced header file in lv_conf.h: `#define LV_GPU_RA6M3_G2D_INCLUDE "hal_data.h"`
### RT-Thread Example:
```c
#define COLOR_BUFFER (LV_HOR_RES_MAX * LV_VER_RES_MAX)
static lv_disp_drv_t disp_drv;
/*A static or global variable to store the buffers*/
static lv_color_t buf_1[COLOR_BUFFER];
```
- After initializing your peripherals (such as SPI, GPIOs, and LCD) in the `lv_port_disp_init()` function, you can initialize LVGL using [`lv_init()`.](https://docs.lvgl.io/master/API/core/lv_obj.html#_CPPv47lv_initv) Next, register the frame buffers using `lv_disp_draw_buf_init()` and create a new display driver using `lv_disp_drv_init()`.
```c
/*Initialize `disp_buf` with the buffer(s). With only one buffer use NULL instead buf_2 */
lv_disp_draw_buf_init(&disp_buf, buf_1, RT_NULL, COLOR_BUFFER);
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
/*Set the resolution of the display*/
disp_drv.hor_res = LV_HOR_RES_MAX;
disp_drv.ver_res = LV_VER_RES_MAX;
/*Set a display buffer*/
disp_drv.draw_buf = &disp_buf;
/*Used to copy the buffer's content to the display*/
disp_drv.flush_cb = disp_flush;
/* Initialize GPU module */
lv_port_gpu_hw_init();
/*Finally register the driver*/
lv_disp_drv_register(&disp_drv);
```
* To run LVGL, youll need to create a thread. You can find examples of how to do this using RT-Thread in the `env_support/rt-thread/lv_rt_thread_port.c` file.
```c
static void lvgl_thread_entry(void *parameter)
{
#if LV_USE_LOG
lv_log_register_print_cb(lv_rt_log);
#endif /* LV_USE_LOG */
lv_init();
lv_port_disp_init();
lv_port_indev_init();
lv_user_gui_init();
/* handle the tasks of LVGL */
while(1)
{
lv_task_handler();
rt_thread_mdelay(LV_DISP_DEF_REFR_PERIOD);
}
}
static int lvgl_thread_init(void)
{
rt_err_t err;
/* create lvgl thread */
err = rt_thread_init(&lvgl_thread, "LVGL", lvgl_thread_entry, RT_NULL,
&lvgl_thread_stack[0], sizeof(lvgl_thread_stack), PKG_LVGL_THREAD_PRIO, 10);
if(err != RT_EOK)
{
LOG_E("Failed to create LVGL thread");
return -1;
}
rt_thread_startup(&lvgl_thread);
return 0;
}
INIT_ENV_EXPORT(lvgl_thread_init);
```
- The last step is to create a function to output the frame buffer to your LCD. The specifics of this function will depend on the features of your MCU. Heres an example for a typical MCU interface: `my_flush_cb`.
```c
static void my_flush_cb(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p)
{
#ifdef PKG_USING_ILI9341
lcd_fill_array_spi(area->x1, area->y1, area->x2, area->y2, color_p);
#elif LV_USE_GPU_RA6M3_G2D
lv_port_gpu_blit(area->x1, area->y1, color_p, area);
#else
......
#endif
lv_disp_flush_ready(disp_drv);
}
```

@ -132,7 +132,7 @@ LVGL needs just one simple driver function to copy an array of pixels into a giv
If you can do this with your display then you can use it with LVGL. If you can do this with your display then you can use it with LVGL.
Some examples of the supported display types: Some examples of the supported display types:
- TFTs with 16 or 24 bit color depth - TFTs with 16 or 32 bit color depth
- Monitors with an HDMI port - Monitors with an HDMI port
- Small monochrome displays - Small monochrome displays
- Gray-scale displays - Gray-scale displays

@ -2,14 +2,38 @@
# File System Interfaces # File System Interfaces
LVGL has a [File system](https://docs.lvgl.io/master/overview/file-system.html) module to provide an abstraction layer for various file system drivers. LVGL has a [File system](https://docs.lvgl.io/master/overview/file-system.html) module to provide an abstraction layer for various file system drivers.
You still need to provide the drivers and libraries, this extension provides only the bridge between FATFS, LittleFS, STDIO, POSIX, WIN32 and LVGL.
LVG has built in support for: ## Built in wrappers
- [FATFS](http://elm-chan.org/fsw/ff/00index_e.html)
- STDIO (Linux and Windows using C standard function .e.g fopen, fread)
- POSIX (Linux and Windows using POSIX function .e.g open, read)
- WIN32 (Windows using Win32 API function .e.g CreateFileA, ReadFile)
You still need to provide the drivers and libraries, this extension provides only the bridge between FATFS, STDIO, POSIX, WIN32 and LVGL. ### FATFS
Bridge for [FatFS](http://elm-chan.org/fsw/ff/00index_e.html). FatFS itself is not part of LVGL, but can be added and initialized externally.
### LittleFS
Though `lv_fs_littlefs` uses [LittleFS]((https://github.com/littlefs-project/littlefs)) API, the LittleFS library needs other external libraries that handle the mounting of partitions and low-level accesses, according to the given architecture. The functions for the latter are given to the lfs_t structure as pointers by an external low-level library.
There's a convenience function called `lv_fs_littlefs_set_driver(LV_FS_LITTLEFS_LETTER, my_lfs)`, specific to `lv_fs_littlefs`, to attach a `lfs_t` object's pointer to a registered driver-letter. See its comments for more info.
[esp_littlefs](https://components.espressif.com/components/joltwallet/littlefs) is a wrapper for LittleFS to be used in Espressif ESP-devices. It handles the mounting and has the low-level `littlefs_api` functions to read/write/erase blocks that LittleFS library needs. On mounting by `esp_littlefs` the `lfs_t` structures are created. You need to get a handle to these to use ESP with `lv_fs_littlefs`, as all functions use that `lfs_t` in LittleFS to identify the mounted partition.
In case you don't find a special function in the `lv_fs_littlefs` wrapper, you can look for it in the `esp_littlefs` API and use it directly, as `lv_fs_littlefs` and the `esp_littlefs` APIs can be used side-by-side.
### STDIO
Bride to C standard functions on Linux and Windows. For example `fopen`, `fread`, etc.
### POSIX
Bride to POSIX functions on Linux and Windows. For example `open`, `read`, etc.
### WIN32
Bride to Win32 API function. For example `CreateFileA`, `ReadFile`, etc.
## Usage ## Usage

@ -12,6 +12,7 @@
png png
gif gif
freetype freetype
tiny_ttf
qrcode qrcode
rlottie rlottie
ffmpeg ffmpeg

@ -0,0 +1,35 @@
# Tiny TTF font engine
## Usage
Use https://github.com/nothings/stb to render TrueType fonts in LVGL.
When enabled in `lv_conf.h` with `LV_USE_TINY_TTF`
`lv_tiny_ttf_create_data(data, data_size, font_size)` can be used to
create a TTF font instance at the specified font size. You can then
use that font anywhere `lv_font_t` is accepted.
By default, the TTF or OTF file must be embedded as an array, either in
a header, or loaded into RAM in order to function.
However, if `LV_TINY_TTF_FILE_SUPPORT` is enabled,
`lv_tiny_ttf_create_file(path, font_size)` will also be available,
allowing tiny_ttf to stream from a file. The file must remain open the
entire time the font is being used, and streaming on demand may be
considerably slower.
After a font is created, you can change the font size in pixels by using
`lv_tiny_ttf_set_size(font, font_size)`.
By default, a font will use up to 4KB of cache to speed up rendering
glyphs. This maximum can be changed by using
`lv_tiny_ttf_create_data_ex(data, data_size, font_size, cache_size)`
or `lv_tiny_ttf_create_file_ex(path, font_size, cache_size)` (when
available). The cache size is indicated in bytes.
## API
```eval_rst
.. doxygenfile:: lv_tiny_ttf.h
:project: lvgl
```

@ -63,12 +63,11 @@ See the [Display background](#display-background) section for more details. If t
This configuration (transparent screen and display) could be used to create for example OSD menus where a video is played on a lower layer, and a menu is overlayed on an upper layer. This configuration (transparent screen and display) could be used to create for example OSD menus where a video is played on a lower layer, and a menu is overlayed on an upper layer.
To handle transparent displays, special (slower) color mixing algorithms need to be used by LVGL so this feature needs to enabled with `LV_COLOR_SCREEN_TRANSP` in `lv_conf.h`. To handle transparent displays, special (slower) color mixing algorithms need to be used by LVGL so this feature needs to enabled with `LV_COLOR_SCREEN_TRANSP` in `lv_conf.h`.
As this mode operates on the Alpha channel of the pixels `LV_COLOR_DEPTH = 32` is also required. The Alpha channel of 32-bit colors will be 0 where there are no objects and 255 where there are solid objects. The Alpha channel of 32-bit colors will be 0 where there are no objects and 255 where there are solid objects.
In summary, to enable transparent screens and displays for OSD menu-like UIs: In summary, to enable transparent screens and displays for OSD menu-like UIs:
- Enable `LV_COLOR_SCREEN_TRANSP` in `lv_conf.h` - Enable `LV_COLOR_SCREEN_TRANSP` in `lv_conf.h`
- Be sure to use `LV_COLOR_DEPTH 32` - Set the screen's opacity to `LV_OPA_TRANSP` e.g. with `lv_obj_set_style_bg_opa(lv_scr_act(), LV_OPA_TRANSP, LV_PART_MAIN)`
- Set the screen's opacity to `LV_OPA_TRANSP` e.g. with `lv_obj_set_style_local_bg_opa(lv_scr_act(), LV_OBJMASK_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP)`
- Set the display opacity to `LV_OPA_TRANSP` with `lv_disp_set_bg_opa(NULL, LV_OPA_TRANSP);` - Set the display opacity to `LV_OPA_TRANSP` with `lv_disp_set_bg_opa(NULL, LV_OPA_TRANSP);`
## Features of displays ## Features of displays

@ -34,11 +34,11 @@ lv_label_set_text(label2, "Button 2"); /*Set the text of the label*/
lv_obj_del(label2); lv_obj_del(label2);
``` ```
## Bring to the foreground ## Change order
There are four explicit ways to bring an object to the foreground: There are four explicit ways to bring an object to the foreground:
- Use `lv_obj_move_foreground(obj)` to bring an object to the foreground. Similarly, use `lv_obj_move_background(obj)` to move it to the background. - Use `lv_obj_move_foreground(obj)` to bring an object to the foreground. Similarly, use `lv_obj_move_background(obj)` to move it to the background.
- Use `lv_obj_move_up(obj)` to move an object one position up in the hierarchy, Similarly, use `lv_obj_move_down(obj)` to move an object one position down in the hierarchy. - Use `lv_obj_move_to_index(obj, idx)` to move an object to a given index in the order of children. (0: backgroud, child_num - 1: foreground, <0: count from the top, to move forward (up): `lv_obj_move_to_index(obj, lv_obj_get_index(obj) - 1)`)
- Use `lv_obj_swap(obj1, obj2)` to swap the relative layer position of two objects. - Use `lv_obj_swap(obj1, obj2)` to swap the relative layer position of two objects.
- When `lv_obj_set_parent(obj, new_parent)` is used, `obj` will be on the foreground of the `new_parent`. - When `lv_obj_set_parent(obj, new_parent)` is used, `obj` will be on the foreground of the `new_parent`.

@ -173,7 +173,7 @@ All inputs are disabled during the screen animation.
Screens are created on the currently selected *default display*. Screens are created on the currently selected *default display*.
The *default display* is the last registered display with `lv_disp_drv_register`. You can also explicitly select a new default display using `lv_disp_set_default(disp)`. The *default display* is the last registered display with `lv_disp_drv_register`. You can also explicitly select a new default display using `lv_disp_set_default(disp)`.
`lv_scr_act()`, `lv_scr_load()` and `lv_scr_load_anim()` operate on the default screen. `lv_scr_act()`, `lv_scr_load()` and `lv_scr_load_anim()` operate on the default display.
Visit [Multi-display support](/overview/display) to learn more. Visit [Multi-display support](/overview/display) to learn more.

@ -1,4 +1,32 @@
# ARM-2D GPU # Arm-2D GPU
TODO Arm-2D is not a GPU but **an abstraction layer for 2D GPUs dedicated to Microcontrollers**. It supports all Cortex-M processors ranging from Cortex-M0 to the latest Cortex-M85.
Arm-2D is an open-source project on Github. For more, please refer to: https://github.com/ARM-software/Arm-2D.
## How to Use
In general, you can set the macro `LV_USE_GPU_ARM2D` to `1`in `lv_conf.h` to enable Arm-2D acceleration for LVGL.
If you are using **[CMSIS-Pack](https://github.com/lvgl/lvgl/tree/master/env_support/cmsis-pack)** to deploy the LVGL. You don't have to define the macro `LV_USE_GPU_ARM2D` manually, instead, please select the component `GPU Arm-2D` in the **RTE** dialog. This step will define the macro for us.
## Design Considerations
As mentioned before, Arm-2D is an abstraction layer for 2D GPU; hence if there is no accelerator or dedicated instruction set (such as Helium or ACI) available for Arm-2D, it provides negligible performance boost for LVGL (sometimes worse) for regular Cortex-M processors.
**We highly recommend you enable Arm-2D acceleration for LVGL** when:
- The target processors are **Cortex-M55** and/or **Cortex-M85**
- The target processors support **[Helium](https://developer.arm.com/documentation/102102/0103/?lang=en)**.
- The device vendor provides an arm-2d compliant driver for their propriotory 2D accelerators and/or customized instruction set.
- The target device contains [DMA-350](https://community.arm.com/arm-community-blogs/b/internet-of-things-blog/posts/arm-corelink-dma-350-next-generation-direct-memory-access-for-endpoint-ai)
## Examples
- [A Cortex-M55 (supports Helium) based MDK Project, PC emulation is available.](https://github.com/lvgl/lv_port_an547_cm55_sim)

@ -355,7 +355,7 @@ Set the opacity of the border. Value 0, `LV_OPA_0` or `LV_OPA_TRANSP` means full
</ul> </ul>
### border_width ### border_width
Set hte width of the border. Only pixel values can be used. Set the width of the border. Only pixel values can be used.
<ul> <ul>
<li style='display:inline; margin-right: 20px; margin-left: 0px'><strong>Default</strong> 0</li> <li style='display:inline; margin-right: 20px; margin-left: 0px'><strong>Default</strong> 0</li>
<li style='display:inline; margin-right: 20px; margin-left: 0px'><strong>Inherited</strong> No</li> <li style='display:inline; margin-right: 20px; margin-left: 0px'><strong>Inherited</strong> No</li>
@ -708,6 +708,15 @@ Scale down all opacity values of the object by this factor. Value 0, `LV_OPA_0`
<li style='display:inline; margin-right: 20px; margin-left: 0px'><strong>Ext. draw</strong> No</li> <li style='display:inline; margin-right: 20px; margin-left: 0px'><strong>Ext. draw</strong> No</li>
</ul> </ul>
### opa_layered
First draw the object on the layer, then scale down layer opacity factor. Value 0, `LV_OPA_0` or `LV_OPA_TRANSP` means fully transparent, 255, `LV_OPA_100` or `LV_OPA_COVER` means fully covering, other values or LV_OPA_10, LV_OPA_20, etc means semi transparency.
<ul>
<li style='display:inline; margin-right: 20px; margin-left: 0px'><strong>Default</strong> `LV_OPA_COVER`</li>
<li style='display:inline; margin-right: 20px; margin-left: 0px'><strong>Inherited</strong> Yes</li>
<li style='display:inline; margin-right: 20px; margin-left: 0px'><strong>Layout</strong> No</li>
<li style='display:inline; margin-right: 20px; margin-left: 0px'><strong>Ext. draw</strong> No</li>
</ul>
### color_filter_dsc ### color_filter_dsc
Mix a color to all colors of the object. Mix a color to all colors of the object.
<ul> <ul>
@ -772,7 +781,7 @@ Describes how to blend the colors to the background. The possible values are `LV
</ul> </ul>
### layout ### layout
Set the layout if the object. The children will be repositioned and resized according to the policies set for the layout. For the possible values see the documentation of the layouts. Set the layout of the object. The children will be repositioned and resized according to the policies set for the layout. For the possible values see the documentation of the layouts.
<ul> <ul>
<li style='display:inline; margin-right: 20px; margin-left: 0px'><strong>Default</strong> 0</li> <li style='display:inline; margin-right: 20px; margin-left: 0px'><strong>Default</strong> 0</li>
<li style='display:inline; margin-right: 20px; margin-left: 0px'><strong>Inherited</strong> No</li> <li style='display:inline; margin-right: 20px; margin-left: 0px'><strong>Inherited</strong> No</li>

@ -204,6 +204,10 @@ The default rotation of your display when it is initialized can be set using the
Display rotation can also be changed at runtime using the `lv_disp_set_rotation(disp, rot)` API. Display rotation can also be changed at runtime using the `lv_disp_set_rotation(disp, rot)` API.
If you enable rotation the coordinates of the pointer input devices (e.g. touchpad) will be rotated too.
Note that when using software rotation, you cannot use neither `direct_mode` nor `full_refresh` in the driver. When using either of these, you will have to rotate the pixels yourself e.g. in the `flush_cb`.
Support for software rotation is a new feature, so there may be some glitches/bugs depending on your configuration. If you encounter a problem please open an issue on [GitHub](https://github.com/lvgl/lvgl/issues). Support for software rotation is a new feature, so there may be some glitches/bugs depending on your configuration. If you encounter a problem please open an issue on [GitHub](https://github.com/lvgl/lvgl/issues).
### Decoupling the display refresh timer ### Decoupling the display refresh timer

@ -114,7 +114,7 @@ You need to have 3 buttons available:
- `LV_KEY_RIGHT` will simulate turning encoder right - `LV_KEY_RIGHT` will simulate turning encoder right
- other keys will be passed to the focused widget - other keys will be passed to the focused widget
If you hold the keys it will simulate an encoder advance with period specified in `indev_drv.long_press_rep_time`. If you hold the keys it will simulate an encoder advance with period specified in `indev_drv.long_press_repeat_time`.
```c ```c
indev_drv.type = LV_INDEV_TYPE_ENCODER; indev_drv.type = LV_INDEV_TYPE_ENCODER;
@ -172,7 +172,7 @@ The default value of the following parameters can be changed in `lv_indev_drv_t`
- `scroll_limit` Number of pixels to slide before actually scrolling the object. - `scroll_limit` Number of pixels to slide before actually scrolling the object.
- `scroll_throw` Scroll throw (momentum) slow-down in [%]. Greater value means faster slow-down. - `scroll_throw` Scroll throw (momentum) slow-down in [%]. Greater value means faster slow-down.
- `long_press_time` Press time to send `LV_EVENT_LONG_PRESSED` (in milliseconds) - `long_press_time` Press time to send `LV_EVENT_LONG_PRESSED` (in milliseconds)
- `long_press_rep_time` Interval of sending `LV_EVENT_LONG_PRESSED_REPEAT` (in milliseconds) - `long_press_repeat_time` Interval of sending `LV_EVENT_LONG_PRESSED_REPEAT` (in milliseconds)
- `read_timer` pointer to the `lv_timer` which reads the input device. Its parameters can be changed by `lv_timer_...()` functions. `LV_INDEV_DEF_READ_PERIOD` in `lv_conf.h` sets the default read period. - `read_timer` pointer to the `lv_timer` which reads the input device. Its parameters can be changed by `lv_timer_...()` functions. `LV_INDEV_DEF_READ_PERIOD` in `lv_conf.h` sets the default read period.
### Feedback ### Feedback

@ -25,7 +25,7 @@ So in the example the first row will have 2 buttons each with 50% width and a se
The buttons' width can be set relative to the other button in the same row with `lv_btnmatrix_set_btn_width(btnm, btn_id, width)` The buttons' width can be set relative to the other button in the same row with `lv_btnmatrix_set_btn_width(btnm, btn_id, width)`
E.g. in a line with two buttons: *btnA, width = 1* and *btnB, width = 2*, *btnA* will have 33 % width and *btnB* will have 66 % width. E.g. in a line with two buttons: *btnA, width = 1* and *btnB, width = 2*, *btnA* will have 33 % width and *btnB* will have 66 % width.
It's similar to how the [`flex-grow`](https://developer.mozilla.org/en-US/docs/Web/CSS/flex-grow) property works in CSS. It's similar to how the [`flex-grow`](https://developer.mozilla.org/en-US/docs/Web/CSS/flex-grow) property works in CSS.
The width must be in the \[1..7\] range and the default width is 1. The width must be in the \[1..15\] range and the default width is 1.
In addition to the width, each button can be customized with the following parameters: In addition to the width, each button can be customized with the following parameters:
- `LV_BTNMATRIX_CTRL_HIDDEN` Makes a button hidden (hidden buttons still take up space in the layout, they are just not visible or clickable) - `LV_BTNMATRIX_CTRL_HIDDEN` Makes a button hidden (hidden buttons still take up space in the layout, they are just not visible or clickable)

@ -43,7 +43,7 @@ Options are passed to the drop-down list as a string with `lv_dropdown_set_optio
The `lv_dropdown_add_option(dropdown, "New option", pos)` function inserts a new option to `pos` index. The `lv_dropdown_add_option(dropdown, "New option", pos)` function inserts a new option to `pos` index.
To save memory the options can set from a static(constant) string too with `lv_dropdown_set_static_options(dropdown, options)`. To save memory the options can set from a static(constant) string too with `lv_dropdown_set_options_static(dropdown, options)`.
In this case the options string should be alive while the drop-down list exists and `lv_dropdown_add_option` can't be used In this case the options string should be alive while the drop-down list exists and `lv_dropdown_add_option` can't be used
You can select an option manually with `lv_dropdown_set_selected(dropdown, id)`, where `id` is the index of an option. You can select an option manually with `lv_dropdown_set_selected(dropdown, id)`, where `id` is the index of an option.

@ -44,7 +44,9 @@ This is not the case with `lv_label_set_text_static`. The buffer you pass to `lv
### Text recolor ### Text recolor
In the text, you can use commands to recolor parts of the text. For example: `"Write a #ff0000 red# word"`. In the text, you can use commands to recolor parts of the text. For example: `"Write a #ff0000 red# word"`.
This feature can be enabled individually for each label by `lv_label_set_recolor()` function. This feature can be enabled individually for each label by `lv_label_set_recolor()` function,
recoloring is only supported when the text wrapped with `##ff0000 ... #`sintax is in one line,
it is not supported in wrapped text, see example `Line wrap, recoloring and scrolling`.
### Text selection ### Text selection
If enabled by `LV_LABEL_TEXT_SELECTION` part of the text can be selected. It's similar to when you use your mouse on a PC to select a text. If enabled by `LV_LABEL_TEXT_SELECTION` part of the text can be selected. It's similar to when you use your mouse on a PC to select a text.

@ -1,5 +1,7 @@
# Calendar (lv_calendar) # Calendar (lv_calendar)
**From v8.1 the header is added directly into the Calendar widget and the API of the headers has been changed.**
## Overview ## Overview
The Calendar object is a classic calendar which can: The Calendar object is a classic calendar which can:
@ -13,13 +15,16 @@ The Calendar is added to the default group (if it is set). Calendar is an editab
To make the Calendar flexible, by default it doesn't show the current year or month. Instead, there are optional "headers" that can be attached to the calendar. To make the Calendar flexible, by default it doesn't show the current year or month. Instead, there are optional "headers" that can be attached to the calendar.
## Parts and Styles ## Parts and Styles
The calendar object uses the [Button matrix](/widgets/core/btnmatrix) object under the hood to arrange the days into a matrix. The Calendar is composed of 3 widegets
- `LV_PART_MAIN` The background of the calendar. Uses all the background related style properties. - Container: A rectangle which is a container for the *Header* and the *Days*. Uses only `LV_PART_MAIN` where all the background related style properties are working.
- `LV_PART_ITEMS` Refers to the dates and day names. Button matrix control flags are set to differentiate the buttons and a custom drawer event is added modify the properties of the buttons as follows: - Days: It's a [Button matrix](/widgets/core/btnmatrix) object under the hood to arrange the days into a matrix. `lv_calendar_get_btnmatrix(calendar)` can be used to get it.
- `LV_PART_MAIN` The background of the calendar. Uses all the background related style properties.
- `LV_PART_ITEMS` Refers to the dates and day names. Button matrix control flags are set to differentiate the buttons and a custom drawer event is added modify the properties of the buttons as follows:
- day names have no border, no background and drawn with a gray color - day names have no border, no background and drawn with a gray color
- days of the previous and next month have `LV_BTNMATRIX_CTRL_DISABLED` flag - days of the previous and next month have `LV_BTNMATRIX_CTRL_DISABLED` flag
- today has a thicker border with the theme's primary color - today has a thicker border with the theme's primary color
- highlighted days have some opacity with the theme's primary color. - highlighted days have some opacity with the theme's primary color.
- Header: Not created by default, the details are up to the given header.
## Usage ## Usage
@ -53,8 +58,6 @@ Learn more about [Keys](/overview/indev).
## Headers ## Headers
**From v8.1 the header is added directly into the Calendar widget and the API of the headers has been changed.**
### Arrow buttons ### Arrow buttons
`lv_calendar_header_arrow_create(calendar)` creates a header that contains a left and right arrow on the sides and a text with the current year and month between them. `lv_calendar_header_arrow_create(calendar)` creates a header that contains a left and right arrow on the sides and a text with the current year and month between them.

@ -63,6 +63,12 @@ install(
FILES_MATCHING FILES_MATCHING
PATTERN "*.h") PATTERN "*.h")
install(
FILES "${LV_CONF_PATH}"
DESTINATION "${CMAKE_INSTALL_PREFIX}/${INC_INSTALL_DIR}/../"
RENAME "lv_conf.h"
OPTIONAL)
set_target_properties( set_target_properties(
lvgl lvgl
PROPERTIES OUTPUT_NAME lvgl PROPERTIES OUTPUT_NAME lvgl

@ -12,22 +12,43 @@ if(LV_MICROPYTHON)
${LVGL_ROOT_DIR}/../ ${LVGL_ROOT_DIR}/../
REQUIRES REQUIRES
main) main)
else()
if(CONFIG_LV_BUILD_EXAMPLES)
file(GLOB_RECURSE EXAMPLE_SOURCES ${LVGL_ROOT_DIR}/examples/*.c)
set_source_files_properties(${EXAMPLE_SOURCES} COMPILE_FLAGS "-Wno-unused-variable -Wno-format")
endif()
target_compile_definitions(${COMPONENT_LIB} if(CONFIG_LV_USE_DEMO_WIDGETS)
INTERFACE "-DLV_CONF_INCLUDE_SIMPLE") file(GLOB_RECURSE DEMO_WIDGETS_SOURCES ${LVGL_ROOT_DIR}/demos/widgets/*.c)
list(APPEND DEMO_SOURCES ${DEMO_WIDGETS_SOURCES})
if(CONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM) endif()
target_compile_definitions(${COMPONENT_LIB} if(CONFIG_LV_USE_DEMO_KEYPAD_AND_ENCODER)
INTERFACE "-DLV_ATTRIBUTE_FAST_MEM=IRAM_ATTR") file(GLOB_RECURSE DEMO_KEYPAD_AND_ENCODER_SOURCES ${LVGL_ROOT_DIR}/demos/keypad_encoder/*.c)
list(APPEND DEMO_SOURCES ${DEMO_KEYPAD_AND_ENCODER_SOURCES})
endif()
if(CONFIG_LV_USE_DEMO_BENCHMARK)
file(GLOB_RECURSE DEMO_BENCHMARK_SOURCES ${LVGL_ROOT_DIR}/demos/benchmark/*.c)
list(APPEND DEMO_SOURCES ${DEMO_BENCHMARK_SOURCES})
endif()
if(CONFIG_LV_USE_DEMO_STRESS)
file(GLOB_RECURSE DEMO_STRESS_SOURCES ${LVGL_ROOT_DIR}/demos/stress/*.c)
list(APPEND DEMO_SOURCES ${DEMO_STRESS_SOURCES})
endif()
if(CONFIG_LV_USE_DEMO_MUSIC)
file(GLOB_RECURSE DEMO_MUSIC_SOURCES ${LVGL_ROOT_DIR}/demos/music/*.c)
list(APPEND DEMO_SOURCES ${DEMO_MUSIC_SOURCES})
set_source_files_properties(${DEMO_MUSIC_SOURCES} COMPILE_FLAGS "-Wno-format")
endif() endif()
else()
idf_component_register(SRCS ${SOURCES} INCLUDE_DIRS ${LVGL_ROOT_DIR}
${LVGL_ROOT_DIR}/src ${LVGL_ROOT_DIR}/../)
target_compile_definitions(${COMPONENT_LIB} PUBLIC "-DLV_CONF_INCLUDE_SIMPLE") idf_component_register(SRCS ${SOURCES} ${EXAMPLE_SOURCES} ${DEMO_SOURCES}
INCLUDE_DIRS ${LVGL_ROOT_DIR} ${LVGL_ROOT_DIR}/src ${LVGL_ROOT_DIR}/../
${LVGL_ROOT_DIR}/examples ${LVGL_ROOT_DIR}/demos
REQUIRES esp_timer)
endif()
target_compile_definitions(${COMPONENT_LIB} PUBLIC "-DLV_CONF_INCLUDE_SIMPLE")
if(CONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM) if(CONFIG_LV_ATTRIBUTE_FAST_MEM_USE_IRAM)
target_compile_definitions(${COMPONENT_LIB} target_compile_definitions(${COMPONENT_LIB}
PUBLIC "-DLV_ATTRIBUTE_FAST_MEM=IRAM_ATTR") PUBLIC "-DLV_ATTRIBUTE_FAST_MEM=IRAM_ATTR")
endif()
endif() endif()

@ -20,7 +20,7 @@
--> -->
<package schemaVersion="1.4" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="PACK.xsd"> <package schemaVersion="1.4" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="https://raw.githubusercontent.com/Open-CMSIS-Pack/Open-CMSIS-Pack-Spec/v1.7.7/schema/PACK.xsd">
<vendor>LVGL</vendor> <vendor>LVGL</vendor>
<name>lvgl</name> <name>lvgl</name>
<description>LVGL (Light and Versatile Graphics Library) is a free and open-source graphics library providing everything you need to create an embedded GUI with easy-to-use graphical elements, beautiful visual effects and a low memory footprint.</description> <description>LVGL (Light and Versatile Graphics Library) is a free and open-source graphics library providing everything you need to create an embedded GUI with easy-to-use graphical elements, beautiful visual effects and a low memory footprint.</description>
@ -36,12 +36,47 @@
<repository type="git">https://github.com/lvgl/lvgl.git</repository> <repository type="git">https://github.com/lvgl/lvgl.git</repository>
<releases> <releases>
<release date="2022-07-06" version="1.0.6" url="https://raw.githubusercontent.com/lvgl/lvgl/master/env_support/cmsis-pack/LVGL.lvgl.1.0.6.pack"> <release date="2023-12-05" version="8.3.11" url="https://raw.githubusercontent.com/lvgl/lvgl/master/env_support/cmsis-pack/LVGL.lvgl.8.3.11.pack">
- LVGL 8.3.0 release - LVGL 8.3.11
- Apply patch for memory leaking issue - Add LittleFS Library to LVGL8
- Apply patch to speed up non normal blend mode - Backport Tiny TTF to LVGL8
- Add 9-key input mode to pinyin - Some minor fixes
- Other minor changes </release>
<release date="2023-09-19" version="8.3.10" url="https://github.com/lvgl/lvgl/raw/9e388055ec0bcad5179461e66d6dac6823129eee/env_support/cmsis-pack/LVGL.lvgl.8.3.10.pack">
- LVGL 8.3.10
- Some minor fixes
</release>
<release date="2023-08-04" version="8.3.9" url="https://github.com/lvgl/lvgl/raw/bdf5bfb88ce107f16cf9128cf75e61394b3219d0/env_support/cmsis-pack/LVGL.lvgl.8.3.9.pack">
- LVGL 8.3.10
- Add snapshot, fragment, imgfont, gridnav, msg and monkey
- Other minor fixes
</release>
<release date="2023-07-04" version="8.3.8" url="https://github.com/lvgl/lvgl/raw/15433d69b9d8ae6aa74f49946874af81a0cc5921/env_support/cmsis-pack/LVGL.lvgl.8.3.8.pack">
- LVGL 8.3.8
- Add renesas-ra6m3 gpu adaptation
- Improve performance and add more features for PXP and VGLite
- Minor updates
</release>
<release date="2023-04-28" version="8.3.7" url="https://github.com/lvgl/lvgl/raw/2b56e04205481daa6575bd5f7ab5df59d11676eb/env_support/cmsis-pack/LVGL.lvgl.8.3.7.pack">
- LVGL 8.3.7
- Minor updates
</release>
<release date="2023-04-02" version="8.3.6" url="https://github.com/lvgl/lvgl/raw/6b0092c0d91b2c7bfded48e04cc7b486ed3a72bd/env_support/cmsis-pack/LVGL.lvgl.8.3.6.pack">
- LVGL 8.3.6 release
- Various fixes, See CHANGELOG.md
</release>
<release date="2023-02-06" version="8.3.5" url="https://github.com/lvgl/lvgl/raw/e7e8cf846dce96f7542e27b5c9655bab680c31a1/env_support/cmsis-pack/LVGL.lvgl.8.3.5.pack">
- LVGL 8.3.5 release
- Use LVGL version as the cmsis-pack version
- Fix GPU support for NXP PXP and NXP VGLite
- Rework stm32 DMA2D support
- Various fixes
</release>
<release date="2022-12-31" version="1.0.6-p1" url="https://github.com/lvgl/lvgl/raw/dbb15bb3ea0365373bc1ba8b182556f937e61e7d/env_support/cmsis-pack/LVGL.lvgl.1.0.6-p1.pack">
- LVGL 8.3.4 release
- Update GPU Arm-2D support
- Various fixes
</release> </release>
<release date="2022-06-29" version="1.0.5" url="https://github.com/GorgonMeducer/lvgl/raw/922108dbbe6d1c0be1069c342ca8693afee8c169/env_support/cmsis-pack/LVGL.lvgl.1.0.5.pack"> <release date="2022-06-29" version="1.0.5" url="https://github.com/GorgonMeducer/lvgl/raw/922108dbbe6d1c0be1069c342ca8693afee8c169/env_support/cmsis-pack/LVGL.lvgl.1.0.5.pack">
- LVGL 8.3.0-dev - LVGL 8.3.0-dev
@ -159,6 +194,90 @@
<require Cclass="Acceleration" Cgroup="Arm-2D"/> <require Cclass="Acceleration" Cgroup="Arm-2D"/>
</condition> </condition>
<condition id="LVGL-GPU-Arm-2D">
<description>Enable LVGL Arm-2D GPU Support</description>
<require Cclass="LVGL" Cgroup="lvgl" Csub="Essential"/>
<!--<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU Arm-2D"/>-->
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU STM32-DMA2D"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU SWM341-DMA2D"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU NXP-PXP"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU NXP-VGLite"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU GD32-IPA"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="LVGL-GPU-RA6M3-G2D"/>
</condition>
<condition id="LVGL-GPU-STM32-DMA2D">
<description>Enable LVGL Arm-2D GPU Support</description>
<require Cclass="LVGL" Cgroup="lvgl" Csub="Essential"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU Arm-2D"/>
<!--<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU STM32-DMA2D"/>-->
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU SWM341-DMA2D"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU NXP-PXP"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU NXP-VGLite"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU GD32-IPA"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="LVGL-GPU-RA6M3-G2D"/>
</condition>
<condition id="LVGL-GPU-SWM341-DMA2D">
<description>Enable LVGL Arm-2D GPU Support</description>
<require Cclass="LVGL" Cgroup="lvgl" Csub="Essential"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU Arm-2D"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU STM32-DMA2D"/>
<!--<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU SWM341-DMA2D"/>-->
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU NXP-PXP"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU NXP-VGLite"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU GD32-IPA"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="LVGL-GPU-RA6M3-G2D"/>
</condition>
<condition id="LVGL-GPU-NXP-PXP">
<description>Enable LVGL Arm-2D GPU Support</description>
<require Cclass="LVGL" Cgroup="lvgl" Csub="Essential"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU Arm-2D"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU STM32-DMA2D"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU SWM341-DMA2D"/>
<!--<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU NXP-PXP"/>-->
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU NXP-VGLite"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU GD32-IPA"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="LVGL-GPU-RA6M3-G2D"/>
</condition>
<condition id="LVGL-GPU-NXP-VGLite">
<description>Enable LVGL Arm-2D GPU Support</description>
<require Cclass="LVGL" Cgroup="lvgl" Csub="Essential"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU Arm-2D"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU STM32-DMA2D"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU SWM341-DMA2D"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU NXP-PXP"/>
<!--<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU NXP-VGLite"/>-->
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU GD32-IPA"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="LVGL-GPU-RA6M3-G2D"/>
</condition>
<condition id="LVGL-GPU-GD32-IPA">
<description>Enable LVGL Arm-2D GPU Support</description>
<require Cclass="LVGL" Cgroup="lvgl" Csub="Essential"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU Arm-2D"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU STM32-DMA2D"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU SWM341-DMA2D"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU NXP-PXP"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU NXP-VGLite"/>
<!--<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU GD32-IPA"/>-->
<deny Cclass="LVGL" Cgroup="lvgl" Csub="LVGL-GPU-RA6M3-G2D"/>
</condition>
<condition id="LVGL-GPU-RA6M3-G2D">
<description>Enable LVGL Arm-2D GPU Support</description>
<require Cclass="LVGL" Cgroup="lvgl" Csub="Essential"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU Arm-2D"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU STM32-DMA2D"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU SWM341-DMA2D"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU NXP-PXP"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU NXP-VGLite"/>
<deny Cclass="LVGL" Cgroup="lvgl" Csub="GPU GD32-IPA"/>
<!--<deny Cclass="LVGL" Cgroup="lvgl" Csub="LVGL-GPU-RA6M3-G2D"/>-->
</condition>
</conditions> </conditions>
<!-- apis section (optional - for Application Programming Interface descriptions) --> <!-- apis section (optional - for Application Programming Interface descriptions) -->
<!-- <!--
@ -191,7 +310,7 @@
--> -->
<components> <components>
<bundle Cbundle="LVGL" Cclass="LVGL" Cversion="8.3.0"> <bundle Cbundle="LVGL" Cclass="LVGL" Cversion="8.3.11">
<description>LVGL (Light and Versatile Graphics Library) is a free and open-source graphics library providing everything you need to create an embedded GUI with easy-to-use graphical elements, beautiful visual effects and a low memory footprint.</description> <description>LVGL (Light and Versatile Graphics Library) is a free and open-source graphics library providing everything you need to create an embedded GUI with easy-to-use graphical elements, beautiful visual effects and a low memory footprint.</description>
<doc></doc> <doc></doc>
<component Cgroup="lvgl" Csub="Essential" > <component Cgroup="lvgl" Csub="Essential" >
@ -324,11 +443,19 @@
<file category="sourceC" name="src/widgets/lv_textarea.c" /> <file category="sourceC" name="src/widgets/lv_textarea.c" />
<!-- general --> <!-- general -->
<file category="preIncludeGlobal" name="lv_conf_cmsis.h" attr="config" version="1.0.2" /> <file category="preIncludeGlobal" name="lv_conf_cmsis.h" attr="config" version="1.0.4" />
<file category="sourceC" name="lv_cmsis_pack.c" attr="config" version="1.0.0" /> <file category="sourceC" name="lv_cmsis_pack.c" attr="config" version="1.0.0" />
<file category="header" name="lvgl.h" /> <file category="header" name="lvgl.h" />
<file category="doc" name="README.md"/> <file category="doc" name="README.md"/>
<!-- code template -->
<file category="header" name="examples/porting/lv_port_disp_template.h" attr="template" select="Display port template" version="2.0.0"/>
<file category="sourceC" name="examples/porting/lv_port_disp_template.c" attr="template" select="Display port template" version="2.0.0"/>
<file category="header" name="examples/porting/lv_port_indev_template.h" attr="template" select="Input devices port template" version="2.0.0"/>
<file category="sourceC" name="examples/porting/lv_port_indev_template.c" attr="template" select="Input devices port template" version="2.0.0"/>
<file category="header" name="examples/porting/lv_port_fs_template.h" attr="template" select="File system port template" version="2.0.0"/>
<file category="sourceC" name="examples/porting/lv_port_fs_template.c" attr="template" select="File system port template" version="2.0.0"/>
</files> </files>
<Pre_Include_Global_h> <Pre_Include_Global_h>
@ -360,7 +487,7 @@
</files> </files>
</component> </component>
<component Cgroup="lvgl" Csub="GPU Arm-2D" condition="LVGL-Essential" Cversion="1.0.3"> <component Cgroup="lvgl" Csub="GPU Arm-2D" condition="LVGL-GPU-Arm-2D" Cversion="1.2.2">
<description>A 2D image processing library from Arm (i.e. Arm-2D) for All Cortex-M processors including Cortex-M0</description> <description>A 2D image processing library from Arm (i.e. Arm-2D) for All Cortex-M processors including Cortex-M0</description>
<files> <files>
<file category="sourceC" name="src/draw/arm2d/lv_gpu_arm2d.c" condition="Arm-2D"/> <file category="sourceC" name="src/draw/arm2d/lv_gpu_arm2d.c" condition="Arm-2D"/>
@ -375,7 +502,7 @@
</component> </component>
<component Cgroup="lvgl" Csub="GPU STM32-DMA2D" condition="LVGL-Essential"> <component Cgroup="lvgl" Csub="GPU STM32-DMA2D" condition="LVGL-GPU-STM32-DMA2D">
<description>An hardware acceleration from STM32-DMA2D</description> <description>An hardware acceleration from STM32-DMA2D</description>
<files> <files>
<file category="sourceC" name="src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.c" /> <file category="sourceC" name="src/draw/stm32_dma2d/lv_gpu_stm32_dma2d.c" />
@ -389,7 +516,7 @@
</component> </component>
<component Cgroup="lvgl" Csub="GPU SWM341-DMA2D" condition="LVGL-Essential"> <component Cgroup="lvgl" Csub="GPU SWM341-DMA2D" condition="LVGL-GPU-SWM341-DMA2D">
<description>An hardware acceleration from SWM341-DMA2D</description> <description>An hardware acceleration from SWM341-DMA2D</description>
<files> <files>
<file category="sourceC" name="src/draw/swm341_dma2d/lv_gpu_swm341_dma2d.c" /> <file category="sourceC" name="src/draw/swm341_dma2d/lv_gpu_swm341_dma2d.c" />
@ -403,10 +530,10 @@
</component> </component>
<component Cgroup="lvgl" Csub="GPU NXP-PXP" condition="LVGL-Essential"> <component Cgroup="lvgl" Csub="GPU NXP-PXP" condition="LVGL-GPU-NXP-PXP">
<description>An hardware acceleration from NXP-PXP</description> <description>An hardware acceleration from NXP-PXP</description>
<files> <files>
<file category="sourceC" name="src/draw/nxp/lv_gpu_nxp.c" /> <file category="sourceC" name="src/draw/nxp/pxp/lv_draw_pxp.c" />
<file category="sourceC" name="src/draw/nxp/pxp/lv_draw_pxp_blend.c" /> <file category="sourceC" name="src/draw/nxp/pxp/lv_draw_pxp_blend.c" />
<file category="sourceC" name="src/draw/nxp/pxp/lv_gpu_nxp_pxp.c" /> <file category="sourceC" name="src/draw/nxp/pxp/lv_gpu_nxp_pxp.c" />
<file category="sourceC" name="src/draw/nxp/pxp/lv_gpu_nxp_pxp_osa.c" /> <file category="sourceC" name="src/draw/nxp/pxp/lv_gpu_nxp_pxp_osa.c" />
@ -420,14 +547,16 @@
</component> </component>
<component Cgroup="lvgl" Csub="GPU NXP-VGLite" condition="LVGL-Essential"> <component Cgroup="lvgl" Csub="GPU NXP-VGLite" condition="LVGL-GPU-NXP-VGLite">
<description>An hardware acceleration from NXP-VGLite</description> <description>An hardware acceleration from NXP-VGLite</description>
<files> <files>
<file category="sourceC" name="src/draw/nxp/lv_gpu_nxp.c" /> <file category="sourceC" name="src/draw/nxp/vglite/lv_draw_vglite.c" />
<file category="sourceC" name="src/draw/nxp/vglite/lv_draw_vglite_arc.c" /> <file category="sourceC" name="src/draw/nxp/vglite/lv_draw_vglite_arc.c" />
<file category="sourceC" name="src/draw/nxp/vglite/lv_draw_vglite_blend.c" /> <file category="sourceC" name="src/draw/nxp/vglite/lv_draw_vglite_blend.c" />
<file category="sourceC" name="src/draw/nxp/vglite/lv_draw_vglite_line.c" />
<file category="sourceC" name="src/draw/nxp/vglite/lv_draw_vglite_rect.c" /> <file category="sourceC" name="src/draw/nxp/vglite/lv_draw_vglite_rect.c" />
<file category="sourceC" name="src/draw/nxp/vglite/lv_gpu_nxp_vglite.c" /> <file category="sourceC" name="src/draw/nxp/vglite/lv_vglite_buf.c" />
<file category="sourceC" name="src/draw/nxp/vglite/lv_vglite_utils.c" />
</files> </files>
<RTE_Components_h> <RTE_Components_h>
@ -438,6 +567,22 @@
</component> </component>
<component Cgroup="lvgl" Csub="GPU RA6M3-G2D" condition="LVGL-GPU-RA6M3-G2D">
<description>An hardware acceleration from Renesas RA6M3-G2D</description>
<files>
<file category="sourceC" name="src/draw/renesas/lv_gpu_d2_draw_label.c" />
<file category="sourceC" name="src/draw/renesas/lv_gpu_d2_ra6m3.c" />
</files>
<RTE_Components_h>
/*! \brief enable RA6M3-G2D */
#define LV_USE_GPU_RA6M3_G2D 1
</RTE_Components_h>
</component>
<component Cgroup="lvgl" Csub="Extra Themes" condition="LVGL-Essential"> <component Cgroup="lvgl" Csub="Extra Themes" condition="LVGL-Essential">
<description>Extra Themes, Widgets and Layouts</description> <description>Extra Themes, Widgets and Layouts</description>
<files> <files>
@ -583,10 +728,27 @@
<file category="sourceC" name="src/extra/libs/fsdrv/lv_fs_fatfs.c" /> <file category="sourceC" name="src/extra/libs/fsdrv/lv_fs_fatfs.c" />
<file category="sourceC" name="src/extra/libs/fsdrv/lv_fs_posix.c" /> <file category="sourceC" name="src/extra/libs/fsdrv/lv_fs_posix.c" />
<file category="sourceC" name="src/extra/libs/fsdrv/lv_fs_stdio.c" /> <file category="sourceC" name="src/extra/libs/fsdrv/lv_fs_stdio.c" />
<file category="sourceC" name="src/extra/libs/fsdrv/lv_fs_littlefs.c" />
</files> </files>
</component> </component>
<component Cgroup="lvgl" Csub="Libs Tiny TTF" condition="LVGL-Essential">
<description>Add Tiny TTF Library</description>
<files>
<!-- src/extra/libs/tiny_ttf -->
<file category="sourceC" name="src/extra/libs/tiny_ttf/lv_tiny_ttf.c" />
</files>
<RTE_Components_h>
/*! \brief enable Tiny TTF Library */
#define LV_USE_TINY_TTF 1
</RTE_Components_h>
</component>
<component Cgroup="lvgl" Csub="Libs RLOTTIE" condition="LVGL-Essential"> <component Cgroup="lvgl" Csub="Libs RLOTTIE" condition="LVGL-Essential">
<description>Add RLOTTIE support, an extra librbary is required.</description> <description>Add RLOTTIE support, an extra librbary is required.</description>
<files> <files>
@ -632,6 +794,97 @@
</component> </component>
<component Cgroup="lvgl" Csub="Snapshot" condition="LVGL-Essential">
<description>Add the Snapshot service</description>
<files>
<!-- src/extra/others/snapshot -->
<file category="sourceC" name="src/extra/others/snapshot/lv_snapshot.c" />
</files>
<RTE_Components_h>
/*! \brief enable snapshot support */
#define LV_USE_SNAPSHOT 1
</RTE_Components_h>
</component>
<component Cgroup="lvgl" Csub="Fragment" condition="LVGL-Essential">
<description>Add the Fragment service</description>
<files>
<!-- src/extra/others/fragment -->
<file category="sourceC" name="src/extra/others/fragment/lv_fragment.c" />
<file category="sourceC" name="src/extra/others/fragment/lv_fragment_manager.c" />
</files>
<RTE_Components_h>
/*! \brief enable fragment support */
#define LV_USE_FRAGMENT 1
</RTE_Components_h>
</component>
<component Cgroup="lvgl" Csub="Grid Navigation" condition="LVGL-Essential">
<description>Add the Grid Navigation service</description>
<files>
<!-- src/extra/others/gridnav -->
<file category="sourceC" name="src/extra/others/gridnav/lv_gridnav.c" />
</files>
<RTE_Components_h>
/*! \brief enable the Grid Navigation support*/
#define LV_USE_GRIDNAV 1
</RTE_Components_h>
</component>
<component Cgroup="lvgl" Csub="Image Font" condition="LVGL-Essential">
<description>Add the Image Font service</description>
<files>
<!-- src/extra/others/imgfont -->
<file category="sourceC" name="src/extra/others/imgfont/lv_imgfont.c" />
</files>
<RTE_Components_h>
/*! \brief enable the image font support*/
#define LV_USE_IMGFONT 1
</RTE_Components_h>
</component>
<component Cgroup="lvgl" Csub="Monkey" condition="LVGL-Essential">
<description>Add the Monkey service</description>
<files>
<!-- src/extra/others/monkey -->
<file category="sourceC" name="src/extra/others/monkey/lv_monkey.c" />
</files>
<RTE_Components_h>
/*! \brief enable the monkey service support*/
#define LV_USE_MONKEY 1
</RTE_Components_h>
</component>
<component Cgroup="lvgl" Csub="Message" condition="LVGL-Essential">
<description>Add the Message service</description>
<files>
<!-- src/extra/others/msg -->
<file category="sourceC" name="src/extra/others/msg/lv_msg.c" />
</files>
<RTE_Components_h>
/*! \brief enable the message service support*/
#define LV_USE_MSG 1
</RTE_Components_h>
</component>
<component Cgroup="lvgl" Csub="Benchmark" condition="LVGL-Essential"> <component Cgroup="lvgl" Csub="Benchmark" condition="LVGL-Essential">
<description>Add the official benchmark.</description> <description>Add the official benchmark.</description>
<files> <files>

@ -2,8 +2,8 @@
<index schemaVersion="1.0.0" xs:noNamespaceSchemaLocation="PackIndex.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"> <index schemaVersion="1.0.0" xs:noNamespaceSchemaLocation="PackIndex.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance">
<vendor>LVGL</vendor> <vendor>LVGL</vendor>
<url>https://raw.githubusercontent.com/lvgl/lvgl/master/env_support/cmsis-pack/</url> <url>https://raw.githubusercontent.com/lvgl/lvgl/master/env_support/cmsis-pack/</url>
<timestamp>2022-07-06T00:09:27</timestamp> <timestamp>2023-12-09</timestamp>
<pindex> <pindex>
<pdsc url="https://raw.githubusercontent.com/lvgl/lvgl/master/env_support/cmsis-pack/" vendor="LVGL" name="lvgl" version="1.0.6"/> <pdsc url="https://raw.githubusercontent.com/lvgl/lvgl/release/v8.3/env_support/cmsis-pack/" vendor="LVGL" name="lvgl" version="8.3.11"/>
</pindex> </pindex>
</index> </index>

@ -46,12 +46,33 @@ remove the misleading guide above this code segment.
- LV_USE_GPU_SWM341_DMA2D - LV_USE_GPU_SWM341_DMA2D
- LV_USE_GPU_ARM2D - LV_USE_GPU_ARM2D
- LV_USE_IME_PINYIN - LV_USE_IME_PINYIN
- LV_USE_PNG
- LV_USE_BMP
- LV_USE_SJPG
- LV_USE_GIF
- LV_USE_QRCODE
- LV_USE_FREETYPE
- LV_USE_TINY_TTF
- LV_USE_RLOTTIE
- LV_USE_FFMPEG
- LV_USE_SNAPSHOT
- LV_USE_MONKEY
- LV_USE_GRIDNAV
- LV_USE_FRAGMENT
- LV_USE_IMGFONT
- LV_USE_MSG
- LV_USE_IME_PINYIN
5. Update macro `LV_ATTRIBUTE_MEM_ALIGN` and `LV_ATTRIBUTE_MEM_ALIGN_SIZE` to force a WORD alignment. 5. Update macro `LV_ATTRIBUTE_MEM_ALIGN` and `LV_ATTRIBUTE_MEM_ALIGN_SIZE` to force a WORD alignment.
```c ```c
#define LV_ATTRIBUTE_MEM_ALIGN_SIZE 4 #define LV_ATTRIBUTE_MEM_ALIGN_SIZE 4
#define LV_ATTRIBUTE_MEM_ALIGN __attribute__((aligned(4))) #define LV_ATTRIBUTE_MEM_ALIGN __attribute__((aligned(4)))
``` ```
Update macro `LV_MEM_SIZE` to `(64*1024U)`. Update macro `LV_MEM_SIZE` to `(64*1024U)`.
Update macro `LV_FONT_MONTSERRAT_12` to `1`.
Update macro `LV_FONT_MONTSERRAT_12` to `1`.
6. Update Theme related macros: 6. Update Theme related macros:
```c ```c
@ -90,24 +111,40 @@ Update macro `LV_MEM_SIZE` to `(64*1024U)`.
#if LV_TICK_CUSTOM #if LV_TICK_CUSTOM
extern uint32_t SystemCoreClock; extern uint32_t SystemCoreClock;
#define LV_TICK_CUSTOM_INCLUDE "perf_counter.h" #define LV_TICK_CUSTOM_INCLUDE "perf_counter.h"
#if __PER_COUNTER_VER__ < 10902ul
#define LV_TICK_CUSTOM_SYS_TIME_EXPR ((uint32_t)get_system_ticks() / (SystemCoreClock / 1000ul))
#else
#define LV_TICK_CUSTOM_SYS_TIME_EXPR get_system_ms() #define LV_TICK_CUSTOM_SYS_TIME_EXPR get_system_ms()
#endif
#endif /*LV_TICK_CUSTOM*/ #endif /*LV_TICK_CUSTOM*/
#else #else
#define LV_TICK_CUSTOM 0 #define LV_TICK_CUSTOM 0
#if LV_TICK_CUSTOM #if LV_TICK_CUSTOM
#define LV_TICK_CUSTOM_INCLUDE "Arduino.h" /*Header for the system time function*/ #define LV_TICK_CUSTOM_INCLUDE "Arduino.h" /*Header for the system time function*/
#define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis()) /*Expression evaluating to current system time in ms*/ #define LV_TICK_CUSTOM_SYS_TIME_EXPR (millis()) /*Expression evaluating to current system time in ms*/
/*If using lvgl as ESP32 component*/
// #define LV_TICK_CUSTOM_INCLUDE "esp_timer.h"
// #define LV_TICK_CUSTOM_SYS_TIME_EXPR ((esp_timer_get_time() / 1000LL))
#endif /*LV_TICK_CUSTOM*/ #endif /*LV_TICK_CUSTOM*/
#endif /*__PERF_COUNTER__*/ #endif /*__PERF_COUNTER__*/
``` ```
9. Thoroughly remove the `DEMO USAGE` section.
10. Thoroughly remove the '3rd party libraries' section.
10. rename '**lv_conf_template.h**' to '**lv_conf_cmsis.h**'. 9. Remove all content in `DEMO USAGE` section but keep the following:
```c
/*Show some widget. It might be required to increase `LV_MEM_SIZE` */
#if LV_USE_DEMO_WIDGETS
#define LV_DEMO_WIDGETS_SLIDESHOW 0
#endif
/*Benchmark your system*/
#if LV_USE_DEMO_BENCHMARK
/*Use RGB565A8 images with 16 bit color depth instead of ARGB8565*/
#define LV_DEMO_BENCHMARK_RGB565A8 1
#endif
```
10. Thoroughly remove the `3rd party libraries` section.
11. rename '**lv_conf_template.h**' to '**lv_conf_cmsis.h**'.

@ -21,8 +21,8 @@ if [ `uname -s` = "Linux" ]
CMSIS_PACK_PATH="/home/$USER/.arm/Packs/ARM/CMSIS/5.7.0/" CMSIS_PACK_PATH="/home/$USER/.arm/Packs/ARM/CMSIS/5.7.0/"
PATH_TO_ADD="$CMSIS_PACK_PATH/CMSIS/Utilities/Linux64/" PATH_TO_ADD="$CMSIS_PACK_PATH/CMSIS/Utilities/Linux64/"
else else
CMSIS_PACK_PATH="/C/Users/gabriel/AppData/Local/Arm/Packs/ARM/CMSIS/5.7.0" CMSIS_PACK_PATH="/C/Users/$USER/AppData/Local/Arm/Packs/ARM/CMSIS/5.7.0"
PATH_TO_ADD="/C/Program Files (x86)/7-Zip/:$CMSIS_PACK_PATH/CMSIS/Utilities/Win32/:/C/xmllint/" PATH_TO_ADD="/C/Program Files (x86)/7-Zip/:/C/Program Files/7-Zip/:$CMSIS_PACK_PATH/CMSIS/Utilities/Win32/:/C/xmllint/"
fi fi
[[ ":$PATH:" != *":$PATH_TO_ADD}:"* ]] && PATH="${PATH}:${PATH_TO_ADD}" [[ ":$PATH:" != *":$PATH_TO_ADD}:"* ]] && PATH="${PATH}:${PATH_TO_ADD}"
echo $PATH_TO_ADD appended to PATH echo $PATH_TO_ADD appended to PATH

Some files were not shown because too many files have changed in this diff Show More