Exemple #1
0
    def _clone_out(self):
        start = time.time()

        status = chirp_common.Status()
        status.msg = _("Cloning to radio")
        status.max = self._memsize
        pos = 0
        for addr_from, addr_to, blocksize in self._blocks:
            for addr in range(addr_from, addr_to, blocksize):
                self._write(addr, self._mmap[pos:(pos + blocksize)])
                pos += blocksize
                status.cur = pos
                self.status_fn(status)

        LOG.info("Clone completed in %i seconds" % (time.time() - start))
Exemple #2
0
    def _upload(self, limit):
        if not self._detect_baudrate_and_identify():
            raise Exception("I can't talk to this model")

        for addr in range(0x200, self._memsize, 0x40):
            self._upload_chunk(addr)
            # Other Alinco drivers delay here, but doesn't seem to be necessary
            # for this model.

            if self.status_fn:
                status = chirp_common.Status()
                status.cur = addr
                status.max = self._memsize
                status.msg = "Uploading to radio"
                self.status_fn(status)
Exemple #3
0
def _chunk_write(pipe, data, status_fn, block):
    delay = 0.03
    count = 0
    for i in range(0, len(data), block):
        chunk = data[i:i + block]
        pipe.write(chunk)
        count += len(chunk)
        LOG.debug("@_chunk_write, count: %i, blocksize: %i" % (count, block))
        time.sleep(delay)

        status = chirp_common.Status()
        status.msg = "Cloning to radio"
        status.max = len(data)
        status.cur = count
        status_fn(status)
Exemple #4
0
def _clone_in(radio):
    data = ""

    radio.pipe.setTimeout(1)
    attempts = 30

    data = memmap.MemoryMap("\x00" * (radio._memsize + 128))
    length = 0
    last_addr = 0
    while length < radio._memsize:
        frame = radio.pipe.read(131)
        if length and not frame:
            raise errors.RadioError("Radio not responding")

        if not frame:
            attempts -= 1
            if attempts <= 0:
                raise errors.RadioError("Radio not responding")

        if frame:
            addr, = struct.unpack(">H", frame[0:2])
            checksum = ord(frame[130])
            block = frame[2:130]

            cs = 0
            for i in frame[:-1]:
                cs = (cs + ord(i)) % 256
            if cs != checksum:
                print "Calc: %02x Real: %02x Len: %i" % (cs, checksum,
                                                         len(block))
                raise errors.RadioError("Block failed checksum")

            radio.pipe.write("\x06")
            time.sleep(0.05)

            if os.getenv("CHIRP_DEBUG") and (last_addr + 128) != addr:
                print "Gap, expecting %04x, got %04x" % (last_addr + 128, addr)
            last_addr = addr
            data[addr] = block
            length += len(block)

        status = chirp_common.Status()
        status.cur = length
        status.max = radio._memsize
        status.msg = "Cloning from radio"
        radio.status_fn(status)

    return data
Exemple #5
0
def _upload(radio):
    """Upload procedure"""
    # put radio in program mode
    _ident_radio(radio)

    # identify radio
    radio_ident = _get_radio_firmware_version(radio)
    LOG.info("Radio firmware version:")
    LOG.debug(util.hexprint(radio_ident))
    # identify image
    image_ident = _get_image_firmware_version(radio)
    LOG.info("Image firmware version:")
    LOG.debug(util.hexprint(image_ident))

    if radio_ident != "0xFF" * 16 and image_ident == radio_ident:
        _ranges = radio._ranges
    else:
        _ranges = [(0x0000, 0x0DF0),
                   (0x0E00, 0x1800)]

    # UI progress
    status = chirp_common.Status()
    status.cur = 0
    status.max = radio._mem_size / radio._send_block_size
    status.msg = "Cloning to radio..."
    radio.status_fn(status)

    # the fun start here
    for start, end in _ranges:
        for addr in range(start, end, radio._send_block_size):
            # sending the data
            data = radio.get_mmap()[addr:addr + radio._send_block_size]

            frame = _make_frame("X", addr, radio._send_block_size, data)

            _rawsend(radio, frame)
            time.sleep(0.05)

            # receiving the response
            ack = _rawrecv(radio, 1)
            if ack != "\x06":
                msg = "Bad ack writing block 0x%04x" % addr
                raise errors.RadioError(msg)

            # UI Update
            status.cur = addr / radio._send_block_size
            status.msg = "Cloning to radio..."
            radio.status_fn(status)
