コード例 #1
0
ファイル: devices.py プロジェクト: gotnone/hwa
 def start_application(self):
     self.resume()
     self.ncmds += 1
     s = bytearray(b'X')
     s.extend(CRC.check(b'X').to_bytes(2, byteorder='big'))
     self.link.tx(s)  # execute would read more than 1 byte
     r = self.link.rx(1)
     return r[0] == 0
コード例 #2
0
ファイル: devices.py プロジェクト: duparq/hwa
 def write_eeprom(self, address, data):
     if len(data)==0 or len(data)>255:
         die()
     ah = (address >>  8) & 0xFF
     al = address & 0xFF
     s = 'E'+chr(al)+chr(ah)+chr(len(data))+data
     crc = CRC.check(s)
     s += struct.pack('>H', crc)
     self.execute(s, 1, timeout=0.1)
コード例 #3
0
 def write_eeprom(self, address, data):
     if len(data) == 0 or len(data) > 255:
         die()
     ah = (address >> 8) & 0xFF
     al = address & 0xFF
     s = 'E' + chr(al) + chr(ah) + chr(len(data)) + data
     crc = CRC.check(s)
     s += struct.pack('>H', crc)
     self.execute(s, 1, timeout=0.1)
コード例 #4
0
ファイル: devices.py プロジェクト: gotnone/hwa
 def write_eeprom(self, address, data):
     if len(data) == 0 or len(data) > 255:
         die()
     s = bytearray(b'E')
     s.extend(address.to_bytes(2, byteorder='little'))
     s.append(len(data))
     s.extend(data)
     s.extend(CRC.check(s).to_bytes(2, byteorder='big'))
     self.execute(s, 1, timeout=0.1)
コード例 #5
0
ファイル: devices.py プロジェクト: duparq/hwa
    def appstat(self, data):
        """
        Compute length of application code and CRC.

        The CRC is computed from the end to the beginning of the memory, skipping
        the 0xFF bytes at the end.

        For devices without boot section the first two bytes of reset vector
        (rjmp to Diabolo) are not computed.

        """
        crc = CRC.init()
        if not self.bootsection:
            end = 1
        else:
            end = -1

        top = min( len(data), self.bladdr )-1
        for x in range(top, end, -1):
            if data[x] != '\xFF':
                break
        for i in range(x, end, -1):
            crc = CRC.add(crc, data[i])
        return x+1, crc
コード例 #6
0
    def appstat(self, data):
        """
        Compute length of application code and CRC.

        The CRC is computed from the end to the beginning of the memory, skipping
        the 0xFF bytes at the end.

        For devices without boot section the first two bytes of reset vector
        (rjmp to Diabolo) are not computed.

        """
        crc = CRC.init()
        if not self.bootsection:
            end = 1
        else:
            end = -1

        top = min(len(data), self.bladdr) - 1
        for x in range(top, end, -1):
            if data[x] != '\xFF':
                break
        for i in range(x, end, -1):
            crc = CRC.add(crc, data[i])
        return x + 1, crc
コード例 #7
0
    def write_flash_page(self, address, data):
        if address >= self.bladdr:
            return 'A'

        if address % self.pagesize != 0:
            return 'A'

        if len(data) != self.pagesize:
            dbg(
                _('got %d bytes of data for flash page write, expected %d' %
                  (len(data), self.pagesize)))
            return 'L'

        #  Do not write a page known to be left unchanged
        #
        # if self.flash and self.flash[address:address+self.pagesize] == data:
        #     return '-'

        ah = (address >> 8) & 0xFF
        al = address & 0xFF
        s = 'F' + chr(al) + chr(ah) + data
        crc = CRC.check(s)
        s += struct.pack('>H', crc)
        x = ord(self.execute(s, 1 + 1, 1, timeout=0.1)[0])
        if x & 0xF0 == 0:
            #
            #  No error, update the known content of the flash
            #
            # if self.flash:
            #     self.flash = self.flash[:address] \
            #         + data \
            #         + self.flash[address+self.pagesize:]
            #
            #  Return a code of what has been done
            #
            self.flash_changed = True
            if x == 0x01:
                return '*'  # Erased
            if x == 0x02:
                return 'w'  # Programmed
            if x == 0x03:
                return 'W'  # Erased + Programmed
        #trace("\nError code: %02X in programming flash page at 0x%04X" % (x,address))
        if x == 0x80:
            return 'C'  # CRC error
        if x & 0x10:
            return '!'  # Programming failed
        return '<%02X>' % x  # Unknown error
