mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-10-31 04:59:55 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			172 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			172 lines
		
	
	
		
			7.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
 | |
| # SPDX-License-Identifier: Apache-2.0
 | |
| 
 | |
| from textwrap import dedent
 | |
| from typing import Optional
 | |
| 
 | |
| from .exceptions import InconsistentFATAttributes
 | |
| from .utils import (ALLOWED_SECTOR_SIZES, FAT12, FAT12_MAX_CLUSTERS, FAT16, FAT16_MAX_CLUSTERS,
 | |
|                     RESERVED_CLUSTERS_COUNT, FATDefaults, get_fat_sectors_count, get_fatfs_type,
 | |
|                     get_non_data_sectors_cnt, number_of_clusters)
 | |
| 
 | |
| 
 | |
| class FATFSState:
 | |
|     """
 | |
|     The class represents the state and the configuration of the FATFS.
 | |
|     """
 | |
| 
 | |
|     def __init__(self,
 | |
|                  sector_size: int,
 | |
|                  reserved_sectors_cnt: int,
 | |
|                  root_dir_sectors_cnt: int,
 | |
|                  size: int,
 | |
|                  media_type: int,
 | |
|                  sectors_per_cluster: int,
 | |
|                  volume_label: str,
 | |
|                  oem_name: str,
 | |
|                  fat_tables_cnt: int,
 | |
|                  sec_per_track: int,
 | |
|                  num_heads: int,
 | |
|                  hidden_sectors: int,
 | |
|                  file_sys_type: str,
 | |
|                  use_default_datetime: bool,
 | |
|                  explicit_fat_type: Optional[int] = None,
 | |
|                  long_names_enabled: bool = False):
 | |
|         self.boot_sector_state = BootSectorState(oem_name=oem_name,
 | |
|                                                  sector_size=sector_size,
 | |
|                                                  sectors_per_cluster=sectors_per_cluster,
 | |
|                                                  reserved_sectors_cnt=reserved_sectors_cnt,
 | |
|                                                  fat_tables_cnt=fat_tables_cnt,
 | |
|                                                  root_dir_sectors_cnt=root_dir_sectors_cnt,
 | |
|                                                  sectors_count=size // sector_size,
 | |
|                                                  media_type=media_type,
 | |
|                                                  sec_per_track=sec_per_track,
 | |
|                                                  num_heads=num_heads,
 | |
|                                                  hidden_sectors=hidden_sectors,
 | |
|                                                  volume_label=volume_label,
 | |
|                                                  file_sys_type=file_sys_type,
 | |
|                                                  volume_uuid=-1)
 | |
| 
 | |
|         self._explicit_fat_type: Optional[int] = explicit_fat_type
 | |
|         self.long_names_enabled: bool = long_names_enabled
 | |
|         self.use_default_datetime: bool = use_default_datetime
 | |
| 
 | |