Exemple #6
0
def _clone_from_radio(radio):
    md = get_model_data(radio)

    if md[0:4] != radio.get_model():
        LOG.info("This model: %s" % util.hexprint(md[0:4]))
        LOG.info("Supp model: %s" % util.hexprint(radio.get_model()))
        raise errors.RadioError("I can't talk to this model")

    if radio.is_hispeed():
        start_hispeed_clone(radio, CMD_CLONE_OUT)
    else:
        send_clone_frame(radio, CMD_CLONE_OUT, radio.get_model(), raw=True)

    LOG.debug("Sent clone frame")

    stream = RadioStream(radio.pipe)

    addr = 0
    _mmap = memmap.MemoryMap(chr(0x00) * radio.get_memsize())
    last_size = 0
    while True:
        frames = stream.get_frames()
        if not frames:
            break

        for frame in frames:
            if frame.cmd == CMD_CLONE_DAT:
                src, dst = process_data_frame(radio, frame, _mmap)
                if last_size != (dst - src):
                    LOG.debug("ICF Size change from %i to %i at %04x" %
                              (last_size, dst - src, src))
                    last_size = dst - src
                if addr != src:
                    LOG.debug("ICF GAP %04x - %04x" % (addr, src))
                addr = dst
            elif frame.cmd == CMD_CLONE_END:
                LOG.debug("End frame (%i):\n%s" %
                          (len(frame.payload), util.hexprint(frame.payload)))
                LOG.debug("Last addr: %04x" % addr)

        if radio.status_fn:
            status = chirp_common.Status()
            status.msg = "Cloning from radio"
            status.max = radio.get_memsize()
            status.cur = addr
            radio.status_fn(status)

    return _mmap
Exemple #7
0
 def _do_download(self):
     self._ip620_enter_programming_mode()
     _data = ""
     _status = chirp_common.Status()
     _status.msg = "Cloning from radio"
     _status.cur = 0
     _status.max = self._memsize
     for _addr in range(0, self._memsize, READ_BLOCK_SIZE):
         _status.cur = _addr + READ_BLOCK_SIZE
         self.status_fn(_status)
         _block = self._ip620_read_block(_addr)
         _data += _block
         LOG.debug("Address: %04x" % _addr)
         LOG.debug(util.hexprint(_block))
     self._ip620_exit_programming_mode()
     return memmap.MemoryMap(_data)
Exemple #8
0
def upload(radio):
    if command(radio.pipe, "0M PROGRAM") != "0M":
        raise errors.RadioError("No response from radio")

    for i in range(0, 0x7F):
        r = write_block(radio.pipe, i, radio._mmap)
        if not r:
            raise errors.RadioError("Radio NAK'd block %i" % i)
        if radio.status_fn:
            s = chirp_common.Status()
            s.msg = "Cloning to radio"
            s.max = 256 * 0x7E
            s.cur = 256 * i
            radio.status_fn(s)

    radio.pipe.write("E")
Exemple #9
0
def do_upload(radio):
    status = chirp_common.Status()
    status.msg = "Uploading to radio"

    _rt26_enter_programming_mode(radio)

    status.cur = 0
    status.max = 0x0190

    for start_addr, end_addr, block_size in radio._ranges:
        for addr in range(start_addr, end_addr, block_size):
            status.cur = addr + block_size
            radio.status_fn(status)
            _rt26_write_block(radio, addr, block_size)

    _rt26_exit_programming_mode(radio)
Exemple #10
0
def do_upload(radio):
    """The upload function"""
    do_program(radio)
    # UI progress
    status = chirp_common.Status()
    status.cur = 0
    status.max = MEM_SIZE
    status.msg = "Cloning to radio..."
    radio.status_fn(status)

    for addr in range(0x0000, MEM_SIZE, BLOCK_SIZE):
        send(radio, make_frame("W", addr),
             radio.get_mmap()[addr:addr+BLOCK_SIZE])
        # UI Update
        status.cur = addr
        radio.status_fn(status)
Exemple #11
0
def do_upload(radio):
    status = chirp_common.Status()
    status.msg = "Uploading to radio"

    _enter_programming_mode(radio)

    status.cur = 0
    status.max = radio._memsize

    for start_addr, end_addr in radio._ranges:
        for addr in range(start_addr, end_addr, radio.BLOCK_SIZE_UP):
            status.cur = addr + radio.BLOCK_SIZE_UP
            radio.status_fn(status)
            _write_block(radio, addr, radio.BLOCK_SIZE_UP)

    _exit_programming_mode(radio)