コード例 #8
0
ファイル: devices.py プロジェクト: duparq/hwa
    def write_flash_page(self, address, data):
        if address >= self.bladdr:
            return 'A'

        if address % self.pagesize != 0:
            return 'A'

        if len(data) != self.pagesize:
            dbg(_('got %d bytes of data for flash page write, expected %d' %
                  (len(data), self.pagesize)))
            return 'L'

        #  Do not write a page known to be left unchanged
        #
        # if self.flash and self.flash[address:address+self.pagesize] == data:
        #     return '-'

        ah = (address >>  8) & 0xFF
        al = address & 0xFF
        s = 'F'+chr(al)+chr(ah)+data
        crc = CRC.check(s)
        s += struct.pack('>H', crc)
        x = ord(self.execute(s, 1+1, 1, timeout=0.1)[0])
        if x & 0xF0 == 0:
            #
            #  No error, update the known content of the flash
            #
            # if self.flash:
            #     self.flash = self.flash[:address] \
            #         + data \
            #         + self.flash[address+self.pagesize:]
            #
            #  Return a code of what has been done
            #
            self.flash_changed = True
            if x == 0x01:
                return '*'	# Erased
            if x == 0x02:
                return 'w'	# Programmed
            if x == 0x03:
                return 'W'	# Erased + Programmed
        #trace("\nError code: %02X in programming flash page at 0x%04X" % (x,address))
        if x == 0x80:
            return 'C'		# CRC error
        if x & 0x10:
            return '!'		# Programming failed
        return '<%02X>' % x	# Unknown error
コード例 #9
0
ファイル: devices.py プロジェクト: duparq/hwa
 def start_application(self):
     self.resume()
     self.ncmds += 1
     self.link.tx('X'+struct.pack('>H', CRC.check('X')))
     self.link.rx(1)
     return self.link.lastchar == '\0'