|         if (size // sector_size) * sectors_per_cluster in (FAT12_MAX_CLUSTERS, FAT16_MAX_CLUSTERS):
 | |
|             print('WARNING: It is not recommended to create FATFS with bounding '
 | |
|                   f'count of clusters: {FAT12_MAX_CLUSTERS} or {FAT16_MAX_CLUSTERS}')
 | |
|         self.check_fat_type()
 | |
| 
 | |
|     @property
 | |
|     def binary_image(self) -> bytearray:
 | |
|         return self.boot_sector_state.binary_image
 | |
| 
 | |
|     @binary_image.setter
 | |
|     def binary_image(self, value: bytearray) -> None:
 | |
|         self.boot_sector_state.binary_image = value
 | |
| 
 | |
|     def check_fat_type(self) -> None:
 | |
|         _type = self.boot_sector_state.fatfs_type
 | |
|         if self._explicit_fat_type is not None and self._explicit_fat_type != _type:
 | |
|             raise InconsistentFATAttributes(dedent(
 | |
|                 f"""FAT type you specified is inconsistent with other attributes of the system.
 | |
|                     The specified FATFS type: FAT{self._explicit_fat_type}
 | |
|                     The actual FATFS type: FAT{_type}"""))
 | |
|         if _type not in (FAT12, FAT16):
 | |
|             raise NotImplementedError('FAT32 is currently not supported.')
 | |
| 
 | |
| 
 | |
| class BootSectorState:
 | |
|     # pylint: disable=too-many-instance-attributes
 | |
|     def __init__(self,
 | |
|                  oem_name: str,
 | |
|                  sector_size: int,
 | |
|                  sectors_per_cluster: int,
 | |
|                  reserved_sectors_cnt: int,
 | |
|                  fat_tables_cnt: int,
 | |
|                  root_dir_sectors_cnt: int,
 | |
|                  sectors_count: int,
 | |
|                  media_type: int,
 | |
|                  sec_per_track: int,
 | |
|                  num_heads: int,
 | |
|                  hidden_sectors: int,
 | |
|                  volume_label: str,
 | |
|                  file_sys_type: str,
 | |
|                  volume_uuid: int = -1) -> None:
 | |
|         self.oem_name: str = oem_name
 | |
|         self.sector_size: int = sector_size
 | |
|         assert self.sector_size in ALLOWED_SECTOR_SIZES
 | |
|         self.sectors_per_cluster: int = sectors_per_cluster
 | |
|         self.reserved_sectors_cnt: int = reserved_sectors_cnt
 | |
|         self.fat_tables_cnt: int = fat_tables_cnt
 | |
|         self.root_dir_sectors_cnt: int = root_dir_sectors_cnt
 | |
|         self.sectors_count: int = sectors_count
 | |
|         self.media_type: int = media_type
 | |
|         self.sectors_per_fat_cnt = get_fat_sectors_count(self.size // self.sector_size, self.sector_size)
 | |
|         self.sec_per_track: int = sec_per_track
 | |
|         self.num_heads: int = num_heads
 | |
|         self.hidden_sectors: int = hidden_sectors
 | |
|         self.volume_label: str = volume_label
 | |
|         self.file_sys_type: str = file_sys_type
 | |
|         self.volume_uuid: int = volume_uuid
 | |
|         self._binary_image: bytearray = bytearray(b'')
 | |
| 
 | |
|     @property
 | |
|     def binary_image(self) -> bytearray:
 | |
|         return self._binary_image
 | |
| 
 | |
|     @binary_image.setter
 | |
|     def binary_image(self, value: bytearray) -> None:
 | |
|         self._binary_image = value
 | |
| 
 | |
|     @property
 | |
|     def size(self) -> int:
 | |
|         return self.sector_size * self.sectors_count
 | |
| 
 | |
|     @property
 | |
|     def data_region_start(self) -> int:
 | |
|         return self.non_data_sectors * self.sector_size
 | |
| 
 | |
|     @property
 | |
|     def fatfs_type(self) -> int:
 | |
|         # variable typed_fatfs_type must be explicitly typed to avoid mypy error
 | |
|         typed_fatfs_type: int = get_fatfs_type(self.clusters)
 | |
|         return typed_fatfs_type
 | |
| 
 | |
|     @property
 | |
|     def clusters(self) -> int:
 | |
|         """
 | |
|         The actual number of clusters is calculated by `number_of_clusters`,
 | |
|         however, the initial two blocks of FAT are reserved (device type and root directory),
 | |
|         despite they don't refer to the data region.
 | |
|         Since that, two clusters are added to use the full potential of the FAT file system partition.
 | |
|         """
 | |
|         clusters_cnt_: int = number_of_clusters(self.data_sectors, self.sectors_per_cluster) + RESERVED_CLUSTERS_COUNT
 | |
|         return clusters_cnt_
 | |
| 
 | |
|     @property
 | |
|     def data_sectors(self) -> int:
 | |
|         # self.sector_size is checked in constructor if has one of allowed values (ALLOWED_SECTOR_SIZES)
 | |
|         return (self.size // self.sector_size) - self.non_data_sectors
 | |
| 
 | |
|     @property
 | |
|     def non_data_sectors(self) -> int:
 | |
|         non_data_sectors_: int = get_non_data_sectors_cnt(self.reserved_sectors_cnt,
 | |
|                                                           self.sectors_per_fat_cnt,
 | |
|                                                           self.fat_tables_cnt,
 | |
|                                                           self.root_dir_sectors_cnt)
 | |
|         return non_data_sectors_
 | |
| 
 | |
|     @property
 | |
|     def fat_table_start_address(self) -> int:
 | |
|         return self.sector_size * self.reserved_sectors_cnt
 | |
| 
 | |
|     @property
 | |
|     def entries_root_count(self) -> int:
 | |
|         entries_root_count_: int = (self.root_dir_sectors_cnt * self.sector_size) // FATDefaults.ENTRY_SIZE
 | |
|         return entries_root_count_
 | |
| 
 | |
|     @property
 | |
|     def root_directory_start(self) -> int:
 | |
|         root_dir_start: int = (self.reserved_sectors_cnt + self.sectors_per_fat_cnt * self.fat_tables_cnt) * self.sector_size
 | |
|         return root_dir_start
 | 