Exemple #12
0
def _chunk_read(pipe, count, status_fn):
    block = 32
    data = ""
    for _i in range(0, count, block):
        data += pipe.read(block)
        if data:
            if data[0] == chr(CMD_ACK):
                data = data[1:]  # Chew an echo'd ack if using a 2-pin cable
                # LOG.debug("Chewed an ack")
        status = chirp_common.Status()
        status.msg = "Cloning from radio"
        status.max = count
        status.cur = len(data)
        status_fn(status)
        LOG.debug("Read %i/%i" % (len(data), count))
    return data
Exemple #13
0
    def _clone_in(self):
        start = time.time()

        data = ""
        status = chirp_common.Status()
        status.msg = _("Cloning from radio")
        status.max = self._memsize
        for addr_from, addr_to, blocksize in self._blocks:
            for addr in range(addr_from, addr_to, blocksize):
                data += self._read(addr, blocksize)
                status.cur = len(data)
                self.status_fn(status)

        LOG.info("Clone completed in %i seconds" % (time.time() - start))

        return memmap.MemoryMap(data)
Exemple #14
0
def _download(radio):
    """Get the memory map"""
    # put radio in program mode
    ident = _ident_radio(radio)

    # UI progress
    status = chirp_common.Status()
    status.cur = 0
    status.max = radio._mem_size / radio._recv_block_size
    status.msg = "Cloning from radio..."
    radio.status_fn(status)

    data = ""
    for addr in range(0, radio._mem_size, radio._recv_block_size):
        frame = _make_frame("R", addr, radio._recv_block_size)
        # DEBUG
        LOG.info("Request sent:")
        LOG.debug(util.hexprint(frame))

        # sending the read request
        _rawsend(radio, frame)

        # now we read
        d = _recv(radio, addr, radio._recv_block_size)

        time.sleep(0.05)

        _rawsend(radio, "\x06")

        ack = _rawrecv(radio, 1)
        if ack != "\x06":
            raise errors.RadioError("Radio refused to send block 0x%04x" %
                                    addr)

        ####time.sleep(0.05)

        # aggregate the data
        data += d

        # UI Update
        status.cur = addr / radio._recv_block_size
        status.msg = "Cloning from radio..."
        radio.status_fn(status)

    data += radio.MODEL.ljust(8)

    return data
Exemple #15
0
    def _upload(self, limit):
        if not self._identify():
            raise Exception("I can't talk to this model")

        for addr in range(0x100, limit, 16):
            self._upload_chunk(addr)
            time.sleep(0.1)

            if self.status_fn:
                status = chirp_common.Status()
                status.cur = addr + 16
                status.max = self._memsize
                status.msg = "Uploading to radio"
                self.status_fn(status)

        self._send("AL~E\r\n")
        self.pipe._read(20)
Exemple #16
0
    def _clone_out(self):
        looppredelay = 0.4
        looppostdelay = 1.9
        start = time.time()

        blocknum = 0
        pos = 0
        status = chirp_common.Status()
        status.msg = "Cloning to radio..."
        self.status_fn(status)
        status.max = len(self._block_lengths)

        for blocksize in self._block_lengths:
            checksum = yaesu_clone.YaesuChecksum(pos, pos + blocksize - 1)
            blocknumbyte = chr(blocknum)
            payloadbytes = self.get_mmap()[pos:pos + blocksize]
            checksumbyte = chr(checksum.get_calculated(self.get_mmap()))
            if CHIRP_DEBUG:
                print "Block %i - will send from %i to %i byte " % \
                    (blocknum, pos, pos + blocksize)
                print util.hexprint(blocknumbyte)
                print util.hexprint(payloadbytes)
                print util.hexprint(checksumbyte)
            # send wrapped bytes
            time.sleep(looppredelay)
            self.pipe.write(blocknumbyte)
            self.pipe.write(payloadbytes)
            self.pipe.write(checksumbyte)
            tmp = self.pipe.read(blocksize + 2)  #chew echo
            if CHIRP_DEBUG:
                print "bytes echoed: "
                print util.hexprint(tmp)
            # radio is slow to write/ack:
            time.sleep(looppostdelay)
            buf = self.pipe.read(1)
            if CHIRP_DEBUG:
                print "ack recd:"
                print util.hexprint(buf)
            if buf != CMD_ACK:
                raise Exception("Radio did not ack block %i" % blocknum)
            pos += blocksize
            blocknum += 1
            status.cur = blocknum
            self.status_fn(status)

        print "Clone completed in %i seconds" % (time.time() - start)
Exemple #17
0
def download(radio):
    if command(radio.pipe, "0M PROGRAM") != "0M":
        raise errors.RadioError("No response from radio")

    data = ""
    for i in range(0, 0x7F):
        data += read_block(radio.pipe, i)
        if radio.status_fn:
            s = chirp_common.Status()
            s.msg = "Cloning from radio"
            s.max = 256 * 0x7E
            s.cur = len(data)
            radio.status_fn(s)

    radio.pipe.write("E")

    return memmap.MemoryMap(data)
Exemple #18
0
    def _download(self, limit):
        self._detect_baudrate_and_identify()

        data = "\x00" * 0x200

        for addr in range(0x200, limit, 0x40):
            data += self._download_chunk(addr)
            # Other Alinco drivers delay here, but doesn't seem to be necessary
            # for this model.

            if self.status_fn:
                status = chirp_common.Status()
                status.cur = addr
                status.max = limit
                status.msg = "Downloading from radio"
                self.status_fn(status)
        return memmap.MemoryMap(data)
Exemple #19
0
def do_upload(radio):

    _ident(radio)

    for start,end in radio._ranges:
        for addr in range(start,end,0x10):
            if addr < 0x0100:
                continue
            block = radio._mmap[addr:addr+0x10]
            _send(radio,'W',addr,len(block),block)
            status = chirp_common.Status()
            status.cur = addr
            status.max = end
            status.msg = "Uploading to Radio"
            radio.status_fn(status)

    _finish(radio)
Exemple #20
0
def _download(radio):
    data = ""
    for _i in range(0, 10):
        data = radio.pipe.read(8)
        if data == IDBLOCK:
            break

    LOG.debug("Header:\n%s" % util.hexprint(data))

    if len(data) != 8:
        raise Exception("Failed to read header")

    _send(radio.pipe, ACK)

    data = ""

    while len(data) < radio._block_sizes[1]:
        time.sleep(0.1)
        chunk = radio.pipe.read(38)
        LOG.debug("Got: %i:\n%s" % (len(chunk), util.hexprint(chunk)))
        if len(chunk) == 8:
            LOG.debug("END?")
        elif len(chunk) != 38:
            LOG.debug("Should fail?")
            break
            # raise Exception("Failed to get full data block")
        else:
            cs = 0
            for byte in chunk[:-1]:
                cs += ord(byte)
            if ord(chunk[-1]) != (cs & 0xFF):
                raise Exception("Block failed checksum!")

            data += chunk[5:-1]

        _send(radio.pipe, ACK)
        if radio.status_fn:
            status = chirp_common.Status()
            status.max = radio._block_sizes[1]
            status.cur = len(data)
            status.msg = "Cloning from radio"
            radio.status_fn(status)

    LOG.debug("Total: %i" % len(data))

    return memmap.MemoryMap(data)
Exemple #21
0
 def _clone_out(self):
     delay = 0.5
     start = time.time()
 
     blocks = 0
     pos = 0
     status = chirp_common.Status()
     status.msg = _("Cloning to radio")
     status.max = len(self._block_lengths) + 39
     for block in self._block_lengths:
         if blocks == 8:
             # repeated read of 40 block same size (memory area)
             repeat = 40
         else:
             repeat = 1
         for _i in range(0, repeat):
             time.sleep(0.01)
             checksum = yaesu_clone.YaesuChecksum(pos, pos+block-1)
             if os.getenv("CHIRP_DEBUG"):
                 print "Block %i - will send from %i to %i byte " % \
                     (blocks,
                      pos,
                      pos + block)
                 print util.hexprint(chr(blocks))
                 print util.hexprint(self.get_mmap()[pos:pos+block])
                 print util.hexprint(chr(checksum.get_calculated(
                             self.get_mmap())))
             self.pipe.write(chr(blocks))
             self.pipe.write(self.get_mmap()[pos:pos+block])
             self.pipe.write(chr(checksum.get_calculated(self.get_mmap())))
             buf = self.pipe.read(1)
             if not buf or buf[0] != chr(CMD_ACK):
                 time.sleep(delay)
                 buf = self.pipe.read(1)
             if not buf or buf[0] != chr(CMD_ACK):
                 if os.getenv("CHIRP_DEBUG"):
                     print util.hexprint(buf)
                 raise Exception(_("Radio did not ack block %i") % blocks)
             pos += block
             blocks += 1
             status.cur = blocks
             self.status_fn(status)
 
     print "Clone completed in %i seconds" % (time.time() - start)
Exemple #22
0
def do_upload(radio):
    """The upload function"""
    SHX8800_prep(radio)

    # UI progress
    status = chirp_common.Status()
    status.cur = 0
    status.max = MEM_SIZE
    status.msg = "Cloning to radio..."
    radio.status_fn(status)

    for addr in range(0x0000, MEM_SIZE, BLOCK_SIZE_TX):
        _write_block(radio, addr, BLOCK_SIZE_TX,
                     radio._mmap[addr:addr + BLOCK_SIZE_TX])
        # UI Update
        status.cur = addr
        radio.status_fn(status)

    SHX8800_exit(radio)
Exemple #23
0
def _upload(radio):
    cur = 0
    for block in radio._block_lengths:
        for _i in range(0, block, radio._block_size):
            length = min(radio._block_size, block)
            # LOG.debug("i=%i length=%i range: %i-%i" %
            #           (i, length, cur, cur+length))
            _send(radio.pipe, radio.get_mmap()[cur:cur + length])
            if radio.pipe.read(1) != ACK:
                raise errors.RadioError("Radio did not ack block at %i" % cur)
            cur += length
            time.sleep(0.05)

            if radio.status_fn:
                status = chirp_common.Status()
                status.cur = cur
                status.max = radio.get_memsize()
                status.msg = "Cloning to radio"
                radio.status_fn(status)
Exemple #24
0
def _upload(radio):
    _identify(radio)
    for i in range(0, 0x2000, 0x40):
        msg = struct.pack('>cHb', 'W', i, 0x40)
        msg += radio._mmap[i:(i + 0x40)]
        radio.pipe.write(msg)
        ack = radio.pipe.read(1)
        if ack != '\x06':
            raise errors.RadioError('Radio did not ACK block %i (0x%04x)' % (
                i, i))

        if radio.status_fn:
            status = chirp_common.Status()
            status.cur = i
            status.max = 0x2000
            status.msg = "Cloning from radio"
            radio.status_fn(status)

    radio.pipe.write("E")
Exemple #25
0
def do_download(radio):
    '''Download memories from the radio'''

    # Get the serial port connection
    serial = radio.pipe

    try:
        enter_program_mode(radio)

        memory_data = bytes()

        # status info for the UI
        status = chirp_common.Status()
        status.cur = 0
        status.max = (MEMORY_ADDRESS_RANGE[1] -
                      MEMORY_ADDRESS_RANGE[0]) / MEMORY_RW_BLOCK_SIZE
        status.msg = 'Cloning from radio...'
        radio.status_fn(status)

        for addr in range(MEMORY_ADDRESS_RANGE[0],
                          MEMORY_ADDRESS_RANGE[1] + MEMORY_RW_BLOCK_SIZE,
                          MEMORY_RW_BLOCK_SIZE):
            read_command = struct.pack('>BHB', 0x52, addr,
                                       MEMORY_RW_BLOCK_SIZE)
            read_response = send_serial_command(serial, read_command,
                                                MEMORY_RW_BLOCK_CMD_SIZE)
            # LOG.debug('read response:\n%s' % util.hexprint(read_response))

            address, data, valid = parse_read_response(read_response)
            memory_data += data

            # update UI
            status.cur = (addr - MEMORY_ADDRESS_RANGE[0])\
                / MEMORY_RW_BLOCK_SIZE
            radio.status_fn(status)

        exit_program_mode(radio)
    except errors.RadioError as e:
        raise e
    except Exception as e:
        raise errors.RadioError('Failed to download from radio: %s' % e)

    return memmap.MemoryMapBytes(memory_data)
Exemple #26
0
def _upload(radio):
    for _i in range(0, 10):
        data = radio.pipe.read(256)
        if not data:
            break
        LOG.debug("What is this garbage?\n%s" % util.hexprint(data))
        raise Exception("Radio sent unrecognized data")

    _send(radio.pipe, radio.IDBLOCK)
    time.sleep(.2)
    ack = radio.pipe.read(300)
    LOG.debug("Ack was (%i):\n%s" % (len(ack), util.hexprint(ack)))
    if ack != ACK:
        raise Exception("Radio did not ack ID. Check cable, verify"
                        " radio is not locked.\n"
                        " (press & Hold red \"*L\" button to unlock"
                        " radio if needed)")

    block = 0
    cs = INITIAL_CHECKSUM
    for byte in radio.IDBLOCK:
        cs += ord(byte)

    while block < (radio.get_memsize() / 32):
        data = radio.get_mmap()[block * 32:(block + 1) * 32]

        LOG.debug("Writing block %i:\n%s" % (block, util.hexprint(data)))

        _send(radio.pipe, data)
        time.sleep(0.03)

        for byte in data:
            cs += ord(byte)

        if radio.status_fn:
            status = chirp_common.Status()
            status.max = radio._block_sizes[1]
            status.cur = block * 32
            status.msg = "Cloning to radio"
            radio.status_fn(status)
        block += 1

    _send(radio.pipe, chr(cs & 0xFF))
