Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MicroPython Support #3559

Open
5 of 8 tasks
ofabel opened this issue Apr 1, 2024 · 20 comments
Open
5 of 8 tasks

MicroPython Support #3559

ofabel opened this issue Apr 1, 2024 · 20 comments
Assignees

Comments

@ofabel
Copy link

ofabel commented Apr 1, 2024

Describe the enhancement you're suggesting.

Since Python is a very popular programming language, I think it would be great to add support for this on the Flipper Zero. My first research using MicroPython already shows that this is absolutely possible.

Anything else?

I'm willing to contribute to this project. So this issue is just to let you know about. Checkout the proof of concept or the firmware fork for the progress. There is also a FAP version available (currently in public beta).

Progress

  • Proof of Concept
  • Python REPL as CLI command
  • Run Python files from the CLI
  • Find a solution for the tight ROM requirements
  • Run Python files from the file browser
  • flipperzero Python module with full feature support
  • Bytecode cache on the SD card
  • Settings dialog to configure heap and stack size.
@ofabel ofabel changed the title Micropython Support MicroPython Support Apr 1, 2024
@SuperJakov
Copy link

It's not possible

Flipper zero has this specifications

  • Flash: 1024 KB
  • SRAM: 256 KB

While micropython requires about 64kb, it is recommended to use more. Even when using 64kb, flipper will not have enough space, so it is not possible.

@ofabel
Copy link
Author

ofabel commented Apr 2, 2024

It's not possible

Flipper zero has this specifications

  • Flash: 1024 KB
  • SRAM: 256 KB

While micropython requires about 64kb, it is recommended to use more. Even when using 64kb, flipper will not have enough space, so it is not possible.

I'm not so sure about this and my research so far points out that it's might possible. I'm only using the Flipper's RAM for my tests so far (by developing a FAP, which cannot use the ROM). I've also compiled the Python files on the Flipper and didn't use the cross compiler feature.

@ofabel
Copy link
Author

ofabel commented Apr 3, 2024

So far so good. I think I've done enough research on this to proof that it's possible. What I have achieved so far:

  • Created a simple FAP, that can compile and execute Python files on the Flipper Zero.
  • MicroPython is compiled with floating point support.
  • Python time and random modules are supported.
  • Implemented a simple Python module flipperzero with the following functions:
    • Turn vibration motor on and off.
    • Turn LED and Backlight on and off, set LED color and brightness.
    • Set speaker volume and frequency.
    • Draw on display (very wacky and basic implementation).
  • Support for external imports (you can just import other Python files from the SD card).

The app works, but is a bit fuzzy and crashes sometimes before it's fully loaded (possibly due to memory fragmentation). So I think this is as far as I could go with only using the SRAM. More could be achieved by using the ROM. But as far as I understand, this would mean making the project to a part of the firmware.

I need some input from you firmware developers now before going further:

  • Is this something useful for the Flipper Zero community?
  • Could you imagine this to be a part of the official firmware?

I also could use some directions in terms of the requirements:

  • Should the compiler run on the device itself or should only the runtime be shipped with the firmware and users compile the Python files on their computer using the mpy-cross compiler?
    • It works out of the box and it would also be possible providing a REPL (e.g. in the CLI)
    • Only shipping the runtime saves memory but requires further tooling on the user's computer.
  • Since ROM is tight: What's a reasonable size of the produced binary?

@ofabel
Copy link
Author

ofabel commented Apr 4, 2024

I've managed to do a quick and dirty integration of my little project in a fork of the latest firmware release:

Firmware size
.text         660636 (645.15 K)
.rodata       171980 (167.95 K)
.data           1756 (  1.71 K)
.bss            5612 (  5.48 K)
.free_flash   213864 (208.85 K)

Still enough space left - as far as I can tell!

This quick and dirty version shipps the whole MicroPython compiler and runtime environment and can execute Python scripts from the SD card on the CLI interface using the py command (similar to the new js command).

>: py /ext/apps_assets/mp_flipper_app/flipperzero_speaker_test.py
Running script /ext/apps_assets/mp_flipper_app/flipperzero_speaker_test.py, press CTRL+C to stop
-----
allocated memory is 73116 bytes
stack size is 2048 bytes
-----
import time
import flipperzero

def play_frequency(frequency: float):
  volume = 0.8

  flipperzero.speaker_start(frequency, volume)

  for _ in range(0, 150):
    volume *= 0.9945679

    flipperzero.speaker_set_volume(volume)

    time.sleep_ms(1)

  flipperzero.speaker_stop()

play_frequency(100.0)
play_frequency(200.0)
play_frequency(300.0)
play_frequency(500.0)
play_frequency(800.0)
play_frequency(1300.0)
play_frequency(2100.0)
play_frequency(3400.0)

