示例#1
0
文件: helpers.py 项目: minkione/Yand
 def _ParseHeader(self):
     self.header_length = 0
     magic = self.file.read(3)
     if magic != b'P5\x0a':
         raise errors.YandException(
             'Input file {0:s} is not a PGM picture (bad magic \'{1!s}\')'.
             format(self.filepath, magic))
     self.header_length += 3
     comment = b''
     bb = self.file.read(1)
     self.header_length += 1
     while bb != b'\x0a':
         # Comment
         comment += bb
         bb = self.file.read(1)
         self.header_length += 1
     while self.file.read(1) == b'\x0a':
         self.header_length += 1
     self.file.seek(-1, SEEK_CUR)
     dimensions = b''
     bb = self.file.read(1)
     while bb != b'\x0a':
         dimensions += bb
         bb = self.file.read(1)
     self.header_length += len(dimensions) + 1
     self.width, self.height = [int(d) for d in dimensions.split(b' ')]
     if self.file.read(4) != b'255\x0a':
         raise errors.YandException(
             ('Input file {0:s} is not a PGM picture '
              '(should have 255 as max value)').format(self.filepath))
     self.header_length += 4
示例#2
0
    def Write(self, data, command=False, address=False):
        """Write a set of bytes to the device.

        Args:
            data(bytearray): the data to write.
            command(bool): if it is a command.
            address(bool): if it is an address.
        Raises:
            errors.YandException: if both command & address types are set.
        """
        cmd_type = 0
        if command and address:
            raise errors.YandException(
                'Can\'t set command and address latch simultaneously')
        if command:
            cmd_type |= 0x40
        elif address:
            cmd_type |= 0x80
        if not self.write_protect:
            cmd_type |= 0x20

        cmds = [ftdi.Ftdi.WRITE_EXTENDED, cmd_type, 0, data[0]]
        for i in range(len(data) - 1):
            cmds += [ftdi.Ftdi.WRITE_SHORT, 0, data[i + 1]]
        self.ftdi.write_data(bytearray(cmds))
示例#3
0
    def WriteFileToFlash(self, filename, write_check=False):
        """Overwrite file to NAND Flash.

        Args:
            filename(str): path to the dump to write.
            write_check(bool): Whether to check every page written.
        Raises:
            errors.YandException: if filename has more data than the NAND Flash.
        """
        filesize = os.stat(filename).st_size
        if filesize > self.GetTotalSize():
            raise errors.YandException(
                'Input file is {0:d} bytes, more than the current NAND Flash size ({1:d})'.format(
                    filesize, self.GetTotalSize()))
        if filesize < self.GetTotalSize():
            self.logger.debug(
                'input file is {0:d}, less than the current NAND Flash size ({1:d})'.format(
                    filesize, self.GetTotalSize()))

        progress_bar = tqdm(
            total=self.GetTotalSize(),
            unit_scale=True,
            unit_divisor=1024,
            unit='B'
        )
        with open(filename, 'rb') as input_file:
            for page_number in range(self.GetTotalPages()):
                page_data = input_file.read(self.page_size)
                self.WritePage(page_number, page_data, write_check=write_check)
                progress_bar.update(self.page_size)
示例#4
0
    def DumpFlashToFile(self, destination, start_page=0, end_page=None):
        """Reads all pages from the flash, and writes it to a file.

        Args:
            destination(str): the destination file.
            start_page(int): Page to start dumping from.
            end_page(int): Page to stop dumping at. Default is to the end.
        Raises:
            errors.YandException: if no destination file is provided.
        """
        if not destination:
            raise errors.YandException('Please specify where to write')

        if not end_page:
            end_page = self.GetTotalPages()

        if destination == "-":
            for page in range(start_page, end_page):
                sys.stdout.buffer.write(self.ReadPage(page))
        else:
            progress_bar = tqdm(
                total=(end_page - start_page) * self.page_size,
                unit_scale=True,
                unit_divisor=1024,
                unit='B'
            )
            with open(destination, 'wb') as dest_file:
                for page in range(start_page, end_page):
                    dest_file.write(self.ReadPage(page))
                    progress_bar.update(self.page_size)
