diff --git a/README.md b/README.md index 95a173b..c8ab30c 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ MicroHydra is a simple MicroPython based app launcher with some OS-like features *MicroHydra is currently going through a major overhaul to enable multi-platform support. Many features and APIs will likely undergo significant change by version 2.0.* please use the "releases" section for stable versions of MicroHydra. -This code was built with MicroPython v1.23.0 (preview), for a Generic ESP32-S3 controller. +This code was built with MicroPython v1.23, for the ESP32-S3. The main function of MicroHydra is to provide an interface to easily switch between MicroPython apps. And to help lower the barriers to entry for anyone wanting to develop apps for their Cardputer. @@ -36,9 +36,7 @@ Python scripts can be placed in the /apps folder on the flash, or in a /apps fol Take a look at the [wiki](https://github.com/echo-lalia/Cardputer-MicroHydra/wiki) for some basic guides to get you started with a MicroPython app. -If you're looking for the compiled firmware, that lives over [here](https://github.com/echo-lalia/microhydra-frozen). - -And for a work-in-progress repository of MicroHydra apps, see [here](https://github.com/echo-lalia/MicroHydra-Apps) +And for a repository of community-made MicroHydra apps, see [here](https://github.com/echo-lalia/MicroHydra-Apps).


@@ -67,9 +65,7 @@ Apps are designed to work very simply in this launcher. Any Python file placed i This means that a simple app can be contained as one script, which will be executed when the app is selected from the launcher. It also means more complicated apps can place a startup file in the apps directory, which imports anything it needs from another folder in the filesystem. -Some apps for MH can be found [here](https://github.com/echo-lalia/MicroHydra-Apps), but there are many other apps (especially work-in-progress apps) living in other locations, as well. - -*Quick note about apps on the SD card: The apps wont be able to use SPI slot 2 for the display (or anything else) because it will be occupied by the SD card. Thankfully, the display works fine in slot 1.* +Some apps for MH can be found [here](https://github.com/echo-lalia/MicroHydra-Apps), but there are other apps (especially work-in-progress apps) living in other locations, as well.


@@ -78,6 +74,10 @@ Some apps for MH can be found [here](https://github.com/echo-lalia/MicroHydra-Ap # Installing MicroHydra: +> NOTE: This guide is for MicroHydra 1.x, and will not work for 2.x due to the new way device-specific source files are dynamically created. +> If you want to test out v2.0, check out the preview binaries in the 'releases' section. +> The full 2.x guides will be coming soon :) + You can install MicroHydra a few different ways. - *Install plain .py version on MicroPython:* diff --git a/wiki/Home.md b/wiki/Home.md index eb623ff..cb6b881 100644 --- a/wiki/Home.md +++ b/wiki/Home.md @@ -1,7 +1,20 @@ -Welcome to the MicroHydra wiki! +### Welcome to the MicroHydra wiki! *This wiki is community-editable! If you'd like to help clarify or expand its contents, just fork this repo, make your changes to [/wiki](https://github.com/echo-lalia/Cardputer-MicroHydra/tree/main/wiki), and submit a pull request :)* +
+ +## Multiplatform support +MicroHydra uses a few different ideas in order to output code for multiple devices. You can learn about this [here](https://github.com/echo-lalia/Cardputer-MicroHydra/wiki/multi-platform) + +## Making Apps +For a basic overview of how MicroHydra apps work, see the [App Format](https://github.com/echo-lalia/Cardputer-MicroHydra/wiki/App-Format) section. + +
+ + +## Lib + MicroHydra includes a built-in library, intended to help you easily make apps. Click on a module below to learn more about it. ---- @@ -25,7 +38,7 @@ MicroHydra includes a built-in library, intended to help you easily make apps. C │       │ │       ├── $hydra$ │       │       ├── [beeper](https://github.com/echo-lalia/Cardputer-MicroHydra/wiki/Playing-Sound#beeper) -│       │       ├── color +│       │       ├── [color](https://github.com/echo-lalia/Cardputer-MicroHydra/wiki/color) │       │       ├── [config](https://github.com/echo-lalia/Cardputer-MicroHydra/wiki/Accessing-config-files) │       │       ├── [menu](https://github.com/echo-lalia/Cardputer-MicroHydra/wiki/HydraMenu) │       │       └── [popup](https://github.com/echo-lalia/Cardputer-MicroHydra/wiki/popup) diff --git a/wiki/multi-platform.md b/wiki/multi-platform.md new file mode 100644 index 0000000..bfadf96 --- /dev/null +++ b/wiki/multi-platform.md @@ -0,0 +1,229 @@ +MicroHydra 2.0 brings a major overhaul to the structure of the project, all with the intention of expanding the code to work on multiple different devices, and develop for them all simultaneously. + +This is an overview of how this currently works. + + +

+ +## Main directory structure + +*MicroHydra (base repository)* +│ +├── **src/** +│           \ +│             *This is where the majority of the source code for the program lives* +│ +│ +├── **devices/** +│           \ +│             *This is where the device definitions, and device specific drivers come from* +│ +│ +├── **tools/** +│           \ +│             *`parse_files.py`, and other useful scripts live in here* +│ +│ +└── **MicroHydra/** +            \ +              *`parse_files.py` creates this directory by combining the source code in `src/`,* +              *with the definitions and drivers from `devices/`, for each device.* + + +

+ +## devices/ + +The `devices/` directory contains a `default.yml` file with the following structure: +``` Yaml +# 'constants' contains all the existing hydra constants from device definitions, +# plus the most common value from the devices. +# The values are all strings representing MicroPython code to put in a `const()` declaration +# The keys follow a "_CONST_CASE" naming convention, and always start with "_MH_" +constants: + _MH_CAPS_CASE_KEY_NAME: 'value' + _MH_DISPLAY_BACKLIGHT: '38' + _MH_BATT_ADC: 'None' + +# 'features' contains a list of every single feature that exists in any device definition. +# The entries here follow +features: +- display +- wifi +- keyboard +- any_other_feature + +# This is the MicroPython arch to use when compiling code for the device. +# It is "xtensawin" for any ESP32-S3 based device. +mpy_arch: xtensawin + +# This is the starting point to use when creating a firmware `.bin` file for the device. +# It specifies the name of a directory under `MicroPython/ports/esp32/boards/` +source_board: ESP32_GENERIC_S3 +``` + +Then, each device has its own directory containing a `definition.yml` file, along with MicroPython build files and any device-specific drivers. + +*DEVICENAME* +├── definition.yml +├── manifest.py +├── mpconfigboard.cmake +└── *lib/* +          └── device_drivers.py + +The `definition.yml` file has the exact same structure as the `default.yml` file, but the values are tailored to that specific device. +Any "constants" that are not in `definition.yml` use the defaults set in `default.yml` instead. +Any "features" that are not in `definition.yml` are assumed to not exist on that device. + +Any additional driver files in this folder are coppied over to the device-specific MicroHydra output folder (after copying the `src` files over) + + +

+ +## Magic Constants + +MicroHydra's 'magic' constants, are device constants that will be automatically replaced with the apropriate device-specific value by `tools/parse_files.py`. +These constants are declared in the device `definition.yml` file, and they can used in any file in `src/`. + +For example, if I write a file `src/lib/example.py`, and include the following line: +``` Py +_MH_DISPLAY_WIDTH = const(1234) +``` +When I run `parse_files.py`, the corrisponding output file for the Cardputer will be created in `MicroHydra/CARDPUTER/lib/example.py`, and the line will now look like this: +``` Py +_MH_DISPLAY_WIDTH = const(240) +``` + +*Side note:* +> Because MicroPython supports 'real' constants, this functionality can be especially useful for MicroHydra. +> When a MicroPython program is run, it must first be compiled into bytecode. At this time, the MicroPython compiler actually replaces the constants with hard-coded values. +> This can slightly increase speed (no need to look-up the values), and can decrease RAM usage (no need to store the value name). + + + +


+ +## Hydra conditionals + +It's really difficult to account for all the possible differences between devices just by using device constants, and separate driver files. +This is especially true because of the limited memory available to work with on these devices *(assuming you don't have PSRAM)*, so you really don't want to have code you don't need just taking up memory space. + +That's where this final (and most complicated) feature of `tools/parse_files.py` comes in. + +

+ +Hydra conditionals are used to selectively include or exclude blocks of code from `src/` based on device names, included features, and whether the code is 'frozen' or not. + +These statements take the following form: +``` Py +# mh_if {feature}: +my_code() +# mh_end_if +``` +In the above example, if {feature} is in the device-specific `definition.yml` file, then the line `my_code()` will be included in the output code for that device. Otherwise, the entire line is removed. +The `# mh_if...` and `# mh_end_if` lines will be removed regardless of whether or not {feature} matches a feature in the device definition. + +
+ +You can also use the "not" keyword: +``` Py +# mh_if not {feature}: +my_code() +# mh_end_if +``` +Which, as expected, will exclude this line of code when {feature} exists on a device. + +
+ +If/elif/else statements are also supported: +``` Py +# mh_if {feature}: +feature_code() +# mh_else_if {other_feature}: +other_feature_code() +# mh_else: +no_features_code() +# mh_end_if +``` + +
+ +In order to make testing this code directly a bit easier, these conditionals also work on 'commented-out' code. +In this example, the commented out code will be uncommented if the device has no touchscreen: +``` Py +# mh_if touchscreen: +print("this device has a touchscreen!") +# mh_else: +# print("this device has no touchscreen!") +# mh_end_if +``` + +> Note the spacing after the `#`. In order for the commenting/uncommenting to work correctly, this extra space needs to be there. +> This is because Python cares a lot about indentation, and without this space, the `parse_files` script might not correctly guess what the actual indentation was meant to be. + +

+ +Finally, here are some real examples from `src/` to illustrate these features further! + +> From launcher/launcher.py: +``` Py +DISPLAY = display.Display( + # mh_if spi_ram: + # use_tiny_buf=False, + # mh_else: + use_tiny_buf=True, + # mh_end_if + ) +``` +``` Py + # add an appname for builtin file browser + app_names.append("Files") + # mh_if frozen: + # app_paths["Files"] = ".frozen/launcher/files" + # mh_else: + app_paths["Files"] = "/launcher/files" + # mh_end_if +``` + +
+ +> From launcher/settings.py: +``` Py +# mh_if touchscreen: +def process_touch(keys): + events = kb.get_touch_events() + for event in events: + if hasattr(event, 'direction'): + # is a swipe + keys.append(event.direction) + + elif _CONFIRM_MIN_X < event.x < _CONFIRM_MAX_X \ + and _CONFIRM_MIN_Y < event.y < _CONFIRM_MAX_Y: + keys.append("ENT") +# mh_end_if +``` +``` Py +while True: + keys = kb.get_new_keys() + + # mh_if touchscreen: + process_touch(keys) + # mh_end_if +``` + +
+ +> From lib/display/display.py: +``` Py + def __init__(self, use_tiny_buf=False, **kwargs): + # mh_if TDECK: + # # Enable Peripherals: + # machine.Pin(10, machine.Pin.OUT, value=1) + # mh_end_if +``` + +

+ +*Final note on hydra conditionals:* +> These conditionals can also be nested. However, this is discouraged because it becomes very hard to read (because indentation must be maintained to match the original code). +> It's an option in your toolkit, but please try to find another solution first if it comes to that.