[FL-1443, FL-1289] Move assets compilation to separate Makefile. Add scripts folder. Add OTP flashing with DFU. (#531)
* Assets: move assets compilation to separate Makefile. Move all scripts to scripts folder. Add scripts ReadMe. Add precompiled assets. * Split assets.py into separate entities. Option bytes for FL-1289 and checker/setter. * Cli: explicitly initialize variable befor use in api_hal_vcp_rx_with_timeout * Rename ob_check script to ob.
This commit is contained in:
		| @@ -51,7 +51,7 @@ size_t cli_read(Cli* cli, uint8_t* buffer, size_t size) { | ||||
| } | ||||
|  | ||||
| bool cli_cmd_interrupt_received(Cli* cli) { | ||||
|     char c; | ||||
|     char c = '\0'; | ||||
|     api_hal_vcp_rx_with_timeout((uint8_t*)&c, 1, 1); | ||||
|     return c == CliSymbolAsciiETX; | ||||
| } | ||||
|   | ||||
							
								
								
									
										11
									
								
								assets/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								assets/Makefile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| PROJECT_ROOT		= $(abspath $(dir $(abspath $(firstword $(MAKEFILE_LIST))))..) | ||||
|  | ||||
| include				$(PROJECT_ROOT)/assets/assets.mk | ||||
|  | ||||
| $(ASSETS): $(ASSETS_SOURCES) $(ASSETS_COMPILLER) | ||||
| 	@echo "\tASSETS\t" $@ | ||||
| 	@$(ASSETS_COMPILLER) icons -s $(ASSETS_SOURCE_DIR) -o $(ASSETS_COMPILED_DIR) | ||||
|  | ||||
| clean: | ||||
| 	@echo "\tCLEAN\t" | ||||
| 	@$(RM) $(ASSETS) | ||||
| @@ -1,3 +1,13 @@ | ||||
| # Requirements | ||||
|  | ||||
| - Python3 | ||||
| - ImageMagic | ||||
| - Make | ||||
|  | ||||
| # Compiling | ||||
|  | ||||
| 	make all | ||||
|  | ||||
| # Asset naming rules | ||||
|  | ||||
| ## Images and Animations | ||||
|   | ||||
| @@ -1,10 +1,10 @@ | ||||
| ASSETS_DIR			:= $(PROJECT_ROOT)/assets | ||||
| ASSETS_COMPILLER	:= $(ASSETS_DIR)/assets.py | ||||
| ASSETS_OUTPUT_DIR	:= $(ASSETS_DIR)/output | ||||
| ASSETS_COMPILLER	:= $(PROJECT_ROOT)/scripts/assets.py | ||||
| ASSETS_COMPILED_DIR	:= $(ASSETS_DIR)/compiled | ||||
| ASSETS_SOURCE_DIR	:= $(ASSETS_DIR)/icons | ||||
|  | ||||
| ASSETS_SOURCES		+= $(shell find $(ASSETS_SOURCE_DIR) -type f -iname '*.png' -or -iname 'frame_rate') | ||||
| ASSETS				+= $(ASSETS_OUTPUT_DIR)/assets_icons.c | ||||
| ASSETS				+= $(ASSETS_COMPILED_DIR)/assets_icons.c | ||||
|  | ||||
| CFLAGS				+= -I$(ASSETS_OUTPUT_DIR) | ||||
| C_SOURCES			+= $(ASSETS_OUTPUT_DIR)/assets_icons.c | ||||
| CFLAGS				+= -I$(ASSETS_COMPILED_DIR) | ||||
| C_SOURCES			+= $(ASSETS_COMPILED_DIR)/assets_icons.c | ||||
|   | ||||
							
								
								
									
										617
									
								
								assets/compiled/assets_icons.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										617
									
								
								assets/compiled/assets_icons.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										131
									
								
								assets/compiled/assets_icons.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										131
									
								
								assets/compiled/assets_icons.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,131 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <gui/icon.h> | ||||
|  | ||||
| typedef enum { | ||||
| 	I_SDQuestion_35x43, | ||||
| 	I_SDError_43x35, | ||||
| 	I_Health_16x16, | ||||
| 	I_FaceCharging_29x14, | ||||
| 	I_BatteryBody_52x28, | ||||
| 	I_Voltage_16x16, | ||||
| 	I_Temperature_16x16, | ||||
| 	I_FaceNopower_29x14, | ||||
| 	I_FaceNormal_29x14, | ||||
| 	I_Battery_16x16, | ||||
| 	I_FaceConfused_29x14, | ||||
| 	I_PassportBottom_128x17, | ||||
| 	I_DoorLeft_8x56, | ||||
| 	I_DoorLocked_10x56, | ||||
| 	I_DoorRight_8x56, | ||||
| 	I_DoorLeft_70x55, | ||||
| 	I_PassportLeft_6x47, | ||||
| 	I_DoorRight_70x55, | ||||
| 	I_LockPopup_100x49, | ||||
| 	I_WalkR2_32x32, | ||||
| 	I_WalkL2_32x32, | ||||
| 	I_WalkRB1_32x32, | ||||
| 	I_Home_painting_17x20, | ||||
| 	I_WalkLB2_32x32, | ||||
| 	I_Sofa_40x13, | ||||
| 	I_WalkLB1_32x32, | ||||
| 	I_PC_22x29, | ||||
| 	I_WalkL1_32x32, | ||||
| 	I_TV_20x20, | ||||
| 	I_WalkR1_32x32, | ||||
| 	I_WalkRB2_32x32, | ||||
| 	I_TV_20x24, | ||||
| 	I_dir_10px, | ||||
| 	I_Nfc_10px, | ||||
| 	I_sub1_10px, | ||||
| 	I_ir_10px, | ||||
| 	I_ibutt_10px, | ||||
| 	I_unknown_10px, | ||||
| 	I_ble_10px, | ||||
| 	I_125_10px, | ||||
| 	I_FX_SittingB_40x27, | ||||
| 	I_BigGames_24x24, | ||||
| 	I_BigProfile_24x24, | ||||
| 	I_DolphinOkay_41x43, | ||||
| 	I_DolphinFirstStart5_45x53, | ||||
| 	I_DolphinFirstStart4_67x53, | ||||
| 	I_DolphinFirstStart2_59x51, | ||||
| 	I_DolphinFirstStart0_70x53, | ||||
| 	I_DolphinFirstStart6_58x54, | ||||
| 	I_DolphinFirstStart1_59x53, | ||||
| 	I_DolphinFirstStart8_56x51, | ||||
| 	I_DolphinFirstStart7_61x51, | ||||
| 	I_Flipper_young_80x60, | ||||
| 	I_BigBurger_24x24, | ||||
| 	I_FX_Bang_32x6, | ||||
| 	I_DolphinFirstStart3_57x48, | ||||
| 	I_BadUsb_9x8, | ||||
| 	I_PlaceholderR_30x13, | ||||
| 	I_Background_128x8, | ||||
| 	I_Lock_8x8, | ||||
| 	I_Battery_26x8, | ||||
| 	I_PlaceholderL_11x13, | ||||
| 	I_Battery_19x8, | ||||
| 	I_SDcardMounted_11x8, | ||||
| 	I_SDcardFail_11x8, | ||||
| 	I_USBConnected_15x8, | ||||
| 	I_Bluetooth_5x8, | ||||
| 	I_Background_128x11, | ||||
| 	I_IrdaArrowUp_4x8, | ||||
| 	I_IrdaLearnShort_128x31, | ||||
| 	I_IrdaArrowDown_4x8, | ||||
| 	I_IrdaLearn_128x64, | ||||
| 	I_IrdaSend_128x64, | ||||
| 	I_IrdaSendShort_128x34, | ||||
| 	I_passport_happy1_43x45, | ||||
| 	I_passport_bad3_43x45, | ||||
| 	I_passport_okay2_43x45, | ||||
| 	I_passport_bad2_43x45, | ||||
| 	I_passport_okay3_43x45, | ||||
| 	I_passport_bad1_43x45, | ||||
| 	I_passport_happy3_43x45, | ||||
| 	I_passport_happy2_43x45, | ||||
| 	I_passport_okay1_43x45, | ||||
| 	I_ButtonRightSmall_3x5, | ||||
| 	I_ButtonLeft_4x7, | ||||
| 	I_ButtonLeftSmall_3x5, | ||||
| 	I_ButtonRight_4x7, | ||||
| 	I_ButtonCenter_7x7, | ||||
| 	A_Games_14, | ||||
| 	A_Plugins_14, | ||||
| 	A_Passport_14, | ||||
| 	A_Sub1ghz_14, | ||||
| 	A_NFC_14, | ||||
| 	A_Tamagotchi_14, | ||||
| 	A_FileManager_14, | ||||
| 	A_125khz_14, | ||||
| 	A_U2F_14, | ||||
| 	A_Infrared_14, | ||||
| 	A_Power_14, | ||||
| 	A_Settings_14, | ||||
| 	A_iButton_14, | ||||
| 	A_Bluetooth_14, | ||||
| 	A_GPIO_14, | ||||
| 	I_DolphinMafia_115x62, | ||||
| 	I_DolphinExcited_64x63, | ||||
| 	I_iButtonDolphinSuccess_109x60, | ||||
| 	I_iButtonDolphinVerySuccess_108x52, | ||||
| 	I_iButtonKey_49x44, | ||||
| 	I_DolphinNice_96x59, | ||||
| 	I_DolphinWait_61x59, | ||||
| 	A_Wink_128x64, | ||||
| 	A_MDWL_32x32, | ||||
| 	A_MDWR_32x32, | ||||
| 	A_WatchingTV_128x64, | ||||
| 	A_MDI_32x32, | ||||
| 	A_MDWRB_32x32, | ||||
| 	A_MDIB_32x32, | ||||
| 	A_FX_Sitting_40x27, | ||||
| 	A_MDWLB_32x32, | ||||
| 	I_KeySave_24x11, | ||||
| 	I_KeyBackspaceSelected_16x9, | ||||
| 	I_KeySaveSelected_24x11, | ||||
| 	I_KeyBackspace_16x9, | ||||
| } IconName; | ||||
|  | ||||
| Icon * assets_icons_get(IconName name); | ||||
							
								
								
									
										5
									
								
								assets/compiled/assets_icons_i.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								assets/compiled/assets_icons_i.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <assets_icons.h> | ||||
|  | ||||
| const IconData * assets_icons_get_data(IconName name); | ||||
							
								
								
									
										1
									
								
								assets/output/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								assets/output/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1 +0,0 @@ | ||||
| * | ||||
| @@ -8,7 +8,7 @@ ASM_SOURCES		+= $(wildcard src/*.s) | ||||
| C_SOURCES		+= $(wildcard src/*.c) | ||||
| CPP_SOURCES		+= $(wildcard src/*.cpp) | ||||
|  | ||||
| TARGET			?= f5 | ||||
| TARGET			?= f6 | ||||
| TARGET_DIR		= targets/$(TARGET) | ||||
| include			$(TARGET_DIR)/target.mk | ||||
|  | ||||
|   | ||||
| @@ -3,6 +3,7 @@ PROJECT			= firmware | ||||
|  | ||||
| include 		$(PROJECT_ROOT)/make/base.mk | ||||
| include			$(PROJECT_ROOT)/assets/assets.mk | ||||
| CFLAGS			+= -I$(ASSETS_COMPILED_DIR) | ||||
| include			$(PROJECT_ROOT)/core/core.mk | ||||
| include 		$(PROJECT_ROOT)/applications/applications.mk | ||||
| include			$(PROJECT_ROOT)/lib/lib.mk | ||||
| @@ -10,7 +11,7 @@ include			$(PROJECT_ROOT)/lib/lib.mk | ||||
| CFLAGS += -Werror -Wno-address-of-packed-member | ||||
| CPPFLAGS += -Werror | ||||
|  | ||||
| TARGET			?= f5 | ||||
| TARGET			?= f6 | ||||
|  | ||||
| TARGET_DIR		= targets/$(TARGET) | ||||
|  | ||||
|   | ||||
| @@ -1,9 +0,0 @@ | ||||
| #!/bin/bash | ||||
|  | ||||
| set -x -e | ||||
|  | ||||
| rm bootloader/.obj/f*/flash || true | ||||
| make -C bootloader -j9 flash | ||||
|  | ||||
| rm firmware/.obj/f*/flash || true | ||||
| make -C firmware -j9 flash | ||||
| @@ -47,15 +47,15 @@ $(OBJ_DIR)/$(PROJECT).bin: $(OBJ_DIR)/$(PROJECT).elf | ||||
| 	@echo "\tBIN\t" $@ | ||||
| 	@$(BIN) $< $@ | ||||
|  | ||||
| $(OBJ_DIR)/%.o: %.c $(OBJ_DIR)/BUILD_FLAGS $(ASSETS) | ||||
| $(OBJ_DIR)/%.o: %.c $(OBJ_DIR)/BUILD_FLAGS | ||||
| 	@echo "\tCC\t" $< "->" $@ | ||||
| 	@$(CC) $(CFLAGS) -c $< -o $@ | ||||
|  | ||||
| $(OBJ_DIR)/%.o: %.s $(OBJ_DIR)/BUILD_FLAGS $(ASSETS) | ||||
| $(OBJ_DIR)/%.o: %.s $(OBJ_DIR)/BUILD_FLAGS | ||||
| 	@echo "\tASM\t" $< "->" $@ | ||||
| 	@$(AS) $(CFLAGS) -c $< -o $@ | ||||
|  | ||||
| $(OBJ_DIR)/%.o: %.cpp $(OBJ_DIR)/BUILD_FLAGS $(ASSETS) | ||||
| $(OBJ_DIR)/%.o: %.cpp $(OBJ_DIR)/BUILD_FLAGS | ||||
| 	@echo "\tCPP\t" $< "->" $@ | ||||
| 	@$(CPP) $(CFLAGS) $(CPPFLAGS) -c $< -o $@ | ||||
|  | ||||
| @@ -67,10 +67,6 @@ $(OBJ_DIR)/upload: $(OBJ_DIR)/$(PROJECT).bin | ||||
| 	dfu-util -D $(OBJ_DIR)/$(PROJECT).bin -a 0 -s $(FLASH_ADDRESS) $(DFU_OPTIONS) | ||||
| 	touch $@ | ||||
|  | ||||
| $(ASSETS): $(ASSETS_SOURCES) $(ASSETS_COMPILLER) | ||||
| 	@echo "\tASSETS\t" $@ | ||||
| 	@$(ASSETS_COMPILLER) icons -s $(ASSETS_SOURCE_DIR) -o $(ASSETS_OUTPUT_DIR) | ||||
|  | ||||
| flash: $(OBJ_DIR)/flash | ||||
|  | ||||
| upload: $(OBJ_DIR)/upload | ||||
| @@ -104,7 +100,6 @@ bm_debug: flash | ||||
| clean: | ||||
| 	@echo "\tCLEAN\t" | ||||
| 	@$(RM) $(OBJ_DIR)/* | ||||
| 	@$(RM) $(ASSETS) | ||||
|  | ||||
| z: clean | ||||
| 	$(MAKE) all | ||||
| @@ -123,7 +118,7 @@ format: | ||||
| 	@echo "Formatting sources with clang-format" | ||||
| 	@clang-format -style=file -i $(FORMAT_SOURCES) | ||||
|  | ||||
| generate_cscope_db: $(ASSETS) | ||||
| generate_cscope_db: | ||||
| 	@echo "$(C_SOURCES) $(CPP_SOURCES) $(ASM_SOURCES)" | tr ' ' '\n' > $(OBJ_DIR)/source.list.p | ||||
| 	@cat ~/headers.list >> $(OBJ_DIR)/source.list.p | ||||
| 	@cat $(OBJ_DIR)/source.list.p | sed -e "s|^[^//]|$$PWD/&|g" > $(OBJ_DIR)/source.list | ||||
|   | ||||
							
								
								
									
										51
									
								
								scripts/ReadMe.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								scripts/ReadMe.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| # About | ||||
|  | ||||
| This folder contains differnt scripts that automates routine actions. | ||||
| Flashing scripts are based on cli version of [STM32CubeProgrammer](https://www.st.com/en/development-tools/stm32cubeprog.html). | ||||
| You will need to add STM32_Programmer_CLI to your path to use them. | ||||
|  | ||||
| # Flashing empty MCU/Flipper | ||||
|  | ||||
| Always flash your device in the folllowing sequence: | ||||
|  | ||||
| - OTP (Only on empty MCU) | ||||
| - Core2 firmware | ||||
| - Core1 firmware | ||||
| - Option Bytes | ||||
|  | ||||
| ## Otp flashing | ||||
|  | ||||
| !!! Flashing incorrect OTP may permanently brick your device !!! | ||||
|  | ||||
| Normally OTP data generated and flashed at factory. | ||||
| In case if MCU was replaced you'll need correct OTP data to be able to use companion applications. | ||||
| Use `otp.py` to generate OTP data and `flash_otp_version_*` to flash OTP zone. | ||||
| You will need exact main board revision to genrate OTP data. It can be found on main PCB. | ||||
|  | ||||
| !!! Flashing incorrect OTP may permanently brick your device !!! | ||||
|  | ||||
| ## Core2 flashing | ||||
|  | ||||
| Script blindly updates FUS and Radiostack. This operation is going to corrupt bootloader and firmware. | ||||
| Reflash Core1 after Core2. | ||||
|  | ||||
| ## Core1 flashing | ||||
|  | ||||
| Script compiles and flashes both bootloader and firmware. | ||||
|  | ||||
| ## Option Bytes | ||||
|  | ||||
| !!! Setting incorrect Otion Bytes may brick your MCU !!! | ||||
|  | ||||
| Defaults are mostly OK, but there are couple things that we'd like to tune. | ||||
| Also OB may be damaged, so we've made couple scripts to check and set option bytes. | ||||
|  | ||||
| !!! Setting incorrect Otion Bytes may brick your MCU !!! | ||||
|  | ||||
| Checking option bytes: | ||||
|  | ||||
| 	ob.py check | ||||
|  | ||||
| Setting option bytes: | ||||
|  | ||||
| 	ob.py set | ||||
| @@ -6,9 +6,6 @@ import subprocess | ||||
| import io | ||||
| import os | ||||
| import sys | ||||
| import re | ||||
| import struct | ||||
| import datetime | ||||
| 
 | ||||
| ICONS_SUPPORTED_FORMATS = ["png"] | ||||
| 
 | ||||
| @@ -51,7 +48,7 @@ Icon * assets_icons_get(IconName name) { | ||||
| """ | ||||
| 
 | ||||
| 
 | ||||
| class Assets: | ||||
| class Main: | ||||
|     def __init__(self): | ||||
|         # command args | ||||
|         self.parser = argparse.ArgumentParser() | ||||
| @@ -67,22 +64,6 @@ class Assets: | ||||
|             "-o", "--output-directory", help="Output directory" | ||||
|         ) | ||||
|         self.parser_icons.set_defaults(func=self.icons) | ||||
|         self.parser_otp = self.subparsers.add_parser( | ||||
|             "otp", help="OTP HW version generator" | ||||
|         ) | ||||
|         self.parser_otp.add_argument( | ||||
|             "--version", type=int, help="Version", required=True | ||||
|         ) | ||||
|         self.parser_otp.add_argument( | ||||
|             "--firmware", type=int, help="Firmware", required=True | ||||
|         ) | ||||
|         self.parser_otp.add_argument("--body", type=int, help="Body", required=True) | ||||
|         self.parser_otp.add_argument( | ||||
|             "--connect", type=int, help="Connect", required=True | ||||
|         ) | ||||
|         self.parser_otp.add_argument("--name", type=str, help="Name", required=True) | ||||
|         self.parser_otp.add_argument("file", help="Output file") | ||||
|         self.parser_otp.set_defaults(func=self.otp) | ||||
|         # logging | ||||
|         self.logger = logging.getLogger() | ||||
| 
 | ||||
| @@ -101,39 +82,6 @@ class Assets: | ||||
|         # execute requested function | ||||
|         self.args.func() | ||||
| 
 | ||||
|     def otp(self): | ||||
|         self.logger.debug(f"Generating OTP") | ||||
| 
 | ||||
|         if self.args.name: | ||||
|             name = re.sub( | ||||
|                 "[^a-zA-Z0-9.]", "", self.args.name | ||||
|             )  # Filter all special characters | ||||
|             name = list( | ||||
|                 map(str, map(ord, name[0:8])) | ||||
|             )  # Strip to 8 chars and map to ascii codes | ||||
|             while len(name) < 8: | ||||
|                 name.append("0") | ||||
| 
 | ||||
|             n1, n2, n3, n4, n5, n6, n7, n8 = map(int, name) | ||||
| 
 | ||||
|         data = struct.pack( | ||||
|             "<BBBBLBBBBBBBB", | ||||
|             self.args.version, | ||||
|             self.args.firmware, | ||||
|             self.args.body, | ||||
|             self.args.connect, | ||||
|             int(datetime.datetime.now().timestamp()), | ||||
|             n1, | ||||
|             n2, | ||||
|             n3, | ||||
|             n4, | ||||
|             n5, | ||||
|             n6, | ||||
|             n7, | ||||
|             n8, | ||||
|         ) | ||||
|         open(self.args.file, "wb").write(data) | ||||
| 
 | ||||
|     def icons(self): | ||||
|         self.logger.debug(f"Converting icons") | ||||
|         icons_c = open(os.path.join(self.args.output_directory, "assets_icons.c"), "w") | ||||
| @@ -248,4 +196,4 @@ class Assets: | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
|     Assets()() | ||||
|     Main()() | ||||
							
								
								
									
										12
									
								
								scripts/flash_core1_main_swd.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										12
									
								
								scripts/flash_core1_main_swd.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| #!/bin/bash | ||||
|  | ||||
| set -x -e | ||||
|  | ||||
| SCRIPT_DIR="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" | ||||
| PROJECT_DIR="$(dirname "$SCRIPT_DIR")" | ||||
|  | ||||
| rm $PROJECT_DIR/bootloader/.obj/f*/flash || true | ||||
| make -C $PROJECT_DIR/bootloader -j9 flash | ||||
|  | ||||
| rm $PROJECT_DIR/firmware/.obj/f*/flash || true | ||||
| make -C $PROJECT_DIR/firmware -j9 flash | ||||
| @@ -2,8 +2,9 @@ | ||||
| 
 | ||||
| set -x -e | ||||
| 
 | ||||
| COPRO_DIR="lib/STM32CubeWB/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x" | ||||
| 
 | ||||
| SCRIPT_DIR="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" | ||||
| PROJECT_DIR="$(dirname "$SCRIPT_DIR")" | ||||
| COPRO_DIR="$PROJECT_DIR/lib/STM32CubeWB/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x" | ||||
| 
 | ||||
| STM32_Programmer_CLI -c port=swd -fwupgrade $COPRO_DIR/stm32wb5x_FUS_fw_1_0_2.bin 0x080EC000 || true | ||||
| STM32_Programmer_CLI -c port=swd | ||||
							
								
								
									
										17
									
								
								scripts/flash_otp_version_dfu.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										17
									
								
								scripts/flash_otp_version_dfu.sh
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| #!/bin/bash | ||||
|  | ||||
| set -x -e | ||||
|  | ||||
| if [ "$#" -ne 1 ]; then | ||||
|     echo "OTP file required" | ||||
|     exit | ||||
| fi | ||||
|  | ||||
| if [ ! -f $1 ]; then | ||||
|     echo "Unable to open OTP file" | ||||
|     exit | ||||
| fi | ||||
|  | ||||
| STM32_Programmer_CLI -c port=usb1 -d $1 0x1FFF7000 | ||||
|  | ||||
| STM32_Programmer_CLI -c port=usb1 -r8 0x1FFF7000 8 | ||||
							
								
								
									
										113
									
								
								scripts/ob.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										113
									
								
								scripts/ob.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,113 @@ | ||||
| #!/usr/bin/env python3 | ||||
|  | ||||
| import logging | ||||
| import argparse | ||||
| import subprocess | ||||
| import sys | ||||
| import os | ||||
|  | ||||
|  | ||||
| class Main: | ||||
|     def __init__(self): | ||||
|         # command args | ||||
|         self.parser = argparse.ArgumentParser() | ||||
|         self.parser.add_argument("-d", "--debug", action="store_true", help="Debug") | ||||
|         self.subparsers = self.parser.add_subparsers(help="sub-command help") | ||||
|         self.parser_check = self.subparsers.add_parser( | ||||
|             "check", help="Check Option Bytes" | ||||
|         ) | ||||
|         self.parser_check.set_defaults(func=self.check) | ||||
|         self.parser_set = self.subparsers.add_parser("set", help="Set Option Bytes") | ||||
|         self.parser_set.set_defaults(func=self.set) | ||||
|         # logging | ||||
|         self.logger = logging.getLogger() | ||||
|         # OB | ||||
|         self.ob = {} | ||||
|  | ||||
|     def __call__(self): | ||||
|         self.args = self.parser.parse_args() | ||||
|         if "func" not in self.args: | ||||
|             self.parser.error("Choose something to do") | ||||
|         # configure log output | ||||
|         self.log_level = logging.DEBUG if self.args.debug else logging.INFO | ||||
|         self.logger.setLevel(self.log_level) | ||||
|         self.handler = logging.StreamHandler(sys.stdout) | ||||
|         self.handler.setLevel(self.log_level) | ||||
|         self.formatter = logging.Formatter("%(asctime)s [%(levelname)s] %(message)s") | ||||
|         self.handler.setFormatter(self.formatter) | ||||
|         self.logger.addHandler(self.handler) | ||||
|         # execute requested function | ||||
|         self.loadOB() | ||||
|         self.args.func() | ||||
|  | ||||
|     def loadOB(self): | ||||
|         self.logger.info(f"Loading Option Bytes data") | ||||
|         file_path = os.path.join(os.path.dirname(sys.argv[0]), "ob.data") | ||||
|         file = open(file_path, "r") | ||||
|         for line in file.readlines(): | ||||
|             k, v, o = line.split(":") | ||||
|             self.ob[k.strip()] = v.strip(), o.strip() | ||||
|  | ||||
|     def check(self): | ||||
|         self.logger.info(f"Checking Option Bytes") | ||||
|         try: | ||||
|             output = subprocess.check_output( | ||||
|                 ["STM32_Programmer_CLI", "-q", "-c port=swd", "-ob displ"] | ||||
|             ) | ||||
|             assert output | ||||
|         except Exception as e: | ||||
|             self.logger.error(f"Failed to call STM32_Programmer_CLI") | ||||
|             self.logger.exception(e) | ||||
|             return | ||||
|         ob_correct = True | ||||
|         for line in output.decode().split("\n"): | ||||
|             line = line.strip() | ||||
|             if not ":" in line: | ||||
|                 self.logger.debug(f"Skipping line: {line}") | ||||
|                 continue | ||||
|             key, data = line.split(":", 1) | ||||
|             key = key.strip() | ||||
|             data = data.strip() | ||||
|             if not key in self.ob.keys(): | ||||
|                 self.logger.debug(f"Skipping key: {key}") | ||||
|                 continue | ||||
|             self.logger.debug(f"Processing key: {key} {data}") | ||||
|             value, comment = data.split(" ", 1) | ||||
|             value = value.strip() | ||||
|             comment = comment.strip() | ||||
|             if self.ob[key][0] != value: | ||||
|                 self.logger.error( | ||||
|                     f"Invalid OB: {key} {value}, expected: {self.ob[key][0]}" | ||||
|                 ) | ||||
|                 ob_correct = False | ||||
|         if ob_correct: | ||||
|             self.logger.info(f"OB Check OK") | ||||
|         else: | ||||
|             self.logger.error(f"OB Check FAIL") | ||||
|             exit(255) | ||||
|  | ||||
|     def set(self): | ||||
|         self.logger.info(f"Setting Option Bytes") | ||||
|         options = [] | ||||
|         for key, (value, attr) in self.ob.items(): | ||||
|             if "w" in attr: | ||||
|                 options.append(f"{key}={value}") | ||||
|         try: | ||||
|             output = subprocess.check_output( | ||||
|                 [ | ||||
|                     "STM32_Programmer_CLI", | ||||
|                     "-q", | ||||
|                     "-c port=swd", | ||||
|                     f"-ob {' '.join(options)}", | ||||
|                 ] | ||||
|             ) | ||||
|             assert output | ||||
|             self.logger.info(f"Success") | ||||
|         except Exception as e: | ||||
|             self.logger.error(f"Failed to call STM32_Programmer_CLI") | ||||
|             self.logger.exception(e) | ||||
|             return | ||||
|  | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     Main()() | ||||
							
								
								
									
										34
									
								
								scripts/ob_check.data
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								scripts/ob_check.data
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| RDP:0xAA:r | ||||
| BOR_LEV:0x4:rw | ||||
| nBOOT0:0x1:rw | ||||
| nBOOT1:0x1:rw | ||||
| nSWBOOT0:0x1:rw | ||||
| SRAM2RST:0x0:rw | ||||
| SRAM2PE:0x1:rw | ||||
| nRST_STOP:0x1:rw | ||||
| nRST_STDBY:0x1:rw | ||||
| nRSTSHDW:0x1:rw | ||||
| WWDGSW:0x1:rw | ||||
| IWGDSTDBY:0x1:rw | ||||
| IWDGSTOP:0x1:rw | ||||
| IWDGSW:0x1:rw | ||||
| IPCCDBA:0x0:rw | ||||
| ESE:0x1:r | ||||
| SFSA:0xCB:r | ||||
| FSD:0x0:r | ||||
| DDS:0x1:r | ||||
| C2OPT:0x1:r | ||||
| NBRSD:0x0:r | ||||
| SNBRSA:0xF:r | ||||
| BRSD:0x0:r | ||||
| SBRSA:0xA:r | ||||
| SBRV:0x32C00:r | ||||
| PCROP1A_STRT:0x1FF:r | ||||
| PCROP1A_END:0x0:r | ||||
| PCROP_RDP:0x1:r | ||||
| PCROP1B_STRT:0x1FF:r | ||||
| PCROP1B_END:0x0:r | ||||
| WRP1A_STRT:0xFF:r | ||||
| WRP1A_END:0x0:r | ||||
| WRP1B_STRT:0xFF:r | ||||
| WRP1B_END:0x0:r | ||||
							
								
								
									
										91
									
								
								scripts/otp.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										91
									
								
								scripts/otp.py
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,91 @@ | ||||
| #!/usr/bin/env python3 | ||||
|  | ||||
| import logging | ||||
| import argparse | ||||
| import os | ||||
| import sys | ||||
| import re | ||||
| import struct | ||||
| import datetime | ||||
|  | ||||
|  | ||||
| class Main: | ||||
|     def __init__(self): | ||||
|         # command args | ||||
|         self.parser = argparse.ArgumentParser() | ||||
|         self.parser.add_argument("-d", "--debug", action="store_true", help="Debug") | ||||
|         self.subparsers = self.parser.add_subparsers(help="sub-command help") | ||||
|         self.parser_generate = self.subparsers.add_parser( | ||||
|             "generate", help="OTP HW version generator" | ||||
|         ) | ||||
|         self.parser_generate.add_argument( | ||||
|             "--version", type=int, help="Version", required=True | ||||
|         ) | ||||
|         self.parser_generate.add_argument( | ||||
|             "--firmware", type=int, help="Firmware", required=True | ||||
|         ) | ||||
|         self.parser_generate.add_argument( | ||||
|             "--body", type=int, help="Body", required=True | ||||
|         ) | ||||
|         self.parser_generate.add_argument( | ||||
|             "--connect", type=int, help="Connect", required=True | ||||
|         ) | ||||
|         self.parser_generate.add_argument( | ||||
|             "--name", type=str, help="Name", required=True | ||||
|         ) | ||||
|         self.parser_generate.add_argument("file", help="Output file") | ||||
|         self.parser_generate.set_defaults(func=self.generate) | ||||
|         # logging | ||||
|         self.logger = logging.getLogger() | ||||
|  | ||||
|     def __call__(self): | ||||
|         self.args = self.parser.parse_args() | ||||
|         if "func" not in self.args: | ||||
|             self.parser.error("Choose something to do") | ||||
|         # configure log output | ||||
|         self.log_level = logging.DEBUG if self.args.debug else logging.INFO | ||||
|         self.logger.setLevel(self.log_level) | ||||
|         self.handler = logging.StreamHandler(sys.stdout) | ||||
|         self.handler.setLevel(self.log_level) | ||||
|         self.formatter = logging.Formatter("%(asctime)s [%(levelname)s] %(message)s") | ||||
|         self.handler.setFormatter(self.formatter) | ||||
|         self.logger.addHandler(self.handler) | ||||
|         # execute requested function | ||||
|         self.args.func() | ||||
|  | ||||
|     def generate(self): | ||||
|         self.logger.debug(f"Generating OTP") | ||||
|  | ||||
|         if self.args.name: | ||||
|             name = re.sub( | ||||
|                 "[^a-zA-Z0-9.]", "", self.args.name | ||||
|             )  # Filter all special characters | ||||
|             name = list( | ||||
|                 map(str, map(ord, name[0:8])) | ||||
|             )  # Strip to 8 chars and map to ascii codes | ||||
|             while len(name) < 8: | ||||
|                 name.append("0") | ||||
|  | ||||
|             n1, n2, n3, n4, n5, n6, n7, n8 = map(int, name) | ||||
|  | ||||
|         data = struct.pack( | ||||
|             "<BBBBLBBBBBBBB", | ||||
|             self.args.version, | ||||
|             self.args.firmware, | ||||
|             self.args.body, | ||||
|             self.args.connect, | ||||
|             int(datetime.datetime.now().timestamp()), | ||||
|             n1, | ||||
|             n2, | ||||
|             n3, | ||||
|             n4, | ||||
|             n5, | ||||
|             n6, | ||||
|             n7, | ||||
|             n8, | ||||
|         ) | ||||
|         open(self.args.file, "wb").write(data) | ||||
|  | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     Main()() | ||||
| @@ -1,4 +0,0 @@ | ||||
| #!/usr/bin/env bash | ||||
|  | ||||
| echo "RUN SYNTAX CHECK INSIDE CONTAINER" | ||||
| docker-compose exec dev ./docker/syntax_check.sh | ||||
		Reference in New Issue
	
	Block a user