Esempio n. 1
0
def raw_write_file(device, buf, applet_id, file_index, raw):
    logger.debug('Preparing to write file')
    size = len(buf)
    command = MessageConst.REQUEST_WRITE_RAW_FILE if raw else MessageConst.REQUEST_WRITE_FILE
    message = Message(command, [(file_index, 1, 1), (size, 2, 3),
                                (applet_id, 5, 2)])
    send_message(device, message, MessageConst.RESPONSE_WRITE_FILE)
    logger.debug('Writing block file data')
    write_extended_data(device, buf)
    message = Message(MessageConst.REQUEST_CONFIRM_WRITE_FILE)
    send_message(device, message, MessageConst.RESPONSE_CONFIRM_WRITE_FILE)
    logger.info('Writing file complete')
Esempio n. 2
0
def read_extended_data(device, size):
    """
    Read binary data blocks in response to some other command, handling segmentation
    and checksum validation.

    The command sequence is:

        While data left to read
            OUT:    0x10    ASMESSAGE_REQUEST_BLOCK_READ
            IN:     0x4d    ASMESSAGE_RESPONSE_BLOCK_READ
            OUT:    data
    """
    logger.debug('Reading extended data')
    remaining = size
    message = Message(MessageConst.REQUEST_BLOCK_READ, [])
    result = util.create_buffer(0)

    while remaining > 0:
        response = send_message(device, message)
        if response.command() == MessageConst.RESPONSE_BLOCK_READ_EMPTY:
            break
        if response.command() == MessageConst.RESPONSE_BLOCK_READ:
            blocksize = response.argument(1, 4)
            checksum = response.argument(5, 2)
            buf = device.read(blocksize)
            assert calculate_data_checksum(buf) == checksum
            result.extend(buf)
            remaining = remaining - len(buf)
        else:
            raise NeotoolsError('Unexpected response %s' % response)

    return result.tobytes()
Esempio n. 3
0
def set_settings(device, applet_id, settings):
    settings_buf = settings.to_raw()
    checksum = calculate_data_checksum(settings_buf)
    device.dialogue_start()
    logger.info('Requesting to write settings for applet_id=%s', applet_id)
    message = Message(MessageConst.REQUEST_SET_SETTINGS,
                      [(len(settings_buf), 1, 4), (checksum, 5, 2)])
    send_message(device, message, MessageConst.RESPONSE_BLOCK_WRITE)
    logger.info('Writing settings')
    device.write(settings_buf)
    receive_message(device, MessageConst.RESPONSE_BLOCK_WRITE_DONE)

    message = Message(MessageConst.REQUEST_SET_APPLET, [(0, 1, 4),
                                                        (applet_id, 5, 2)])
    send_message(device, message, MessageConst.RESPONSE_SET_APPLET)
    device.dialogue_end()
Esempio n. 4
0
 def flip_to_keyboard_mode(self):
     logger.info('Switching Neo to keyboard mode')
     self.dialogue_start()
     message = Message(MessageConst.REQUEST_RESTART, [])
     response = send_message(self, message)
     assert_success(response, MessageConst.RESPONSE_RESTART)
     self.dialogue_end()
Esempio n. 5
0
def get_system_memory(device):
    device.dialogue_start()
    message = Message(MessageConst.REQUEST_GET_AVAIL_SPACE, [])
    response = send_message(device, message)
    assert response.command() == MessageConst.RESPONSE_GET_AVAIL_SPACE
    result = {
        'free_rom': response.argument(1, 4),
        'free_ram': response.argument(5, 2) * 256
    }
    device.dialogue_end()
    return result