The application just allocates 50% of the free SRAM memory for the Python runtime environment (which is about 73 kB in the example output above). This is a big improvement in comparison to the FAP version, where the limit was about 16 kB. The 73 kB should already be enough to do something real. But I don't think that this is the upper limit.

@ofabel
Copy link
Author

ofabel commented Apr 5, 2024

Houston, we have a REPL

Screencast_20240405_143412-1.webm

@DrZlo13 DrZlo13 self-assigned this Apr 8, 2024
@ofabel
Copy link
Author

ofabel commented Apr 8, 2024

For those who are interested, I've uploaded a firmware update (based on 0.100.3) with the current progress:

  • Micropython library is integrated as submodule.
  • REPL implementation is complete (py without argument):
    • Allocates 30% of the free heap for the Python VM.
    • gc.collect() can be used (import gc first)
    • History contains up to 16 commands.
    • Auto-completion is supported.
  • Can execute Python files from the SD card (usage py /ext/<path>).
  • Free flash space is about 200K.
Screencast_20240408_043208-1.webm

@unnamedd
Copy link

unnamedd commented Apr 8, 2024

@ofabel, thank you for your hard work here! It is really nice to see some folks not only wishing to have support for specific technology but also working hard on it.

From community to community!
I really love it!

@DrZlo13
Copy link
Member

DrZlo13 commented Apr 8, 2024

  • Free flash space is about 200K.

Actually around 32k because you forgot that core2 exists and 32k is a really dangerous watermark for internal storage.
We will discuss micropython within the team, but I'm afraid that our decision will not change, it requires too many resources for flipperzero hw.

@CookiePLMonster
Copy link
Contributor

CookiePLMonster commented Apr 8, 2024

Perhaps the FAP version is more attainable, even if it comes at a cost of less usable memory? It's a really cool incentive, even though the flash space concerns are understandable.

Perhaps python modules could become plugins embedded in the FAP file, which means users would not pay the code size cost of modules they don't need.

@ofabel
Copy link
Author

ofabel commented Apr 8, 2024

@unnamedd, many thanks for the feedback!

@DrZlo13, thanks a lot for making thinks clear! What would be an acceptable watermark for the internal storage? I have to say, for now I'm just working on making things work and didn't optimize anything. I think there are a lot of options to shrink binary size of the MicroPython library. It might also be an option to make the REPL command a FAP instead and just store the compiler and runtime on the flash.

@ofabel
Copy link
Author

ofabel commented Apr 8, 2024

So I did the math: right now, my additions to the original 0.100.3 firmware enlarges the resulting binary about 100 K.

From official the MicroPython FAQ:

Generally, we keep minimal configuration of MicroPython under 80K of ARM Thumb2 code (which includes compiler and interactive prompt, much less size can be achieved disabling those).

Removing the compiler and REPL feature from the library (my additional logic around the repl not included) should reduce the resulting binary by about 20 K.

As @CookiePLMonster suggested, I could also imagine a solution where some parts run as FAPs. A reasonable solution could be only shipping the runtime with the firmware in ROM and provide the compiler as an additional FAP from the SD card. Users would be able to execute compiled *.mpy files out of the box (those files could also be distributed as an alternative form of apps). The optional compiler would just be required to develop own Python files and use the REPL.

@CookiePLMonster
Copy link
Contributor

The optional compiler would just be required to develop own Python files and use the REPL.

This sounds reasonable to me - I wasn't aware MicroPython doesn't interpret .py files as-is, but the fact it's Micro explains it.

Do note that there is a precedent to this already - VGM is an official Flipper's component, yet it can only be updated only with an external FAP. An official external MicroPython compiler FAP would not be out of place.

@ofabel
Copy link
Author

ofabel commented Apr 11, 2024

@CookiePLMonster, thanks for the hint about the VGM app - I wasn't aware of that 👍

I wasn't aware MicroPython doesn't interpret .py files as-is, but the fact it's Micro explains it.

Well, MicroPython can interpret Python files as-is - but you can compile and ship the library also without the compiler. In fact, even the normal version of CPython contains such a compiler. Because this is how most interpreted languages work these days, they compile the programm code to language dependent byte code and then execute the byte code in the runtime environment.

@ofabel
Copy link
Author

ofabel commented Apr 11, 2024

Update on the binary size: After some optimizations and sorting out the compiler "free" flash space went up to 229.78 K. So the runtime requires around 70 K. But I think I can still do better than this. @DrZlo13 is this more of an acceptable watermark for the internal storage?

.text         644696 (629.59 K)
.rodata       166476 (162.57 K)
.data           1772 (  1.73 K)
.bss            5592 (  5.46 K)
.free_flash   235296 (229.78 K)

