[FL-2627] Flipper applications: SDK, build and debug system (#1387)
* Added support for running applications from SD card (FAPs - Flipper Application Packages) * Added plugin_dist target for fbt to build FAPs * All apps of type FlipperAppType.EXTERNAL and FlipperAppType.PLUGIN are built as FAPs by default * Updated VSCode configuration for new fbt features - re-deploy stock configuration to use them * Added debugging support for FAPs with fbt debug & VSCode * Added public firmware API with automated versioning Co-authored-by: hedger <hedger@users.noreply.github.com> Co-authored-by: SG <who.just.the.doctor@gmail.com> Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
from dataclasses import dataclass, field
|
||||
from typing import List, Optional
|
||||
from typing import List, Optional, Tuple
|
||||
from enum import Enum
|
||||
import os
|
||||
|
||||
@@ -25,7 +25,7 @@ class FlipperAppType(Enum):
|
||||
class FlipperApplication:
|
||||
appid: str
|
||||
apptype: FlipperAppType
|
||||
name: Optional[str] = None
|
||||
name: Optional[str] = ""
|
||||
entry_point: Optional[str] = None
|
||||
flags: List[str] = field(default_factory=lambda: ["Default"])
|
||||
cdefines: List[str] = field(default_factory=list)
|
||||
@@ -35,7 +35,14 @@ class FlipperApplication:
|
||||
stack_size: int = 2048
|
||||
icon: Optional[str] = None
|
||||
order: int = 0
|
||||
_appdir: Optional[str] = None
|
||||
sdk_headers: List[str] = field(default_factory=list)
|
||||
version: Tuple[int] = field(default_factory=lambda: (0, 0))
|
||||
sources: List[str] = field(default_factory=lambda: ["*.c*"])
|
||||
fap_icon: Optional[str] = None
|
||||
fap_libs: List[str] = field(default_factory=list)
|
||||
fap_category: str = ""
|
||||
_appdir: Optional[object] = None
|
||||
_apppath: Optional[str] = None
|
||||
|
||||
|
||||
class AppManager:
|
||||
@@ -50,7 +57,13 @@ class AppManager:
|
||||
f"Missing application manifest for '{appname}'"
|
||||
)
|
||||
|
||||
def load_manifest(self, app_manifest_path: str, app_dir_name: str):
|
||||
def find_by_appdir(self, appdir: str):
|
||||
for app in self.known_apps.values():
|
||||
if app._appdir.name == appdir:
|
||||
return app
|
||||
return None
|
||||
|
||||
def load_manifest(self, app_manifest_path: str, app_dir_node: object):
|
||||
if not os.path.exists(app_manifest_path):
|
||||
raise FlipperManifestException(
|
||||
f"App manifest not found at path {app_manifest_path}"
|
||||
@@ -61,7 +74,14 @@ class AppManager:
|
||||
|
||||
def App(*args, **kw):
|
||||
nonlocal app_manifests
|
||||
app_manifests.append(FlipperApplication(*args, **kw, _appdir=app_dir_name))
|
||||
app_manifests.append(
|
||||
FlipperApplication(
|
||||
*args,
|
||||
**kw,
|
||||
_appdir=app_dir_node,
|
||||
_apppath=os.path.dirname(app_manifest_path),
|
||||
),
|
||||
)
|
||||
|
||||
try:
|
||||
with open(app_manifest_path, "rt") as manifest_file:
|
||||
@@ -172,19 +192,32 @@ class AppBuildset:
|
||||
cdefs.update(app.cdefines)
|
||||
return sorted(list(cdefs))
|
||||
|
||||
def get_apps_of_type(self, apptype: FlipperAppType):
|
||||
def get_sdk_headers(self):
|
||||
sdk_headers = []
|
||||
for app in self.apps:
|
||||
sdk_headers.extend([app._appdir.File(header) for header in app.sdk_headers])
|
||||
return sdk_headers
|
||||
|
||||
def get_apps_of_type(self, apptype: FlipperAppType, all_known: bool = False):
|
||||
return sorted(
|
||||
filter(lambda app: app.apptype == apptype, self.apps),
|
||||
filter(
|
||||
lambda app: app.apptype == apptype,
|
||||
self.appmgr.known_apps.values() if all_known else self.apps,
|
||||
),
|
||||
key=lambda app: app.order,
|
||||
)
|
||||
|
||||
def get_builtin_apps(self):
|
||||
return list(
|
||||
filter(lambda app: app.apptype in self.BUILTIN_APP_TYPES, self.apps)
|
||||
)
|
||||
|
||||
def get_builtin_app_folders(self):
|
||||
return sorted(
|
||||
set(
|
||||
app._appdir
|
||||
for app in filter(
|
||||
lambda app: app.apptype in self.BUILTIN_APP_TYPES, self.apps
|
||||
)
|
||||
(app._appdir, source_type)
|
||||
for app in self.get_builtin_apps()
|
||||
for source_type in app.sources
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user