Esempio n. 6
0
def create_file(device, filename, password, data, applet_id):
    """

    Create a new file.

    The sequence for creating a new file is a little counter intuitive, starting with the file attributes:

    --> REQUEST_SET_FILE_ATTRIBUTES     ; set up the attributes (see rawWriteAttributes())
    <-- RESPONSE_SET_FILE_ATTRIBUTES
    --> REQUEST_BLOCK_WRITE
    --> Attribute data
    <-- RESPONSE_BLOCK_WRITE_DONE
    --> REQUEST_COMMIT                  ; create the file
    <-- RESPONSE_COMMIT
    --> REQUEST_WRITE_RAW_FILE          ; the following sequence is as for writing an existing file (see rawWriteFile())
    <-- RESPONSE_WRITE_FILE
    --> REQUEST_BLOCK_WRITE
    --> File data
    <-- RESPONSE_BLOCK_WRITE_DONE
    --> REQUEST_CONFIRM_WRITE_FILE
    <-- RESPONSE_CONFIRM_WRITE_FILE

    :param device:
    :param filename:
    :param password:
    :param data: The buffer to write.
    :param applet_id:
    :return: The new FileAttributes.
    """
    usage = get_applet_resource_usage(device, applet_id)
    system_memory = get_system_memory(device)
    if isinstance(data, str):
        data = data.encode('utf-8')

    size = len(data)
    if size + 1024 > system_memory['free_ram']:
        # REVIEW: arbitrarily choosing to keep at least 1k unused on the device
        raise NeotoolsError('The device does not have enough RAM')

    device.dialogue_start()

    file_index = usage['file_count'] + 1
    # The space is unbound, it is not index
    attrs = FileAttributes(file_index, filename, 0, password, size, size, 0)
    raw_set_file_attributes(device, attrs, applet_id, file_index)

    # Sending this message appears to bind the attributes to a new file -
    # not sending it will still result in a new file, but the attributes will not be correct.
    message = Message(MessageConst.REQUEST_COMMIT, [(file_index, 4, 1),
                                                    (applet_id, 5, 2)])
    response = send_message(device, message, MessageConst.RESPONSE_COMMIT)
    raw_write_file(device, data, applet_id, file_index, True)
    device.dialogue_end()
Esempio n. 7
0
def get_applet_resource_usage(device, applet_id):
    device.dialogue_start()
    message = Message(MessageConst.REQUEST_GET_USED_SPACE, [(0x00000001, 1, 4),
                                                            (applet_id, 5, 2)])
    response = send_message(device, message,
                            MessageConst.RESPONSE_GET_USED_SPACE)
    result = {
        'ram': response.argument(1, 4),
        'file_count': response.argument(5, 2)
    }
    device.dialogue_end()
    return result
Esempio n. 8
0
def clear_file(device, applet_id, file_index):
    attrs = get_file_attributes(device, applet_id, file_index)
    if attrs is None:
        return None
    attrs.alloc_size = attrs.min_size = 0

    device.dialogue_start()
    raw_set_file_attributes(device, attrs, applet_id, file_index)
    message = Message(MessageConst.REQUEST_COMMIT, [(file_index, 4, 1),
                                                    (applet_id, 5, 2)])
    send_message(device, message, MessageConst.RESPONSE_COMMIT)
    raw_write_file(device, b'', applet_id, file_index, True)
    device.dialogue_end()
Esempio n. 9
0
def raw_set_file_attributes(device, attrs, applet_id, file_index):
    """
    OUT:    0x1d    ASMESSAGE_REQUEST_SET_FILE_ATTRIBUTES
    IN:     0x5b    ASMESSAGE_RESPONSE_SET_FILE_ATTRIBUTES
    OUT:    0x02    ASMESSAGE_REQUEST_BLOCK_WRITE
    IN:     0x42    ASMESSAGE_RESPONSE_BLOCK_WRITE
    OUT:    data
    IN:     0x43    ASMESSAGE_RESPONSE_BLOCK_WRITE_DONE
    """
    assert file_index < 256
    logger.debug('Setting file attributes applet_id=%s file_index=%s attrs=%s',
                 applet_id, file_index, attrs)
    message = Message(MessageConst.REQUEST_SET_FILE_ATTRIBUTES,
                      [(file_index, 1, 4), (applet_id, 5, 2)])
    send_message(device, message, MessageConst.RESPONSE_SET_FILE_ATTRIBUTES)
    write_extended_data(device, attrs.to_raw())