Exemple #27
0
    def do_fetch(self):
        """Fetches frequencies for all subcategories in a county."""
        self._freqs = []

        try:
            service = self._client.service
            zipcode = service.getZipcodeInfo(self._zip, self._auth)
            county = service.getCountyInfo(zipcode.ctid, self._auth)
        except WebFault as err:
            raise errors.RadioError(err)

        status = chirp_common.Status()
        status.max = 0
        for cat in county.cats:
            status.max += len(cat.subcats)
        status.max += len(county.agencyList)

        for cat in county.cats:
            LOG.debug("Fetching category:", cat.cName)
            for subcat in cat.subcats:
                LOG.debug("\t", subcat.scName)
                result = self._client.service.getSubcatFreqs(
                    subcat.scid, self._auth)
                self._freqs += result
                status.cur += 1
                self.status_fn(status)
        status.max -= len(county.agencyList)
        for agency in county.agencyList:
            agency = self._client.service.getAgencyInfo(agency.aid, self._auth)
            for cat in agency.cats:
                status.max += len(cat.subcats)
            for cat in agency.cats:
                LOG.debug("Fetching category:", cat.cName)
                for subcat in cat.subcats:
                    try:
                        LOG.debug("\t", subcat.scName)
                    except AttributeError:
                        pass
                    result = self._client.service.getSubcatFreqs(
                        subcat.scid, self._auth)
                    self._freqs += result
                    status.cur += 1
                    self.status_fn(status)
Exemple #28
0
    def _download(self, limit):
        self._identify()

        data = ""
        for addr in range(0, limit, 16):
            data += self._download_chunk(addr)
            time.sleep(0.1)

            if self.status_fn:
                status = chirp_common.Status()
                status.cur = addr + 16
                status.max = self._memsize
                status.msg = "Downloading from radio"
                self.status_fn(status)

        self._send("AL~E\r\n")
        self._read(20)

        return memmap.MemoryMap(data)
Exemple #29
0
def do_download(radio):
    """ The download function """
    do_program(radio)
    # UI progress
    status = chirp_common.Status()
    status.cur = 0
    status.max = MEM_SIZE
    status.msg = "Cloning from radio..."
    radio.status_fn(status)
    data = ""
    for addr in range(0x0000, MEM_SIZE, BLOCK_SIZE):
        send(radio, make_frame("R", addr))
        d = recv(radio)
        data += d
        # UI Update
        status.cur = addr
        radio.status_fn(status)

    return memmap.MemoryMap(data)
Exemple #30
0
def _upload(radio):
    for _i in range(0, 10):
        data = radio.pipe.read(256)
        if not data:
            break
        print "What is this garbage?\n%s" % util.hexprint(data)

    _send(radio.pipe, IDBLOCK)
    time.sleep(1)
    ack = radio.pipe.read(300)
    if DEBUG:
        print "Ack was (%i):\n%s" % (len(ack), util.hexprint(ack))
    if ack != ACK:
        raise Exception("Radio did not ack ID")

    block = 0
    while block < (radio.get_memsize() / 32):
        data = "\x0C\x03\x00\x00" + chr(block)
        data += radio.get_mmap()[block * 32:(block + 1) * 32]
        cs = 0
        for byte in data:
            cs += ord(byte)
        data += chr(cs & 0xFF)

        if DEBUG:
            print "Writing block %i:\n%s" % (block, util.hexprint(data))

        _send(radio.pipe, data)
        time.sleep(0.1)
        ack = radio.pipe.read(3)
        if ack != ACK:
            raise Exception("Radio did not ack block %i" % block)

        if radio.status_fn:
            status = chirp_common.Status()
            status.max = radio._block_sizes[1]
            status.cur = block * 32
            status.msg = "Cloning to radio"
            radio.status_fn(status)
        block += 1

    _send(radio.pipe, TRAILER)