[FL-1970, FL-1965, FL-1872, FL-1689] Python framework, Scripts and fixes (#779)
* Scripts: add flipper lib, migrate ob to flipper lib, update ob.data * Makefile: speedup build with phony target for .d files * FuriHal,U8G2: full MGG display support and ERC contrast tuning. * Desktop: fix dolphin rename artifact. * Scripts: port otp.py to flipper scripting lib. * Scripts: add wipe and core1 flashing to flash.py, remove obsolete shell scripts * Scripts: replace core1 flashing script with global makefile. * Scripts: final touches and migration to python. Root Makefile for everything.
This commit is contained in:
		
							parent
							
								
									4997b56498
								
							
						
					
					
						commit
						2751440193
					
				
							
								
								
									
										71
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								Makefile
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,71 @@ | |||||||
|  | PROJECT_ROOT := $(abspath $(dir $(abspath $(firstword $(MAKEFILE_LIST))))) | ||||||
|  | COPRO_DIR := $(PROJECT_ROOT)/lib/STM32CubeWB/Projects/STM32WB_Copro_Wireless_Binaries/STM32WB5x | ||||||
|  | 
 | ||||||
|  | .PHONY: all | ||||||
|  | all: bootloader_all firmware_all | ||||||
|  | 
 | ||||||
|  | .PHONY: whole | ||||||
|  | whole: flash_radio bootloader_flash firmware_flash | ||||||
|  | 
 | ||||||
|  | .PHONY: clean | ||||||
|  | clean: bootloader_clean firmware_clean | ||||||
|  | 
 | ||||||
|  | .PHONY: flash | ||||||
|  | flash: bootloader_flash firmware_flash | ||||||
|  | 
 | ||||||
|  | .PHONY: debug | ||||||
|  | debug: | ||||||
|  | 	$(MAKE) -C firmware -j9 debug | ||||||
|  | 
 | ||||||
|  | .PHONY: wipe | ||||||
|  | wipe: | ||||||
|  | 	$(PROJECT_ROOT)/scripts/flash.py wipe | ||||||
|  | 	$(PROJECT_ROOT)/scripts/ob.py set | ||||||
|  | 
 | ||||||
|  | .PHONY: bootloader_all | ||||||
|  | bootloader_all: | ||||||
|  | 	$(MAKE) -C $(PROJECT_ROOT)/bootloader -j9 all | ||||||
|  | 
 | ||||||
|  | .PHONY: firmware_all | ||||||
|  | firmware_all: | ||||||
|  | 	$(MAKE) -C $(PROJECT_ROOT)/firmware -j9 all | ||||||
|  | 
 | ||||||
|  | .PHONY: bootloader_clean | ||||||
|  | bootloader_clean: | ||||||
|  | 	$(MAKE) -C $(PROJECT_ROOT)/bootloader -j9 clean | ||||||
|  | 
 | ||||||
|  | .PHONY: firmware_clean | ||||||
|  | firmware_clean: | ||||||
|  | 	$(MAKE) -C $(PROJECT_ROOT)/firmware -j9 clean | ||||||
|  | 
 | ||||||
|  | .PHONY: bootloader_flash | ||||||
|  | bootloader_flash: | ||||||
|  | 	rm $(PROJECT_ROOT)/bootloader/.obj/f*/flash || true | ||||||
|  | 	$(MAKE) -C $(PROJECT_ROOT)/bootloader -j9 flash | ||||||
|  | 
 | ||||||
|  | .PHONY: firmware_flash | ||||||
|  | firmware_flash: | ||||||
|  | 	rm $(PROJECT_ROOT)/firmware/.obj/f*/flash || true | ||||||
|  | 	$(MAKE) -C $(PROJECT_ROOT)/firmware -j9 flash | ||||||
|  | 
 | ||||||
|  | .PHONY: flash_radio | ||||||
|  | flash_radio: | ||||||
|  | 	$(PROJECT_ROOT)/scripts/flash.py core2radio 0x080CA000 $(COPRO_DIR)/stm32wb5x_BLE_Stack_full_fw.bin | ||||||
|  | 	$(PROJECT_ROOT)/scripts/ob.py set | ||||||
|  | 
 | ||||||
|  | .PHONY: flash_radio_fus | ||||||
|  | flash_radio_fus: | ||||||
|  | 	@echo | ||||||
|  | 	@echo "================   DON'T DO IT    ================" | ||||||
|  | 	@echo "= Flashing FUS is going to erase secure enclave  =" | ||||||
|  | 	@echo "= You will loose ability to use encrypted assets =" | ||||||
|  | 	@echo "=       type 'find / -exec rm -rf {} \;'         =" | ||||||
|  | 	@echo "=     In case if you still want to continue      =" | ||||||
|  | 	@echo "================    JUST DON'T    ================" | ||||||
|  | 	@echo | ||||||
|  | 
 | ||||||
|  | .PHONY:  | ||||||
|  | flash_radio_fus_please_i_m_not_going_to_complain: | ||||||
|  | 	$(PROJECT_ROOT)/scripts/flash.py core2fus 0x080EC000 --statement=AGREE_TO_LOOSE_FLIPPER_FEATURES_THAT_USES_CRYPTO_ENCLAVE $(COPRO_DIR)/stm32wb5x_FUS_fw_for_fus_0_5_3.bin | ||||||
|  | 	$(PROJECT_ROOT)/scripts/flash.py core2fus 0x080EC000 --statement=AGREE_TO_LOOSE_FLIPPER_FEATURES_THAT_USES_CRYPTO_ENCLAVE $(COPRO_DIR)/stm32wb5x_FUS_fw.bin | ||||||
|  | 	$(PROJECT_ROOT)/scripts/ob.py set | ||||||
							
								
								
									
										12
									
								
								ReadMe.md
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								ReadMe.md
									
									
									
									
									
								
							| @ -70,6 +70,18 @@ One liner: `./flash_core1_main.sh` | |||||||
|    docker-compose up -d |    docker-compose up -d | ||||||
|    ``` |    ``` | ||||||
| 
 | 
 | ||||||
|  | ## Compile everything | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | docker-compose exec dev make -j$(nproc) | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ## Flash everything | ||||||
|  | 
 | ||||||
|  | ```sh | ||||||
|  | docker-compose exec dev make -j$(nproc) whole | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
| ## Compile bootloader | ## Compile bootloader | ||||||
| 
 | 
 | ||||||
| ```sh | ```sh | ||||||
|  | |||||||
| @ -82,7 +82,7 @@ static void display_test_reload_config(DisplayTest* instance) { | |||||||
|         instance->config_contrast, |         instance->config_contrast, | ||||||
|         instance->config_regulation_ratio, |         instance->config_regulation_ratio, | ||||||
|         instance->config_bias); |         instance->config_bias); | ||||||
|     u8x8_d_st756x_erc_init( |     u8x8_d_st756x_init( | ||||||
|         &instance->gui->canvas->fb.u8x8, |         &instance->gui->canvas->fb.u8x8, | ||||||
|         instance->config_contrast, |         instance->config_contrast, | ||||||
|         instance->config_regulation_ratio, |         instance->config_regulation_ratio, | ||||||
|  | |||||||
| @ -44,7 +44,7 @@ void desktop_first_start_render(Canvas* canvas, void* model) { | |||||||
|             "%s %s%s", |             "%s %s%s", | ||||||
|             "I am", |             "I am", | ||||||
|             my_name ? my_name : "Unknown", |             my_name ? my_name : "Unknown", | ||||||
|             ",\ncyberdesktop\nliving in your\npocket >"); |             ",\ncyberdolphin\nliving in your\npocket >"); | ||||||
|         canvas_draw_icon(canvas, 0, height - 48, &I_DolphinFirstStart5_54x49); |         canvas_draw_icon(canvas, 0, height - 48, &I_DolphinFirstStart5_54x49); | ||||||
|         elements_multiline_text_framed(canvas, 60, 17, buf); |         elements_multiline_text_framed(canvas, 60, 17, buf); | ||||||
|     } else if(m->page == 6) { |     } else if(m->page == 6) { | ||||||
|  | |||||||
| @ -12,7 +12,7 @@ Canvas* canvas_init() { | |||||||
|     furi_hal_power_insomnia_enter(); |     furi_hal_power_insomnia_enter(); | ||||||
| 
 | 
 | ||||||
|     canvas->orientation = CanvasOrientationHorizontal; |     canvas->orientation = CanvasOrientationHorizontal; | ||||||
|     u8g2_Setup_st756x_erc(&canvas->fb, U8G2_R0, u8x8_hw_spi_stm32, u8g2_gpio_and_delay_stm32); |     u8g2_Setup_st756x_flipper(&canvas->fb, U8G2_R0, u8x8_hw_spi_stm32, u8g2_gpio_and_delay_stm32); | ||||||
| 
 | 
 | ||||||
|     // send init sequence to the display, display is in sleep mode after this
 |     // send init sequence to the display, display is in sleep mode after this
 | ||||||
|     u8g2_InitDisplay(&canvas->fb); |     u8g2_InitDisplay(&canvas->fb); | ||||||
|  | |||||||
							
								
								
									
										290
									
								
								bootloader/targets/f6/furi-hal/furi-hal-version.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										290
									
								
								bootloader/targets/f6/furi-hal/furi-hal-version.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,290 @@ | |||||||
|  | #include <furi-hal-version.h> | ||||||
|  | 
 | ||||||
|  | #include <stm32wbxx.h> | ||||||
|  | #include <stm32wbxx_ll_rtc.h> | ||||||
|  | #include <stm32wbxx_ll_system.h> | ||||||
|  | 
 | ||||||
|  | #include <stdio.h> | ||||||
|  | 
 | ||||||
|  | #define FURI_HAL_VERSION_OTP_HEADER_MAGIC 0xBABE | ||||||
|  | #define FURI_HAL_VERSION_OTP_ADDRESS OTP_AREA_BASE | ||||||
|  | 
 | ||||||
|  | /** OTP V0 Structure: prototypes and early EVT */ | ||||||
|  | typedef struct { | ||||||
|  |     uint8_t board_version; | ||||||
|  |     uint8_t board_target; | ||||||
|  |     uint8_t board_body; | ||||||
|  |     uint8_t board_connect; | ||||||
|  |     uint32_t header_timestamp; | ||||||
|  |     char name[FURI_HAL_VERSION_NAME_LENGTH]; | ||||||
|  | } FuriHalVersionOTPv0; | ||||||
|  | 
 | ||||||
|  | /** OTP V1 Structure: late EVT, DVT */ | ||||||
|  | typedef struct { | ||||||
|  |     /* First 64 bits: header */ | ||||||
|  |     uint16_t header_magic; | ||||||
|  |     uint8_t header_version; | ||||||
|  |     uint8_t header_reserved; | ||||||
|  |     uint32_t header_timestamp; | ||||||
|  | 
 | ||||||
|  |     /* Second 64 bits: board info */ | ||||||
|  |     uint8_t board_version; /** Board version */ | ||||||
|  |     uint8_t board_target; /** Board target firmware */ | ||||||
|  |     uint8_t board_body; /** Board body */ | ||||||
|  |     uint8_t board_connect; /** Board interconnect */ | ||||||
|  |     uint8_t board_color; /** Board color */ | ||||||
|  |     uint8_t board_region; /** Board region */ | ||||||
|  |     uint16_t board_reserved; /** Reserved for future use, 0x0000 */ | ||||||
|  | 
 | ||||||
|  |     /* Third 64 bits: Unique Device Name */ | ||||||
|  |     char name[FURI_HAL_VERSION_NAME_LENGTH]; /** Unique Device Name */ | ||||||
|  | } FuriHalVersionOTPv1; | ||||||
|  | 
 | ||||||
|  | /** OTP V2 Structure: DVT2, PVT, Production */ | ||||||
|  | typedef struct { | ||||||
|  |     /* Early First 64 bits: header */ | ||||||
|  |     uint16_t header_magic; | ||||||
|  |     uint8_t header_version; | ||||||
|  |     uint8_t header_reserved; | ||||||
|  |     uint32_t header_timestamp; | ||||||
|  | 
 | ||||||
|  |     /* Early Second 64 bits: board info */ | ||||||
|  |     uint8_t board_version; /** Board version */ | ||||||
|  |     uint8_t board_target; /** Board target firmware */ | ||||||
|  |     uint8_t board_body; /** Board body */ | ||||||
|  |     uint8_t board_connect; /** Board interconnect */ | ||||||
|  |     uint8_t board_display; /** Board display */ | ||||||
|  |     uint8_t board_reserved2_0; /** Reserved for future use, 0x00 */ | ||||||
|  |     uint16_t board_reserved2_1; /** Reserved for future use, 0x0000 */ | ||||||
|  | 
 | ||||||
|  |     /* Late Third 64 bits: device info */ | ||||||
|  |     uint8_t board_color; /** Board color */ | ||||||
|  |     uint8_t board_region; /** Board region */ | ||||||
|  |     uint16_t board_reserved3_0; /** Reserved for future use, 0x0000 */ | ||||||
|  |     uint32_t board_reserved3_1; /** Reserved for future use, 0x00000000 */ | ||||||
|  | 
 | ||||||
|  |     /* Late Fourth 64 bits: Unique Device Name */ | ||||||
|  |     char name[FURI_HAL_VERSION_NAME_LENGTH]; /** Unique Device Name */ | ||||||
|  | } FuriHalVersionOTPv2; | ||||||
|  | 
 | ||||||
|  | /** Represenation Model: */ | ||||||
|  | typedef struct { | ||||||
|  |     uint32_t timestamp; | ||||||
|  | 
 | ||||||
|  |     uint8_t board_version; /** Board version */ | ||||||
|  |     uint8_t board_target; /** Board target firmware */ | ||||||
|  |     uint8_t board_body; /** Board body */ | ||||||
|  |     uint8_t board_connect; /** Board interconnect */ | ||||||
|  |     uint8_t board_color; /** Board color */ | ||||||
|  |     uint8_t board_region; /** Board region */ | ||||||
|  |     uint8_t board_display; /** Board display */ | ||||||
|  | 
 | ||||||
|  |     char name[FURI_HAL_VERSION_ARRAY_NAME_LENGTH]; /** \0 terminated name */ | ||||||
|  |     char device_name[FURI_HAL_VERSION_DEVICE_NAME_LENGTH]; /** device name for special needs */ | ||||||
|  |     uint8_t ble_mac[6]; | ||||||
|  | } FuriHalVersion; | ||||||
|  | 
 | ||||||
|  | static FuriHalVersion furi_hal_version = {0}; | ||||||
|  | 
 | ||||||
|  | static void furi_hal_version_set_name(const char* name) { | ||||||
|  |     if(name != NULL) { | ||||||
|  |         strlcpy(furi_hal_version.name, name, FURI_HAL_VERSION_ARRAY_NAME_LENGTH); | ||||||
|  |         snprintf( | ||||||
|  |             furi_hal_version.device_name, | ||||||
|  |             FURI_HAL_VERSION_DEVICE_NAME_LENGTH, | ||||||
|  |             "xFlipper %s", | ||||||
|  |             furi_hal_version.name); | ||||||
|  |     } else { | ||||||
|  |         snprintf(furi_hal_version.device_name, FURI_HAL_VERSION_DEVICE_NAME_LENGTH, "xFlipper"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     furi_hal_version.device_name[0] = 0; | ||||||
|  | 
 | ||||||
|  |     // BLE Mac address
 | ||||||
|  |     uint32_t udn = LL_FLASH_GetUDN(); | ||||||
|  |     uint32_t company_id = LL_FLASH_GetSTCompanyID(); | ||||||
|  |     uint32_t device_id = LL_FLASH_GetDeviceID(); | ||||||
|  |     furi_hal_version.ble_mac[0] = (uint8_t)(udn & 0x000000FF); | ||||||
|  |     furi_hal_version.ble_mac[1] = (uint8_t)((udn & 0x0000FF00) >> 8); | ||||||
|  |     furi_hal_version.ble_mac[2] = (uint8_t)((udn & 0x00FF0000) >> 16); | ||||||
|  |     furi_hal_version.ble_mac[3] = (uint8_t)device_id; | ||||||
|  |     furi_hal_version.ble_mac[4] = (uint8_t)(company_id & 0x000000FF); | ||||||
|  |     furi_hal_version.ble_mac[5] = (uint8_t)((company_id & 0x0000FF00) >> 8); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void furi_hal_version_load_otp_default() { | ||||||
|  |     furi_hal_version_set_name(NULL); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void furi_hal_version_load_otp_v0() { | ||||||
|  |     const FuriHalVersionOTPv0* otp = (FuriHalVersionOTPv0*)FURI_HAL_VERSION_OTP_ADDRESS; | ||||||
|  | 
 | ||||||
|  |     furi_hal_version.timestamp = otp->header_timestamp; | ||||||
|  |     furi_hal_version.board_version = otp->board_version; | ||||||
|  |     furi_hal_version.board_target = otp->board_target; | ||||||
|  |     furi_hal_version.board_body = otp->board_body; | ||||||
|  |     furi_hal_version.board_connect = otp->board_connect; | ||||||
|  | 
 | ||||||
|  |     furi_hal_version_set_name(otp->name); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void furi_hal_version_load_otp_v1() { | ||||||
|  |     const FuriHalVersionOTPv1* otp = (FuriHalVersionOTPv1*)FURI_HAL_VERSION_OTP_ADDRESS; | ||||||
|  | 
 | ||||||
|  |     furi_hal_version.timestamp = otp->header_timestamp; | ||||||
|  |     furi_hal_version.board_version = otp->board_version; | ||||||
|  |     furi_hal_version.board_target = otp->board_target; | ||||||
|  |     furi_hal_version.board_body = otp->board_body; | ||||||
|  |     furi_hal_version.board_connect = otp->board_connect; | ||||||
|  |     furi_hal_version.board_color = otp->board_color; | ||||||
|  |     furi_hal_version.board_region = otp->board_region; | ||||||
|  | 
 | ||||||
|  |     furi_hal_version_set_name(otp->name); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void furi_hal_version_load_otp_v2() { | ||||||
|  |     const FuriHalVersionOTPv2* otp = (FuriHalVersionOTPv2*)FURI_HAL_VERSION_OTP_ADDRESS; | ||||||
|  | 
 | ||||||
|  |     // 1st block, programmed afer baking
 | ||||||
|  |     furi_hal_version.timestamp = otp->header_timestamp; | ||||||
|  | 
 | ||||||
|  |     // 2nd block, programmed afer baking
 | ||||||
|  |     furi_hal_version.board_version = otp->board_version; | ||||||
|  |     furi_hal_version.board_target = otp->board_target; | ||||||
|  |     furi_hal_version.board_body = otp->board_body; | ||||||
|  |     furi_hal_version.board_connect = otp->board_connect; | ||||||
|  |     furi_hal_version.board_display = otp->board_display; | ||||||
|  | 
 | ||||||
|  |     // 3rd and 4th blocks, programmed on FATP stage
 | ||||||
|  |     if(otp->board_color != 0xFF) { | ||||||
|  |         furi_hal_version.board_color = otp->board_color; | ||||||
|  |         furi_hal_version.board_region = otp->board_region; | ||||||
|  |         furi_hal_version_set_name(otp->name); | ||||||
|  |     } else { | ||||||
|  |         furi_hal_version.board_color = 0; | ||||||
|  |         furi_hal_version.board_region = 0; | ||||||
|  |         furi_hal_version_set_name(NULL); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void furi_hal_version_init() { | ||||||
|  |     switch(furi_hal_version_get_otp_version()) { | ||||||
|  |     case FuriHalVersionOtpVersionUnknown: | ||||||
|  |         furi_hal_version_load_otp_default(); | ||||||
|  |         break; | ||||||
|  |     case FuriHalVersionOtpVersionEmpty: | ||||||
|  |         furi_hal_version_load_otp_default(); | ||||||
|  |         break; | ||||||
|  |     case FuriHalVersionOtpVersion0: | ||||||
|  |         furi_hal_version_load_otp_v0(); | ||||||
|  |         break; | ||||||
|  |     case FuriHalVersionOtpVersion1: | ||||||
|  |         furi_hal_version_load_otp_v1(); | ||||||
|  |         break; | ||||||
|  |     case FuriHalVersionOtpVersion2: | ||||||
|  |         furi_hal_version_load_otp_v2(); | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|  |         furi_hal_version_load_otp_default(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool furi_hal_version_do_i_belong_here() { | ||||||
|  |     return furi_hal_version_get_hw_target() == 7; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const char* furi_hal_version_get_model_name() { | ||||||
|  |     return "Flipper Zero"; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const FuriHalVersionOtpVersion furi_hal_version_get_otp_version() { | ||||||
|  |     if(*(uint64_t*)FURI_HAL_VERSION_OTP_ADDRESS == 0xFFFFFFFF) { | ||||||
|  |         return FuriHalVersionOtpVersionEmpty; | ||||||
|  |     } else { | ||||||
|  |         if(((FuriHalVersionOTPv1*)FURI_HAL_VERSION_OTP_ADDRESS)->header_magic == | ||||||
|  |            FURI_HAL_VERSION_OTP_HEADER_MAGIC) { | ||||||
|  |             // Version 1+
 | ||||||
|  |             uint8_t version = ((FuriHalVersionOTPv1*)FURI_HAL_VERSION_OTP_ADDRESS)->header_version; | ||||||
|  |             if(version >= FuriHalVersionOtpVersion1 && version <= FuriHalVersionOtpVersion2) { | ||||||
|  |                 return version; | ||||||
|  |             } else { | ||||||
|  |                 return FuriHalVersionOtpVersionUnknown; | ||||||
|  |             } | ||||||
|  |         } else if(((FuriHalVersionOTPv0*)FURI_HAL_VERSION_OTP_ADDRESS)->board_version <= 10) { | ||||||
|  |             // Version 0
 | ||||||
|  |             return FuriHalVersionOtpVersion0; | ||||||
|  |         } else { | ||||||
|  |             // Version Unknown
 | ||||||
|  |             return FuriHalVersionOtpVersionUnknown; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const uint8_t furi_hal_version_get_hw_version() { | ||||||
|  |     return furi_hal_version.board_version; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const uint8_t furi_hal_version_get_hw_target() { | ||||||
|  |     return furi_hal_version.board_target; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const uint8_t furi_hal_version_get_hw_body() { | ||||||
|  |     return furi_hal_version.board_body; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const FuriHalVersionColor furi_hal_version_get_hw_color() { | ||||||
|  |     return furi_hal_version.board_color; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const uint8_t furi_hal_version_get_hw_connect() { | ||||||
|  |     return furi_hal_version.board_connect; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const FuriHalVersionRegion furi_hal_version_get_hw_region() { | ||||||
|  |     return furi_hal_version.board_region; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const FuriHalVersionDisplay furi_hal_version_get_hw_display() { | ||||||
|  |     return furi_hal_version.board_display; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const uint32_t furi_hal_version_get_hw_timestamp() { | ||||||
|  |     return furi_hal_version.timestamp; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const char* furi_hal_version_get_name_ptr() { | ||||||
|  |     return *furi_hal_version.name == 0x00 ? NULL : furi_hal_version.name; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const char* furi_hal_version_get_device_name_ptr() { | ||||||
|  |     return furi_hal_version.device_name + 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const char* furi_hal_version_get_ble_local_device_name_ptr() { | ||||||
|  |     return furi_hal_version.device_name; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const uint8_t* furi_hal_version_get_ble_mac() { | ||||||
|  |     return furi_hal_version.ble_mac; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const struct Version* furi_hal_version_get_firmware_version(void) { | ||||||
|  |     return version_get(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const struct Version* furi_hal_version_get_boot_version(void) { | ||||||
|  | #ifdef NO_BOOTLOADER | ||||||
|  |     return 0; | ||||||
|  | #else | ||||||
|  |     /* Backup register which points to structure in flash memory */ | ||||||
|  |     return (const struct Version*)LL_RTC_BAK_GetRegister(RTC, LL_RTC_BKP_DR1); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | size_t furi_hal_version_uid_size() { | ||||||
|  |     return 64 / 8; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const uint8_t* furi_hal_version_uid() { | ||||||
|  |     return (const uint8_t*)UID64_BASE; | ||||||
|  | } | ||||||
| @ -5,6 +5,7 @@ void furi_hal_init() { | |||||||
|     furi_hal_i2c_init(); |     furi_hal_i2c_init(); | ||||||
|     furi_hal_light_init(); |     furi_hal_light_init(); | ||||||
|     furi_hal_spi_init(); |     furi_hal_spi_init(); | ||||||
|  |     furi_hal_version_init(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void delay(float milliseconds) { | void delay(float milliseconds) { | ||||||
|  | |||||||
| @ -189,7 +189,7 @@ void target_display_init() { | |||||||
|     hal_gpio_init_simple(&gpio_display_di, GpioModeOutputPushPull); |     hal_gpio_init_simple(&gpio_display_di, GpioModeOutputPushPull); | ||||||
|     // Initialize
 |     // Initialize
 | ||||||
|     u8g2_t fb; |     u8g2_t fb; | ||||||
|     u8g2_Setup_st756x_erc(&fb, U8G2_R0, u8x8_hw_spi_stm32, u8g2_gpio_and_delay_stm32); |     u8g2_Setup_st756x_flipper(&fb, U8G2_R0, u8x8_hw_spi_stm32, u8g2_gpio_and_delay_stm32); | ||||||
|     u8g2_InitDisplay(&fb); |     u8g2_InitDisplay(&fb); | ||||||
|     // Create payload
 |     // Create payload
 | ||||||
|     u8g2_ClearBuffer(&fb); |     u8g2_ClearBuffer(&fb); | ||||||
|  | |||||||
							
								
								
									
										290
									
								
								bootloader/targets/f7/furi-hal/furi-hal-version.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										290
									
								
								bootloader/targets/f7/furi-hal/furi-hal-version.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,290 @@ | |||||||
|  | #include <furi-hal-version.h> | ||||||
|  | 
 | ||||||
|  | #include <stm32wbxx.h> | ||||||
|  | #include <stm32wbxx_ll_rtc.h> | ||||||
|  | #include <stm32wbxx_ll_system.h> | ||||||
|  | 
 | ||||||
|  | #include <stdio.h> | ||||||
|  | 
 | ||||||
|  | #define FURI_HAL_VERSION_OTP_HEADER_MAGIC 0xBABE | ||||||
|  | #define FURI_HAL_VERSION_OTP_ADDRESS OTP_AREA_BASE | ||||||
|  | 
 | ||||||
|  | /** OTP V0 Structure: prototypes and early EVT */ | ||||||
|  | typedef struct { | ||||||
|  |     uint8_t board_version; | ||||||
|  |     uint8_t board_target; | ||||||
|  |     uint8_t board_body; | ||||||
|  |     uint8_t board_connect; | ||||||
|  |     uint32_t header_timestamp; | ||||||
|  |     char name[FURI_HAL_VERSION_NAME_LENGTH]; | ||||||
|  | } FuriHalVersionOTPv0; | ||||||
|  | 
 | ||||||
|  | /** OTP V1 Structure: late EVT, DVT */ | ||||||
|  | typedef struct { | ||||||
|  |     /* First 64 bits: header */ | ||||||
|  |     uint16_t header_magic; | ||||||
|  |     uint8_t header_version; | ||||||
|  |     uint8_t header_reserved; | ||||||
|  |     uint32_t header_timestamp; | ||||||
|  | 
 | ||||||
|  |     /* Second 64 bits: board info */ | ||||||
|  |     uint8_t board_version; /** Board version */ | ||||||
|  |     uint8_t board_target; /** Board target firmware */ | ||||||
|  |     uint8_t board_body; /** Board body */ | ||||||
|  |     uint8_t board_connect; /** Board interconnect */ | ||||||
|  |     uint8_t board_color; /** Board color */ | ||||||
|  |     uint8_t board_region; /** Board region */ | ||||||
|  |     uint16_t board_reserved; /** Reserved for future use, 0x0000 */ | ||||||
|  | 
 | ||||||
|  |     /* Third 64 bits: Unique Device Name */ | ||||||
|  |     char name[FURI_HAL_VERSION_NAME_LENGTH]; /** Unique Device Name */ | ||||||
|  | } FuriHalVersionOTPv1; | ||||||
|  | 
 | ||||||
|  | /** OTP V2 Structure: DVT2, PVT, Production */ | ||||||
|  | typedef struct { | ||||||
|  |     /* Early First 64 bits: header */ | ||||||
|  |     uint16_t header_magic; | ||||||
|  |     uint8_t header_version; | ||||||
|  |     uint8_t header_reserved; | ||||||
|  |     uint32_t header_timestamp; | ||||||
|  | 
 | ||||||
|  |     /* Early Second 64 bits: board info */ | ||||||
|  |     uint8_t board_version; /** Board version */ | ||||||
|  |     uint8_t board_target; /** Board target firmware */ | ||||||
|  |     uint8_t board_body; /** Board body */ | ||||||
|  |     uint8_t board_connect; /** Board interconnect */ | ||||||
|  |     uint8_t board_display; /** Board display */ | ||||||
|  |     uint8_t board_reserved2_0; /** Reserved for future use, 0x00 */ | ||||||
|  |     uint16_t board_reserved2_1; /** Reserved for future use, 0x0000 */ | ||||||
|  | 
 | ||||||
|  |     /* Late Third 64 bits: device info */ | ||||||
|  |     uint8_t board_color; /** Board color */ | ||||||
|  |     uint8_t board_region; /** Board region */ | ||||||
|  |     uint16_t board_reserved3_0; /** Reserved for future use, 0x0000 */ | ||||||
|  |     uint32_t board_reserved3_1; /** Reserved for future use, 0x00000000 */ | ||||||
|  | 
 | ||||||
|  |     /* Late Fourth 64 bits: Unique Device Name */ | ||||||
|  |     char name[FURI_HAL_VERSION_NAME_LENGTH]; /** Unique Device Name */ | ||||||
|  | } FuriHalVersionOTPv2; | ||||||
|  | 
 | ||||||
|  | /** Represenation Model: */ | ||||||
|  | typedef struct { | ||||||
|  |     uint32_t timestamp; | ||||||
|  | 
 | ||||||
|  |     uint8_t board_version; /** Board version */ | ||||||
|  |     uint8_t board_target; /** Board target firmware */ | ||||||
|  |     uint8_t board_body; /** Board body */ | ||||||
|  |     uint8_t board_connect; /** Board interconnect */ | ||||||
|  |     uint8_t board_color; /** Board color */ | ||||||
|  |     uint8_t board_region; /** Board region */ | ||||||
|  |     uint8_t board_display; /** Board display */ | ||||||
|  | 
 | ||||||
|  |     char name[FURI_HAL_VERSION_ARRAY_NAME_LENGTH]; /** \0 terminated name */ | ||||||
|  |     char device_name[FURI_HAL_VERSION_DEVICE_NAME_LENGTH]; /** device name for special needs */ | ||||||
|  |     uint8_t ble_mac[6]; | ||||||
|  | } FuriHalVersion; | ||||||
|  | 
 | ||||||
|  | static FuriHalVersion furi_hal_version = {0}; | ||||||
|  | 
 | ||||||
|  | static void furi_hal_version_set_name(const char* name) { | ||||||
|  |     if(name != NULL) { | ||||||
|  |         strlcpy(furi_hal_version.name, name, FURI_HAL_VERSION_ARRAY_NAME_LENGTH); | ||||||
|  |         snprintf( | ||||||
|  |             furi_hal_version.device_name, | ||||||
|  |             FURI_HAL_VERSION_DEVICE_NAME_LENGTH, | ||||||
|  |             "xFlipper %s", | ||||||
|  |             furi_hal_version.name); | ||||||
|  |     } else { | ||||||
|  |         snprintf(furi_hal_version.device_name, FURI_HAL_VERSION_DEVICE_NAME_LENGTH, "xFlipper"); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     furi_hal_version.device_name[0] = 0; | ||||||
|  | 
 | ||||||
|  |     // BLE Mac address
 | ||||||
|  |     uint32_t udn = LL_FLASH_GetUDN(); | ||||||
|  |     uint32_t company_id = LL_FLASH_GetSTCompanyID(); | ||||||
|  |     uint32_t device_id = LL_FLASH_GetDeviceID(); | ||||||
|  |     furi_hal_version.ble_mac[0] = (uint8_t)(udn & 0x000000FF); | ||||||
|  |     furi_hal_version.ble_mac[1] = (uint8_t)((udn & 0x0000FF00) >> 8); | ||||||
|  |     furi_hal_version.ble_mac[2] = (uint8_t)((udn & 0x00FF0000) >> 16); | ||||||
|  |     furi_hal_version.ble_mac[3] = (uint8_t)device_id; | ||||||
|  |     furi_hal_version.ble_mac[4] = (uint8_t)(company_id & 0x000000FF); | ||||||
|  |     furi_hal_version.ble_mac[5] = (uint8_t)((company_id & 0x0000FF00) >> 8); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void furi_hal_version_load_otp_default() { | ||||||
|  |     furi_hal_version_set_name(NULL); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void furi_hal_version_load_otp_v0() { | ||||||
|  |     const FuriHalVersionOTPv0* otp = (FuriHalVersionOTPv0*)FURI_HAL_VERSION_OTP_ADDRESS; | ||||||
|  | 
 | ||||||
|  |     furi_hal_version.timestamp = otp->header_timestamp; | ||||||
|  |     furi_hal_version.board_version = otp->board_version; | ||||||
|  |     furi_hal_version.board_target = otp->board_target; | ||||||
|  |     furi_hal_version.board_body = otp->board_body; | ||||||
|  |     furi_hal_version.board_connect = otp->board_connect; | ||||||
|  | 
 | ||||||
|  |     furi_hal_version_set_name(otp->name); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void furi_hal_version_load_otp_v1() { | ||||||
|  |     const FuriHalVersionOTPv1* otp = (FuriHalVersionOTPv1*)FURI_HAL_VERSION_OTP_ADDRESS; | ||||||
|  | 
 | ||||||
|  |     furi_hal_version.timestamp = otp->header_timestamp; | ||||||
|  |     furi_hal_version.board_version = otp->board_version; | ||||||
|  |     furi_hal_version.board_target = otp->board_target; | ||||||
|  |     furi_hal_version.board_body = otp->board_body; | ||||||
|  |     furi_hal_version.board_connect = otp->board_connect; | ||||||
|  |     furi_hal_version.board_color = otp->board_color; | ||||||
|  |     furi_hal_version.board_region = otp->board_region; | ||||||
|  | 
 | ||||||
|  |     furi_hal_version_set_name(otp->name); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void furi_hal_version_load_otp_v2() { | ||||||
|  |     const FuriHalVersionOTPv2* otp = (FuriHalVersionOTPv2*)FURI_HAL_VERSION_OTP_ADDRESS; | ||||||
|  | 
 | ||||||
|  |     // 1st block, programmed afer baking
 | ||||||
|  |     furi_hal_version.timestamp = otp->header_timestamp; | ||||||
|  | 
 | ||||||
|  |     // 2nd block, programmed afer baking
 | ||||||
|  |     furi_hal_version.board_version = otp->board_version; | ||||||
|  |     furi_hal_version.board_target = otp->board_target; | ||||||
|  |     furi_hal_version.board_body = otp->board_body; | ||||||
|  |     furi_hal_version.board_connect = otp->board_connect; | ||||||
|  |     furi_hal_version.board_display = otp->board_display; | ||||||
|  | 
 | ||||||
|  |     // 3rd and 4th blocks, programmed on FATP stage
 | ||||||
|  |     if(otp->board_color != 0xFF) { | ||||||
|  |         furi_hal_version.board_color = otp->board_color; | ||||||
|  |         furi_hal_version.board_region = otp->board_region; | ||||||
|  |         furi_hal_version_set_name(otp->name); | ||||||
|  |     } else { | ||||||
|  |         furi_hal_version.board_color = 0; | ||||||
|  |         furi_hal_version.board_region = 0; | ||||||
|  |         furi_hal_version_set_name(NULL); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void furi_hal_version_init() { | ||||||
|  |     switch(furi_hal_version_get_otp_version()) { | ||||||
|  |     case FuriHalVersionOtpVersionUnknown: | ||||||
|  |         furi_hal_version_load_otp_default(); | ||||||
|  |         break; | ||||||
|  |     case FuriHalVersionOtpVersionEmpty: | ||||||
|  |         furi_hal_version_load_otp_default(); | ||||||
|  |         break; | ||||||
|  |     case FuriHalVersionOtpVersion0: | ||||||
|  |         furi_hal_version_load_otp_v0(); | ||||||
|  |         break; | ||||||
|  |     case FuriHalVersionOtpVersion1: | ||||||
|  |         furi_hal_version_load_otp_v1(); | ||||||
|  |         break; | ||||||
|  |     case FuriHalVersionOtpVersion2: | ||||||
|  |         furi_hal_version_load_otp_v2(); | ||||||
|  |         break; | ||||||
|  |     default: | ||||||
|  |         furi_hal_version_load_otp_default(); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool furi_hal_version_do_i_belong_here() { | ||||||
|  |     return furi_hal_version_get_hw_target() == 7; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const char* furi_hal_version_get_model_name() { | ||||||
|  |     return "Flipper Zero"; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const FuriHalVersionOtpVersion furi_hal_version_get_otp_version() { | ||||||
|  |     if(*(uint64_t*)FURI_HAL_VERSION_OTP_ADDRESS == 0xFFFFFFFF) { | ||||||
|  |         return FuriHalVersionOtpVersionEmpty; | ||||||
|  |     } else { | ||||||
|  |         if(((FuriHalVersionOTPv1*)FURI_HAL_VERSION_OTP_ADDRESS)->header_magic == | ||||||
|  |            FURI_HAL_VERSION_OTP_HEADER_MAGIC) { | ||||||
|  |             // Version 1+
 | ||||||
|  |             uint8_t version = ((FuriHalVersionOTPv1*)FURI_HAL_VERSION_OTP_ADDRESS)->header_version; | ||||||
|  |             if(version >= FuriHalVersionOtpVersion1 && version <= FuriHalVersionOtpVersion2) { | ||||||
|  |                 return version; | ||||||
|  |             } else { | ||||||
|  |                 return FuriHalVersionOtpVersionUnknown; | ||||||
|  |             } | ||||||
|  |         } else if(((FuriHalVersionOTPv0*)FURI_HAL_VERSION_OTP_ADDRESS)->board_version <= 10) { | ||||||
|  |             // Version 0
 | ||||||
|  |             return FuriHalVersionOtpVersion0; | ||||||
|  |         } else { | ||||||
|  |             // Version Unknown
 | ||||||
|  |             return FuriHalVersionOtpVersionUnknown; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const uint8_t furi_hal_version_get_hw_version() { | ||||||
|  |     return furi_hal_version.board_version; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const uint8_t furi_hal_version_get_hw_target() { | ||||||
|  |     return furi_hal_version.board_target; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const uint8_t furi_hal_version_get_hw_body() { | ||||||
|  |     return furi_hal_version.board_body; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const FuriHalVersionColor furi_hal_version_get_hw_color() { | ||||||
|  |     return furi_hal_version.board_color; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const uint8_t furi_hal_version_get_hw_connect() { | ||||||
|  |     return furi_hal_version.board_connect; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const FuriHalVersionRegion furi_hal_version_get_hw_region() { | ||||||
|  |     return furi_hal_version.board_region; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const FuriHalVersionDisplay furi_hal_version_get_hw_display() { | ||||||
|  |     return furi_hal_version.board_display; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const uint32_t furi_hal_version_get_hw_timestamp() { | ||||||
|  |     return furi_hal_version.timestamp; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const char* furi_hal_version_get_name_ptr() { | ||||||
|  |     return *furi_hal_version.name == 0x00 ? NULL : furi_hal_version.name; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const char* furi_hal_version_get_device_name_ptr() { | ||||||
|  |     return furi_hal_version.device_name + 1; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const char* furi_hal_version_get_ble_local_device_name_ptr() { | ||||||
|  |     return furi_hal_version.device_name; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const uint8_t* furi_hal_version_get_ble_mac() { | ||||||
|  |     return furi_hal_version.ble_mac; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const struct Version* furi_hal_version_get_firmware_version(void) { | ||||||
|  |     return version_get(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const struct Version* furi_hal_version_get_boot_version(void) { | ||||||
|  | #ifdef NO_BOOTLOADER | ||||||
|  |     return 0; | ||||||
|  | #else | ||||||
|  |     /* Backup register which points to structure in flash memory */ | ||||||
|  |     return (const struct Version*)LL_RTC_BAK_GetRegister(RTC, LL_RTC_BKP_DR1); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | size_t furi_hal_version_uid_size() { | ||||||
|  |     return 64 / 8; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const uint8_t* furi_hal_version_uid() { | ||||||
|  |     return (const uint8_t*)UID64_BASE; | ||||||
|  | } | ||||||
| @ -5,6 +5,7 @@ void furi_hal_init() { | |||||||
|     furi_hal_i2c_init(); |     furi_hal_i2c_init(); | ||||||
|     furi_hal_light_init(); |     furi_hal_light_init(); | ||||||
|     furi_hal_spi_init(); |     furi_hal_spi_init(); | ||||||
|  |     furi_hal_version_init(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void delay(float milliseconds) { | void delay(float milliseconds) { | ||||||
|  | |||||||
| @ -1,14 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| 
 |  | ||||||
| #include <furi-hal-i2c.h> |  | ||||||
| #include <furi-hal-light.h> |  | ||||||
| #include <furi-hal-resources.h> |  | ||||||
| #include <furi-hal-spi.h> |  | ||||||
| 
 |  | ||||||
| #define furi_assert(value) (void)(value) |  | ||||||
| 
 |  | ||||||
| void furi_hal_init(); |  | ||||||
| 
 |  | ||||||
| void delay(float milliseconds); |  | ||||||
| 
 |  | ||||||
| void delay_us(float microseconds); |  | ||||||
| @ -189,7 +189,7 @@ void target_display_init() { | |||||||
|     hal_gpio_init_simple(&gpio_display_di, GpioModeOutputPushPull); |     hal_gpio_init_simple(&gpio_display_di, GpioModeOutputPushPull); | ||||||
|     // Initialize
 |     // Initialize
 | ||||||
|     u8g2_t fb; |     u8g2_t fb; | ||||||
|     u8g2_Setup_st756x_erc(&fb, U8G2_R0, u8x8_hw_spi_stm32, u8g2_gpio_and_delay_stm32); |     u8g2_Setup_st756x_flipper(&fb, U8G2_R0, u8x8_hw_spi_stm32, u8g2_gpio_and_delay_stm32); | ||||||
|     u8g2_InitDisplay(&fb); |     u8g2_InitDisplay(&fb); | ||||||
|     // Create payload
 |     // Create payload
 | ||||||
|     u8g2_ClearBuffer(&fb); |     u8g2_ClearBuffer(&fb); | ||||||
|  | |||||||
							
								
								
									
										173
									
								
								bootloader/targets/furi-hal-include/furi-hal-version.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								bootloader/targets/furi-hal-include/furi-hal-version.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,173 @@ | |||||||
|  | /**
 | ||||||
|  |  * @file furi-hal-version.h | ||||||
|  |  * Version HAL API | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <stdbool.h> | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include <lib/toolbox/version.h> | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | extern "C" { | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | #define FURI_HAL_VERSION_NAME_LENGTH 8 | ||||||
|  | #define FURI_HAL_VERSION_ARRAY_NAME_LENGTH (FURI_HAL_VERSION_NAME_LENGTH + 1) | ||||||
|  | /** BLE symbol + "Flipper " + name */ | ||||||
|  | #define FURI_HAL_VERSION_DEVICE_NAME_LENGTH (1 + 8 + FURI_HAL_VERSION_ARRAY_NAME_LENGTH) | ||||||
|  | 
 | ||||||
|  | /** OTP Versions enum */ | ||||||
|  | typedef enum { | ||||||
|  |     FuriHalVersionOtpVersion0 = 0x00, | ||||||
|  |     FuriHalVersionOtpVersion1 = 0x01, | ||||||
|  |     FuriHalVersionOtpVersion2 = 0x02, | ||||||
|  |     FuriHalVersionOtpVersionEmpty = 0xFFFFFFFE, | ||||||
|  |     FuriHalVersionOtpVersionUnknown = 0xFFFFFFFF, | ||||||
|  | } FuriHalVersionOtpVersion; | ||||||
|  | 
 | ||||||
|  | /** Device Colors */ | ||||||
|  | typedef enum { | ||||||
|  |     FuriHalVersionColorUnknown = 0x00, | ||||||
|  |     FuriHalVersionColorBlack = 0x01, | ||||||
|  |     FuriHalVersionColorWhite = 0x02, | ||||||
|  | } FuriHalVersionColor; | ||||||
|  | 
 | ||||||
|  | /** Device Regions */ | ||||||
|  | typedef enum { | ||||||
|  |     FuriHalVersionRegionUnknown = 0x00, | ||||||
|  |     FuriHalVersionRegionEuRu = 0x01, | ||||||
|  |     FuriHalVersionRegionUsCaAu = 0x02, | ||||||
|  |     FuriHalVersionRegionJp = 0x03, | ||||||
|  | } FuriHalVersionRegion; | ||||||
|  | 
 | ||||||
|  | /** Device Display */ | ||||||
|  | typedef enum { | ||||||
|  |     FuriHalVersionDisplayUnknown = 0x00, | ||||||
|  |     FuriHalVersionDisplayErc = 0x01, | ||||||
|  |     FuriHalVersionDisplayMgg = 0x02, | ||||||
|  | } FuriHalVersionDisplay; | ||||||
|  | 
 | ||||||
|  | /** Init flipper version
 | ||||||
|  |  */ | ||||||
|  | void furi_hal_version_init(); | ||||||
|  | 
 | ||||||
|  | /** Check target firmware version
 | ||||||
|  |  * | ||||||
|  |  * @return     true if target and real matches | ||||||
|  |  */ | ||||||
|  | bool furi_hal_version_do_i_belong_here(); | ||||||
|  | 
 | ||||||
|  | /** Get model name
 | ||||||
|  |  * | ||||||
|  |  * @return     model name C-string | ||||||
|  |  */ | ||||||
|  | const char* furi_hal_version_get_model_name(); | ||||||
|  | 
 | ||||||
|  | /** Get OTP version
 | ||||||
|  |  * | ||||||
|  |  * @return     OTP Version | ||||||
|  |  */ | ||||||
|  | const FuriHalVersionOtpVersion furi_hal_version_get_otp_version(); | ||||||
|  | 
 | ||||||
|  | /** Get hardware version
 | ||||||
|  |  * | ||||||
|  |  * @return     Hardware Version | ||||||
|  |  */ | ||||||
|  | const uint8_t furi_hal_version_get_hw_version(); | ||||||
|  | 
 | ||||||
|  | /** Get hardware target
 | ||||||
|  |  * | ||||||
|  |  * @return     Hardware Target | ||||||
|  |  */ | ||||||
|  | const uint8_t furi_hal_version_get_hw_target(); | ||||||
|  | 
 | ||||||
|  | /** Get hardware body
 | ||||||
|  |  * | ||||||
|  |  * @return     Hardware Body | ||||||
|  |  */ | ||||||
|  | const uint8_t furi_hal_version_get_hw_body(); | ||||||
|  | 
 | ||||||
|  | /** Get hardware body color
 | ||||||
|  |  * | ||||||
|  |  * @return     Hardware Color | ||||||
|  |  */ | ||||||
|  | const FuriHalVersionColor furi_hal_version_get_hw_color(); | ||||||
|  | 
 | ||||||
|  | /** Get hardware connect
 | ||||||
|  |  * | ||||||
|  |  * @return     Hardware Interconnect | ||||||
|  |  */ | ||||||
|  | const uint8_t furi_hal_version_get_hw_connect(); | ||||||
|  | 
 | ||||||
|  | /** Get hardware region
 | ||||||
|  |  * | ||||||
|  |  * @return     Hardware Region | ||||||
|  |  */ | ||||||
|  | const FuriHalVersionRegion furi_hal_version_get_hw_region(); | ||||||
|  | 
 | ||||||
|  | /** Get hardware display id
 | ||||||
|  |  * | ||||||
|  |  * @return     Display id | ||||||
|  |  */ | ||||||
|  | const FuriHalVersionDisplay furi_hal_version_get_hw_display(); | ||||||
|  | 
 | ||||||
|  | /** Get hardware timestamp
 | ||||||
|  |  * | ||||||
|  |  * @return     Hardware Manufacture timestamp | ||||||
|  |  */ | ||||||
|  | const uint32_t furi_hal_version_get_hw_timestamp(); | ||||||
|  | 
 | ||||||
|  | /** Get pointer to target name
 | ||||||
|  |  * | ||||||
|  |  * @return     Hardware Name C-string | ||||||
|  |  */ | ||||||
|  | const char* furi_hal_version_get_name_ptr(); | ||||||
|  | 
 | ||||||
|  | /** Get pointer to target device name
 | ||||||
|  |  * | ||||||
|  |  * @return     Hardware Device Name C-string | ||||||
|  |  */ | ||||||
|  | const char* furi_hal_version_get_device_name_ptr(); | ||||||
|  | 
 | ||||||
|  | /** Get pointer to target ble local device name
 | ||||||
|  |  * | ||||||
|  |  * @return     Ble Device Name C-string | ||||||
|  |  */ | ||||||
|  | const char* furi_hal_version_get_ble_local_device_name_ptr(); | ||||||
|  | 
 | ||||||
|  | /** Get BLE MAC address
 | ||||||
|  |  * | ||||||
|  |  * @return     pointer to BLE MAC address | ||||||
|  |  */ | ||||||
|  | const uint8_t* furi_hal_version_get_ble_mac(); | ||||||
|  | 
 | ||||||
|  | /** Get address of version structure of bootloader, stored in chip flash.
 | ||||||
|  |  * | ||||||
|  |  * @return     Address of boot version structure. | ||||||
|  |  */ | ||||||
|  | const struct Version* furi_hal_version_get_boot_version(); | ||||||
|  | 
 | ||||||
|  | /** Get address of version structure of firmware.
 | ||||||
|  |  * | ||||||
|  |  * @return     Address of firmware version structure. | ||||||
|  |  */ | ||||||
|  | const struct Version* furi_hal_version_get_firmware_version(); | ||||||
|  | 
 | ||||||
|  | /** Get platform UID size in bytes
 | ||||||
|  |  * | ||||||
|  |  * @return     UID size in bytes | ||||||
|  |  */ | ||||||
|  | size_t furi_hal_version_uid_size(); | ||||||
|  | 
 | ||||||
|  | /** Get const pointer to UID
 | ||||||
|  |  * | ||||||
|  |  * @return     pointer to UID | ||||||
|  |  */ | ||||||
|  | const uint8_t* furi_hal_version_uid(); | ||||||
|  | 
 | ||||||
|  | #ifdef __cplusplus | ||||||
|  | } | ||||||
|  | #endif | ||||||
| @ -4,6 +4,7 @@ | |||||||
| #include <furi-hal-light.h> | #include <furi-hal-light.h> | ||||||
| #include <furi-hal-resources.h> | #include <furi-hal-resources.h> | ||||||
| #include <furi-hal-spi.h> | #include <furi-hal-spi.h> | ||||||
|  | #include <furi-hal-version.h> | ||||||
| 
 | 
 | ||||||
| #define furi_assert(value) (void)(value) | #define furi_assert(value) (void)(value) | ||||||
| 
 | 
 | ||||||
| @ -185,7 +185,7 @@ uint8_t u8x8_d_st756x_common(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *a | |||||||
|     return 1; |     return 1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void u8x8_d_st756x_erc_init(u8x8_t *u8x8, uint8_t contrast, uint8_t regulation_ratio, bool bias) { | void u8x8_d_st756x_init(u8x8_t *u8x8, uint8_t contrast, uint8_t regulation_ratio, bool bias) { | ||||||
|     contrast = contrast & 0b00111111; |     contrast = contrast & 0b00111111; | ||||||
|     regulation_ratio = regulation_ratio & 0b111; |     regulation_ratio = regulation_ratio & 0b111; | ||||||
| 
 | 
 | ||||||
| @ -209,7 +209,7 @@ void u8x8_d_st756x_erc_init(u8x8_t *u8x8, uint8_t contrast, uint8_t regulation_r | |||||||
|     u8x8_cad_EndTransfer(u8x8); |     u8x8_cad_EndTransfer(u8x8); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| uint8_t u8x8_d_st756x_erc(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) { | uint8_t u8x8_d_st756x_flipper(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr) { | ||||||
|     /* call common procedure first and handle messages there */ |     /* call common procedure first and handle messages there */ | ||||||
|     if (u8x8_d_st756x_common(u8x8, msg, arg_int, arg_ptr) == 0) { |     if (u8x8_d_st756x_common(u8x8, msg, arg_int, arg_ptr) == 0) { | ||||||
|         /* msg not handled, then try here */ |         /* msg not handled, then try here */ | ||||||
| @ -219,13 +219,24 @@ uint8_t u8x8_d_st756x_erc(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ | |||||||
|             break; |             break; | ||||||
|         case U8X8_MSG_DISPLAY_INIT: |         case U8X8_MSG_DISPLAY_INIT: | ||||||
|             u8x8_d_helper_display_init(u8x8); |             u8x8_d_helper_display_init(u8x8); | ||||||
|             /* Bias, EV and Regulation Ration
 |             FuriHalVersionDisplay display = furi_hal_version_get_hw_display(); | ||||||
|              * EV = 32 |             if (display == FuriHalVersionDisplayMgg) { | ||||||
|              * RR = V0 / ((1 - (63 - EV) / 162) * 2.1) |                 /* MGG v0+(ST7567)
 | ||||||
|              * RR = 10 / ((1 - (63 - 32) / 162) * 2.1) ~= 5.88 is 5.5 (0b101) |                  * EV = 32 | ||||||
|              * Bias = 1/9 (false) |                  * RR = V0 / ((1 - (63 - EV) / 162) * 2.1) | ||||||
|              */ |                  * RR = 10 / ((1 - (63 - 32) / 162) * 2.1) ~= 5.88 is 6 (0b110) | ||||||
|             u8x8_d_st756x_erc_init(u8x8, 32, 0b101, false); |                  * Bias = 1/9 (false) | ||||||
|  |                  */ | ||||||
|  |                 u8x8_d_st756x_init(u8x8, 32, 0b110, false); | ||||||
|  |             } else { | ||||||
|  |                 /* ERC v1(ST7565) and v2(ST7567)
 | ||||||
|  |                  * EV = 33 | ||||||
|  |                  * RR = V0 / ((1 - (63 - EV) / 162) * 2.1) | ||||||
|  |                  * RR = 9.3 / ((1 - (63 - 32) / 162) * 2.1) ~= 5.47 is 5.5 (0b101) | ||||||
|  |                  * Bias = 1/9 (false) | ||||||
|  |                  */ | ||||||
|  |                 u8x8_d_st756x_init(u8x8, 33, 0b101, false); | ||||||
|  |             } | ||||||
|             break; |             break; | ||||||
|         case U8X8_MSG_DISPLAY_SET_FLIP_MODE: |         case U8X8_MSG_DISPLAY_SET_FLIP_MODE: | ||||||
|             if ( arg_int == 0 ) { |             if ( arg_int == 0 ) { | ||||||
| @ -244,10 +255,10 @@ uint8_t u8x8_d_st756x_erc(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ | |||||||
|     return 1; |     return 1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void u8g2_Setup_st756x_erc(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb) { | void u8g2_Setup_st756x_flipper(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb) { | ||||||
|     uint8_t tile_buf_height; |     uint8_t tile_buf_height; | ||||||
|     uint8_t *buf; |     uint8_t *buf; | ||||||
|     u8g2_SetupDisplay(u8g2, u8x8_d_st756x_erc, u8x8_cad_001, byte_cb, gpio_and_delay_cb); |     u8g2_SetupDisplay(u8g2, u8x8_d_st756x_flipper, u8x8_cad_001, byte_cb, gpio_and_delay_cb); | ||||||
|     buf = u8g2_m_16_8_f(&tile_buf_height); |     buf = u8g2_m_16_8_f(&tile_buf_height); | ||||||
|     u8g2_SetupBuffer(u8g2, buf, tile_buf_height, u8g2_ll_hvline_vertical_top_lsb, rotation); |     u8g2_SetupBuffer(u8g2, buf, tile_buf_height, u8g2_ll_hvline_vertical_top_lsb, rotation); | ||||||
| } | } | ||||||
|  | |||||||
| @ -7,6 +7,6 @@ uint8_t u8g2_gpio_and_delay_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, vo | |||||||
| 
 | 
 | ||||||
| uint8_t u8x8_hw_spi_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr); | uint8_t u8x8_hw_spi_stm32(u8x8_t* u8x8, uint8_t msg, uint8_t arg_int, void* arg_ptr); | ||||||
| 
 | 
 | ||||||
| void u8g2_Setup_st756x_erc(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb); | void u8g2_Setup_st756x_flipper(u8g2_t *u8g2, const u8g2_cb_t *rotation, u8x8_msg_cb byte_cb, u8x8_msg_cb gpio_and_delay_cb); | ||||||
| 
 | 
 | ||||||
| void u8x8_d_st756x_erc_init(u8x8_t *u8x8, uint8_t contrast, uint8_t regulation_ratio, bool bias); | void u8x8_d_st756x_init(u8x8_t *u8x8, uint8_t contrast, uint8_t regulation_ratio, bool bias); | ||||||
|  | |||||||
| @ -140,7 +140,7 @@ generate_cscope_db: | |||||||
| 	@cscope -b -k -i $(OBJ_DIR)/source.list -f $(OBJ_DIR)/cscope.out | 	@cscope -b -k -i $(OBJ_DIR)/source.list -f $(OBJ_DIR)/cscope.out | ||||||
| 	@rm -rf $(OBJ_DIR)/source.list $(OBJ_DIR)/source.list.p | 	@rm -rf $(OBJ_DIR)/source.list $(OBJ_DIR)/source.list.p | ||||||
| 
 | 
 | ||||||
|  | # Prevent make from trying to find .d targets
 | ||||||
|  | %.d: ; | ||||||
| 
 | 
 | ||||||
| ifneq ("$(wildcard $(OBJ_DIR)/*.d)","") |  | ||||||
| -include $(DEPS) | -include $(DEPS) | ||||||
| endif |  | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| # About | # About | ||||||
| 
 | 
 | ||||||
| This folder contains differnt scripts that automates routine actions. | This folder contains supplementary scripts that automates routine actions. | ||||||
| Flashing scripts are based on cli version of [STM32CubeProgrammer](https://www.st.com/en/development-tools/stm32cubeprog.html). | 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. | You will need to add STM32_Programmer_CLI to your path to use them. | ||||||
| 
 | 
 | ||||||
| @ -9,29 +9,26 @@ You will need to add STM32_Programmer_CLI to your path to use them. | |||||||
| Always flash your device in the folllowing sequence: | Always flash your device in the folllowing sequence: | ||||||
| 
 | 
 | ||||||
| - OTP (Only on empty MCU) | - OTP (Only on empty MCU) | ||||||
| - Core2 firmware | - Core1 and Core2 firmware flashing | ||||||
| - Core1 firmware |  | ||||||
| - Option Bytes | - Option Bytes | ||||||
| 
 | 
 | ||||||
| ## Otp flashing | ## Otp flashing | ||||||
| 
 | 
 | ||||||
| !!! Flashing incorrect OTP may permanently brick your device !!! | !!! Flashing incorrect OTP may permanently brick your device !!! | ||||||
| 
 | 
 | ||||||
| Normally OTP data generated and flashed at factory. | Normally OTP data generated and flashed at the factory. | ||||||
| In case if MCU was replaced you'll need correct OTP data to be able to use companion applications. | 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. | Use `otp.py` to generate and flash OTP data. | ||||||
| You will need exact main board revision to genrate OTP data. It can be found on main PCB. | You will need exact main board revision to genrate OTP data. It can be found on main PCB. | ||||||
|  | Also display type, region and etc... | ||||||
| 
 | 
 | ||||||
| !!! Flashing incorrect OTP may permanently brick your device !!! | !!! Flashing incorrect OTP may permanently brick your device !!! | ||||||
| 
 | 
 | ||||||
| ## Core2 flashing | ## Core1 and Core2 firmware flashing | ||||||
| 
 | 
 | ||||||
| Script blindly updates FUS and Radiostack. This operation is going to corrupt bootloader and firmware. | Main flashing sequence can be found in root `Makefile`. | ||||||
| Reflash Core1 after Core2. | Core2 goes first, then Core1. | ||||||
| 
 | Never flash FUS or you will loose your job, girlfriend and keys in secure enclave. | ||||||
| ## Core1 flashing |  | ||||||
| 
 |  | ||||||
| Script compiles and flashes both bootloader and firmware. |  | ||||||
| 
 | 
 | ||||||
| ## Option Bytes | ## Option Bytes | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										152
									
								
								scripts/flash.py
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										152
									
								
								scripts/flash.py
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,152 @@ | |||||||
|  | #!/usr/bin/env python3 | ||||||
|  | 
 | ||||||
|  | import logging | ||||||
|  | import argparse | ||||||
|  | import sys | ||||||
|  | import os | ||||||
|  | 
 | ||||||
|  | from flipper.app import App | ||||||
|  | from flipper.cube import CubeProgrammer | ||||||
|  | 
 | ||||||
|  | STATEMENT = "AGREE_TO_LOOSE_FLIPPER_FEATURES_THAT_USES_CRYPTO_ENCLAVE" | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class Main(App): | ||||||
|  |     def init(self): | ||||||
|  |         self.subparsers = self.parser.add_subparsers(help="sub-command help") | ||||||
|  |         # Wipe | ||||||
|  |         self.parser_wipe = self.subparsers.add_parser("wipe", help="Wipe MCU Flash") | ||||||
|  |         self.parser_wipe.set_defaults(func=self.wipe) | ||||||
|  |         # Core 1 boot | ||||||
|  |         self.parser_core1boot = self.subparsers.add_parser( | ||||||
|  |             "core1boot", help="Flash Core1 Bootloader" | ||||||
|  |         ) | ||||||
|  |         self._addArgsSWD(self.parser_core1boot) | ||||||
|  |         self.parser_core1boot.add_argument( | ||||||
|  |             "bootloader", type=str, help="Bootloader binary" | ||||||
|  |         ) | ||||||
|  |         self.parser_core1boot.set_defaults(func=self.core1boot) | ||||||
|  |         # Core 1 firmware | ||||||
|  |         self.parser_core1firmware = self.subparsers.add_parser( | ||||||
|  |             "core1firmware", help="Flash Core1 Firmware" | ||||||
|  |         ) | ||||||
|  |         self._addArgsSWD(self.parser_core1firmware) | ||||||
|  |         self.parser_core1firmware.add_argument( | ||||||
|  |             "firmware", type=str, help="Firmware binary" | ||||||
|  |         ) | ||||||
|  |         self.parser_core1firmware.set_defaults(func=self.core1firmware) | ||||||
|  |         # Core 1 all | ||||||
|  |         self.parser_core1 = self.subparsers.add_parser( | ||||||
|  |             "core1", help="Flash Core1 Boot and Firmware" | ||||||
|  |         ) | ||||||
|  |         self._addArgsSWD(self.parser_core1) | ||||||
|  |         self.parser_core1.add_argument("bootloader", type=str, help="Bootloader binary") | ||||||
|  |         self.parser_core1.add_argument("firmware", type=str, help="Firmware binary") | ||||||
|  |         self.parser_core1.set_defaults(func=self.core1) | ||||||
|  |         # Core 2 fus | ||||||
|  |         self.parser_core2fus = self.subparsers.add_parser( | ||||||
|  |             "core2fus", help="Flash Core2 Firmware Update Service" | ||||||
|  |         ) | ||||||
|  |         self._addArgsSWD(self.parser_core2fus) | ||||||
|  |         self.parser_core2fus.add_argument( | ||||||
|  |             "--statement", | ||||||
|  |             type=str, | ||||||
|  |             help="NEVER FLASH FUS, IT WILL ERASE CRYPTO ENCLAVE", | ||||||
|  |             required=True, | ||||||
|  |         ) | ||||||
|  |         self.parser_core2fus.add_argument( | ||||||
|  |             "fus_address", type=str, help="Firmware Update Service Address" | ||||||
|  |         ) | ||||||
|  |         self.parser_core2fus.add_argument( | ||||||
|  |             "fus", type=str, help="Firmware Update Service Binary" | ||||||
|  |         ) | ||||||
|  |         self.parser_core2fus.set_defaults(func=self.core2fus) | ||||||
|  |         # Core 2 radio stack | ||||||
|  |         self.parser_core2radio = self.subparsers.add_parser( | ||||||
|  |             "core2radio", help="Flash Core2 Radio stack" | ||||||
|  |         ) | ||||||
|  |         self._addArgsSWD(self.parser_core2radio) | ||||||
|  |         self.parser_core2radio.add_argument( | ||||||
|  |             "radio_address", type=str, help="Radio Stack Binary Address" | ||||||
|  |         ) | ||||||
|  |         self.parser_core2radio.add_argument( | ||||||
|  |             "radio", type=str, help="Radio Stack Binary" | ||||||
|  |         ) | ||||||
|  |         self.parser_core2radio.set_defaults(func=self.core2radio) | ||||||
|  | 
 | ||||||
|  |     def _addArgsSWD(self, parser): | ||||||
|  |         parser.add_argument( | ||||||
|  |             "--port", type=str, help="Port to connect: swd or usb1", default="swd" | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |     def wipe(self): | ||||||
|  |         self.logger.info(f"Wiping flash") | ||||||
|  |         cp = CubeProgrammer("swd") | ||||||
|  |         self.logger.info(f"Setting RDP to 0xBB") | ||||||
|  |         cp.setOptionBytes({"RDP": ("0xBB", "rw")}) | ||||||
|  |         self.logger.info(f"Verifying RDP") | ||||||
|  |         r = cp.checkOptionBytes({"RDP": ("0xBB", "rw")}) | ||||||
|  |         assert r == True | ||||||
|  |         self.logger.info(f"Result: {r}") | ||||||
|  |         self.logger.info(f"Setting RDP to 0xAA") | ||||||
|  |         cp.setOptionBytes({"RDP": ("0xAA", "rw")}) | ||||||
|  |         self.logger.info(f"Verifying RDP") | ||||||
|  |         r = cp.checkOptionBytes({"RDP": ("0xAA", "rw")}) | ||||||
|  |         assert r == True | ||||||
|  |         self.logger.info(f"Result: {r}") | ||||||
|  |         self.logger.info(f"Complete") | ||||||
|  |         return 0 | ||||||
|  | 
 | ||||||
|  |     def core1boot(self): | ||||||
|  |         self.logger.info(f"Flashing bootloader") | ||||||
|  |         cp = CubeProgrammer(self.args.port) | ||||||
|  |         cp.flashBin("0x08000000", self.args.bootloader) | ||||||
|  |         self.logger.info(f"Complete") | ||||||
|  |         cp.resetTarget() | ||||||
|  |         return 0 | ||||||
|  | 
 | ||||||
|  |     def core1firmware(self): | ||||||
|  |         self.logger.info(f"Flashing firmware") | ||||||
|  |         cp = CubeProgrammer(self.args.port) | ||||||
|  |         cp.flashBin("0x08008000", self.args.firmware) | ||||||
|  |         self.logger.info(f"Complete") | ||||||
|  |         cp.resetTarget() | ||||||
|  |         return 0 | ||||||
|  | 
 | ||||||
|  |     def core1(self): | ||||||
|  |         self.logger.info(f"Flashing bootloader") | ||||||
|  |         cp = CubeProgrammer(self.args.port) | ||||||
|  |         cp.flashBin("0x08000000", self.args.bootloader) | ||||||
|  |         self.logger.info(f"Flashing firmware") | ||||||
|  |         cp.flashBin("0x08008000", self.args.firmware) | ||||||
|  |         cp.resetTarget() | ||||||
|  |         self.logger.info(f"Complete") | ||||||
|  |         return 0 | ||||||
|  | 
 | ||||||
|  |     def core2fus(self): | ||||||
|  |         if self.args.statement != STATEMENT: | ||||||
|  |             self.logger.error( | ||||||
|  |                 f"PLEASE DON'T. THIS FEATURE INTENDED ONLY FOR FACTORY FLASHING" | ||||||
|  |             ) | ||||||
|  |             return 1 | ||||||
|  |         self.logger.info(f"Flashing Firmware Update Service") | ||||||
|  |         cp = CubeProgrammer(self.args.port) | ||||||
|  |         cp.flashCore2(self.args.fus_address, self.args.fus) | ||||||
|  |         self.logger.info(f"Complete") | ||||||
|  |         return 0 | ||||||
|  | 
 | ||||||
|  |     def core2radio(self): | ||||||
|  |         if int(self.args.radio_address, 16) > 0x080E0000: | ||||||
|  |             self.logger.error(f"I KNOW WHAT YOU DID LAST SUMMER") | ||||||
|  |             return 1 | ||||||
|  |         cp = CubeProgrammer(self.args.port) | ||||||
|  |         self.logger.info(f"Removing Current Radio Stack") | ||||||
|  |         cp.deleteCore2RadioStack() | ||||||
|  |         self.logger.info(f"Flashing Radio Stack") | ||||||
|  |         cp.flashCore2(self.args.radio_address, self.args.radio) | ||||||
|  |         self.logger.info(f"Complete") | ||||||
|  |         return 0 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | if __name__ == "__main__": | ||||||
|  |     Main()() | ||||||
| @ -1,12 +0,0 @@ | |||||||
| #!/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 |  | ||||||
| @ -1,20 +0,0 @@ | |||||||
| #!/bin/bash |  | ||||||
| 
 |  | ||||||
| set -x -e |  | ||||||
| 
 |  | ||||||
| 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_for_fus_0_5_3.bin 0x080EC000 || true |  | ||||||
| STM32_Programmer_CLI -c port=swd |  | ||||||
| 
 |  | ||||||
| STM32_Programmer_CLI -c port=swd -fwupgrade "$COPRO_DIR"/stm32wb5x_FUS_fw.bin 0x080EC000 || true |  | ||||||
| STM32_Programmer_CLI -c port=swd |  | ||||||
| 
 |  | ||||||
| STM32_Programmer_CLI -c port=swd -fwdelete |  | ||||||
| 
 |  | ||||||
| STM32_Programmer_CLI -c port=swd -fwupgrade "$COPRO_DIR"/stm32wb5x_BLE_Stack_full_fw.bin 0x080CA000 firstinstall=0 |  | ||||||
| 
 |  | ||||||
| STM32_Programmer_CLI -c port=swd -ob nSWBOOT0=1 nBOOT0=1 |  | ||||||
| 
 |  | ||||||
| @ -1,17 +0,0 @@ | |||||||
| #!/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 |  | ||||||
| @ -1,17 +0,0 @@ | |||||||
| #!/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=swd -d "$1" 0x1FFF7000 |  | ||||||
| 
 |  | ||||||
| STM32_Programmer_CLI -c port=swd -r8 0x1FFF7000 8 |  | ||||||
| @ -1,11 +0,0 @@ | |||||||
| #!/bin/bash |  | ||||||
| 
 |  | ||||||
| set -x -e |  | ||||||
| 
 |  | ||||||
| STM32_Programmer_CLI -c port=swd -ob RDP=0xBB |  | ||||||
| 
 |  | ||||||
| STM32_Programmer_CLI -c port=swd -ob displ |  | ||||||
| 
 |  | ||||||
| STM32_Programmer_CLI -c port=swd --readunprotect |  | ||||||
| 
 |  | ||||||
| STM32_Programmer_CLI -c port=swd -ob displ |  | ||||||
							
								
								
									
										47
									
								
								scripts/flipper/app.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								scripts/flipper/app.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,47 @@ | |||||||
|  | import logging | ||||||
|  | import argparse | ||||||
|  | import sys | ||||||
|  | import os | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class App: | ||||||
|  |     def __init__(self): | ||||||
|  |         # Argument Parser | ||||||
|  |         self.parser = argparse.ArgumentParser() | ||||||
|  |         self.parser.add_argument("-d", "--debug", action="store_true", help="Debug") | ||||||
|  |         # Logging | ||||||
|  |         self.logger = logging.getLogger() | ||||||
|  |         # Application specific initialization | ||||||
|  |         self.init() | ||||||
|  | 
 | ||||||
|  |     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.before() | ||||||
|  |         return_code = self.args.func() | ||||||
|  |         self.after() | ||||||
|  |         if isinstance(return_code, int): | ||||||
|  |             exit(return_code) | ||||||
|  |         else: | ||||||
|  |             self.logger.error(f"Missing return code") | ||||||
|  |             exit(255) | ||||||
|  | 
 | ||||||
|  |     def init(self): | ||||||
|  |         raise Exception("init() is not implemented") | ||||||
|  | 
 | ||||||
|  |     def before(self): | ||||||
|  |         pass | ||||||
|  | 
 | ||||||
|  |     def after(self): | ||||||
|  |         pass | ||||||
							
								
								
									
										91
									
								
								scripts/flipper/cube.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								scripts/flipper/cube.py
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,91 @@ | |||||||
|  | import logging | ||||||
|  | import subprocess | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class CubeProgrammer: | ||||||
|  |     """STM32 Cube Programmer cli wrapper""" | ||||||
|  | 
 | ||||||
|  |     def __init__(self, port, params=[]): | ||||||
|  |         self.port = port | ||||||
|  |         self.params = params | ||||||
|  |         # logging | ||||||
|  |         self.logger = logging.getLogger() | ||||||
|  | 
 | ||||||
|  |     def _execute(self, args): | ||||||
|  |         try: | ||||||
|  |             output = subprocess.check_output( | ||||||
|  |                 [ | ||||||
|  |                     "STM32_Programmer_CLI", | ||||||
|  |                     "-q", | ||||||
|  |                     f"-c port={self.port}", | ||||||
|  |                     *self.params, | ||||||
|  |                     *args, | ||||||
|  |                 ] | ||||||
|  |             ) | ||||||
|  |         except subprocess.CalledProcessError as e: | ||||||
|  |             if e.output: | ||||||
|  |                 print("Process output:\n", e.output.decode()) | ||||||
|  |             print("Process return code:", e.returncode) | ||||||
|  |             raise e | ||||||
|  |         assert output | ||||||
|  |         return output.decode() | ||||||
|  | 
 | ||||||
|  |     def getVersion(self): | ||||||
|  |         output = self._execute(["--version"]) | ||||||
|  | 
 | ||||||
|  |     def checkOptionBytes(self, option_bytes): | ||||||
|  |         output = self._execute(["-ob displ"]) | ||||||
|  |         ob_correct = True | ||||||
|  |         for line in output.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 option_bytes.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 option_bytes[key][0] != value: | ||||||
|  |                 self.logger.error( | ||||||
|  |                     f"Invalid OB: {key} {value}, expected: {option_bytes[key][0]}" | ||||||
|  |                 ) | ||||||
|  |                 ob_correct = False | ||||||
|  |         return ob_correct | ||||||
|  | 
 | ||||||
|  |     def setOptionBytes(self, option_bytes): | ||||||
|  |         options = [] | ||||||
|  |         for key, (value, attr) in option_bytes.items(): | ||||||
|  |             if "w" in attr: | ||||||
|  |                 options.append(f"{key}={value}") | ||||||
|  |         self._execute(["-ob", *options]) | ||||||
|  |         return True | ||||||
|  | 
 | ||||||
|  |     def flashBin(self, address, filename): | ||||||
|  |         self._execute( | ||||||
|  |             [ | ||||||
|  |                 "-d", | ||||||
|  |                 filename, | ||||||
|  |                 f"{address}", | ||||||
|  |             ] | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |     def flashCore2(self, address, filename): | ||||||
|  |         self._execute( | ||||||
|  |             [ | ||||||
|  |                 "-fwupgrade", | ||||||
|  |                 filename, | ||||||
|  |                 f"{address}", | ||||||
|  |             ] | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |     def deleteCore2RadioStack(self): | ||||||
|  |         self._execute(["-fwdelete"]) | ||||||
|  | 
 | ||||||
|  |     def resetTarget(self): | ||||||
|  |         self._execute([]) | ||||||
| @ -25,7 +25,7 @@ SBRSA:0xA:r | |||||||
| SBRV:0x32800:r | SBRV:0x32800:r | ||||||
| PCROP1A_STRT:0x1FF:r | PCROP1A_STRT:0x1FF:r | ||||||
| PCROP1A_END:0x0:r | PCROP1A_END:0x0:r | ||||||
| PCROP_RDP:0x1:r | PCROP_RDP:0x1:rw | ||||||
| PCROP1B_STRT:0x1FF:r | PCROP1B_STRT:0x1FF:r | ||||||
| PCROP1B_END:0x0:r | PCROP1B_END:0x0:r | ||||||
| WRP1A_STRT:0xFF:r | WRP1A_STRT:0xFF:r | ||||||
|  | |||||||
							
								
								
									
										116
									
								
								scripts/ob.py
									
									
									
									
									
								
							
							
						
						
									
										116
									
								
								scripts/ob.py
									
									
									
									
									
								
							| @ -6,12 +6,12 @@ import subprocess | |||||||
| import sys | import sys | ||||||
| import os | import os | ||||||
| 
 | 
 | ||||||
|  | from flipper.app import App | ||||||
|  | from flipper.cube import CubeProgrammer | ||||||
| 
 | 
 | ||||||
| class Main: | 
 | ||||||
|     def __init__(self): | class Main(App): | ||||||
|         # command args |     def init(self): | ||||||
|         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.subparsers = self.parser.add_subparsers(help="sub-command help") | ||||||
|         self.parser_check = self.subparsers.add_parser( |         self.parser_check = self.subparsers.add_parser( | ||||||
|             "check", help="Check Option Bytes" |             "check", help="Check Option Bytes" | ||||||
| @ -20,39 +20,16 @@ class Main: | |||||||
|             "--port", type=str, help="Port to connect: swd or usb1", default="swd" |             "--port", type=str, help="Port to connect: swd or usb1", default="swd" | ||||||
|         ) |         ) | ||||||
|         self.parser_check.set_defaults(func=self.check) |         self.parser_check.set_defaults(func=self.check) | ||||||
|  |         # Set command | ||||||
|         self.parser_set = self.subparsers.add_parser("set", help="Set Option Bytes") |         self.parser_set = self.subparsers.add_parser("set", help="Set Option Bytes") | ||||||
|         self.parser_set.add_argument( |         self.parser_set.add_argument( | ||||||
|             "--port", type=str, help="Port to connect: swd or usb1", default="swd" |             "--port", type=str, help="Port to connect: swd or usb1", default="swd" | ||||||
|         ) |         ) | ||||||
|         self.parser_set.set_defaults(func=self.set) |         self.parser_set.set_defaults(func=self.set) | ||||||
|         # logging |  | ||||||
|         self.logger = logging.getLogger() |  | ||||||
|         # OB |         # OB | ||||||
|         self.ob = {} |         self.ob = {} | ||||||
| 
 | 
 | ||||||
|     def __call__(self): |     def before(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() |  | ||||||
| 
 |  | ||||||
|         return_code = self.args.func() |  | ||||||
|         if isinstance(return_code, int): |  | ||||||
|             return return_code |  | ||||||
|         else: |  | ||||||
|             self.logger.error(f"Forgotten return code") |  | ||||||
|             return 255 |  | ||||||
| 
 |  | ||||||
|     def loadOB(self): |  | ||||||
|         self.logger.info(f"Loading Option Bytes data") |         self.logger.info(f"Loading Option Bytes data") | ||||||
|         file_path = os.path.join(os.path.dirname(sys.argv[0]), "ob.data") |         file_path = os.path.join(os.path.dirname(sys.argv[0]), "ob.data") | ||||||
|         file = open(file_path, "r") |         file = open(file_path, "r") | ||||||
| @ -62,47 +39,8 @@ class Main: | |||||||
| 
 | 
 | ||||||
|     def check(self): |     def check(self): | ||||||
|         self.logger.info(f"Checking Option Bytes") |         self.logger.info(f"Checking Option Bytes") | ||||||
|         try: |         cp = CubeProgrammer(self.args.port) | ||||||
|             output = subprocess.check_output( |         if cp.checkOptionBytes(self.ob): | ||||||
|                 [ |  | ||||||
|                     "STM32_Programmer_CLI", |  | ||||||
|                     "-q", |  | ||||||
|                     "-c", |  | ||||||
|                     f"port={self.args.port}", |  | ||||||
|                     "-ob displ", |  | ||||||
|                 ] |  | ||||||
|             ) |  | ||||||
|             assert output |  | ||||||
|         except subprocess.CalledProcessError as e: |  | ||||||
|             self.logger.error(e.output.decode()) |  | ||||||
|             self.logger.error(f"Failed to call STM32_Programmer_CLI") |  | ||||||
|             return 127 |  | ||||||
|         except Exception as e: |  | ||||||
|             self.logger.error(f"Failed to call STM32_Programmer_CLI") |  | ||||||
|             self.logger.exception(e) |  | ||||||
|             return 126 |  | ||||||
|         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") |             self.logger.info(f"OB Check OK") | ||||||
|             return 0 |             return 0 | ||||||
|         else: |         else: | ||||||
| @ -111,34 +49,14 @@ class Main: | |||||||
| 
 | 
 | ||||||
|     def set(self): |     def set(self): | ||||||
|         self.logger.info(f"Setting Option Bytes") |         self.logger.info(f"Setting Option Bytes") | ||||||
|         options = [] |         cp = CubeProgrammer(self.args.port) | ||||||
|         for key, (value, attr) in self.ob.items(): |         if cp.setOptionBytes(self.ob): | ||||||
|             if "w" in attr: |             self.logger.info(f"OB Set OK") | ||||||
|                 options.append(f"{key}={value}") |             return 0 | ||||||
|         try: |         else: | ||||||
|             output = subprocess.check_output( |             self.logger.error(f"OB Set FAIL") | ||||||
|                 [ |             return 255 | ||||||
|                     "STM32_Programmer_CLI", |  | ||||||
|                     "-q", |  | ||||||
|                     "-c", |  | ||||||
|                     f"port={self.args.port}", |  | ||||||
|                     "-ob", |  | ||||||
|                     *options, |  | ||||||
|                 ] |  | ||||||
|             ) |  | ||||||
|             assert output |  | ||||||
|             self.logger.info(f"Success") |  | ||||||
|         except subprocess.CalledProcessError as e: |  | ||||||
|             self.logger.error(e.output.decode()) |  | ||||||
|             self.logger.error(f"Failed to call STM32_Programmer_CLI") |  | ||||||
|             return 125 |  | ||||||
|         except Exception as e: |  | ||||||
|             self.logger.error(f"Failed to call STM32_Programmer_CLI") |  | ||||||
|             self.logger.exception(e) |  | ||||||
|             return 124 |  | ||||||
|         return 0 |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| if __name__ == "__main__": | if __name__ == "__main__": | ||||||
|     return_code = Main()() |     Main()() | ||||||
|     exit(return_code) |  | ||||||
|  | |||||||
							
								
								
									
										131
									
								
								scripts/otp.py
									
									
									
									
									
								
							
							
						
						
									
										131
									
								
								scripts/otp.py
									
									
									
									
									
								
							| @ -32,12 +32,13 @@ OTP_DISPLAYS = { | |||||||
|     "mgg": 0x02, |     "mgg": 0x02, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | from flipper.app import App | ||||||
|  | from flipper.cube import CubeProgrammer | ||||||
| 
 | 
 | ||||||
| class Main: | 
 | ||||||
|     def __init__(self): | class Main(App): | ||||||
|         # command args |     def init(self): | ||||||
|         self.parser = argparse.ArgumentParser() |         # SubParsers | ||||||
|         self.parser.add_argument("-d", "--debug", action="store_true", help="Debug") |  | ||||||
|         self.subparsers = self.parser.add_subparsers(help="sub-command help") |         self.subparsers = self.parser.add_subparsers(help="sub-command help") | ||||||
|         # Generate All |         # Generate All | ||||||
|         self.parser_generate_all = self.subparsers.add_parser( |         self.parser_generate_all = self.subparsers.add_parser( | ||||||
| @ -73,21 +74,6 @@ class Main: | |||||||
|         self.logger = logging.getLogger() |         self.logger = logging.getLogger() | ||||||
|         self.timestamp = datetime.datetime.now().timestamp() |         self.timestamp = datetime.datetime.now().timestamp() | ||||||
| 
 | 
 | ||||||
|     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 _add_swd_args(self, parser): |     def _add_swd_args(self, parser): | ||||||
|         parser.add_argument( |         parser.add_argument( | ||||||
|             "--port", type=str, help="Port to connect: swd or usb1", default="swd" |             "--port", type=str, help="Port to connect: swd or usb1", default="swd" | ||||||
| @ -153,89 +139,90 @@ class Main: | |||||||
|         ) |         ) | ||||||
| 
 | 
 | ||||||
|     def generate_all(self): |     def generate_all(self): | ||||||
|         self.logger.debug(f"Generating OTP") |         self.logger.info(f"Generating OTP") | ||||||
|         self._process_first_args() |         self._process_first_args() | ||||||
|         self._process_second_args() |         self._process_second_args() | ||||||
|         open(f"{self.args.file}_first.bin", "wb").write(self._pack_first()) |         open(f"{self.args.file}_first.bin", "wb").write(self._pack_first()) | ||||||
|         open(f"{self.args.file}_second.bin", "wb").write(self._pack_second()) |         open(f"{self.args.file}_second.bin", "wb").write(self._pack_second()) | ||||||
|  |         self.logger.info( | ||||||
|  |             f"Generated files: {self.args.file}_first.bin and {self.args.file}_second.bin" | ||||||
|  |         ) | ||||||
|  | 
 | ||||||
|  |         return 0 | ||||||
| 
 | 
 | ||||||
|     def flash_first(self): |     def flash_first(self): | ||||||
|         self.logger.debug(f"Flashing first block of OTP") |         self.logger.info(f"Flashing first block of OTP") | ||||||
| 
 | 
 | ||||||
|         self._process_first_args() |         self._process_first_args() | ||||||
| 
 | 
 | ||||||
|         filename = f"otp_unknown_first_{self.timestamp}.bin" |         filename = f"otp_unknown_first_{self.timestamp}.bin" | ||||||
|         file = open(filename, "wb") |  | ||||||
|         file.write(self._pack_first()) |  | ||||||
|         file.close() |  | ||||||
| 
 | 
 | ||||||
|         self._flash_bin("0x1FFF7000", filename) |         try: | ||||||
|  |             self.logger.info(f"Packing binary data") | ||||||
|  |             file = open(filename, "wb") | ||||||
|  |             file.write(self._pack_first()) | ||||||
|  |             file.close() | ||||||
|  |             self.logger.info(f"Flashing OTP") | ||||||
|  |             cp = CubeProgrammer(self.args.port) | ||||||
|  |             cp.flashBin("0x1FFF7000", filename) | ||||||
|  |             cp.resetTarget() | ||||||
|  |             self.logger.info(f"Flashed Successfully") | ||||||
|  |             os.remove(filename) | ||||||
|  |         except Exception as e: | ||||||
|  |             self.logger.exception(e) | ||||||
|  |             return 0 | ||||||
| 
 | 
 | ||||||
|         os.remove(filename) |         return 1 | ||||||
| 
 | 
 | ||||||
|     def flash_second(self): |     def flash_second(self): | ||||||
|         self.logger.debug(f"Flashing second block of OTP") |         self.logger.info(f"Flashing second block of OTP") | ||||||
| 
 | 
 | ||||||
|         self._process_second_args() |         self._process_second_args() | ||||||
| 
 | 
 | ||||||
|         filename = f"otp_{self.args.name}_second_{self.timestamp}.bin" |         filename = f"otp_{self.args.name}_second_{self.timestamp}.bin" | ||||||
|         file = open(filename, "wb") |  | ||||||
|         file.write(self._pack_second()) |  | ||||||
|         file.close() |  | ||||||
| 
 | 
 | ||||||
|         self._flash_bin("0x1FFF7010", filename) |         try: | ||||||
|  |             self.logger.info(f"Packing binary data") | ||||||
|  |             file = open(filename, "wb") | ||||||
|  |             file.write(self._pack_second()) | ||||||
|  |             file.close() | ||||||
|  |             self.logger.info(f"Flashing OTP") | ||||||
|  |             cp = CubeProgrammer(self.args.port) | ||||||
|  |             cp.flashBin("0x1FFF7010", filename) | ||||||
|  |             cp.resetTarget() | ||||||
|  |             self.logger.info(f"Flashed Successfully") | ||||||
|  |             os.remove(filename) | ||||||
|  |         except Exception as e: | ||||||
|  |             self.logger.exception(e) | ||||||
|  |             return 1 | ||||||
| 
 | 
 | ||||||
|         os.remove(filename) |         return 0 | ||||||
| 
 | 
 | ||||||
|     def flash_all(self): |     def flash_all(self): | ||||||
|         self.logger.debug(f"Flashing OTP") |         self.logger.info(f"Flashing OTP") | ||||||
| 
 | 
 | ||||||
|         self._process_first_args() |         self._process_first_args() | ||||||
|         self._process_second_args() |         self._process_second_args() | ||||||
| 
 | 
 | ||||||
|         filename = f"otp_{self.args.name}_whole_{self.timestamp}.bin" |         filename = f"otp_{self.args.name}_whole_{self.timestamp}.bin" | ||||||
|         file = open(filename, "wb") |  | ||||||
|         file.write(self._pack_first()) |  | ||||||
|         file.write(self._pack_second()) |  | ||||||
|         file.close() |  | ||||||
| 
 | 
 | ||||||
|         self._flash_bin("0x1FFF7000", filename) |  | ||||||
| 
 |  | ||||||
|         os.remove(filename) |  | ||||||
| 
 |  | ||||||
|     def _flash_bin(self, address, filename): |  | ||||||
|         self.logger.debug(f"Programming {filename} at {address}") |  | ||||||
|         try: |         try: | ||||||
|             output = subprocess.check_output( |             self.logger.info(f"Packing binary data") | ||||||
|                 [ |             file = open(filename, "wb") | ||||||
|                     "STM32_Programmer_CLI", |             file.write(self._pack_first()) | ||||||
|                     "-q", |             file.write(self._pack_second()) | ||||||
|                     "-c", |             file.close() | ||||||
|                     f"port={self.args.port}", |             self.logger.info(f"Flashing OTP") | ||||||
|                     "-d", |             cp = CubeProgrammer(self.args.port) | ||||||
|                     filename, |             cp.flashBin("0x1FFF7000", filename) | ||||||
|                     f"{address}", |             cp.resetTarget() | ||||||
|                 ] |             self.logger.info(f"Flashed Successfully") | ||||||
|             ) |             os.remove(filename) | ||||||
|             assert output |  | ||||||
|             self.logger.info(f"Success") |  | ||||||
|         except subprocess.CalledProcessError as e: |  | ||||||
|             self.logger.error(e.output.decode()) |  | ||||||
|             self.logger.error(f"Failed to call STM32_Programmer_CLI") |  | ||||||
|             return |  | ||||||
|         except Exception as e: |         except Exception as e: | ||||||
|             self.logger.error(f"Failed to call STM32_Programmer_CLI") |  | ||||||
|             self.logger.exception(e) |             self.logger.exception(e) | ||||||
|             return |             return 1 | ||||||
|         # reboot | 
 | ||||||
|         subprocess.check_output( |         return 0 | ||||||
|             [ |  | ||||||
|                 "STM32_Programmer_CLI", |  | ||||||
|                 "-q", |  | ||||||
|                 "-c", |  | ||||||
|                 f"port={self.args.port}", |  | ||||||
|             ] |  | ||||||
|         ) |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| if __name__ == "__main__": | if __name__ == "__main__": | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 あく
						あく