lvgl / lvgl-project-creator

Create LVGL projects quickly and easily
6 stars 1 forks source link

Zephyr intergration #5

Open kisvegabor opened 1 week ago

kisvegabor commented 1 week ago

cc @faxe1008

Finally, the project creator is released! Based on our previous discussion, we are ready to jump into Zephyr integration.

If I understood correctly we should generate manifest.json files (similar to these) from the board description that you already have in Zephyr.

Some notes:

faxe1008 commented 1 week ago

Is it possible to make the manifest an array instead of a single board? Also, is there a plan for a shield mechanism of sorts? So you can choose your base board and whatever display shield. Most devboards have uno r3 compatible headers which would duplicate all information of the base board if we list each combination dedicated.

kisvegabor commented 1 week ago

Is it possible to make the manifest an array instead of a single board?

Absolutely, yes!

Also, is there a plan for a shield mechanism of sorts?

So for example we have this for a given board:

An somewhere else we list:

And we merge to two to have

This way the user will see the shield options, they can select a compatible display, and we can generate the get started instructions accordingly. If you agree with this, think we can create 3 JSON files:

  1. A long one for all the board with the shield interfaces
  2. An other one for the list of shields and compatible displays
  3. A final one where 1) and 2) and merged by a script.

How does it sound?

If it seems doable can you link where we can find the list of all boards (ideally with a minimal tech spec, like CPU, memories, etc), compatible shields, and list of displays (with minimal specs again) and shield options for the displays.

faxe1008 commented 3 days ago

One thing that is absolutely needed imo is a validation for the manifest of some kind:

import json
from jsonschema import validate, ValidationError
import argparse

schema = {
    "type": "array",
    "items": {
        "type": "object",
        "properties": {
            "name": {"type": "string"},
            "maintainer": {"type": "string"},
            "hostOperatingsystem": {
                "type": "array",
                "items": {"type": "string"}
            },
            "environment": {
                "type": "array",
                "items": {"type": "string"}
            },
            "hardware": {
                "type": "object",
                "properties": {
                    "chipVendor": {"type": "string"},
                    "manufacturer": {"type": "string"},
                    "specs": {
                        "type": "object",
                        "properties": {
                            "MCU": {"type": "string"},
                            "RAM": {"type": "string"},
                            "Flash": {"type": "string"},
                            "GPU": {"type": ["string", "null"]},
                            "Resolution": {"type": "string"},
                            "Display Size": {"type": "string"},
                            "Interface": {"type": "string"},
                            "Color Depth": {"type": "string"},
                            "Technology": {"type": "string"},
                            "DPI": {"type": "string"},
                            "Touch Pad": {"type": "string"}
                        },
                        "required": ["MCU", "RAM", "Flash"]
                    }
                },
                "required": ["chipVendor", "manufacturer", "specs"]
            },
            "description": {"type": "string"},
            "shortDescription": {"type": "string"},
            "urlToClone": {"type": "string"},
            "logo": {"type": "string"},
            "branches": {
                "type": "array",
                "items": {"type": "string"}
            },
            "settings": {
                "type": "array",
                "items": {
                    "type": "object",
                    "properties": {
                        "type": {"type": "string"},
                        "label": {"type": "string"},
                        "options": {
                            "type": "array",
                            "items": {
                                "type": "object",
                                "properties": {
                                    "name": {"type": "string"},
                                    "value": {"type": "string"},
                                    "default": {"type": "string", "enum": ["true", "false"], "default": "false"}
                                },
                                "required": ["name", "value"]
                            }
                        },
                        "actions": {
                            "type": "array",
                            "items": {
                                "type": "object",
                                "properties": {
                                    "ifValue": {"type": "string"},
                                    "toAppend": {"type": "string"},
                                    "toReplace": {"type": "string"},
                                    "newContent": {"type": "string"},
                                    "filePath": {"type": "string"}
                                }
                            }
                        }
                    },
                    "required": ["type", "label", "options"]
                }
            }
        },
        "required": ["name", "maintainer", "hostOperatingsystem", "environment", "description", "shortDescription", "urlToClone", "logo", "branches", "settings"]
    }
}

def validate_json(json_data):
    try:
        validate(instance=json_data, schema=schema)
        print("JSON is valid")
    except ValidationError as e:
        print(f"JSON validation error: {e.message}")
        if e.path:
            print(f"Error location: {' -> '.join(map(str, e.path))}")

def main():
    parser = argparse.ArgumentParser(description="Validate JSON structure against a defined schema.")
    parser.add_argument('file', type=argparse.FileType('r'), help='Path to the JSON file')

    args = parser.parse_args()

    try:
        with args.file as f:
            json_data = json.load(f)
        validate_json(json_data)
    except JSONDecodeError as e:
        print(f"Error reading JSON file: {e.msg} at line {e.lineno}, column {e.colno}")
    except ValidationError as e:
        print(f"Schema validation error: {e.message}")

if __name__ == "__main__":
    main()
kisvegabor commented 2 days ago

Good idea, just added here

faxe1008 commented 2 days ago

Just downloaded the creator and took a look how the data is displayed in the GUI: image

Your proposal makes sense, but I fear this will make it so that there are like 300+ boards on the starting page if we add one entry per board. I would rather have it like this:

In the main menu page you can select "LVGL on Zephyr".

In the options for that you can select a board (so the MCU specs will need to be depedant on the selection)
Depending on the selection of the board the dropdown for the shield changes and offers all compatible shields.

So essentially this would need a restructure of the JSON, having the "environment/plattform/vendor" be the outer structure and have a list of supported MCUs inside it.