mirror of
				https://github.com/espressif/esp-idf.git
				synced 2025-11-04 00:51:42 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			171 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			171 lines
		
	
	
		
			7.3 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.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.sector_size
 | 
						|
        return root_dir_start
 |