@ofabel
Copy link
Author

ofabel commented Apr 13, 2024

Since splitting runtime and compiler is no easy task, I decided to postpone this until I know what an acceptable watermark for the internal storage could be. For now I'm compiling the firmware with COMPACT=1 and DEBUG=0 options. This keeps "free" flash around 233 K.

So I continued adding new features:

  • canvas API support for the flipperzero module
  • interrupts for the flipperzero module
  • execute Python scripts from the file browser

To test canvas and interrupt support, I created a quick and dirty Tic-Tac-Toe game (see source code for details):

Screencast_20240413_114606.webm

The canvas API is straight forward and nothing unusual. Interrupts are implemented in the form of a Python decorator:

import time
import flipperzero as f0

exit = False

@f0.on_input
def input_handler(button, type):
  global exit

  if button == f0.INPUT_BUTTON_BACK and type == f0.INPUT_TYPE_SHORT:
    exit = True

while not exit
  time.sleep_ms(10)

For those who are interested, I've uploaded firmware update with the current progress.

@ofabel
Copy link
Author

ofabel commented Apr 14, 2024

I've invested some time this weekend to give the FAP version a makeover. It's a bit more stable now but still crashes often when started (possibly due to memory fragmentation in RAM).

For those who wan't to try it: https://github.com/ofabel/mp-flipper/releases/download/v0.4.0-beta.1/mp_flipper_app.fap

Install instructions can be found here - but I think those who read this posts here are capable of installing it without guidance.

I'm not sure if I also should add this to the official application catalog. It's just not stable enough from my point of view.

@Willy-JL
Copy link
Contributor

This is very impressive @ofabel, well done!

However, I just wanted to bring up a few concerns, because while it would seem possible on OFW, I think there should also be a discussion of what benefit this brings... Flipper JS is already a thing, adding Python support would not really expand what is possible AFAIK. It would simply be another language to do the same things with same difficulty (as in, JS and Python are more approachable than C or C++, they have a similar level of difficulty), so then it would be yet another surface area to maintain, to develop modules for to interact with Flipper hardware, and to provide documentation for. All of that sounds like a lot compared to the small gain of "write it in python instead of js" being the only difference.

Also I know this is largely irrelevant in this thread as this is about OFW, but CFWs tend to have more internal flash used due to additional functionality, on Momentum for example we currently have 44KB total available, we can't even flash with COMPACT=0, and adding JS support was already a monumental task to find the smallest bits of optimizations in firmware code and making just about everything possible (CLI commands, Settings menus) external. There's nothing really left we could cut to make space for this without removing functionality.

About an acceptable mark for internal storage, from my experience maintaining a CFW, I know that under 28KB total (as seen in Settings > Storage > About Internal Storage) is a non-starter, with 28KB and less you will not even be able to install the firmware in most cases. Personally, I find that 36KB usually allows enough space for the settings files stored on internal flash, I myself am not comfortable shipping the firmware with less than that. But should also consider that there needs to be enough space to allow for future developments of the firmware, so what @DrZlo13 would consider an acceptable amount I would imagine to be more than that, but of course I can't answer for him.

With all those in mind, I personally think that a FAP solution on the application catalog would be best if possible, but of course I can't speak as to what the Flipper team will decide.

@Willy-JL
Copy link
Contributor

I've invested some time this weekend to give the FAP version a makeover. It's a bit more stable now but still crashes often when started (possibly due to memory fragmentation in RAM).

have you tried with #3572 ?

@ofabel
Copy link
Author

ofabel commented Apr 18, 2024

Thanks a lot for bringing these points up for discussion @Willy-JL! I had the same concerns when I started the project. And I still have some doubts on why should the original firmware support JavaScript and MicroPython together.

From my point of view, the mjs implementation of JavaScript has some big limitations and it is indeed not much more than a scripting language. MicroPython on the other hand is much closer to the language standard (which of course also results in a larger binary size). So if we take a look at the available features, you can do much more with MicroPython. So MicroPython might could be used for more complex things, like implementing a whole app. While JavaScript can be used for simpler tasks, like Bad USB scripts.

But this is just my opinion. I would totally understand if @DrZlo13 & the team don't wan't to include this into the original firmware. In this case, I might start my own fork of the firmware (streamlined with the original firmware, just with additional MicroPython support). The FAP version could still be around (maybe with limited feature support).

@ofabel
Copy link
Author

ofabel commented Apr 18, 2024

I've invested some time this weekend to give the FAP version a makeover. It's a bit more stable now but still crashes often when started (possibly due to memory fragmentation in RAM).

have you tried with #3572 ?

Not yet, but looks promising!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants