lib/qmi/codec/user_identity.ex

defmodule QMI.Codec.UserIdentity do
  @moduledoc """
  Codec for making user identity service requests
  """

  @read_transparent 0x0020

  @typedoc """
  The response from issuing a read transparent request
  """
  @type read_transparent_response() :: %{
          sw1_result_code: non_neg_integer() | nil,
          sw2_result_code: non_neg_integer() | nil,
          read_result: binary() | nil
        }

  @doc """
  Read any transparent file in the card and access by path
  """
  @spec read_transparent(non_neg_integer(), non_neg_integer()) :: QMI.request()
  def read_transparent(file_id, file_path) do
    session = session_tlv()
    file = file_id_tlv(file_id, file_path)
    read_info = read_info_tlv()
    tlvs = <<session::binary, file::binary, read_info::binary>>

    size = byte_size(tlvs)

    %{
      service_id: 0x0B,
      payload: [<<@read_transparent::16-little, size::16-little>>, tlvs],
      decode: &parse/1
    }
  end

  defp session_tlv() do
    <<0x01, 0x02, 0x00, 0x00, 0x00>>
  end

  defp file_id_tlv(file_id, file_path) do
    <<0x02, 0x05, 0x00, file_id::16-little, 0x02, file_path::16-little>>
  end

  defp read_info_tlv() do
    <<0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00>>
  end

  defp parse(<<@read_transparent::16-little, size::16-little, tlvs::size(size)-binary>>) do
    %{sw1_result_code: nil, sw2_result_code: nil, read_result: nil}
    |> parse_tlvs(tlvs)
  end

  defp parse(_other) do
    {:error, :unexpected_response}
  end

  defp parse_tlvs(result, <<>>) do
    {:ok, result}
  end

  defp parse_tlvs(
         result,
         <<0x11, _size::16-little, content_len::16-little, bytes::size(content_len)-binary,
           rest::binary>>
       ) do
    result
    |> Map.put(:read_result, bytes)
    |> parse_tlvs(rest)
  end

  defp parse_tlvs(result, <<0x10, 0x02::16-little, sw1_code, sw2_code, rest::binary>>) do
    result
    |> Map.put(:sw1_result_code, sw1_code)
    |> Map.put(:sw2_result_code, sw2_code)
    |> parse_tlvs(rest)
  end

  defp parse_tlvs(result, <<_type, size::16-little, _values::size(size)-binary, rest::binary>>) do
    parse_tlvs(result, rest)
  end
end