コード例 #10
0
ファイル: devices.py プロジェクト: duparq/hwa
    def execute ( self, cmdstr, rlen, repeats=4, **kwargs ):
        """
        Send a command, wait for rlen reply bytes.
        If rlen > 2, check the CRC of the reply.
        Return the reply without the CRC nor the prompt.

        A void reply for the 'write_flash_page' command can mean that the
        inter-char delay is not sufficient and the device has not enough time to
        compute the CRC.

        Repeated CRC errors can mean that the device estimated the baudrate not
        accurately enough.
        """
        dbg("EXECUTE(%s,%d,%d,%s)\n" % (s2hex(cmdstr), rlen, repeats, repr(kwargs)))
        built = None
        crcerrors = 0
        for repeat in range(repeats):
            # if repeat>0:
            #     trace()
            self.resume()
            self.link.lastchar = ""
            dbg("EXECUTE: tx(%s) -> " % (s2hex(cmdstr)))
            self.link.tx(cmdstr)
            self.ncmds += 1
            if rlen == 0:
                return None

            if kwargs.has_key('timeout'):
                #
                #  Wait for a reply until timeout
                #
                r=""
                t=timer()+kwargs['timeout']
                while len(r) < rlen and timer() < t:
                    c=self.link.rx(1)
                    if c:
                        t=timer()+kwargs['timeout']
                        r += c
                #     if r!= "":
                #         break
                # if r=="":
                #     for i in range(256):
                #         self.com.tx('\n')
                #         c = self.com.rx(1)
                #         if c=='!':
                #             dbg("Sent %d \\n\n" % (i+1))
                #             break
                #     # raise Exception("\nCOMMAND FAIL: [%s] -> [%s]\n" % (s2hex(cmdstr), s2hex(r)))
                # else:
                #     # r += self.com.rx(rlen-1)
                #     prev=timer()
                #     while len(r)<rlen and timer() < t:
                #         r += self.com.rx(1)
                #         last=timer()
                #         if last-prev > 0.001:
                #             trace()
                #         prev=last
                        
            else:
                r = self.link.rx(rlen)

            if r:
                dbg("%s\n" % s2hex(r))
            else:
                dbg("no reply\n")

            if self.link.lastchar != '#':
                dbg("  COMMAND FAILED\n")
                self.ncmdfails += 1
                continue

            r = r[:-1]
            if rlen <= 2:
                return r
            else:
                crc = CRC.check(cmdstr+r)
                if crc == 0:
                    if built:
                        dbg("\nBUILT REPLY:  %s:" % s2hex(built))
                        for i in range(rlen-1):
                            if built[i] != r[i]:
                                dbg(" #%d" % i)
                        dbg("\nGOOD REPLY:   %s\n\n" % s2hex(r))
                    return r[:-2]
                dbg("  CRC ERROR: 0x%04X\n" % crc)
                #
                #  CRC error, try to correct it.
                #
                #  Bytes are transfered least significant bit
                #  first. Inaccurate synchronization of the device can lead
                #  to the last transmitted bit (msb) of bytes to be
                #  defective:
                #
                #   * If the device estimated the baudrate a little too
                #     high, the host can sample the stop bit (1) instead of
                #     the msb. This leads to an error only if the original
                #     msb is 0, then it is corrected by setting the msb back
                #     to 0. Only bytes whose received msb is high are
                #     concerned.
                #
                #   * If the device estimated the baudrate a little too low,
                #     the host can sample bit b6 instead of the msb. This
                #     leads to an error only if the original b6 and b7 (msb)
                #     are different, then it is corrected by setting b7 to
                #     the opposite of b6.
                #

                crcerrors += 1
                self.ncrcerrors += 1

                if len(r) != rlen-1:
                    # dbg("  BAD REPLY #%d: %s\n" % (repeat,s2hex(r)))
                    continue

                if not built:
                    #
                    #  Display a rule to make finding bytes easier
                    #
                    dbg("\n             ")
                    for i in range(rlen-1):
                        dbg(" %02d" % i)
                dbg("  BAD REPLY #%d: %s\n" % (repeat,s2hex(r)))

                updated = False
                if not built:
                    built = r
                    updated = True
                else:
                    #
                    #  Try to build the correct frame with bytes whose b7,b6
                    #  bits are different
                    #
                    positions=[]
                    for p in range(rlen-1):
                        if ( (ord(built[p]) & 0xC0) == 0xC0
                             or (ord(built[p]) & 0xC0) == 0x00 )\
                            and ord(r[p]) != ord(built[p]):

                            positions.append(p)
                            built = built[:p] + r[p] + built[p+1:]
                            dbg(" #%d" % p)
                            updated = True
                    if updated:
                        # dbg("\nUPDATED BYTES:")
                        # for p in positions:
                        #     dbg(" #%d" % p)
                        if CRC.check(cmdstr+built) == 0:
                            dbg("\nFRAME FULLY CORRECTED\n\n")
                            return built[:-2]
                        dbg("\n")

                #  Device a little too low?
                #  Try setting b7 to the opposite of b6
                #
                if updated:
                    for p in range(rlen-1):
                        old = ord(built[p])
                        if (old & 0xC0) == 0x00 or (old & 0xC0) == 0xC0:
                            new = old ^ 0x80
                            x = built[:p] + chr(new) + built[p+1:]
                            crc = CRC.check(cmdstr+x)
                            if crc == 0:
                                dbg("\nbyte #%d has been corrected "
                                    "from %02X to %02X\n" % (p,old,new))
                                return x[:-2]

        # s = "\nCOMMAND [%s] FAILED." % s2hex(cmdstr)
        if len(cmdstr) > 8:
            s = "\nCOMMAND [%s ... %s] (%d bytes) FAILED." \
                % (s2hex(cmdstr[:4]), s2hex(cmdstr[-2:]), len(cmdstr))
        else:
            s = "\nCOMMAND [%s] FAILED." % s2hex(cmdstr)
        if crcerrors > 3:
            s += _("\nMany CRC unrecoverable errors detected. Your baudrate setting (%d) "\
                   "may be too high for the device.\n" % self.link.serial.baudrate)
        die(s)
コード例 #11
0
ファイル: diabolo.py プロジェクト: z13z4ck/hwa
            else:  # protocol 5
                l = 256
            data = '\xFF' * self.device.bladdr
            # data = '\xFF'*l
            for a in range(self.device.bladdr, self.device.flashsize, l):
                p = self.device.read_flash_page(a)
                if p == None:
                    cerr(_("\nRead page failed at 0x%04X.\n" % a))
                    return False
                cout('.')
                flushout()
                data += p

            #  Compute the CRC
            #
            crc = CRC.init()
            i = len(data) - 1
            while i >= 0 and data[i] == '\xFF':
                i -= 1
            while i >= 0:
                crc = CRC.add(crc, data[i])
                i -= 1

            # x, crc = self.device.appstat(data)
            cout(
                _("\nRead %d bytes of firmware, CRC=0x%04X.\n" %
                  (len(data), crc)))
            return

        #  Read flash memory?
        #
