[FL-1945] Firmware, Scripts, Cli: add OTPv2, alternative displays support and 2-step OTP programming. #764
This commit is contained in:
		
							parent
							
								
									63428609b7
								
							
						
					
					
						commit
						0e14545d48
					
				| @ -57,10 +57,6 @@ static const uint8_t enclave_signature_expected[ENCLAVE_SIGNATURE_KEY_SLOTS][ENC | ||||
| void cli_command_device_info(Cli* cli, string_t args, void* context) { | ||||
|     // Model name
 | ||||
|     printf("hardware_model      : %s\r\n", furi_hal_version_get_model_name()); | ||||
|     const char* name = furi_hal_version_get_name_ptr(); | ||||
|     if(name) { | ||||
|         printf("hardware_name       : %s\r\n", name); | ||||
|     } | ||||
| 
 | ||||
|     // Unique ID
 | ||||
|     printf("hardware_uid        : "); | ||||
| @ -70,16 +66,24 @@ void cli_command_device_info(Cli* cli, string_t args, void* context) { | ||||
|     } | ||||
|     printf("\r\n"); | ||||
| 
 | ||||
|     // OTP Revision
 | ||||
|     printf("hardware_otp_ver    : %d\r\n", furi_hal_version_get_otp_version()); | ||||
|     printf("hardware_timestamp  : %lu\r\n", furi_hal_version_get_hw_timestamp()); | ||||
| 
 | ||||
|     // Board Revision
 | ||||
|     printf("hardware_ver        : %d\r\n", furi_hal_version_get_hw_version()); | ||||
|     printf("hardware_target     : %d\r\n", furi_hal_version_get_hw_target()); | ||||
|     printf("hardware_body       : %d\r\n", furi_hal_version_get_hw_body()); | ||||
|     printf("hardware_connect    : %d\r\n", furi_hal_version_get_hw_connect()); | ||||
|     printf("hardware_timestamp  : %lu\r\n", furi_hal_version_get_hw_timestamp()); | ||||
|     printf("hardware_display    : %d\r\n", furi_hal_version_get_hw_display()); | ||||
| 
 | ||||
|     // Color and Region
 | ||||
|     // Board Personification
 | ||||
|     printf("hardware_color      : %d\r\n", furi_hal_version_get_hw_color()); | ||||
|     printf("hardware_region     : %d\r\n", furi_hal_version_get_hw_region()); | ||||
|     const char* name = furi_hal_version_get_name_ptr(); | ||||
|     if(name) { | ||||
|         printf("hardware_name       : %s\r\n", name); | ||||
|     } | ||||
| 
 | ||||
|     // Bootloader Version
 | ||||
|     const Version* boot_version = furi_hal_version_get_boot_version(); | ||||
|  | ||||
| @ -10,13 +10,6 @@ | ||||
| #define FURI_HAL_VERSION_OTP_HEADER_MAGIC 0xBABE | ||||
| #define FURI_HAL_VERSION_OTP_ADDRESS OTP_AREA_BASE | ||||
| 
 | ||||
| /** OTP Versions enum */ | ||||
| typedef enum { | ||||
|     FuriHalVersionOtpVersion0=0x00, | ||||
|     FuriHalVersionOtpVersion1=0x01, | ||||
|     FuriHalVersionOtpVersionEmpty=0xFFFFFFFE, | ||||
|     FuriHalVersionOtpVersionUnknown=0xFFFFFFFF, | ||||
| } FuriHalVersionOtpVersion; | ||||
| 
 | ||||
| /** OTP V0 Structure: prototypes and early EVT */ | ||||
| typedef struct { | ||||
| @ -28,7 +21,7 @@ typedef struct { | ||||
|     char name[FURI_HAL_VERSION_NAME_LENGTH]; | ||||
| } FuriHalVersionOTPv0; | ||||
| 
 | ||||
| /** OTP V1 Structure: late EVT, DVT, PVT, Production */ | ||||
| /** OTP V1 Structure: late EVT, DVT */ | ||||
| typedef struct { | ||||
|     /* First 64 bits: header */ | ||||
|     uint16_t header_magic; | ||||
| @ -49,10 +42,35 @@ typedef struct { | ||||
|     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 { | ||||
|     FuriHalVersionOtpVersion otp_version; | ||||
| 
 | ||||
|     uint32_t timestamp; | ||||
| 
 | ||||
|     uint8_t board_version; /** Board version */ | ||||
| @ -61,6 +79,7 @@ typedef struct { | ||||
|     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 */ | ||||
| @ -69,20 +88,6 @@ typedef struct { | ||||
| 
 | ||||
| static FuriHalVersion furi_hal_version = {0}; | ||||
| 
 | ||||
| static 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) { | ||||
|             return FuriHalVersionOtpVersion1; | ||||
|         } else if (((FuriHalVersionOTPv0*)FURI_HAL_VERSION_OTP_ADDRESS)->board_version <= 10) { | ||||
|             return FuriHalVersionOtpVersion0; | ||||
|         } else { | ||||
|             return FuriHalVersionOtpVersionUnknown; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
| @ -124,8 +129,6 @@ static void furi_hal_version_load_otp_v0() { | ||||
|     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 = 0; | ||||
|     furi_hal_version.board_region = 0; | ||||
| 
 | ||||
|     furi_hal_version_set_name(otp->name); | ||||
| } | ||||
| @ -144,9 +147,33 @@ static void furi_hal_version_load_otp_v1() { | ||||
|     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() { | ||||
|     furi_hal_version.otp_version = furi_hal_version_get_otp_version(); | ||||
|     switch(furi_hal_version.otp_version) { | ||||
|     switch(furi_hal_version_get_otp_version()) { | ||||
|         case FuriHalVersionOtpVersionUnknown: | ||||
|             furi_hal_version_load_otp_default(); | ||||
|         break; | ||||
| @ -159,6 +186,9 @@ void furi_hal_version_init() { | ||||
|         case FuriHalVersionOtpVersion1: | ||||
|             furi_hal_version_load_otp_v1(); | ||||
|         break; | ||||
|         case FuriHalVersionOtpVersion2: | ||||
|             furi_hal_version_load_otp_v2(); | ||||
|         break; | ||||
|         default: furi_crash(NULL); | ||||
|     } | ||||
|     FURI_LOG_I("FuriHalVersion", "Init OK"); | ||||
| @ -172,6 +202,28 @@ 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; | ||||
| } | ||||
| @ -196,6 +248,10 @@ 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; | ||||
| } | ||||
|  | ||||
| @ -10,13 +10,6 @@ | ||||
| #define FURI_HAL_VERSION_OTP_HEADER_MAGIC 0xBABE | ||||
| #define FURI_HAL_VERSION_OTP_ADDRESS OTP_AREA_BASE | ||||
| 
 | ||||
| /** OTP Versions enum */ | ||||
| typedef enum { | ||||
|     FuriHalVersionOtpVersion0=0x00, | ||||
|     FuriHalVersionOtpVersion1=0x01, | ||||
|     FuriHalVersionOtpVersionEmpty=0xFFFFFFFE, | ||||
|     FuriHalVersionOtpVersionUnknown=0xFFFFFFFF, | ||||
| } FuriHalVersionOtpVersion; | ||||
| 
 | ||||
| /** OTP V0 Structure: prototypes and early EVT */ | ||||
| typedef struct { | ||||
| @ -28,7 +21,7 @@ typedef struct { | ||||
|     char name[FURI_HAL_VERSION_NAME_LENGTH]; | ||||
| } FuriHalVersionOTPv0; | ||||
| 
 | ||||
| /** OTP V1 Structure: late EVT, DVT, PVT, Production */ | ||||
| /** OTP V1 Structure: late EVT, DVT */ | ||||
| typedef struct { | ||||
|     /* First 64 bits: header */ | ||||
|     uint16_t header_magic; | ||||
| @ -49,10 +42,35 @@ typedef struct { | ||||
|     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 { | ||||
|     FuriHalVersionOtpVersion otp_version; | ||||
| 
 | ||||
|     uint32_t timestamp; | ||||
| 
 | ||||
|     uint8_t board_version; /** Board version */ | ||||
| @ -61,6 +79,7 @@ typedef struct { | ||||
|     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 */ | ||||
| @ -69,20 +88,6 @@ typedef struct { | ||||
| 
 | ||||
| static FuriHalVersion furi_hal_version = {0}; | ||||
| 
 | ||||
| static 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) { | ||||
|             return FuriHalVersionOtpVersion1; | ||||
|         } else if (((FuriHalVersionOTPv0*)FURI_HAL_VERSION_OTP_ADDRESS)->board_version <= 10) { | ||||
|             return FuriHalVersionOtpVersion0; | ||||
|         } else { | ||||
|             return FuriHalVersionOtpVersionUnknown; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
| @ -124,8 +129,6 @@ static void furi_hal_version_load_otp_v0() { | ||||
|     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 = 0; | ||||
|     furi_hal_version.board_region = 0; | ||||
| 
 | ||||
|     furi_hal_version_set_name(otp->name); | ||||
| } | ||||
| @ -144,9 +147,33 @@ static void furi_hal_version_load_otp_v1() { | ||||
|     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() { | ||||
|     furi_hal_version.otp_version = furi_hal_version_get_otp_version(); | ||||
|     switch(furi_hal_version.otp_version) { | ||||
|     switch(furi_hal_version_get_otp_version()) { | ||||
|         case FuriHalVersionOtpVersionUnknown: | ||||
|             furi_hal_version_load_otp_default(); | ||||
|         break; | ||||
| @ -159,6 +186,9 @@ void furi_hal_version_init() { | ||||
|         case FuriHalVersionOtpVersion1: | ||||
|             furi_hal_version_load_otp_v1(); | ||||
|         break; | ||||
|         case FuriHalVersionOtpVersion2: | ||||
|             furi_hal_version_load_otp_v2(); | ||||
|         break; | ||||
|         default: furi_crash(NULL); | ||||
|     } | ||||
|     FURI_LOG_I("FuriHalVersion", "Init OK"); | ||||
| @ -172,6 +202,28 @@ 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; | ||||
| } | ||||
| @ -196,6 +248,10 @@ 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; | ||||
| } | ||||
|  | ||||
| @ -19,6 +19,15 @@ extern "C" { | ||||
| /** 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, | ||||
| @ -34,6 +43,13 @@ typedef enum { | ||||
|     FuriHalVersionRegionJp=0x03, | ||||
| } FuriHalVersionRegion; | ||||
| 
 | ||||
| /** Device Display */ | ||||
| typedef enum { | ||||
|     FuriHalVersionDisplayUnknown=0x00, | ||||
|     FuriHalVersionDisplayErc=0x01, | ||||
|     FuriHalVersionDisplayMgg=0x02, | ||||
| } FuriHalVersionDisplay; | ||||
| 
 | ||||
| /** Init flipper version
 | ||||
|  */ | ||||
| void furi_hal_version_init(); | ||||
| @ -50,6 +66,12 @@ bool furi_hal_version_do_i_belong_here(); | ||||
|  */ | ||||
| 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 | ||||
| @ -86,6 +108,12 @@ const uint8_t furi_hal_version_get_hw_connect(); | ||||
|  */ | ||||
| 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 | ||||
|  | ||||
							
								
								
									
										152
									
								
								scripts/otp.py
									
									
									
									
									
								
							
							
						
						
									
										152
									
								
								scripts/otp.py
									
									
									
									
									
								
							| @ -10,7 +10,7 @@ import struct | ||||
| import datetime | ||||
| 
 | ||||
| OTP_MAGIC = 0xBABE | ||||
| OTP_VERSION = 0x01 | ||||
| OTP_VERSION = 0x02 | ||||
| OTP_RESERVED = 0x00 | ||||
| 
 | ||||
| OTP_COLORS = { | ||||
| @ -18,6 +18,7 @@ OTP_COLORS = { | ||||
|     "black": 0x01, | ||||
|     "white": 0x02, | ||||
| } | ||||
| 
 | ||||
| OTP_REGIONS = { | ||||
|     "unknown": 0x00, | ||||
|     "eu_ru": 0x01, | ||||
| @ -25,7 +26,11 @@ OTP_REGIONS = { | ||||
|     "jp": 0x03, | ||||
| } | ||||
| 
 | ||||
| BOARD_RESERVED = 0x0000 | ||||
| OTP_DISPLAYS = { | ||||
|     "unknown": 0x00, | ||||
|     "erc": 0x01, | ||||
|     "mgg": 0x02, | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| class Main: | ||||
| @ -34,22 +39,36 @@ class Main: | ||||
|         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") | ||||
|         # Generate | ||||
|         self.parser_generate = self.subparsers.add_parser( | ||||
|         # Generate All | ||||
|         self.parser_generate_all = self.subparsers.add_parser( | ||||
|             "generate", help="Generate OTP binary" | ||||
|         ) | ||||
|         self._add_args(self.parser_generate) | ||||
|         self.parser_generate.add_argument("file", help="Output file") | ||||
|         self.parser_generate.set_defaults(func=self.generate) | ||||
|         # Flash | ||||
|         self.parser_flash = self.subparsers.add_parser( | ||||
|             "flash", help="Flash OTP to device" | ||||
|         self._add_first_args(self.parser_generate_all) | ||||
|         self._add_second_args(self.parser_generate_all) | ||||
|         self.parser_generate_all.add_argument("file", help="Output file") | ||||
|         self.parser_generate_all.set_defaults(func=self.generate_all) | ||||
|         # Flash First | ||||
|         self.parser_flash_first = self.subparsers.add_parser( | ||||
|             "flash_first", help="Flash first block of OTP to device" | ||||
|         ) | ||||
|         self._add_args(self.parser_flash) | ||||
|         self.parser_flash.add_argument( | ||||
|             "--port", type=str, help="Port to connect: swd or usb1", default="swd" | ||||
|         self._add_swd_args(self.parser_flash_first) | ||||
|         self._add_first_args(self.parser_flash_first) | ||||
|         self.parser_flash_first.set_defaults(func=self.flash_first) | ||||
|         # Flash Second | ||||
|         self.parser_flash_second = self.subparsers.add_parser( | ||||
|             "flash_second", help="Flash second block of OTP to device" | ||||
|         ) | ||||
|         self.parser_flash.set_defaults(func=self.flash) | ||||
|         self._add_swd_args(self.parser_flash_second) | ||||
|         self._add_second_args(self.parser_flash_second) | ||||
|         self.parser_flash_second.set_defaults(func=self.flash_second) | ||||
|         # Flash All | ||||
|         self.parser_flash_all = self.subparsers.add_parser( | ||||
|             "flash_all", help="Flash OTP to device" | ||||
|         ) | ||||
|         self._add_swd_args(self.parser_flash_all) | ||||
|         self._add_first_args(self.parser_flash_all) | ||||
|         self._add_second_args(self.parser_flash_all) | ||||
|         self.parser_flash_all.set_defaults(func=self.flash_all) | ||||
|         # logging | ||||
|         self.logger = logging.getLogger() | ||||
|         self.timestamp = datetime.datetime.now().timestamp() | ||||
| @ -69,16 +88,29 @@ class Main: | ||||
|         # execute requested function | ||||
|         self.args.func() | ||||
| 
 | ||||
|     def _add_args(self, parser): | ||||
|         parser.add_argument("--version", type=int, help="Version", default=11) | ||||
|         parser.add_argument("--firmware", type=int, help="Firmware", default=7) | ||||
|         parser.add_argument("--body", type=int, help="Body", default=9) | ||||
|         parser.add_argument("--connect", type=int, help="Connect", default=6) | ||||
|         parser.add_argument("--color", type=str, help="Color", default="unknown") | ||||
|         parser.add_argument("--region", type=str, help="Region", default="unknown") | ||||
|     def _add_swd_args(self, parser): | ||||
|         parser.add_argument( | ||||
|             "--port", type=str, help="Port to connect: swd or usb1", default="swd" | ||||
|         ) | ||||
| 
 | ||||
|     def _add_first_args(self, parser): | ||||
|         parser.add_argument("--version", type=int, help="Version", required=True) | ||||
|         parser.add_argument("--firmware", type=int, help="Firmware", required=True) | ||||
|         parser.add_argument("--body", type=int, help="Body", required=True) | ||||
|         parser.add_argument("--connect", type=int, help="Connect", required=True) | ||||
|         parser.add_argument("--display", type=str, help="Display", required=True) | ||||
| 
 | ||||
|     def _add_second_args(self, parser): | ||||
|         parser.add_argument("--color", type=str, help="Color", required=True) | ||||
|         parser.add_argument("--region", type=str, help="Region", required=True) | ||||
|         parser.add_argument("--name", type=str, help="Name", required=True) | ||||
| 
 | ||||
|     def _process_args(self): | ||||
|     def _process_first_args(self): | ||||
|         if self.args.display not in OTP_DISPLAYS: | ||||
|             self.parser.error(f"Invalid display. Use one of {OTP_DISPLAYS.keys()}") | ||||
|         self.args.display = OTP_DISPLAYS[self.args.display] | ||||
| 
 | ||||
|     def _process_second_args(self): | ||||
|         if self.args.color not in OTP_COLORS: | ||||
|             self.parser.error(f"Invalid color. Use one of {OTP_COLORS.keys()}") | ||||
|         self.args.color = OTP_COLORS[self.args.color] | ||||
| @ -94,9 +126,9 @@ class Main: | ||||
|                 "Name contains incorrect symbols. Only a-zA-Z0-9 allowed." | ||||
|             ) | ||||
| 
 | ||||
|     def _pack_struct(self): | ||||
|     def _pack_first(self): | ||||
|         return struct.pack( | ||||
|             "<" "HBBL" "BBBBBBH" "8s", | ||||
|             "<" "HBBL" "BBBBBBH", | ||||
|             OTP_MAGIC, | ||||
|             OTP_VERSION, | ||||
|             OTP_RESERVED, | ||||
| @ -105,25 +137,74 @@ class Main: | ||||
|             self.args.firmware, | ||||
|             self.args.body, | ||||
|             self.args.connect, | ||||
|             self.args.display, | ||||
|             OTP_RESERVED, | ||||
|             OTP_RESERVED, | ||||
|         ) | ||||
| 
 | ||||
|     def _pack_second(self): | ||||
|         return struct.pack( | ||||
|             "<" "BBHL" "8s", | ||||
|             self.args.color, | ||||
|             self.args.region, | ||||
|             BOARD_RESERVED, | ||||
|             OTP_RESERVED, | ||||
|             OTP_RESERVED, | ||||
|             self.args.name.encode("ascii"), | ||||
|         ) | ||||
| 
 | ||||
|     def generate(self): | ||||
|     def generate_all(self): | ||||
|         self.logger.debug(f"Generating OTP") | ||||
|         self._process_args() | ||||
|         data = self._pack_struct() | ||||
|         open(self.args.file, "wb").write(data) | ||||
|         self._process_first_args() | ||||
|         self._process_second_args() | ||||
|         open(f"{self.args.file}_first.bin", "wb").write(self._pack_first()) | ||||
|         open(f"{self.args.file}_second.bin", "wb").write(self._pack_second()) | ||||
| 
 | ||||
|     def flash(self): | ||||
|     def flash_first(self): | ||||
|         self.logger.debug(f"Flashing first block of OTP") | ||||
| 
 | ||||
|         self._process_first_args() | ||||
| 
 | ||||
|         filename = f"otp_unknown_first_{self.timestamp}.bin" | ||||
|         file = open(filename, "wb") | ||||
|         file.write(self._pack_first()) | ||||
|         file.close() | ||||
| 
 | ||||
|         self._flash_bin("0x1FFF7000", filename) | ||||
| 
 | ||||
|         os.remove(filename) | ||||
| 
 | ||||
|     def flash_second(self): | ||||
|         self.logger.debug(f"Flashing second block of OTP") | ||||
| 
 | ||||
|         self._process_second_args() | ||||
| 
 | ||||
|         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) | ||||
| 
 | ||||
|         os.remove(filename) | ||||
| 
 | ||||
|     def flash_all(self): | ||||
|         self.logger.debug(f"Flashing OTP") | ||||
|         self._process_args() | ||||
|         data = self._pack_struct() | ||||
|         filename = f"otp_{self.args.name}_{self.timestamp}.bin" | ||||
|         open(filename, "wb").write(data) | ||||
| 
 | ||||
|         self._process_first_args() | ||||
|         self._process_second_args() | ||||
| 
 | ||||
|         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: | ||||
|             output = subprocess.check_output( | ||||
|                 [ | ||||
| @ -133,7 +214,7 @@ class Main: | ||||
|                     f"port={self.args.port}", | ||||
|                     "-d", | ||||
|                     filename, | ||||
|                     "0x1FFF7000", | ||||
|                     f"{address}", | ||||
|                 ] | ||||
|             ) | ||||
|             assert output | ||||
| @ -155,7 +236,6 @@ class Main: | ||||
|                 f"port={self.args.port}", | ||||
|             ] | ||||
|         ) | ||||
|         os.remove(filename) | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 あく
						あく