Esempio n. 10
0
def raw_read_file(device, applet_id, file_attrs, raw):
    """
    Transfer sequence:
      OUT:    0x12|0x1c   ASMESSAGE_REQUEST_READ_FILE | ASMESSAGE_REQUEST_READ_RAW_FILE
      IN:     0x53        ASMESSAGE_RESPONSE_READ_FILE
      [block read sequence]
    """
    size = file_attrs.alloc_size
    index = file_attrs.file_index
    logger.info('Requesting to read a file at applet_id=%s, file_index=%s',
                applet_id, index)
    command = MessageConst.REQUEST_READ_RAW_FILE if raw else MessageConst.REQUEST_READ_FILE
    message = Message(command, [(size, 1, 3), (index, 4, 1),
                                (applet_id, 5, 2)])
    send_message(device, message)
    return read_extended_data(device, size)
Esempio n. 11
0
def get_settings(device, applet_id, flags):
    device.dialogue_start()
    logger.info('Requesting settings for applet_id=%s, flags=%s', applet_id,
                flags)
    message = Message(MessageConst.REQUEST_GET_SETTINGS, [(flags, 1, 4),
                                                          (applet_id, 5, 2)])
    response = send_message(device, message,
                            MessageConst.RESPONSE_GET_SETTINGS)
    response_size = response.argument(1, 4)
    expected_checksum = response.argument(5, 2)
    logger.info('Retrieving settings data')
    result = device.read(response_size)
    assert calculate_data_checksum(result) == expected_checksum
    device.dialogue_end()
    settings_list = AppletSettingsItem.list_from_raw(result)
    return AppletSettings(settings_list)
Esempio n. 12
0
def get_file_attributes(device, applet_id, index):
    logger.info('Getting file attributes applet_id=%s index=%s', applet_id,
                index)
    device.dialogue_start()
    message = Message(MessageConst.REQUEST_GET_FILE_ATTRIBUTES,
                      [(index, 4, 1), (applet_id, 5, 2)])
    response = send_message(device, message)
    if response.command() == MessageConst.ERROR_PARAMETER:
        # Entry not found. This probably just means that the iteration has exceeded the number of files available.
        return None
    assert_success(response, MessageConst.RESPONSE_GET_FILE_ATTRIBUTES)
    length = response.argument(1, 4)
    checksum = response.argument(5, 2)
    assert length == FILE_ATTRIBUTES_FORMAT['size']
    buf = device.read(FILE_ATTRIBUTES_FORMAT['size'])
    assert checksum == calculate_data_checksum(buf)
    device.dialogue_end()
    return FileAttributes.from_raw(index, buf)
Esempio n. 13
0
def write_extended_data(device, buf):
    remaining = len(buf)
    offset = 0
    while remaining > 0:
        blocksize = min(1024, remaining)
        block = buf[offset:offset + blocksize]
        checksum = calculate_data_checksum(block)

        message = Message(MessageConst.REQUEST_BLOCK_WRITE, [(blocksize, 1, 4),
                                                             (checksum, 5, 2)])
        response = send_message(device, message,
                                MessageConst.RESPONSE_BLOCK_WRITE)

        device.write(block)
        response = receive_message(device,
                                   MessageConst.RESPONSE_BLOCK_WRITE_DONE)

        offset = offset + blocksize
        remaining = remaining - blocksize
Esempio n. 14
0
def raw_read_applet_headers(device, index):
    header_size = APPLET_HEADER_FORMAT['size']
    logger.info('Requesting to read list of applets with index=%s', index)
    message = Message(MessageConst.REQUEST_LIST_APPLETS,
                      [(index, 1, 4), (LIST_APPLETS_REQUEST_COUNT, 5, 2)])
    response = send_message(device, message)
    size = response.argument(1, 4)
    expected_checksum = response.argument(5, 2)
    if size > LIST_APPLETS_REQUEST_COUNT * header_size:
        raise NeotoolsError(
            'rawReadAppletHeaders: reply will return too much data!')

    if size == 0:
        return []

    buf = device.read(size)
    if len(buf) % header_size != 0:
        logger.warning(
            'rawReadAppletHeaders: read returned a partial header (expected header size %s, bytes read %s',
            header_size, len(buf))
    if calculate_data_checksum(buf) != expected_checksum:
        raise NeotoolsError('rawReadAppletHeaders: data checksum error')
    return buf