[FL-3174] Dolphin builder in ufbt; minor ufbt/fbt improvements (#2601)

* ufbt: added "dolphin_ext" target (expects "external" subfolder in cwd with dolphin assets); cleaned up unused code
* ufbt: codestyle fixes
* scripts: fixed style according to ruff linter
* scripts: additional cleanup & codestyle fixes
* github: pass target hw code when installing local SDK with ufbt
* ufbt: added error message for missing folder in dolphin builder
* scripts: more linter fixes
* sdk: added flipper_format_stream; ufbt: support for --extra-define
* fbt: reduced amount of global defines
* scripts, fbt: rearranged imports

Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
This commit is contained in:
hedger 2023-05-03 08:48:49 +03:00 committed by GitHub
parent 015ab4a024
commit c3ececcf96
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
73 changed files with 311 additions and 382 deletions

View File

@ -193,12 +193,14 @@ jobs:
TARGET="$(echo '${{ matrix.target }}' | sed 's/f//')"; \ TARGET="$(echo '${{ matrix.target }}' | sed 's/f//')"; \
./fbt TARGET_HW=$TARGET DEBUG=0 COMPACT=1 fap_dist updater_package ./fbt TARGET_HW=$TARGET DEBUG=0 COMPACT=1 fap_dist updater_package
echo "sdk-file=$(ls dist/${{ matrix.target }}-*/flipper-z-${{ matrix.target }}-sdk-*.zip)" >> $GITHUB_OUTPUT echo "sdk-file=$(ls dist/${{ matrix.target }}-*/flipper-z-${{ matrix.target }}-sdk-*.zip)" >> $GITHUB_OUTPUT
echo "hw-target-code=$TARGET" >> $GITHUB_OUTPUT
- name: Deploy uFBT with SDK - name: Deploy uFBT with SDK
uses: flipperdevices/flipperzero-ufbt-action@v0.1.0 uses: flipperdevices/flipperzero-ufbt-action@v0.1.0
with: with:
task: setup task: setup
sdk-file: ${{ steps.build-fw.outputs.sdk-file }} sdk-file: ${{ steps.build-fw.outputs.sdk-file }}
sdk-hw-target: ${{ steps.build-fw.outputs.hw-target-code }}
- name: Build test app with SDK - name: Build test app with SDK
run: | run: |

View File

@ -1,7 +1,7 @@
Import("env")
from fbt.version import get_git_commit_unix_timestamp from fbt.version import get_git_commit_unix_timestamp
Import("env")
assetsenv = env.Clone( assetsenv = env.Clone(
tools=["fbt_assets"], tools=["fbt_assets"],
FW_LIB_NAME="assets", FW_LIB_NAME="assets",

View File

@ -1,5 +1,3 @@
Import("ENV", "fw_build_meta")
from SCons.Errors import UserError from SCons.Errors import UserError
from SCons.Node import FS from SCons.Node import FS
@ -10,6 +8,8 @@ from fbt_extra.util import (
link_elf_dir_as_latest, link_elf_dir_as_latest,
) )
Import("ENV", "fw_build_meta")
# Building initial C environment for libs # Building initial C environment for libs
env = ENV.Clone( env = ENV.Clone(
tools=[ tools=[

View File

@ -1,5 +1,5 @@
entry,status,name,type,params entry,status,name,type,params
Version,+,23.1,, Version,+,23.3,,
Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli.h,,
Header,+,applications/services/cli/cli_vcp.h,, Header,+,applications/services/cli/cli_vcp.h,,
@ -112,6 +112,7 @@ Header,+,lib/flipper_application/plugins/composite_resolver.h,,
Header,+,lib/flipper_application/plugins/plugin_manager.h,, Header,+,lib/flipper_application/plugins/plugin_manager.h,,
Header,+,lib/flipper_format/flipper_format.h,, Header,+,lib/flipper_format/flipper_format.h,,
Header,+,lib/flipper_format/flipper_format_i.h,, Header,+,lib/flipper_format/flipper_format_i.h,,
Header,+,lib/flipper_format/flipper_format_stream.h,,
Header,+,lib/libusb_stm32/inc/hid_usage_button.h,, Header,+,lib/libusb_stm32/inc/hid_usage_button.h,,
Header,+,lib/libusb_stm32/inc/hid_usage_consumer.h,, Header,+,lib/libusb_stm32/inc/hid_usage_consumer.h,,
Header,+,lib/libusb_stm32/inc/hid_usage_desktop.h,, Header,+,lib/libusb_stm32/inc/hid_usage_desktop.h,,
@ -755,6 +756,11 @@ Function,+,flipper_format_read_uint32,_Bool,"FlipperFormat*, const char*, uint32
Function,+,flipper_format_rewind,_Bool,FlipperFormat* Function,+,flipper_format_rewind,_Bool,FlipperFormat*
Function,+,flipper_format_seek_to_end,_Bool,FlipperFormat* Function,+,flipper_format_seek_to_end,_Bool,FlipperFormat*
Function,+,flipper_format_set_strict_mode,void,"FlipperFormat*, _Bool" Function,+,flipper_format_set_strict_mode,void,"FlipperFormat*, _Bool"
Function,+,flipper_format_stream_delete_key_and_write,_Bool,"Stream*, FlipperStreamWriteData*, _Bool"
Function,+,flipper_format_stream_get_value_count,_Bool,"Stream*, const char*, uint32_t*, _Bool"
Function,+,flipper_format_stream_read_value_line,_Bool,"Stream*, const char*, FlipperStreamValue, void*, size_t, _Bool"
Function,+,flipper_format_stream_write_comment_cstr,_Bool,"Stream*, const char*"
Function,+,flipper_format_stream_write_value_line,_Bool,"Stream*, FlipperStreamWriteData*"
Function,+,flipper_format_string_alloc,FlipperFormat*, Function,+,flipper_format_string_alloc,FlipperFormat*,
Function,+,flipper_format_update_bool,_Bool,"FlipperFormat*, const char*, const _Bool*, const uint16_t" Function,+,flipper_format_update_bool,_Bool,"FlipperFormat*, const char*, const _Bool*, const uint16_t"
Function,+,flipper_format_update_float,_Bool,"FlipperFormat*, const char*, const float*, const uint16_t" Function,+,flipper_format_update_float,_Bool,"FlipperFormat*, const char*, const float*, const uint16_t"

1 entry status name type params
2 Version + 23.1 23.3
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/cli/cli.h
5 Header + applications/services/cli/cli_vcp.h
112 Header + lib/flipper_application/plugins/plugin_manager.h
113 Header + lib/flipper_format/flipper_format.h
114 Header + lib/flipper_format/flipper_format_i.h
115 Header + lib/flipper_format/flipper_format_stream.h
116 Header + lib/libusb_stm32/inc/hid_usage_button.h
117 Header + lib/libusb_stm32/inc/hid_usage_consumer.h
118 Header + lib/libusb_stm32/inc/hid_usage_desktop.h
756 Function + flipper_format_rewind _Bool FlipperFormat*
757 Function + flipper_format_seek_to_end _Bool FlipperFormat*
758 Function + flipper_format_set_strict_mode void FlipperFormat*, _Bool
759 Function + flipper_format_stream_delete_key_and_write _Bool Stream*, FlipperStreamWriteData*, _Bool
760 Function + flipper_format_stream_get_value_count _Bool Stream*, const char*, uint32_t*, _Bool
761 Function + flipper_format_stream_read_value_line _Bool Stream*, const char*, FlipperStreamValue, void*, size_t, _Bool
762 Function + flipper_format_stream_write_comment_cstr _Bool Stream*, const char*
763 Function + flipper_format_stream_write_value_line _Bool Stream*, FlipperStreamWriteData*
764 Function + flipper_format_string_alloc FlipperFormat*
765 Function + flipper_format_update_bool _Bool FlipperFormat*, const char*, const _Bool*, const uint16_t
766 Function + flipper_format_update_float _Bool FlipperFormat*, const char*, const float*, const uint16_t

View File

@ -1,5 +1,5 @@
entry,status,name,type,params entry,status,name,type,params
Version,+,23.1,, Version,+,23.3,,
Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli.h,,
Header,+,applications/services/cli/cli_vcp.h,, Header,+,applications/services/cli/cli_vcp.h,,
@ -118,6 +118,7 @@ Header,+,lib/flipper_application/plugins/composite_resolver.h,,
Header,+,lib/flipper_application/plugins/plugin_manager.h,, Header,+,lib/flipper_application/plugins/plugin_manager.h,,
Header,+,lib/flipper_format/flipper_format.h,, Header,+,lib/flipper_format/flipper_format.h,,
Header,+,lib/flipper_format/flipper_format_i.h,, Header,+,lib/flipper_format/flipper_format_i.h,,
Header,+,lib/flipper_format/flipper_format_stream.h,,
Header,+,lib/ibutton/ibutton_key.h,, Header,+,lib/ibutton/ibutton_key.h,,
Header,+,lib/ibutton/ibutton_protocols.h,, Header,+,lib/ibutton/ibutton_protocols.h,,
Header,+,lib/ibutton/ibutton_worker.h,, Header,+,lib/ibutton/ibutton_worker.h,,
@ -918,6 +919,11 @@ Function,+,flipper_format_read_uint32,_Bool,"FlipperFormat*, const char*, uint32
Function,+,flipper_format_rewind,_Bool,FlipperFormat* Function,+,flipper_format_rewind,_Bool,FlipperFormat*
Function,+,flipper_format_seek_to_end,_Bool,FlipperFormat* Function,+,flipper_format_seek_to_end,_Bool,FlipperFormat*
Function,+,flipper_format_set_strict_mode,void,"FlipperFormat*, _Bool" Function,+,flipper_format_set_strict_mode,void,"FlipperFormat*, _Bool"
Function,+,flipper_format_stream_delete_key_and_write,_Bool,"Stream*, FlipperStreamWriteData*, _Bool"
Function,+,flipper_format_stream_get_value_count,_Bool,"Stream*, const char*, uint32_t*, _Bool"
Function,+,flipper_format_stream_read_value_line,_Bool,"Stream*, const char*, FlipperStreamValue, void*, size_t, _Bool"
Function,+,flipper_format_stream_write_comment_cstr,_Bool,"Stream*, const char*"
Function,+,flipper_format_stream_write_value_line,_Bool,"Stream*, FlipperStreamWriteData*"
Function,+,flipper_format_string_alloc,FlipperFormat*, Function,+,flipper_format_string_alloc,FlipperFormat*,
Function,+,flipper_format_update_bool,_Bool,"FlipperFormat*, const char*, const _Bool*, const uint16_t" Function,+,flipper_format_update_bool,_Bool,"FlipperFormat*, const char*, const _Bool*, const uint16_t"
Function,+,flipper_format_update_float,_Bool,"FlipperFormat*, const char*, const float*, const uint16_t" Function,+,flipper_format_update_float,_Bool,"FlipperFormat*, const char*, const float*, const uint16_t"

1 entry status name type params
2 Version + 23.1 23.3
3 Header + applications/services/bt/bt_service/bt.h
4 Header + applications/services/cli/cli.h
5 Header + applications/services/cli/cli_vcp.h
118 Header + lib/flipper_application/plugins/plugin_manager.h
119 Header + lib/flipper_format/flipper_format.h
120 Header + lib/flipper_format/flipper_format_i.h
121 Header + lib/flipper_format/flipper_format_stream.h
122 Header + lib/ibutton/ibutton_key.h
123 Header + lib/ibutton/ibutton_protocols.h
124 Header + lib/ibutton/ibutton_worker.h
919 Function + flipper_format_rewind _Bool FlipperFormat*
920 Function + flipper_format_seek_to_end _Bool FlipperFormat*
921 Function + flipper_format_set_strict_mode void FlipperFormat*, _Bool
922 Function + flipper_format_stream_delete_key_and_write _Bool Stream*, FlipperStreamWriteData*, _Bool
923 Function + flipper_format_stream_get_value_count _Bool Stream*, const char*, uint32_t*, _Bool
924 Function + flipper_format_stream_read_value_line _Bool Stream*, const char*, FlipperStreamValue, void*, size_t, _Bool
925 Function + flipper_format_stream_write_comment_cstr _Bool Stream*, const char*
926 Function + flipper_format_stream_write_value_line _Bool Stream*, FlipperStreamWriteData*
927 Function + flipper_format_string_alloc FlipperFormat*
928 Function + flipper_format_update_bool _Bool FlipperFormat*, const char*, const _Bool*, const uint16_t
929 Function + flipper_format_update_float _Bool FlipperFormat*, const char*, const float*, const uint16_t

View File

@ -7,6 +7,7 @@ env.Append(
SDK_HEADERS=[ SDK_HEADERS=[
File("flipper_format.h"), File("flipper_format.h"),
File("flipper_format_i.h"), File("flipper_format_i.h"),
File("flipper_format_stream.h"),
], ],
) )

View File

@ -7,9 +7,6 @@ env.Append(
"#/lib/FreeRTOS-Kernel/portable/GCC/ARM_CM4F", "#/lib/FreeRTOS-Kernel/portable/GCC/ARM_CM4F",
"#/lib/FreeRTOS-glue", "#/lib/FreeRTOS-glue",
], ],
CPPDEFINES=[
"HAVE_FREERTOS",
],
) )

View File

@ -4,9 +4,6 @@ env.Append(
CPPPATH=[ CPPPATH=[
"#/lib/libusb_stm32/inc", "#/lib/libusb_stm32/inc",
], ],
CPPDEFINES=[
("USB_PMASIZE", "0x400"),
],
SDK_HEADERS=env.GlobRecursive( SDK_HEADERS=env.GlobRecursive(
"*.h", "*.h",
Dir("libusb_stm32/inc"), Dir("libusb_stm32/inc"),
@ -16,6 +13,11 @@ env.Append(
libenv = env.Clone(FW_LIB_NAME="usb_stm32") libenv = env.Clone(FW_LIB_NAME="usb_stm32")
libenv.ApplyLibFlags() libenv.ApplyLibFlags()
libenv.Append(
CPPDEFINES=[
("USB_PMASIZE", "0x400"),
],
)
sources = [ sources = [

View File

@ -4,14 +4,16 @@ env.Append(
CPPPATH=[ CPPPATH=[
"#/lib/littlefs", "#/lib/littlefs",
], ],
CPPDEFINES=[
("LFS_CONFIG", "lfs_config.h"),
],
) )
libenv = env.Clone(FW_LIB_NAME="littlefs") libenv = env.Clone(FW_LIB_NAME="littlefs")
libenv.ApplyLibFlags() libenv.ApplyLibFlags()
libenv.Append(
CPPDEFINES=[
("LFS_CONFIG", "lfs_config.h"),
],
)
sources = Glob("littlefs/*.c", source=True) sources = Glob("littlefs/*.c", source=True)

View File

@ -1,7 +1,7 @@
Import("env")
from fbt.util import GLOB_FILE_EXCLUSION from fbt.util import GLOB_FILE_EXCLUSION
Import("env")
env.Append( env.Append(
CPPPATH=[ CPPPATH=[
"#/lib/digital_signal", "#/lib/digital_signal",

View File

@ -1,8 +1,8 @@
Import("env")
from fbt.version import get_fast_git_version_id from fbt.version import get_fast_git_version_id
Import("env")
env.Append( env.Append(
CPPPATH=[ CPPPATH=[
"#/lib/toolbox", "#/lib/toolbox",

View File

@ -1,10 +1,10 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import os
from flipper.app import App from flipper.app import App
from flipper.assets.icon import file2image from flipper.assets.icon import file2image
import os
ICONS_SUPPORTED_FORMATS = ["png"] ICONS_SUPPORTED_FORMATS = ["png"]
ICONS_TEMPLATE_H_HEADER = """#pragma once ICONS_TEMPLATE_H_HEADER = """#pragma once
@ -127,7 +127,7 @@ class Main(App):
if not filenames: if not filenames:
continue continue
if "frame_rate" in filenames: if "frame_rate" in filenames:
self.logger.debug(f"Folder contains animation") self.logger.debug("Folder contains animation")
icon_name = "A_" + os.path.split(dirpath)[1].replace("-", "_") icon_name = "A_" + os.path.split(dirpath)[1].replace("-", "_")
width = height = None width = height = None
frame_count = 0 frame_count = 0
@ -186,7 +186,7 @@ class Main(App):
icons_c.write("\n") icons_c.write("\n")
icons.append((icon_name, width, height, 0, 1)) icons.append((icon_name, width, height, 0, 1))
# Create array of images: # Create array of images:
self.logger.debug(f"Finalizing source file") self.logger.debug("Finalizing source file")
for name, width, height, frame_rate, frame_count in icons: for name, width, height, frame_rate, frame_count in icons:
icons_c.write( icons_c.write(
ICONS_TEMPLATE_C_ICONS.format( ICONS_TEMPLATE_C_ICONS.format(
@ -201,7 +201,7 @@ class Main(App):
icons_c.close() icons_c.close()
# Create Public Header # Create Public Header
self.logger.debug(f"Creating header") self.logger.debug("Creating header")
icons_h = open( icons_h = open(
os.path.join(self.args.output_directory, f"{self.args.filename}.h"), os.path.join(self.args.output_directory, f"{self.args.filename}.h"),
"w", "w",
@ -211,7 +211,7 @@ class Main(App):
for name, width, height, frame_rate, frame_count in icons: for name, width, height, frame_rate, frame_count in icons:
icons_h.write(ICONS_TEMPLATE_H_ICON_NAME.format(name=name)) icons_h.write(ICONS_TEMPLATE_H_ICON_NAME.format(name=name))
icons_h.close() icons_h.close()
self.logger.debug(f"Done") self.logger.debug("Done")
return 0 return 0
def manifest(self): def manifest(self):
@ -232,7 +232,7 @@ class Main(App):
new_manifest = Manifest(self.args.timestamp) new_manifest = Manifest(self.args.timestamp)
new_manifest.create(directory_path) new_manifest.create(directory_path)
self.logger.info(f"Comparing new manifest with existing") self.logger.info("Comparing new manifest with existing")
only_in_old, changed, only_in_new = Manifest.compare(old_manifest, new_manifest) only_in_old, changed, only_in_new = Manifest.compare(old_manifest, new_manifest)
for record in only_in_old: for record in only_in_old:
self.logger.info(f"Only in old: {record}") self.logger.info(f"Only in old: {record}")
@ -246,38 +246,38 @@ class Main(App):
else: else:
self.logger.info("Manifest is up-to-date!") self.logger.info("Manifest is up-to-date!")
self.logger.info(f"Complete") self.logger.info("Complete")
return 0 return 0
def copro(self): def copro(self):
from flipper.assets.copro import Copro from flipper.assets.copro import Copro
self.logger.info(f"Bundling coprocessor binaries") self.logger.info("Bundling coprocessor binaries")
copro = Copro(self.args.mcu) copro = Copro(self.args.mcu)
self.logger.info(f"Loading CUBE info") self.logger.info("Loading CUBE info")
copro.loadCubeInfo(self.args.cube_dir, self.args.cube_ver) copro.loadCubeInfo(self.args.cube_dir, self.args.cube_ver)
self.logger.info(f"Bundling") self.logger.info("Bundling")
copro.bundle( copro.bundle(
self.args.output_dir, self.args.output_dir,
self.args.stack_file, self.args.stack_file,
self.args.stack_type, self.args.stack_type,
self.args.stack_addr, self.args.stack_addr,
) )
self.logger.info(f"Complete") self.logger.info("Complete")
return 0 return 0
def dolphin(self): def dolphin(self):
from flipper.assets.dolphin import Dolphin from flipper.assets.dolphin import Dolphin
self.logger.info(f"Processing Dolphin sources") self.logger.info("Processing Dolphin sources")
dolphin = Dolphin() dolphin = Dolphin()
self.logger.info(f"Loading data") self.logger.info("Loading data")
dolphin.load(self.args.input_directory) dolphin.load(self.args.input_directory)
self.logger.info(f"Packing") self.logger.info("Packing")
dolphin.pack(self.args.output_directory, self.args.symbol_name) dolphin.pack(self.args.output_directory, self.args.symbol_name)
self.logger.info(f"Complete") self.logger.info("Complete")
return 0 return 0

View File

@ -1,12 +1,12 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import os
import posixpath
from flipper.app import App from flipper.app import App
from flipper.storage import FlipperStorage, FlipperStorageOperations from flipper.storage import FlipperStorage, FlipperStorageOperations
from flipper.utils.cdc import resolve_port from flipper.utils.cdc import resolve_port
import os
import posixpath
class Main(App): class Main(App):
def init(self): def init(self):

View File

@ -1,7 +1,7 @@
from dataclasses import dataclass, field
from typing import List, Optional, Tuple, Callable
from enum import Enum
import os import os
from dataclasses import dataclass, field
from enum import Enum
from typing import Callable, List, Optional, Tuple
class FlipperManifestException(Exception): class FlipperManifestException(Exception):
@ -93,7 +93,7 @@ class AppManager:
def get(self, appname: str): def get(self, appname: str):
try: try:
return self.known_apps[appname] return self.known_apps[appname]
except KeyError as _: except KeyError:
raise FlipperManifestException( raise FlipperManifestException(
f"Missing application manifest for '{appname}'" f"Missing application manifest for '{appname}'"
) )
@ -223,6 +223,7 @@ class AppBuildset:
return self.appmgr.get(app_name).supports_hardware_target(self.hw_target) return self.appmgr.get(app_name).supports_hardware_target(self.hw_target)
def _get_app_depends(self, app_name: str) -> List[str]: def _get_app_depends(self, app_name: str) -> List[str]:
app_def = self.appmgr.get(app_name)
# Skip app if its target is not supported by the target we are building for # Skip app if its target is not supported by the target we are building for
if not self._check_if_app_target_supported(app_name): if not self._check_if_app_target_supported(app_name):
self._writer( self._writer(
@ -230,7 +231,6 @@ class AppBuildset:
) )
return [] return []
app_def = self.appmgr.get(app_name)
return list( return list(
filter( filter(
self._check_if_app_target_supported, self._check_if_app_target_supported,
@ -296,7 +296,7 @@ class AppBuildset:
try: try:
parent_app = self.appmgr.get(parent_app_id) parent_app = self.appmgr.get(parent_app_id)
parent_app._plugins.append(extension_app) parent_app._plugins.append(extension_app)
except FlipperManifestException as e: except FlipperManifestException:
self._writer( self._writer(
f"Module {extension_app.appid} has unknown parent {parent_app_id}" f"Module {extension_app.appid} has unknown parent {parent_app_id}"
) )

View File

@ -1,12 +1,10 @@
from dataclasses import dataclass
import os import os
import struct import struct
from dataclasses import dataclass, field from dataclasses import dataclass, field
from .appmanifest import FlipperApplication
from flipper.assets.icon import file2image from flipper.assets.icon import file2image
from .appmanifest import FlipperApplication
_MANIFEST_MAGIC = 0x52474448 _MANIFEST_MAGIC = 0x52474448

View File

@ -1,5 +1,5 @@
import os
import hashlib import hashlib
import os
import struct import struct
from typing import TypedDict from typing import TypedDict

View File

@ -1,20 +1,13 @@
import operator
import os
import csv import csv
import operator import operator
import os
from enum import Enum, auto
from typing import Set, ClassVar, Any
from dataclasses import dataclass from dataclasses import dataclass
from enum import Enum, auto
from typing import Any, ClassVar, Set
from ansi.color import fg from ansi.color import fg
from . import ( from . import ApiEntries, ApiEntryFunction, ApiEntryVariable, ApiHeader
ApiEntries,
ApiEntryFunction,
ApiEntryVariable,
ApiHeader,
)
@dataclass(frozen=True) @dataclass(frozen=True)
@ -137,7 +130,7 @@ class SdkCache:
f"API version is still WIP: {self.version}. Review the changes and re-run command." f"API version is still WIP: {self.version}. Review the changes and re-run command."
) )
) )
print(f"CSV file entries to mark up:") print("CSV file entries to mark up:")
print( print(
fg.yellow( fg.yellow(
"\n".join( "\n".join(

View File

@ -1,10 +1,9 @@
import SCons
from SCons.Subst import quote_spaces
from SCons.Errors import StopError
import re
import os import os
import re
import SCons
from SCons.Errors import StopError
from SCons.Subst import quote_spaces
WINPATHSEP_RE = re.compile(r"\\([^\"'\\]|$)") WINPATHSEP_RE = re.compile(r"\\([^\"'\\]|$)")

View File

@ -1,5 +1,5 @@
import subprocess
import datetime import datetime
import subprocess
from functools import cache from functools import cache

View File

@ -3,7 +3,7 @@ def exists():
def generate(env): def generate(env):
if ccache := env.WhereIs("ccache"): if env.WhereIs("ccache"):
env["CCACHE"] = "ccache" env["CCACHE"] = "ccache"
env["CC_NOCACHE"] = env["CC"] env["CC_NOCACHE"] = env["CC"]
env["CC"] = "$CCACHE $CC_NOCACHE" env["CC"] = "$CCACHE $CC_NOCACHE"

View File

@ -1,15 +1,11 @@
from SCons.Errors import StopError import subprocess
from SCons.Tool import asm
from SCons.Tool import gcc
from SCons.Tool import gxx
from SCons.Tool import ar
from SCons.Tool import gnulink
import strip
import gdb import gdb
import objdump import objdump
import strip
from SCons.Action import _subproc from SCons.Action import _subproc
import subprocess from SCons.Errors import StopError
from SCons.Tool import ar, asm, gcc, gnulink, gxx
def prefix_commands(env, command_prefix, cmd_list): def prefix_commands(env, command_prefix, cmd_list):

View File

@ -1,15 +1,14 @@
from SCons.Builder import Builder
from SCons.Action import Action
from SCons.Errors import StopError
from SCons.Warnings import warn, WarningOnByDefault
from ansi.color import fg from ansi.color import fg
from fbt.appmanifest import ( from fbt.appmanifest import (
FlipperAppType,
AppManager,
ApplicationsCGenerator, ApplicationsCGenerator,
AppManager,
FlipperAppType,
FlipperManifestException, FlipperManifestException,
) )
from SCons.Action import Action
from SCons.Builder import Builder
from SCons.Errors import StopError
from SCons.Warnings import WarningOnByDefault, warn
# Adding objects for application management to env # Adding objects for application management to env
# AppManager env["APPMGR"] - loads all manifests; manages list of known apps # AppManager env["APPMGR"] - loads all manifests; manages list of known apps

View File

@ -1,10 +1,10 @@
from SCons.Builder import Builder
from SCons.Action import Action
from SCons.Errors import StopError
import os import os
import subprocess import subprocess
from ansi.color import fg from ansi.color import fg
from SCons.Action import Action
from SCons.Builder import Builder
from SCons.Errors import StopError
def icons_emitter(target, source, env): def icons_emitter(target, source, env):
@ -76,11 +76,11 @@ def proto_ver_generator(target, source, env):
target_file = target[0] target_file = target[0]
src_dir = source[0].dir.abspath src_dir = source[0].dir.abspath
try: try:
git_fetch = _invoke_git( _invoke_git(
["fetch", "--tags"], ["fetch", "--tags"],
source_dir=src_dir, source_dir=src_dir,
) )
except (subprocess.CalledProcessError, EnvironmentError) as e: except (subprocess.CalledProcessError, EnvironmentError):
# Not great, not terrible # Not great, not terrible
print(fg.boldred("Git: fetch failed")) print(fg.boldred("Git: fetch failed"))
@ -89,7 +89,7 @@ def proto_ver_generator(target, source, env):
["describe", "--tags", "--abbrev=0"], ["describe", "--tags", "--abbrev=0"],
source_dir=src_dir, source_dir=src_dir,
) )
except (subprocess.CalledProcessError, EnvironmentError) as e: except (subprocess.CalledProcessError, EnvironmentError):
raise StopError("Git: describe failed") raise StopError("Git: describe failed")
git_major, git_minor = git_describe.split(".") git_major, git_minor = git_describe.split(".")

View File

@ -1,5 +1,3 @@
from re import search
from SCons.Errors import UserError from SCons.Errors import UserError

View File

@ -1,6 +1,5 @@
from SCons.Builder import Builder
from SCons.Action import Action from SCons.Action import Action
from SCons.Script import Mkdir from SCons.Builder import Builder
from SCons.Defaults import Touch from SCons.Defaults import Touch

View File

@ -3,23 +3,19 @@ import os
import pathlib import pathlib
import shutil import shutil
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import Optional, TypedDict from typing import Optional
from ansi.color import fg
import SCons.Warnings import SCons.Warnings
from SCons.Action import Action from ansi.color import fg
from SCons.Builder import Builder
from SCons.Errors import UserError
from SCons.Node import NodeList
from SCons.Node.FS import File, Entry
from fbt.appmanifest import FlipperApplication, FlipperAppType, FlipperManifestException from fbt.appmanifest import FlipperApplication, FlipperAppType, FlipperManifestException
from fbt.elfmanifest import assemble_manifest_data from fbt.elfmanifest import assemble_manifest_data
from fbt.fapassets import FileBundler from fbt.fapassets import FileBundler
from fbt.sdk.cache import SdkCache from fbt.sdk.cache import SdkCache
from fbt.util import extract_abs_dir_path from fbt.util import extract_abs_dir_path
from SCons.Action import Action
from SCons.Builder import Builder
from SCons.Errors import UserError
from SCons.Node.FS import Entry, File
_FAP_META_SECTION = ".fapmeta" _FAP_META_SECTION = ".fapmeta"
_FAP_FILEASSETS_SECTION = ".fapassets" _FAP_FILEASSETS_SECTION = ".fapassets"
@ -289,7 +285,7 @@ def GetExtAppByIdOrPath(env, app_dir):
try: try:
# Maybe user passed an appid? # Maybe user passed an appid?
app = appmgr.get(app_dir) app = appmgr.get(app_dir)
except FlipperManifestException as _: except FlipperManifestException:
# Look up path components in known app dirs # Look up path components in known app dirs
for dir_part in reversed(pathlib.Path(app_dir).parts): for dir_part in reversed(pathlib.Path(app_dir).parts):
if app := appmgr.find_by_appdir(dir_part): if app := appmgr.find_by_appdir(dir_part):

View File

@ -1,5 +1,3 @@
from SCons.Builder import Builder
from SCons.Action import Action
import json import json

View File

@ -1,21 +1,20 @@
import json
import os.path
import pathlib
import posixpath
import shutil import shutil
from SCons.Builder import Builder
from fbt.sdk.cache import SdkCache
from fbt.sdk.collector import SdkCollector
from fbt.util import path_as_posix
from SCons.Action import Action from SCons.Action import Action
from SCons.Builder import Builder
from SCons.Errors import UserError from SCons.Errors import UserError
# from SCons.Scanner import C # from SCons.Scanner import C
from SCons.Script import Entry from SCons.Script import Entry
from SCons.Util import LogicalLines from SCons.Util import LogicalLines
import os.path
import posixpath
import pathlib
import json
from fbt.sdk.collector import SdkCollector
from fbt.sdk.cache import SdkCache
from fbt.util import path_as_posix
def ProcessSdkDepends(env, filename): def ProcessSdkDepends(env, filename):
try: try:

View File

@ -1,15 +1,13 @@
import os
import sys
import traceback
import SCons.Warnings as Warnings import SCons.Warnings as Warnings
from ansi.color import fg
from SCons.Errors import UserError from SCons.Errors import UserError
# from SCons.Script.Main import find_deepest_user_frame # from SCons.Script.Main import find_deepest_user_frame
from ansi.color import fg, bg, fx
import traceback
import sys
import os
def find_deepest_user_frame(tb): def find_deepest_user_frame(tb):
tb.reverse() tb.reverse()

View File

@ -1,5 +1,5 @@
from SCons.Builder import Builder
from SCons.Action import Action from SCons.Action import Action
from SCons.Builder import Builder
def version_emitter(target, source, env): def version_emitter(target, source, env):

View File

@ -1,6 +1,6 @@
from SCons.Builder import Builder
from SCons.Action import Action
import SCons import SCons
from SCons.Action import Action
from SCons.Builder import Builder
__OBJCOPY_ARM_BIN = "arm-none-eabi-objcopy" __OBJCOPY_ARM_BIN = "arm-none-eabi-objcopy"
__NM_ARM_BIN = "arm-none-eabi-nm" __NM_ARM_BIN = "arm-none-eabi-nm"

View File

@ -1,7 +1,3 @@
from SCons.Builder import Builder
from SCons.Action import Action
def generate(env): def generate(env):
env.SetDefault( env.SetDefault(
GDB="gdb", GDB="gdb",

View File

@ -1,5 +1,5 @@
from SCons.Builder import Builder
from SCons.Action import Action from SCons.Action import Action
from SCons.Builder import Builder
def generate(env): def generate(env):

View File

@ -1,7 +1,7 @@
from SCons.Builder import Builder
from SCons.Action import Action
from SCons.Defaults import Touch
import SCons import SCons
from SCons.Action import Action
from SCons.Builder import Builder
from SCons.Defaults import Touch
__OPENOCD_BIN = "openocd" __OPENOCD_BIN = "openocd"

View File

@ -1,11 +1,12 @@
from SCons.Builder import Builder
from SCons.Action import Action
from SCons.Script import Delete, Mkdir, GetBuildFailures, Flatten
import multiprocessing
import webbrowser
import atexit import atexit
import sys import multiprocessing
import subprocess import subprocess
import sys
import webbrowser
from SCons.Action import Action
from SCons.Builder import Builder
from SCons.Script import Delete, Flatten, GetBuildFailures, Mkdir
__no_browser = False __no_browser = False

View File

@ -1,5 +1,6 @@
import posixpath
import os import os
import posixpath
from SCons.Errors import UserError from SCons.Errors import UserError

View File

@ -1,6 +1,6 @@
import SCons import SCons
from SCons.Script import Flatten
from fbt.util import GLOB_FILE_EXCLUSION from fbt.util import GLOB_FILE_EXCLUSION
from SCons.Script import Flatten
def GlobRecursive(env, pattern, node=".", exclude=[]): def GlobRecursive(env, pattern, node=".", exclude=[]):

View File

@ -1,5 +1,5 @@
from SCons.Builder import Builder
from SCons.Action import Action from SCons.Action import Action
from SCons.Builder import Builder
def generate(env): def generate(env):

View File

@ -1,13 +1,9 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import logging
import argparse
import sys
import os
from flipper.app import App from flipper.app import App
from flipper.cube import CubeProgrammer
from flipper.assets.coprobin import CoproBinary from flipper.assets.coprobin import CoproBinary
from flipper.cube import CubeProgrammer
STATEMENT = "AGREE_TO_LOSE_FLIPPER_FEATURES_THAT_USE_CRYPTO_ENCLAVE" STATEMENT = "AGREE_TO_LOSE_FLIPPER_FEATURES_THAT_USE_CRYPTO_ENCLAVE"
@ -94,59 +90,59 @@ class Main(App):
} }
def wipe(self): def wipe(self):
self.logger.info(f"Wiping flash") self.logger.info("Wiping flash")
cp = CubeProgrammer(self._getCubeParams()) cp = CubeProgrammer(self._getCubeParams())
self.logger.info(f"Setting RDP to 0xBB") self.logger.info("Setting RDP to 0xBB")
cp.setOptionBytes({"RDP": ("0xBB", "rw")}) cp.setOptionBytes({"RDP": ("0xBB", "rw")})
self.logger.info(f"Verifying RDP") self.logger.info("Verifying RDP")
r = cp.checkOptionBytes({"RDP": ("0xBB", "rw")}) r = cp.checkOptionBytes({"RDP": ("0xBB", "rw")})
assert r == True assert r is True
self.logger.info(f"Result: {r}") self.logger.info(f"Result: {r}")
self.logger.info(f"Setting RDP to 0xAA") self.logger.info("Setting RDP to 0xAA")
cp.setOptionBytes({"RDP": ("0xAA", "rw")}) cp.setOptionBytes({"RDP": ("0xAA", "rw")})
self.logger.info(f"Verifying RDP") self.logger.info("Verifying RDP")
r = cp.checkOptionBytes({"RDP": ("0xAA", "rw")}) r = cp.checkOptionBytes({"RDP": ("0xAA", "rw")})
assert r == True assert r is True
self.logger.info(f"Result: {r}") self.logger.info(f"Result: {r}")
self.logger.info(f"Complete") self.logger.info("Complete")
return 0 return 0
def core1bootloader(self): def core1bootloader(self):
self.logger.info(f"Flashing bootloader") self.logger.info("Flashing bootloader")
cp = CubeProgrammer(self._getCubeParams()) cp = CubeProgrammer(self._getCubeParams())
cp.flashBin("0x08000000", self.args.bootloader) cp.flashBin("0x08000000", self.args.bootloader)
self.logger.info(f"Complete") self.logger.info("Complete")
cp.resetTarget() cp.resetTarget()
return 0 return 0
def core1firmware(self): def core1firmware(self):
self.logger.info(f"Flashing firmware") self.logger.info("Flashing firmware")
cp = CubeProgrammer(self._getCubeParams()) cp = CubeProgrammer(self._getCubeParams())
cp.flashBin("0x08008000", self.args.firmware) cp.flashBin("0x08008000", self.args.firmware)
self.logger.info(f"Complete") self.logger.info("Complete")
cp.resetTarget() cp.resetTarget()
return 0 return 0
def core1(self): def core1(self):
self.logger.info(f"Flashing bootloader") self.logger.info("Flashing bootloader")
cp = CubeProgrammer(self._getCubeParams()) cp = CubeProgrammer(self._getCubeParams())
cp.flashBin("0x08000000", self.args.bootloader) cp.flashBin("0x08000000", self.args.bootloader)
self.logger.info(f"Flashing firmware") self.logger.info("Flashing firmware")
cp.flashBin("0x08008000", self.args.firmware) cp.flashBin("0x08008000", self.args.firmware)
cp.resetTarget() cp.resetTarget()
self.logger.info(f"Complete") self.logger.info("Complete")
return 0 return 0
def core2fus(self): def core2fus(self):
if self.args.statement != STATEMENT: if self.args.statement != STATEMENT:
self.logger.error( self.logger.error(
f"PLEASE DON'T. THIS FEATURE INTENDED ONLY FOR FACTORY FLASHING" "PLEASE DON'T. THIS FEATURE INTENDED ONLY FOR FACTORY FLASHING"
) )
return 1 return 1
self.logger.info(f"Flashing Firmware Update Service") self.logger.info("Flashing Firmware Update Service")
cp = CubeProgrammer(self._getCubeParams()) cp = CubeProgrammer(self._getCubeParams())
cp.flashCore2(self.args.fus_address, self.args.fus) cp.flashCore2(self.args.fus_address, self.args.fus)
self.logger.info(f"Complete") self.logger.info("Complete")
return 0 return 0
def core2radio(self): def core2radio(self):
@ -163,15 +159,15 @@ class Main(App):
f"Radio address not provided, guessed as 0x{radio_address:X}" f"Radio address not provided, guessed as 0x{radio_address:X}"
) )
if radio_address > 0x080E0000: if radio_address > 0x080E0000:
self.logger.error(f"I KNOW WHAT YOU DID LAST SUMMER") self.logger.error("I KNOW WHAT YOU DID LAST SUMMER")
return 1 return 1
cp = CubeProgrammer(self._getCubeParams()) cp = CubeProgrammer(self._getCubeParams())
self.logger.info(f"Removing Current Radio Stack") self.logger.info("Removing Current Radio Stack")
cp.deleteCore2RadioStack() cp.deleteCore2RadioStack()
self.logger.info(f"Flashing Radio Stack") self.logger.info("Flashing Radio Stack")
cp.flashCore2(radio_address, self.args.radio) cp.flashCore2(radio_address, self.args.radio)
self.logger.info(f"Complete") self.logger.info("Complete")
return 0 return 0

View File

@ -44,7 +44,7 @@ class App:
if isinstance(return_code, int): if isinstance(return_code, int):
return self._exit(return_code) return self._exit(return_code)
else: else:
self.logger.error(f"Missing return code") self.logger.error("Missing return code")
return self._exit(255) return self._exit(255)
def _exit(self, code): def _exit(self, code):

View File

@ -6,7 +6,7 @@ import xml.etree.ElementTree as ET
import posixpath import posixpath
import os import os
from flipper.utils import * from flipper.utils import file_sha256, timestamp
from flipper.assets.coprobin import CoproBinary, get_stack_type from flipper.assets.coprobin import CoproBinary, get_stack_type
@ -45,13 +45,13 @@ class Copro:
cube_manifest = ET.parse(cube_manifest_file) cube_manifest = ET.parse(cube_manifest_file)
cube_package = cube_manifest.find("PackDescription") cube_package = cube_manifest.find("PackDescription")
if not cube_package: if not cube_package:
raise Exception(f"Unknown Cube manifest format") raise Exception("Unknown Cube manifest format")
cube_version = cube_package.get("Patch") or cube_package.get("Release") cube_version = cube_package.get("Patch") or cube_package.get("Release")
if not cube_version or not cube_version.startswith("FW.WB"): if not cube_version or not cube_version.startswith("FW.WB"):
raise Exception(f"Incorrect Cube package or version info") raise Exception("Incorrect Cube package or version info")
cube_version = cube_version.replace("FW.WB.", "", 1) cube_version = cube_version.replace("FW.WB.", "", 1)
if cube_version != reference_cube_version: if cube_version != reference_cube_version:
raise Exception(f"Unsupported cube version") raise Exception("Unsupported cube version")
self.version = cube_version self.version = cube_version
def _getFileName(self, name): def _getFileName(self, name):

View File

@ -1,6 +1,7 @@
import struct import struct
import math import math
import os, os.path import os
import os.path
import sys import sys

View File

@ -1,13 +1,11 @@
import multiprocessing import multiprocessing
import logging import logging
import os import os
import sys
import shutil
from collections import Counter from collections import Counter
from flipper.utils.fff import * from flipper.utils.fff import FlipperFormatFile
from flipper.utils.templite import * from flipper.utils.templite import Templite
from .icon import * from .icon import ImageTools, file2image
def _convert_image_to_bm(pair: set): def _convert_image_to_bm(pair: set):
@ -121,7 +119,7 @@ class DolphinBubbleAnimation:
self.meta["Passive frames"] + self.meta["Active frames"] self.meta["Passive frames"] + self.meta["Active frames"]
== ordered_frames_count == ordered_frames_count
) )
except EOFError as e: except EOFError:
raise Exception("Invalid meta file: too short") raise Exception("Invalid meta file: too short")
except AssertionError as e: except AssertionError as e:
self.logger.exception(e) self.logger.exception(e)
@ -158,7 +156,7 @@ class DolphinBubbleAnimation:
except AssertionError as e: except AssertionError as e:
self.logger.exception(e) self.logger.exception(e)
self.logger.error( self.logger.error(
f"Animation {self.name} bubble slot {bubble_slot} got incorrect data: {bubble}" f"Animation {self.name} bubble slot {bubble['Slot']} got incorrect data: {bubble}"
) )
raise Exception("Meta file is invalid: incorrect bubble data") raise Exception("Meta file is invalid: incorrect bubble data")
except EOFError: except EOFError:

View File

@ -1,9 +1,6 @@
import logging import logging
import argparse
import subprocess import subprocess
import io import io
import os
import sys
ICONS_SUPPORTED_FORMATS = ["png"] ICONS_SUPPORTED_FORMATS = ["png"]
@ -36,11 +33,8 @@ class ImageTools:
@staticmethod @staticmethod
def is_processing_slow(): def is_processing_slow():
try: try:
from PIL import Image, ImageOps
import heatshrink2
return False return False
except ImportError as e: except ImportError:
return True return True
def __init__(self): def __init__(self):
@ -52,7 +46,7 @@ class ImageTools:
try: try:
from PIL import Image, ImageOps from PIL import Image, ImageOps
except ImportError as e: except ImportError:
self.__pil_unavailable = True self.__pil_unavailable = True
self.logger.info("pillow module is missing, using convert cli util") self.logger.info("pillow module is missing, using convert cli util")
return self.png2xbm(file) return self.png2xbm(file)
@ -72,7 +66,7 @@ class ImageTools:
try: try:
import heatshrink2 import heatshrink2
except ImportError as e: except ImportError:
self.__hs2_unavailable = True self.__hs2_unavailable = True
self.logger.info("heatshrink2 module is missing, using heatshrink cli util") self.logger.info("heatshrink2 module is missing, using heatshrink cli util")
return self.xbm2hs(data) return self.xbm2hs(data)

View File

@ -1,11 +1,10 @@
import datetime
import logging import logging
import os import os
import posixpath import posixpath
from pathlib import Path from pathlib import Path
from flipper.utils import * from flipper.utils import timestamp, file_md5
from flipper.utils.fstree import * from flipper.utils.fstree import FsNode, compare_fs_trees
MANIFEST_VERSION = 0 MANIFEST_VERSION = 0

View File

@ -1,7 +1,5 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import logging
import struct
from enum import Enum from enum import Enum
from dataclasses import dataclass from dataclasses import dataclass
@ -181,7 +179,7 @@ class OptionBytesData:
def gen_values(self): def gen_values(self):
obref = ObReferenceValuesGenerator() obref = ObReferenceValuesGenerator()
converted_refs = list(obref.apply(ob) for ob in self.obs) list(obref.apply(ob) for ob in self.obs)
return obref return obref

View File

@ -14,7 +14,7 @@ class CubeProgrammer:
if "port" in config and config["port"]: if "port" in config and config["port"]:
connect.append(f"port={config['port']}") connect.append(f"port={config['port']}")
else: else:
connect.append(f"port=swd") connect.append("port=swd")
if "serial" in config and config["serial"]: if "serial" in config and config["serial"]:
connect.append(f"sn={config['serial']}") connect.append(f"sn={config['serial']}")
self.params.append("-c " + " ".join(connect)) self.params.append("-c " + " ".join(connect))
@ -43,20 +43,20 @@ class CubeProgrammer:
return output.decode() return output.decode()
def getVersion(self): def getVersion(self):
output = self._execute(["--version"]) self._execute(["--version"])
def checkOptionBytes(self, option_bytes): def checkOptionBytes(self, option_bytes):
output = self._execute(["-ob displ"]) output = self._execute(["-ob displ"])
ob_correct = True ob_correct = True
for line in output.split("\n"): for line in output.split("\n"):
line = line.strip() line = line.strip()
if not ":" in line: if ":" not in line:
self.logger.debug(f"Skipping line: {line}") self.logger.debug(f"Skipping line: {line}")
continue continue
key, data = line.split(":", 1) key, data = line.split(":", 1)
key = key.strip() key = key.strip()
data = data.strip() data = data.strip()
if not key in option_bytes.keys(): if key not in option_bytes.keys():
self.logger.debug(f"Skipping key: {key}") self.logger.debug(f"Skipping key: {key}")
continue continue
self.logger.debug(f"Processing key: {key} {data}") self.logger.debug(f"Processing key: {key} {data}")

View File

@ -151,7 +151,7 @@ class FlipperStorage:
try: try:
# TODO: better decoding, considering non-ascii characters # TODO: better decoding, considering non-ascii characters
line = line.decode("ascii") line = line.decode("ascii")
except: except Exception:
continue continue
line = line.strip() line = line.strip()
@ -194,7 +194,7 @@ class FlipperStorage:
try: try:
# TODO: better decoding, considering non-ascii characters # TODO: better decoding, considering non-ascii characters
line = line.decode("ascii") line = line.decode("ascii")
except: except Exception:
continue continue
line = line.strip() line = line.strip()

View File

@ -1,6 +1,5 @@
import datetime import datetime
import hashlib import hashlib
import os
def timestamp(): def timestamp():

View File

@ -31,13 +31,13 @@ class OpenOCDProgrammer(Programmer):
config["interface"] = interface config["interface"] = interface
config["target"] = "target/stm32wbx.cfg" config["target"] = "target/stm32wbx.cfg"
if not serial is None: if serial is not None:
if interface == "interface/cmsis-dap.cfg": if interface == "interface/cmsis-dap.cfg":
config["serial"] = f"cmsis_dap_serial {serial}" config["serial"] = f"cmsis_dap_serial {serial}"
elif "stlink" in interface: elif "stlink" in interface:
config["serial"] = f"stlink_serial {serial}" config["serial"] = f"stlink_serial {serial}"
if not port_base is None: if port_base is not None:
config["port_base"] = port_base config["port_base"] = port_base
self.openocd = OpenOCD(config) self.openocd = OpenOCD(config)
@ -59,7 +59,7 @@ class OpenOCDProgrammer(Programmer):
raise Exception(f"File {file_path} not found") raise Exception(f"File {file_path} not found")
self.openocd.start() self.openocd.start()
self.openocd.send_tcl(f"init") self.openocd.send_tcl("init")
self.openocd.send_tcl( self.openocd.send_tcl(
f"program {file_path} 0x{address:08x}{' verify' if verify else ''} reset exit" f"program {file_path} 0x{address:08x}{' verify' if verify else ''} reset exit"
) )
@ -196,7 +196,7 @@ class OpenOCDProgrammer(Programmer):
if ob_need_to_apply: if ob_need_to_apply:
stm32.option_bytes_apply(self.openocd) stm32.option_bytes_apply(self.openocd)
else: else:
self.logger.info(f"Option Bytes are already correct") self.logger.info("Option Bytes are already correct")
# Load Option Bytes # Load Option Bytes
# That will reset and also lock the Option Bytes and the Flash # That will reset and also lock the Option Bytes and the Flash
@ -256,7 +256,7 @@ class OpenOCDProgrammer(Programmer):
already_written = False already_written = False
if already_written: if already_written:
self.logger.info(f"OTP memory is already written with the given data") self.logger.info("OTP memory is already written with the given data")
return OpenOCDProgrammerResult.Success return OpenOCDProgrammerResult.Success
self.reset(self.RunMode.Stop) self.reset(self.RunMode.Stop)

View File

@ -123,7 +123,7 @@ class STM32WB55:
def clear_flash_errors(self, oocd: OpenOCD): def clear_flash_errors(self, oocd: OpenOCD):
# Errata 2.2.9: Flash OPTVERR flag is always set after system reset # Errata 2.2.9: Flash OPTVERR flag is always set after system reset
# And also clear all other flash error flags # And also clear all other flash error flags
self.logger.debug(f"Resetting flash errors") self.logger.debug("Resetting flash errors")
self.FLASH_SR.load(oocd) self.FLASH_SR.load(oocd)
self.FLASH_SR.OP_ERR = 1 self.FLASH_SR.OP_ERR = 1
self.FLASH_SR.PROG_ERR = 1 self.FLASH_SR.PROG_ERR = 1
@ -218,7 +218,7 @@ class STM32WB55:
raise Exception("Flash lock failed") raise Exception("Flash lock failed")
def option_bytes_apply(self, oocd: OpenOCD): def option_bytes_apply(self, oocd: OpenOCD):
self.logger.debug(f"Applying Option Bytes") self.logger.debug("Applying Option Bytes")
self.FLASH_CR.load(oocd) self.FLASH_CR.load(oocd)
self.FLASH_CR.OPT_STRT = 1 self.FLASH_CR.OPT_STRT = 1
@ -228,7 +228,7 @@ class STM32WB55:
self.flash_wait_for_operation(oocd) self.flash_wait_for_operation(oocd)
def option_bytes_load(self, oocd: OpenOCD): def option_bytes_load(self, oocd: OpenOCD):
self.logger.debug(f"Loading Option Bytes") self.logger.debug("Loading Option Bytes")
self.FLASH_CR.load(oocd) self.FLASH_CR.load(oocd)
self.FLASH_CR.OBL_LAUNCH = 1 self.FLASH_CR.OBL_LAUNCH = 1
self.FLASH_CR.store(oocd) self.FLASH_CR.store(oocd)

View File

@ -77,8 +77,8 @@ class TempliteCompiler:
return return
lines = self.block.splitlines() lines = self.block.splitlines()
margin = min(len(l) - len(l.lstrip()) for l in lines if l.strip()) margin = min(len(line) - len(line.lstrip()) for line in lines if line.strip())
self.block = "\n".join("\t" * self.offset + l[margin:] for l in lines) self.block = "\n".join("\t" * self.offset + line[margin:] for line in lines)
self.blocks.append(self.block) self.blocks.append(self.block)
if self.block.endswith(":"): if self.block.endswith(":"):
self.offset += 1 self.offset += 1

View File

@ -1,10 +1,11 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from flipper.app import App
import subprocess
import os
import math import math
import os
import subprocess
from ansi.color import fg from ansi.color import fg
from flipper.app import App
class Main(App): class Main(App):

View File

@ -1,14 +1,14 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import ssl
import json
import os
import shlex
import re
import string
import random
import argparse import argparse
import datetime import datetime
import json
import os
import random
import re
import shlex
import ssl
import string
import urllib.request import urllib.request

View File

@ -1,14 +1,13 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import multiprocessing
import os import os
import re import re
import shutil import shutil
import subprocess import subprocess
import multiprocessing
from flipper.app import App from flipper.app import App
SOURCE_CODE_FILE_EXTENSIONS = [".h", ".c", ".cpp", ".cxx", ".hpp"] SOURCE_CODE_FILE_EXTENSIONS = [".h", ".c", ".cpp", ".cxx", ".hpp"]
SOURCE_CODE_FILE_PATTERN = r"^[0-9A-Za-z_]+\.[a-z]+$" SOURCE_CODE_FILE_PATTERN = r"^[0-9A-Za-z_]+\.[a-z]+$"
SOURCE_CODE_DIR_PATTERN = r"^[0-9A-Za-z_]+$" SOURCE_CODE_DIR_PATTERN = r"^[0-9A-Za-z_]+$"
@ -59,7 +58,7 @@ class Main(App):
show_message = True show_message = True
if show_message: if show_message:
self.logger.warning( self.logger.warning(
f"Folders are not renamed automatically, please fix it by yourself" "Folders are not renamed automatically, please fix it by yourself"
) )
def _find_sources(self, folders: list): def _find_sources(self, folders: list):
@ -70,7 +69,7 @@ class Main(App):
for filename in filenames: for filename in filenames:
ext = os.path.splitext(filename.lower())[1] ext = os.path.splitext(filename.lower())[1]
if not ext in SOURCE_CODE_FILE_EXTENSIONS: if ext not in SOURCE_CODE_FILE_EXTENSIONS:
continue continue
output.append(os.path.join(dirpath, filename)) output.append(os.path.join(dirpath, filename))
return output return output
@ -80,7 +79,7 @@ class Main(App):
try: try:
subprocess.check_call(task) subprocess.check_call(task)
return True return True
except subprocess.CalledProcessError as e: except subprocess.CalledProcessError:
return False return False
def _format_sources(self, sources: list, dry_run: bool = False): def _format_sources(self, sources: list, dry_run: bool = False):
@ -144,7 +143,7 @@ class Main(App):
def _apply_file_permissions(self, sources: list, dry_run: bool = False): def _apply_file_permissions(self, sources: list, dry_run: bool = False):
execute_permissions = 0o111 execute_permissions = 0o111
pattern = re.compile(SOURCE_CODE_FILE_PATTERN) re.compile(SOURCE_CODE_FILE_PATTERN)
good = [] good = []
bad = [] bad = []
# Check sources for unexpected execute permissions # Check sources for unexpected execute permissions

View File

@ -1,9 +1,10 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import argparse
import os import os
import re import re
import sys import sys
import argparse
from slack_sdk import WebClient from slack_sdk import WebClient
from slack_sdk.errors import SlackApiError from slack_sdk.errors import SlackApiError

View File

@ -1,8 +1,9 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from flipper.app import App
import json import json
from flipper.app import App
class Main(App): class Main(App):
def init(self): def init(self):

View File

@ -44,7 +44,7 @@ class Main(App):
) )
def check(self): def check(self):
self.logger.info(f"Checking Option Bytes") self.logger.info("Checking Option Bytes")
# OpenOCD # OpenOCD
openocd = OpenOCDProgrammer( openocd = OpenOCDProgrammer(
@ -60,7 +60,7 @@ class Main(App):
return return_code return return_code
def set(self): def set(self):
self.logger.info(f"Setting Option Bytes") self.logger.info("Setting Option Bytes")
# OpenOCD # OpenOCD
openocd = OpenOCDProgrammer( openocd = OpenOCDProgrammer(

View File

@ -1,13 +1,13 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import datetime
import logging import logging
import argparse
import subprocess
import os import os
import sys
import re import re
import struct import struct
import datetime
from flipper.app import App
from flipper.utils.programmer_openocd import OpenOCDProgrammer, OpenOCDProgrammerResult
OTP_MAGIC = 0xBABE OTP_MAGIC = 0xBABE
OTP_VERSION = 0x02 OTP_VERSION = 0x02
@ -33,9 +33,6 @@ OTP_DISPLAYS = {
"mgg": 0x02, "mgg": 0x02,
} }
from flipper.app import App
from flipper.utils.programmer_openocd import OpenOCDProgrammer, OpenOCDProgrammerResult
class OTPException(Exception): class OTPException(Exception):
def __init__(self, message: str, result: OpenOCDProgrammerResult): def __init__(self, message: str, result: OpenOCDProgrammerResult):
@ -158,7 +155,7 @@ class Main(App):
) )
def generate_all(self): def generate_all(self):
self.logger.info(f"Generating OTP") self.logger.info("Generating OTP")
self._processFirstArgs() self._processFirstArgs()
self._processSecondArgs() self._processSecondArgs()
with open(f"{self.args.file}_first.bin", "wb") as file: with open(f"{self.args.file}_first.bin", "wb") as file:
@ -172,18 +169,18 @@ class Main(App):
return 0 return 0
def flash_first(self): def flash_first(self):
self.logger.info(f"Flashing first block of OTP") self.logger.info("Flashing first block of OTP")
self._processFirstArgs() self._processFirstArgs()
filename = f"otp_unknown_first_{self.timestamp}.bin" filename = f"otp_unknown_first_{self.timestamp}.bin"
try: try:
self.logger.info(f"Packing binary data") self.logger.info("Packing binary data")
with open(filename, "wb") as file: with open(filename, "wb") as file:
file.write(self._packFirst()) file.write(self._packFirst())
self.logger.info(f"Flashing OTP") self.logger.info("Flashing OTP")
openocd = OpenOCDProgrammer( openocd = OpenOCDProgrammer(
self.args.interface, self.args.interface,
@ -195,7 +192,7 @@ class Main(App):
if programmer_result != OpenOCDProgrammerResult.Success: if programmer_result != OpenOCDProgrammerResult.Success:
raise OTPException("Failed to flash OTP", programmer_result) raise OTPException("Failed to flash OTP", programmer_result)
self.logger.info(f"Flashed Successfully") self.logger.info("Flashed Successfully")
except OTPException as e: except OTPException as e:
self.logger.exception(e) self.logger.exception(e)
return e.get_exit_code() return e.get_exit_code()
@ -205,18 +202,18 @@ class Main(App):
return 0 return 0
def flash_second(self): def flash_second(self):
self.logger.info(f"Flashing second block of OTP") self.logger.info("Flashing second block of OTP")
self._processSecondArgs() self._processSecondArgs()
filename = f"otp_{self.args.name}_second_{self.timestamp}.bin" filename = f"otp_{self.args.name}_second_{self.timestamp}.bin"
try: try:
self.logger.info(f"Packing binary data") self.logger.info("Packing binary data")
with open(filename, "wb") as file: with open(filename, "wb") as file:
file.write(self._packSecond()) file.write(self._packSecond())
self.logger.info(f"Flashing OTP") self.logger.info("Flashing OTP")
openocd = OpenOCDProgrammer( openocd = OpenOCDProgrammer(
self.args.interface, self.args.interface,
@ -228,7 +225,7 @@ class Main(App):
if programmer_result != OpenOCDProgrammerResult.Success: if programmer_result != OpenOCDProgrammerResult.Success:
raise OTPException("Failed to flash OTP", programmer_result) raise OTPException("Failed to flash OTP", programmer_result)
self.logger.info(f"Flashed Successfully") self.logger.info("Flashed Successfully")
except OTPException as e: except OTPException as e:
self.logger.exception(e) self.logger.exception(e)
return e.get_exit_code() return e.get_exit_code()
@ -238,7 +235,7 @@ class Main(App):
return 0 return 0
def flash_all(self): def flash_all(self):
self.logger.info(f"Flashing OTP") self.logger.info("Flashing OTP")
self._processFirstArgs() self._processFirstArgs()
self._processSecondArgs() self._processSecondArgs()
@ -246,12 +243,12 @@ class Main(App):
filename = f"otp_{self.args.name}_whole_{self.timestamp}.bin" filename = f"otp_{self.args.name}_whole_{self.timestamp}.bin"
try: try:
self.logger.info(f"Packing binary data") self.logger.info("Packing binary data")
with open(filename, "wb") as file: with open(filename, "wb") as file:
file.write(self._packFirst()) file.write(self._packFirst())
file.write(self._packSecond()) file.write(self._packSecond())
self.logger.info(f"Flashing OTP") self.logger.info("Flashing OTP")
openocd = OpenOCDProgrammer( openocd = OpenOCDProgrammer(
self.args.interface, self.args.interface,
@ -263,7 +260,7 @@ class Main(App):
if programmer_result != OpenOCDProgrammerResult.Success: if programmer_result != OpenOCDProgrammerResult.Success:
raise OTPException("Failed to flash OTP", programmer_result) raise OTPException("Failed to flash OTP", programmer_result)
self.logger.info(f"Flashed Successfully") self.logger.info("Flashed Successfully")
except OTPException as e: except OTPException as e:
self.logger.exception(e) self.logger.exception(e)
return e.get_exit_code() return e.get_exit_code()

View File

@ -1,13 +1,13 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import typing
import subprocess
import logging import logging
import time
import os import os
import socket import socket
import subprocess
import time
import typing
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from dataclasses import dataclass from dataclasses import dataclass
from flipper.app import App from flipper.app import App
@ -223,7 +223,7 @@ class BlackmagicProgrammer(Programmer):
try: try:
socket.inet_aton(address) socket.inet_aton(address)
return True return True
except: except Exception:
return False return False
def set_serial(self, serial: str): def set_serial(self, serial: str):
@ -415,12 +415,12 @@ class Main(App):
if len(interfaces) == 0: if len(interfaces) == 0:
interfaces = [p for p in network_programmers if p.get_name() == i_name] interfaces = [p for p in network_programmers if p.get_name() == i_name]
else: else:
self.logger.info(f"Probing for interfaces...") self.logger.info("Probing for interfaces...")
interfaces = self._search_interface(self.args.serial) interfaces = self._search_interface(self.args.serial)
if len(interfaces) == 0: if len(interfaces) == 0:
# Probe network blackmagic # Probe network blackmagic
self.logger.info(f"Probing for network interfaces...") self.logger.info("Probing for network interfaces...")
interfaces = self._search_network_interface(self.args.serial) interfaces = self._search_network_interface(self.args.serial)
if len(interfaces) == 0: if len(interfaces) == 0:

View File

@ -1,14 +1,12 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import operator
from functools import reduce
from flipper.app import App from flipper.app import App
from flipper.storage import FlipperStorage, FlipperStorageOperations from flipper.storage import FlipperStorage, FlipperStorageOperations
from flipper.utils.cdc import resolve_port from flipper.utils.cdc import resolve_port
import os
import posixpath
from functools import reduce
import operator
class Main(App): class Main(App):
def init(self): def init(self):
@ -38,8 +36,8 @@ class Main(App):
self.parser.set_defaults(func=self.install) self.parser.set_defaults(func=self.install)
@staticmethod @staticmethod
def flatten(l): def flatten(item_list):
return reduce(operator.concat, l, []) return reduce(operator.concat, item_list, [])
def install(self): def install(self):
self.args.sources = self.flatten(self.args.sources) self.args.sources = self.flatten(self.args.sources)

View File

@ -5,7 +5,7 @@ import shutil
import tarfile import tarfile
import zipfile import zipfile
from os import makedirs, walk from os import makedirs, walk
from os.path import exists, join, relpath, basename, split from os.path import basename, exists, join, relpath
from ansi.color import fg from ansi.color import fg
from flipper.app import App from flipper.app import App

View File

@ -1,14 +1,12 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from typing import final
from flipper.app import App
from flipper.storage import FlipperStorage, FlipperStorageOperations
from flipper.utils.cdc import resolve_port
import logging import logging
import os import os
import pathlib import pathlib
import serial.tools.list_ports as list_ports
from flipper.app import App
from flipper.storage import FlipperStorage, FlipperStorageOperations
from flipper.utils.cdc import resolve_port
class Main(App): class Main(App):
@ -54,7 +52,7 @@ class Main(App):
f"update install {flipper_update_path}/{manifest_name}\r" f"update install {flipper_update_path}/{manifest_name}\r"
) )
result = storage.read.until(storage.CLI_EOL) result = storage.read.until(storage.CLI_EOL)
if not b"Verifying" in result: if b"Verifying" not in result:
self.logger.error(f"Unexpected response: {result.decode('ascii')}") self.logger.error(f"Unexpected response: {result.decode('ascii')}")
return 3 return 3
result = storage.read.until(storage.CLI_EOL) result = storage.read.until(storage.CLI_EOL)

View File

@ -1,9 +1,10 @@
import logging import logging
import subprocess
from flipper.utils.cdc import resolve_port
import os import os
import subprocess
import sys import sys
from flipper.utils.cdc import resolve_port
def main(): def main():
logger = logging.getLogger() logger = logging.getLogger()

View File

@ -1,14 +1,14 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import binascii
import filecmp
import os
import tempfile
from flipper.app import App from flipper.app import App
from flipper.storage import FlipperStorage, FlipperStorageOperations from flipper.storage import FlipperStorage, FlipperStorageOperations
from flipper.utils.cdc import resolve_port from flipper.utils.cdc import resolve_port
import os
import binascii
import filecmp
import tempfile
def WrapStorageOp(func): def WrapStorageOp(func):
def wrapper(*args, **kwargs): def wrapper(*args, **kwargs):
@ -122,7 +122,7 @@ class Main(App):
try: try:
print("Text data:") print("Text data:")
print(data.decode()) print(data.decode())
except: except Exception:
print("Binary hexadecimal data:") print("Binary hexadecimal data:")
print(binascii.hexlify(data).decode()) print(binascii.hexlify(data).decode())

View File

@ -1,7 +1,6 @@
from SCons.Platform import TempFileMunge from SCons.Platform import TempFileMunge
from SCons.Node import FS from SCons.Node import FS
from SCons.Errors import UserError from SCons.Errors import UserError
from SCons.Warnings import warn, WarningOnByDefault
import os import os
@ -14,6 +13,7 @@ SetOption("max_drift", 1)
ufbt_state_dir = Dir(os.environ.get("UFBT_STATE_DIR", "#.ufbt")) ufbt_state_dir = Dir(os.environ.get("UFBT_STATE_DIR", "#.ufbt"))
ufbt_script_dir = Dir(os.environ.get("UFBT_SCRIPT_DIR")) ufbt_script_dir = Dir(os.environ.get("UFBT_SCRIPT_DIR"))
ufbt_build_dir = ufbt_state_dir.Dir("build")
ufbt_current_sdk_dir = ufbt_state_dir.Dir("current") ufbt_current_sdk_dir = ufbt_state_dir.Dir("current")
@ -63,16 +63,7 @@ core_env = Environment(
], ],
) )
if "update" in BUILD_TARGETS: core_env.Append(CPPDEFINES=GetOption("extra_defines"))
SConscript(
"update.scons",
exports={"core_env": core_env},
)
if "purge" in BUILD_TARGETS:
core_env.Execute(Delete(ufbt_state_dir))
print("uFBT state purged")
Exit(0)
# Now we can import stuff bundled with SDK - it was added to sys.path by ufbt_state # Now we can import stuff bundled with SDK - it was added to sys.path by ufbt_state
@ -109,7 +100,7 @@ env = core_env.Clone(
"fbt_assets", "fbt_assets",
("compilation_db", {"COMPILATIONDB_COMSTR": "\tCDB\t${TARGET}"}), ("compilation_db", {"COMPILATIONDB_COMSTR": "\tCDB\t${TARGET}"}),
], ],
FBT_FAP_DEBUG_ELF_ROOT=ufbt_state_dir.Dir("build"), FBT_FAP_DEBUG_ELF_ROOT=ufbt_build_dir,
TEMPFILE=TempFileMunge, TEMPFILE=TempFileMunge,
MAXLINELENGTH=2048, MAXLINELENGTH=2048,
PROGSUFFIX=".elf", PROGSUFFIX=".elf",
@ -427,3 +418,25 @@ dist_env.PhonyTarget(
"get_apiversion", "get_apiversion",
"@echo $( ${UFBT_API_VERSION} $)", "@echo $( ${UFBT_API_VERSION} $)",
) )
# Dolphin animation builder. Expects "external" directory in current dir
# with animation sources & manifests. Builds & uploads them to connected Flipper
dolphin_src_dir = original_app_dir.Dir("external")
if dolphin_src_dir.exists():
dolphin_dir = ufbt_build_dir.Dir("dolphin")
dolphin_external = dist_env.DolphinExtBuilder(
ufbt_build_dir.Dir("dolphin"),
original_app_dir,
DOLPHIN_RES_TYPE="external",
)
dist_env.PhonyTarget(
"dolphin_ext",
'${PYTHON3} ${FBT_SCRIPT_DIR}/storage.py send "${SOURCE}" /ext/dolphin',
source=ufbt_build_dir.Dir("dolphin"),
)
else:
def missing_dolphin_folder(**kw):
raise UserError(f"Dolphin folder not found: {dolphin_src_dir}")
dist_env.PhonyTarget("dolphin_ext", Action(missing_dolphin_folder, None))

View File

@ -1,32 +1,18 @@
AddOption(
"--extra-define",
action="append",
dest="extra_defines",
default=[],
help="Extra global define that will be passed to C/C++ compiler, can be specified multiple times",
)
AddOption( AddOption(
"--proxy-env", "--proxy-env",
action="store", action="store",
dest="proxy_env", dest="proxy_env",
default="", default="",
help="Comma-separated list of additional environment variables to pass to child SCons processes", help="Comma-separated list of additional environment variables to pass to "
) "child SCons processes",
AddOption(
"--channel",
action="store",
dest="sdk_channel",
choices=["dev", "rc", "release"],
default="",
help="Release channel to use for SDK",
)
AddOption(
"--branch",
action="store",
dest="sdk_branch",
help="Custom main repo branch to use for SDK",
)
AddOption(
"--hw-target",
action="store",
dest="sdk_target",
help="SDK Hardware target",
) )
vars = Variables("ufbt_options.py", ARGUMENTS) vars = Variables("ufbt_options.py", ARGUMENTS)

View File

@ -1,8 +1,8 @@
from SCons.Script import GetBuildFailures
import SCons.Errors
import atexit import atexit
import SCons.Errors
from ansi.color import fg, fx from ansi.color import fg, fx
from SCons.Script import GetBuildFailures
def bf_to_str(bf): def bf_to_str(bf):

View File

@ -1,12 +1,11 @@
from SCons.Errors import StopError
from SCons.Warnings import warn, WarningOnByDefault
import json import json
import os import os
import sys
import pathlib import pathlib
import sys
from functools import reduce from functools import reduce
from SCons.Errors import StopError
def _load_sdk_data(sdk_root): def _load_sdk_data(sdk_root):
split_vars = { split_vars = {

View File

@ -1,37 +0,0 @@
from SCons.Errors import StopError
Import("core_env")
update_env = core_env.Clone(
toolpath=[core_env["FBT_SCRIPT_DIR"].Dir("fbt_tools")],
tools=["python3"],
)
print("Updating SDK...")
ufbt_state = update_env["UFBT_STATE"]
update_args = [
"--ufbt-dir",
f'"{update_env["UFBT_STATE_DIR"]}"',
]
if branch_name := GetOption("sdk_branch"):
update_args.extend(["--branch", branch_name])
elif channel_name := GetOption("sdk_channel"):
update_args.extend(["--channel", channel_name])
elif branch_name := ufbt_state.get("branch", None):
update_args.extend(["--branch", branch_name])
elif channel_name := ufbt_state.get("channel", None):
update_args.extend(["--channel", channel_name])
else:
raise StopError("No branch or channel specified for SDK update")
if hw_target := GetOption("sdk_target"):
update_args.extend(["--hw-target", hw_target])
else:
update_args.extend(["--hw-target", ufbt_state["hw_target"]])
update_env.Replace(UPDATE_ARGS=update_args)
result = update_env.Execute(
update_env.subst('$PYTHON3 "$UFBT_BOOTSTRAP_SCRIPT" $UPDATE_ARGS'),
)
Exit(result)

View File

@ -1,16 +1,16 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from flipper.app import App import math
from flipper.utils.fff import FlipperFormatFile
from flipper.assets.coprobin import CoproBinary, get_stack_type
from flipper.assets.obdata import OptionBytesData, ObReferenceValues
from os.path import basename, join, exists
import os import os
import shutil import shutil
import zlib
import tarfile import tarfile
import math import zlib
from os.path import exists, join
from flipper.app import App
from flipper.assets.coprobin import CoproBinary, get_stack_type
from flipper.assets.obdata import ObReferenceValues, OptionBytesData
from flipper.utils.fff import FlipperFormatFile
from slideshow import Main as SlideshowMain from slideshow import Main as SlideshowMain
@ -267,9 +267,9 @@ class Main(App):
@staticmethod @staticmethod
def batch(iterable, n=1): def batch(iterable, n=1):
l = len(iterable) iterable_len = len(iterable)
for ndx in range(0, l, n): for ndx in range(0, iterable_len, n):
yield iterable[ndx : min(ndx + n, l)] yield iterable[ndx : min(ndx + n, iterable_len)]
if __name__ == "__main__": if __name__ == "__main__":

View File

@ -1,12 +1,12 @@
#!/usb/bin/env python3 #!/usb/bin/env python3
from flipper.app import App
import subprocess
import os
import json import json
import os
import subprocess
from datetime import date, datetime from datetime import date, datetime
from flipper.app import App
class GitVersion: class GitVersion:
REVISION_SUFFIX_LENGTH = 8 REVISION_SUFFIX_LENGTH = 8

View File

@ -1,12 +1,12 @@
from dataclasses import dataclass, field from dataclasses import dataclass, field
from fbt.appmanifest import FlipperAppType
from SCons.Node import NodeList from SCons.Node import NodeList
from SCons.Warnings import warn, WarningOnByDefault from SCons.Warnings import warn, WarningOnByDefault
from SCons.Errors import UserError
Import("ENV") Import("ENV")
from fbt.appmanifest import FlipperAppType
appenv = ENV["APPENV"] = ENV.Clone( appenv = ENV["APPENV"] = ENV.Clone(
tools=[ tools=[