示例#5
0
    def _SetupFlash(self):
        """Setup the flash configuration."""

        # First we check if we can gather information form ONFI
        self.SendCommand(self.NAND_CMD_READID)
        self.SendAddress(self.NAND_ADDR_ONFI)
        onfi_result = self.ftdi_device.Read(4)

        if onfi_result == b'ONFI':
            self.SendCommand(self.NAND_CMD_READ_PARAM_PAGE)
            self.SendAddress(self.NAND_ADDR_ID)
            self.ftdi_device.WaitReady()
            onfi_data = self.ftdi_device.Read(self.NAND_SIZE_ONFI)
            self._ParseONFIData(onfi_data)
        else:
            if onfi_result.hex() == '00000000':
                raise errors.YandException(
                    'Flash returned "00000000" as self identification\n'
                    'It is either defective or not connected properly')
            raise errors.YandException(
                'Warning: Could not read ONFI info. Please provide geometry\n'
                'Flash returned "{0:s}"'.format(onfi_result.hex()))
示例#6
0
    def WaitReady(self):
        """Waits for the FTDI device to be ready.

        Raises:
            errors.YandException: if the device is not ready.
        """
        while 1:
            self.ftdi.write_data(bytearray([ftdi.Ftdi.GET_BITS_HIGH]))
            data = self.ftdi.read_data_bytes(1)
            if not data:
                data = self.ftdi.read_data_bytes(1)
                if not data:
                    raise errors.YandException(
                        'FTDI device not responding. Try restarting it.')
            if data[0] & 2 == 0x2:
                break
示例#7
0
    def Setup(self):
        """Sets up the FTDI device."""
        self.ftdi = ftdi.Ftdi()
        try:
            self.ftdi.open(self.DEFAULT_USB_VENDOR,
                           self.DEFAULT_USB_DEVICEID,
                           interface=self.DEFAULT_INTERFACE_NUMBER)
        except OSError:
            raise errors.YandException('Could not open FTDI device\n'
                                       'Check USB connections')

        self.ftdi.set_bitmode(0, ftdi.Ftdi.BITMODE_MCU)
        self.ftdi.write_data(bytearray([ftdi.Ftdi.DISABLE_CLK_DIV5]))
        self.ftdi.purge_buffers()
        self.ftdi.write_data(bytearray([ftdi.Ftdi.SET_BITS_HIGH, 0x0, 0x1]))
        self.WaitReady()
示例#8
0
    def _ParseONFIData(self, onfi_data):
        """Parses a ONFI data block."""
        # Check ONFI magic
        if onfi_data[0:4] != bytearray([0x4F, 0x4E, 0x46, 0x49]):
            raise errors.YandException('ONFI data block does not start with \'ONFI\'')

        # Parses ONFI version support
        _ = onfi_data[4:6]
        # Parses features support
        _ = onfi_data[6:8]
        # Parses optional commands support
        _ = onfi_data[8:10]

        # extended page parameter length
        _ = onfi_data[12:14]
        # Number of parameter pages
        _ = onfi_data[14]

        self.device_manufacturer = onfi_data[32:44].decode()
        self.device_model = onfi_data[44:64].decode()

        # 1 byte manufacturer ID
        self.manufacturer_id = onfi_data[64]

        # 'user data' bytes per page
        user_size = int.from_bytes(onfi_data[80:84], byteorder='little')
        # spare/OOB size per page
        self.oob_size = int.from_bytes(onfi_data[84:86], byteorder='little')
        self.page_size = user_size + self.oob_size

        self.pages_per_block = int.from_bytes(onfi_data[92:96], byteorder='little')

        # Number of blocks per LUN
        number_blocks_per_lun = int.from_bytes(onfi_data[96:100], byteorder='little')

        # Number of LUNs per chip enable
        number_lun_per_chip = onfi_data[100]
        self.number_of_blocks = number_blocks_per_lun * number_lun_per_chip

        address_cycles = onfi_data[101]
        self.address_cycles = (address_cycles & 0x0f) + ((address_cycles & 0xf0) >> 4)
示例#9
0
    def WritePage(self, page_number, data, write_check=False):
        """Writes a page to the NAND Flash

        Args:
            page_number(int): the number of the page.
            data(bytearray): the data to program.
            write_check(bool): Whether to check every page written by reading it.
        Raises:
            errors.YandException: if trying to write more data than a block length.
        """
        if not len(data) == self.page_size:
            raise errors.YandException(
                'Trying to write data that is different than page_size: {0:d} != {1:d}'.format(
                    len(data), self.page_size))
        self.ftdi_device.write_protect = False

        page_address = page_number << 16

        self.SendCommand(self.NAND_CMD_PROG_PAGE)
        # I've had good results when keeping just one "WaitReady" here.
        # Feel free to uncomment if your writes are not super clean
