Closed DrZlo13 closed 4 years ago
At least, we need some "resident" apps, as drivers for screen, battery management, keyboard input. I expect many community versions of that modules, so we need make API and split it from core. We must keep size of core as small, as possible. This lowering count of core hacks and unofficial binary firmwares.
Also, I already think about sharing peripherals: splitting screen and splitting BLE for 2 or even more apps.
I already think about sharing peripherals
When I designed FURI I planned use it for including shared access to peripherial.
For example, you can place timer object pointer or GPIO to FURI record and then you have flexible scenario how to make shared access:
You also can subscribe to state change and listen when peripheral object block and freed.
I also think that having loadable user applications would improve the overall user experience.
Tock OS already supports dynamically loading applications and it was listed in #17 as one of possible OS for Flipper Zero. Some information on how it is implemented in Tock OS can be found at the following links: https://github.com/tock/tock/blob/master/doc/Compilation.md#position-independent-code https://www.tockos.org/blog/2016/dynamic-loading https://reviews.llvm.org/D23195
So it could be an additional argument for Tock OS.
A few more comments.
we have only 128k ram
At the moment, it looks like Flipper Zero will use STM32WB55. We will therefore have a little more SRAM for applications (192k).
It limited in, says, 100k of ram+rom (i think 28k of ram for core is enough), because it will be loaded and executed in ram.
With STM32WB55, we could have something like the following:
Load user apps from .elf with dynamic linking on load, so we get more flexibility in core api.
I think dynamic linking is not strictly necessary if we are using some simplifications. For example, user applications can be copied from micro SD card to fixed address in SRAM, then run from SRAM. That way, we can just copy a .bin file to, say, 0x20010000, and then call a function that points to that address.
and then call a function that points to that address.
Change location of interrupt table
Change location of interrupt table
Maybe. It depends on whether user applications should handle interrupts or not.
If the core system provides a very high level library (like for example Arduino or Linux), then user applications will only call the very high level functions provided by the core system and all interrupts will be handled by the core system.
In this case, the interrupt table entries would point to low-level core system functions and the interrupt table could remain at the initial address.
If the core system provides a very high level library (like for example Arduino or Linux), then user applications will only call the very high level functions provided by the core system and all interrupts will be handled by the core system.
+1
For example, user applications can be copied from micro SD card to fixed address in SRAM, then run from SRAM. That way, we can just copy a .bin file to, say, 0x20010000,
This concept not allows to run more than one app at once and we can get some problems if we will want to change memory layout.
This might have been suggested / dismissed already, but one possible solution for insufficient storage would be using external memory (RAM or ROM) with a flexible memory controller (aka FMC). Unfortunately, it seems like this peripheral is not available in STM32WB55 (but is available in L476). If WB55 as the final MCU is not locked, this could be an option.
Basically, it allows extending the MCU memory space and address external memory as if it is internal.
External RAM are so cool but Flipper never have it :(
We have massive discussion with @DrZlo13 some days ago and I have vision by current project state:
Also I want say about "library" applications — if you want to provide some "shared code":
We researched mmu-less os development (have analyzed tock os, thread x, classic mac os, palm os) and get some conclusions:
With all of the above, we have the following core mechanic:
I would like to draw your attention to the fact that in this solution it is not necessary to have block division of the appheap, everything is completely solved by ordinary memory allocation.
To understand how to organize applications api, I started work in the wip-app-loader branch, where I try to implement drivers, protocols and applications. I have dynamic applications linking in another project, but at this moment this doesn't used, since first of all it would be nice to have an understanding of the general work with FURI. To get understanding, for example, I, now implemented the protocol for FLIPPER CLI #93 via FURI api (which also provided me with more convenient work with application files on a flash card), and in the near future I plan to start rewriting the application loader and implementing a linker.
After long discussion we decide:
Also we have no good solutions for work with static and global variables and forbid using it. Maybe thread-local will be good solution.
Problem with statics seems solved. We can compile user app with flags "-msingle-pic-base -mpic-register = r9", so address of data/bss section will be obtained from register R9. Also core must be compiled with "-ffixed-r9" flag, so that compiler will not use that register.
Next steps is to prove solution. We need look how OS save fixed-register in stack (every user app has own R9 register value) and we need to make sure that manipulations with R9 will be used only with static variables.
When main firmware is built we already know address table for public API, we can provide headers, this table and compilation flags so application can be built without main firmware.
The solution to the problem of rebasing the .data section does not look so easy. single-pic-base and pic-register require compilation with the PIC flag, which leads to the implementation of the PIC linker. So far we have returned to the concept of a monolithic firmware kernel, but in the future this issue we will studied more fully.
will return to this task later
Has this discussion been continued somewhere else, with the upcoming release 1.0.0? I read somwhere this is still an expected feature for the first stable release. Or is this still blocked? Can't find a newer issue here, neither a related post on the forum.
@clasqui this feature will be a part of v1.0.0. We are currently working on external application and SDK. Please check our roadmap.
@skotopes Nice, thank you for the clarification. Is there somewhere where I can follow the discussion on the implementation and the development of this feature? I mean, a post, a discord channel, an issue, a branch...
Yes, we do Q&A sessions on discord and update roadmap from time to time.
Problem
Flipper zero must run user applications.
Constrains
Static storage: solved, recently we get a sd card. Executable storage: we have only 128k ram. Flash storage is not an option because according to the datasheet inner mcu flash has only 10k rewrites. Speed: user apps must run native code, because some protocols require tight gpio timings, eg.
By speed constrains we can't use any of script-driven languages for apps. By exec storage constrains we can't design all systems like a user-app.
Solution
1) Divide apps by two groups. First — "embedded" apps, its a "basic functionality" like a iButton emulator app, and this group embedded into firmware. Second group — real "user" app. It limited in, says, 100k of ram+rom (i think 28k of ram for core is enough), because it will be loaded and executed in ram. 2) Load and exec only one user app at a time. Sounds bad, but I don't see any real cases for running two user applications at the same time. It free us of dynamic ram manager and ram defragmentation problem. 3) Load user apps from .elf with dynamic linking on load, so we get more flexibility in core api. Also we can get more ram in future, so in theory loading two and more user apps is not a problem (besides defragmentation).
My role
I can design and implement dynamic linking because I have a lot of experience in this area.