[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:
SG
2022-09-15 02:11:38 +10:00
committed by Aleksandr Kutuzov
parent 0f6f9ad52e
commit b9a766d909
895 changed files with 8862 additions and 1465 deletions

View File

@@ -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
)
)