コード例 #12
0
ファイル: diabolo.py プロジェクト: duparq/hwa
            else: # protocol 5
                l = 256
            data = '\xFF'*self.device.bladdr
            # data = '\xFF'*l
            for a in range(self.device.bladdr, self.device.flashsize, l):
                p = self.device.read_flash_page(a)
                if p == None:
                    cerr(_("\nRead page failed at 0x%04X.\n" % a))
                    return False
                cout('.')
                flushout()
                data += p

            #  Compute the CRC
            #
            crc = CRC.init()
            i = len(data)-1
            while i>=0 and data[i]=='\xFF':
                i -= 1
            while i>=0:
                crc = CRC.add(crc, data[i])
                i -= 1

            # x, crc = self.device.appstat(data)
            cout(_("\nRead %d bytes of firmware, CRC=0x%04X.\n"
                   % (len(data), crc)))
            return


        #  Read flash memory?
        #
コード例 #13
0
 def start_application(self):
     self.resume()
     self.ncmds += 1
     self.link.tx('X' + struct.pack('>H', CRC.check('X')))
     self.link.rx(1)
     return self.link.lastchar == '\0'
コード例 #14
0
    def execute(self, cmdstr, rlen, repeats=4, **kwargs):
        """
        Send a command, wait for rlen reply bytes.
        If rlen > 2, check the CRC of the reply.
        Return the reply without the CRC nor the prompt.

        A void reply for the 'write_flash_page' command can mean that the
        inter-char delay is not sufficient and the device has not enough time to
        compute the CRC.

        Repeated CRC errors can mean that the device estimated the baudrate not
        accurately enough.
        """
        dbg("EXECUTE(%s,%d,%d,%s)\n" %
            (s2hex(cmdstr), rlen, repeats, repr(kwargs)))
        built = None
        crcerrors = 0
        for repeat in range(repeats):
            # if repeat>0:
            #     trace()
            self.resume()
            self.link.lastchar = ""
            dbg("EXECUTE: tx(%s) -> " % (s2hex(cmdstr)))
            self.link.tx(cmdstr)
            self.ncmds += 1
            if rlen == 0:
                return None

            if kwargs.has_key('timeout'):
                #
                #  Wait for a reply until timeout
                #
                r = ""
                t = timer() + kwargs['timeout']
                while len(r) < rlen and timer() < t:
                    c = self.link.rx(1)
                    if c:
                        t = timer() + kwargs['timeout']
                        r += c
                #     if r!= "":
                #         break
                # if r=="":
                #     for i in range(256):
                #         self.com.tx('\n')
                #         c = self.com.rx(1)
                #         if c=='!':
                #             dbg("Sent %d \\n\n" % (i+1))
                #             break
                #     # raise Exception("\nCOMMAND FAIL: [%s] -> [%s]\n" % (s2hex(cmdstr), s2hex(r)))
                # else:
                #     # r += self.com.rx(rlen-1)
                #     prev=timer()
                #     while len(r)<rlen and timer() < t:
                #         r += self.com.rx(1)
                #         last=timer()
                #         if last-prev > 0.001:
                #             trace()
                #         prev=last

            else:
                r = self.link.rx(rlen)

            if r:
                dbg("%s\n" % s2hex(r))
            else:
                dbg("no reply\n")

            if self.link.lastchar != '#':
                dbg("  COMMAND FAILED\n")
                self.ncmdfails += 1
                continue

            r = r[:-1]
            if rlen <= 2:
                return r
            else:
                crc = CRC.check(cmdstr + r)
                if crc == 0:
                    if built:
                        dbg("\nBUILT REPLY:  %s:" % s2hex(built))
                        for i in range(rlen - 1):
                            if built[i] != r[i]:
                                dbg(" #%d" % i)
                        dbg("\nGOOD REPLY:   %s\n\n" % s2hex(r))
                    return r[:-2]
                dbg("  CRC ERROR: 0x%04X\n" % crc)
                #
                #  CRC error, try to correct it.
                #
                #  Bytes are transfered least significant bit
                #  first. Inaccurate synchronization of the device can lead
                #  to the last transmitted bit (msb) of bytes to be
                #  defective:
                #
                #   * If the device estimated the baudrate a little too
                #     high, the host can sample the stop bit (1) instead of
                #     the msb. This leads to an error only if the original
                #     msb is 0, then it is corrected by setting the msb back
                #     to 0. Only bytes whose received msb is high are
                #     concerned.
                #
                #   * If the device estimated the baudrate a little too low,
                #     the host can sample bit b6 instead of the msb. This
                #     leads to an error only if the original b6 and b7 (msb)
                #     are different, then it is corrected by setting b7 to
                #     the opposite of b6.
                #

                crcerrors += 1
                self.ncrcerrors += 1

                if len(r) != rlen - 1:
                    # dbg("  BAD REPLY #%d: %s\n" % (repeat,s2hex(r)))
                    continue

                if not built:
                    #
                    #  Display a rule to make finding bytes easier
                    #
                    dbg("\n             ")
                    for i in range(rlen - 1):
                        dbg(" %02d" % i)
                dbg("  BAD REPLY #%d: %s\n" % (repeat, s2hex(r)))

                updated = False
                if not built:
                    built = r
                    updated = True
                else:
                    #
                    #  Try to build the correct frame with bytes whose b7,b6
                    #  bits are different
                    #
                    positions = []
                    for p in range(rlen - 1):
                        if ( (ord(built[p]) & 0xC0) == 0xC0
                             or (ord(built[p]) & 0xC0) == 0x00 )\
                            and ord(r[p]) != ord(built[p]):

                            positions.append(p)
                            built = built[:p] + r[p] + built[p + 1:]
                            dbg(" #%d" % p)
                            updated = True
                    if updated:
                        # dbg("\nUPDATED BYTES:")
                        # for p in positions:
                        #     dbg(" #%d" % p)
                        if CRC.check(cmdstr + built) == 0:
                            dbg("\nFRAME FULLY CORRECTED\n\n")
                            return built[:-2]
                        dbg("\n")

                #  Device a little too low?
                #  Try setting b7 to the opposite of b6
                #
                if updated:
                    for p in range(rlen - 1):
                        old = ord(built[p])
                        if (old & 0xC0) == 0x00 or (old & 0xC0) == 0xC0:
                            new = old ^ 0x80
                            x = built[:p] + chr(new) + built[p + 1:]
                            crc = CRC.check(cmdstr + x)
                            if crc == 0:
                                dbg("\nbyte #%d has been corrected "
                                    "from %02X to %02X\n" % (p, old, new))
                                return x[:-2]

        # s = "\nCOMMAND [%s] FAILED." % s2hex(cmdstr)
        if len(cmdstr) > 8:
            s = "\nCOMMAND [%s ... %s] (%d bytes) FAILED." \
                % (s2hex(cmdstr[:4]), s2hex(cmdstr[-2:]), len(cmdstr))
        else:
            s = "\nCOMMAND [%s] FAILED." % s2hex(cmdstr)
        if crcerrors > 3:
            s += _("\nMany CRC unrecoverable errors detected. Your baudrate setting (%d) "\
                   "may be too high for the device.\n" % self.link.serial.baudrate)
        die(s)