#        self.ftdi_device.WaitReady()
        self.SendAddress(page_address, self.address_cycles)
#        self.ftdi_device.WaitReady()
        self.ftdi_device.Write(data)
        self.SendCommand(self.NAND_CMD_PROG_PAGE_START)
        self.ftdi_device.WaitReady()
        self.CheckStatus()
        self.logger.debug('written page {0:d} (addr: {1:d})'.format(page_number, page_address))

        if write_check:
            data_read = self.ReadPage(page_number)
            diff = helpers.Diff(data, data_read)
            if diff != 0:
                self.logger.debug(
                    'data written & data read differ by {0:d} bytes at page {1:d}'.format(
                        diff, page_number))

        self.ftdi_device.write_protect = True
示例#10
0
    def Main(self):
        """Main function"""

        options = self.ParseArguments()

        if options.version:
            print('{0:s}: {1:s}'.format(__file__, __version__))
            sys.exit(0)

        if options.logfile:
            logging.basicConfig(
                filename=options.logfile,
                level=logging.DEBUG,
                format='%(asctime)s %(message)s',
                datefmt='[%Y-%m-%d %H:%M:%S]'
            )

        ftdi_nand = nand_interface.NandInterface()

        if not ftdi_nand:
            self.parser.print_help()
            raise errors.YandException('Need a source to read from')

        # Set up geometry
        if options.page_size:
            try:
                page_size, oob_size = [
                    int(opt) for opt in options.page_size.split(',')]
                ftdi_nand.oob_size = oob_size
                ftdi_nand.page_size = oob_size + page_size
            except ValueError as value_error:
                raise errors.YandException(
                    'Please specify page size as such : "user_data,oob". For example: "2048,128"'
                    ) from value_error
        if options.pages_per_block:
            ftdi_nand.pages_per_block = int(options.pages_per_block)
        if options.number_of_blocks:
            ftdi_nand.number_of_blocks = int(options.number_of_blocks)

        ftdi_nand.Setup()
        infos = 'Chip info: '+ftdi_nand.GetInfos()
        logging.debug(infos)

        if not options.file == '-':
            print(infos)

        if options.read:
            if not options.file:
                Die('Need a destination file (hint: -f)')
            if os.path.exists(options.file):
                if not Confirm(
                        'Destination file {0:s} already exists. Proceed?'.format(options.file),
                        options.yes):
                    Die()
            logging.debug(
                'Starting a read operation (start={0:d}, end={1:d}, destination={2:s})'.format(
                    options.start, options.end or -1, options.file))

            ftdi_nand.DumpFlashToFile(options.file, start_page=options.start, end_page=options.end)
        elif options.write:
            if not Confirm(
                    'Reminder: '
                    'You need to erase the entire flash with -e for this to work as expected\n\n'
                    'About to write the content of "{0:s}" to NAND Flash. Proceed?'.format(
                        options.file), options.yes):
                Die()
            logging.debug(
                'Starting an Dump write operation with file {0:s} (write check is {1!s})'.format(
                    options.file, options.write_check))
            ftdi_nand.WriteFileToFlash(options.file, write_check=options.write_check)
        elif options.erase:
            if not Confirm('About to erase NAND Flash blocks. Proceed?', options.yes):
                Die()
            logging.debug(
                'Starting an erase operation (start={0:d}, end={1:d})'.format(
                    options.start, options.end or -1))
            ftdi_nand.Erase(start_block=options.start, end_block=options.end)
        elif options.write_value is not None:
            if not Confirm(
                    'About to write value {0:d} in NAND Flash. Proceed?'.format(
                        options.write_value), options.yes):
                Die()
            logging.debug(
                'Starting a fill value operation '
                '(start={0:d}, end={1:d}, value={2:d}, write check is {3!s})'.format(
                    options.start, options.end or -1, options.write_value, options.write_check))
            ftdi_nand.FillWithValue(
                options.write_value, start_page=options.start, end_page=options.end,
                write_check=options.write_check)
        elif options.write_pgm:
            if not Confirm(
                    'About to write content of {0:s} in NAND Flash. Proceed?'.format(
                        options.file), options.yes):
                sys.exit(1)
            logging.debug(
                'Starting a write pgm operation '
                '(start={0:d}, end={1:d}, pgm_file={2:s}, write check is {3!s})'.format(
                    options.start, options.end or -1, options.file, options.write_check))
            ftdi_nand.WritePGMToFlash(
                options.file, start_page=options.start, end_page=options.end,
                write_check=options.write_check)