コード例 #15
0
    def run(self):
        flash = None  # Data to burn into flash

        start_time = timer()

        #  Compute a CRC?
        #
        if self.options.stat or self.options.crc or self.options.size:
            if not self.options.filename:
                die(_("Input file is required for CRC computation.\n"))
            if not self.options.mcu:
                die(_("Target device is required for CRC computation.\n"))

            try:
                self.device = devices.devices[self.options.mcu.lower()]()
            except:
                die(_("\"%s\": no such device.\n" % self.options.mcu.lower()))

            data = self.read_file(self.options.filename)
            x, crc = self.device.appstat(data)
            if self.options.stat:
                #
                #  Use sys.stdout.write instead of cout to bypass '--quiet'
                #
                sys.stdout.write(
                    _("%s: %d /%d application bytes, CRC=0x%04X.\n" %
                      (self.options.filename, x, self.device.flashsize, crc)))
            elif self.options.crc:
                sys.stdout.write("%04X\n" % crc)
            else:
                sys.stdout.write("%d\n" % x)
            return

        #  Compute a CRC32?
        #
        if self.options.crc32:
            if not self.options.filename:
                die(_("Input file is required for CRC32 computation.\n"))

            import binascii
            s = open(self.options.filename, 'rb').read()
            crc32 = binascii.crc32(s)
            sys.stdout.write("%08x\n" % (crc32 & 0xFFFFFFFF))
            return

        #  List available ttys?
        #
        if self.options.tty == "list":
            ttys = link.list()
            cout(_("Available ttys:\n" + str(ttys)))
            return

        #  Open the communication channel
        #
        try:
            self.link = link.get(self.options)
        except link.serial.SerialException as e:
            die(str(e))

        #  Reset the device connected to the serial interface
        #
        self.link.set_TXD(0)
        self.link.set_RESET(0)

        if self.options.reset_length:
            time.sleep(self.options.reset_length)

        self.link.set_RESET(1)

        #  Just reset the device and quit?
        #
        if self.options.reset_and_exit:
            return

        if self.options.keep_txd_low == 0:
            cout(
                "WARNING: target will probably not remain in Diabolo if TXD is not "
                "maintained low long enough!\n")
        else:
            time.sleep(self.options.keep_txd_low)

        self.link.set_TXD(1)

        #  This is the best moment for detecting how many wires are used for the
        #  serial communication since the target device is supposed to be
        #  waiting in Diabolo for the synchronization.
        #
        #  It is safe to send data on the serial line now even if the RESET
        #  signal is used to drive the power supply (sending data while the
        #  device is not powered could cause troubles).
        #
        self.link.detect_wires(b'?')
        cout(_("Tty wires: %d\n") % self.link.wires)

        #  We can now send synchronization sequences
        #
        if not self.link.sync():
            die(_("Synchronization failed.\n"))

        #  Identify device
        #
        self.device = devices.get_device(self.link)
        cout(_("Connected to device (protocol %d):\n" % self.device.protocol))
        cout(
            self.device.str(self.options.show_fuses,
                            self.options.decode_fuses))

        #  Check target name
        #
        if self.options.mcu and self.device.name.lower(
        ) != self.options.mcu.lower():
            die(
                _("Target mismatch: connected to %s, %s expected.\n" %
                  (self.device.name, self.options.mcu)))

        #  Compute the CRC of the firmware?
        #
        if self.options.fwcrc:
            cout("\nReading firmware flash: ")
            data = bytearray()
            if self.device.protocol == 4:
                step = self.device.pagesize
            else:  # protocol 5
                step = 256
            for a in range(self.device.bladdr, self.device.flashsize, step):
                page = self.device.read_flash_page(a)
                if page == None:
                    cerr(_("\nRead page failed at 0x%04X.\n" % a))
                    return False
                cout('.')
                flushout()
                data.extend(page)

            #  Compute the CRC
            #
            crc = CRC.init()
            i = len(data) - 1
            while i >= 0 and data[i] == 0xFF:
                i -= 1
            while i >= 0:
                crc = CRC.add(crc, data[i])
                i -= 1

            # x, crc = self.device.appstat(data)
            cout(
                _("\nRead %d bytes of firmware, CRC=0x%04X.\n" %
                  (len(data), crc)))
            return

        #  Read flash memory?
        #
        if self.options.read_flash:
            data = self.read_flash()
            if self.options.hexdump:
                cout(hexdump(0, data) + "\n")
            if self.options.cache:
                self.write_file(self.options.cache, data)
            #return

        #  Read eeprom memory?
        #
        if self.options.read_eeprom:
            data = self.read_eeprom()
            if self.options.hexdump:
                cout(hexdump(0, data) + "\n")
            if self.options.cache:
                self.write_file(self.options.cache, data)
            #return

        #  Erase flash memory?
        #
        if self.options.clear_flash:
            flash = bytearray.fromhex('FF' * self.device.flashsize)

        #  Write flash memory?
        #
        if self.options.burn_flash:
            if not self.options.filename:
                die(_("Input file is required to program flash memory.\n"))
            cache = None
            if self.options.cache:
                if os.path.isfile(self.options.cache):
                    cache = self.read_file(self.options.cache)
                    if len(cache) < self.device.bladdr:
                        cout(_("Wrong cache size. Dropping cache data.\n"))
                        cache = None
                    else:
                        x, cache_crc = self.device.appstat(cache)
                        if self.device.appcrc != cache_crc:
                            cout(_("Cache CRC (%04X) does not match device CRC. "\
                                   "Dropping cache data.\n" % cache_crc))
                            cache = None
                else:
                    cout(
                        _("Cache file does not exist yet, reading flash"
                          " memory is required.\n"))
            if cache == None:
                cache = self.read_flash()
                if self.options.cache:
                    self.write_file(self.options.cache, cache)

            x, cache_crc = self.device.appstat(cache)
            flash = self.read_file(self.options.filename)
            if len(flash) < self.device.bladdr:
                cout(_("Padding data with 0xFF bytes\n"))
                flash.extend(
                    bytes.fromhex('FF' * (self.device.bladdr - len(flash))))

        #  Program flash memory
        #
        if flash:
            #
            #  Override RESET vector for device without bootsection
            #    RJMP opcode: 1111 aaaa aaaa aaaa = 0xC000 + Addr
            #
            if not self.device.bootsection:
                addr = int(self.device.bladdr / 2) - 1
                if addr > 0x0FFF:
                    die(_("Can not set RESET vector opcode.\n"))
                opcode = 0xC000 + addr
                byte0 = opcode & 0xFF
                byte1 = opcode >> 8
                cout(
                    _("Device without bootsection, "
                      "setting RESET vector to computed opcode: %02x %02x\n") %
                    (byte0, byte1))
                #flash = opcode.to_bytes(2,byteorder="little")+flash[2:]
                flash[0] = byte0
                flash[1] = byte1

            x, flash_crc = self.device.appstat(flash)
            if flash_crc == cache_crc:
                cout(
                    _("Cache and data CRC match, nothing to program in Flash memory.\n"
                      ))
                if self.device.eeappcrc != flash_crc:
                    self.device.write_eeprom_appcrc(flash_crc)
                    check = self.device.read_eeprom_appcrc()
                    if check == flash_crc:
                        cout(
                            _("Updated application CRC in EEPROM: 0x%04X\n" %
                              flash_crc))
                    else:
                        raise Exception(_("update of application CRC in EEPROM failed: %04X!=%04X" %\
                                (check, flash_crc)) )
                    x_restart = True
            else:
                self.write_flash(flash, cache)

            x_restart = False
            if self.device.flash_changed:
                # trace()
                self.device.pgmcount += 1
                self.device.write_eeprom_pgmcount(self.device.pgmcount)
                check = self.device.read_eeprom_pgmcount()
                if check == self.device.pgmcount:
                    cout(_("Set program count to %d\n" % self.device.pgmcount))
                else:
                    cout(
                        _("Failed to set program count to %d (read %d)." %
                          (self.device.pgmcount, check)))
                x_restart = True

            if self.device.eeappcrc != flash_crc:
                # trace()
                self.device.write_eeprom_appcrc(flash_crc)
                cout(
                    _("Stored application CRC in EEPROM: 0x%04X\n" %
                      flash_crc))
                x_restart = True

            if x_restart:
                # trace()
                #cout(_("Reset device's Diabolo\n"))
                self.device.resume()
                self.link.tx(
                    b'*')  # Send a bad command to force CRC re-computation
                #
                #  Wait up to 1 s for CRC computation (~50 cycles/byte)
                #
                t = timer() + 1.0
                while timer() < t and not self.link.rx(1):
                    pass
                if timer() >= t:
                    raise Exception("timeout waiting CRC recomputation")
                if self.link.lastchar != ord('!'):
                    raise Exception(
                        "unexpected reply (0x%02X) to '*' command" % ord(c))
                self.link.tx(b'\n')  # Resume
                self.link.rx(1)
                self.device = self.device.identify()
                cout("  Application CRC:\n")
                cout(_("    computed: 0x%04X\n" % self.device.appcrc))
                cout(_("      EEPROM: 0x%04X\n" % self.device.eeappcrc))
                cout(_("  Programmings: %d\n" % self.device.pgmcount))

            #  Update flash cache
            #
            if self.options.cache:
                # trace()
                self.write_file(self.options.cache, flash)

        #  Start application
        #
        if self.device.appcrc == self.device.eeappcrc \
           and self.device.appcrc != 0xFFFF:
            if self.device.start_application():
                cout("Target started its application.\n")
            else:
                cout("ERROR: target did not start its application.\n")

        self.link.close()

        if self.options.diag:
            cout(
                _("%d commands, %d fails, %d resumes, %d crc errors, total time: %.1f s.\n"
                  % (self.device.ncmds, self.device.ncmdfails,
                     self.device.nresumes, self.device.ncrcerrors,
                     timer() - start_time + 0.05)))