Packages
diint_utilites_common_app
1.0.5
1.4.23
1.4.22
1.4.21
1.4.20
1.4.19
1.4.18
1.4.17
1.4.16
1.4.15
1.4.14
1.4.12
1.4.11
1.4.10
1.4.9
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.9
1.3.8
1.3.7
1.3.6
1.3.5
1.3.4
1.3.3
1.3.2
1.3.1
1.3.0
1.2.101
1.2.11
1.2.10
1.2.9
1.2.8
1.2.7
1.2.6
1.2.5
1.2.4
1.2.3
1.2.2
1.2.1
1.2.0
1.1.7
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.13
1.0.12
1.0.11
1.0.10
1.0.9
1.0.8
1.0.7
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
библиотеки для работы с ребитом и протоколы
Current section
Files
Jump to
Current section
Files
src/finance_protocol/protocol_titp.erl
%%%-------------------------------------------------------------------
%%% @author cheese
%%% @copyright (C) 2014, <COMPANY>
%%% @doc
%%%
%%% @end
%%% Created : 20. Jan 2014 4:04 PM
%%%-------------------------------------------------------------------
-module(protocol_titp).
-author("cheese").
-include("../../include/types_finance_protocol.hrl").
%% API
-export([parse/1, get_field_description/1, pack/1, create_field_as_string/2, protocol_info_string/1, field_info_string/1]).
%% Internal Functions
-export([internal_pack_field_header/1, internal_pack_fields/2, internal_pack_field/1, internal_parse_fields/4, internal_parse_fields_from_byte_in_bitmap/5,
internal_parse_field_from_bytes/2, internal_get_valid_message_size/2, internal_get_size_align/1, internal_get_view_data/1, internal_check_size/2,
internal_pack_bitmap/3, internal_protocol_info_string/2]).
parse(<<_L2L1:2/binary, Header_1:1/binary, Header_2_From:2/binary, Header_3_To:2/binary, MTI_Bin:2/binary, Bitmap:8/binary, Data/binary>>) ->
MTI = bytes_extension:bcd_int(MTI_Bin),
BitMapParse = internal_parse_fields(Bitmap, 0, Data, []),
#parsed_iso_message{
header = <<Header_1/binary, Header_2_From/binary, Header_3_To/binary>>,
mti = MTI,
fields = BitMapParse
};
parse(Other) ->
logger_Cheese:info("Invalid request: ~w~n", [Other]),
{error, invalid_data}.
%%----------------------------------------------------------------------------------------------------------------------
%% Разбор полей по битовой маске
%%----------------------------------------------------------------------------------------------------------------------
-spec(internal_parse_fields(binary(), number(), binary(), [#iso_field{}]) -> [#iso_field{}]).
internal_parse_fields(<<>>, _Pos, _Data, AllFields) ->
AllFields;
internal_parse_fields(<<Bt:8/integer, Tail/bytes>>, Pos, Data, AllFields) ->
case internal_parse_fields_from_byte_in_bitmap(Bt, 128, Pos * 8 + 1, Data, []) of
{error, Reason} ->
{error, Reason};
{NewData, Fields} ->
internal_parse_fields(Tail, Pos + 1, NewData, AllFields ++ Fields)
end.
%%----------------------------------------------------------------------------------------------------------------------
%% Разбор полей по одному байту из битовой маски
%%----------------------------------------------------------------------------------------------------------------------
-spec(internal_parse_fields_from_byte_in_bitmap(number(), number(), number(), binary(), [#iso_field{}]) -> {binary(), [#iso_field{}]} | {error, any()}).
internal_parse_fields_from_byte_in_bitmap(_, Pow, _, Bytes, AllFields) when Pow == 0 ->
{Bytes, lists:reverse(AllFields)};
internal_parse_fields_from_byte_in_bitmap(Bt, Pow, Pos, Bytes, AllFields) ->
IsPresent = Bt band Pow,
case IsPresent > 0 of
true ->
Res = get_field_description(Pos),
case Res of
undefined ->
internal_parse_fields_from_byte_in_bitmap(Bt, Pow div 2, Pos + 1, Bytes, AllFields);
FieldInfo ->
case internal_parse_field_from_bytes(FieldInfo, Bytes) of
{error, Reason} ->
{error, Reason};
{Field, NewBytes} ->
internal_parse_fields_from_byte_in_bitmap(Bt, Pow div 2, Pos + 1, NewBytes, [Field | AllFields])
end
end;
false ->
internal_parse_fields_from_byte_in_bitmap(Bt, Pow div 2, Pos + 1, Bytes, AllFields)
end.
%%----------------------------------------------------------------------------------------------------------------------
%% Разбор одного поля
%%----------------------------------------------------------------------------------------------------------------------
-spec(internal_parse_field_from_bytes(#iso_field{}, binary()) -> {error, any()} | {#iso_field{}, binary()}).
internal_parse_field_from_bytes(#iso_field{header = Header, pos = _Pos, type = _Type, size = _Size, info = _Info} = FieldInfo, Bytes) ->
%%logger:simple_message("=============================================", []),
%%logger:simple_message("Parsing field. pos:~w, size:~w, type: ~w, head: ~w, info: ~p", [Pos,Size, Type, Header, Info]),
case internal_get_valid_message_size(FieldInfo, Bytes) of
{error, Reason} ->
{error, Reason};
RealDataSizeFixed ->
%%logger:simple_message("RealDataSizeFixed: ~p", [RealDataSizeFixed]),
FieldDataBytes = binary:part(Bytes, Header, RealDataSizeFixed),
BytesOther = binary:part(Bytes, Header + RealDataSizeFixed, byte_size(Bytes) - Header - RealDataSizeFixed),
%%logger:simple_message("BytesOther: ~w", [BytesOther]),
NewFieldInfoRaw = FieldInfo#iso_field{
raw_data = FieldDataBytes
},
ViewData = internal_get_view_data(NewFieldInfoRaw),
NewFieldInfo = NewFieldInfoRaw#iso_field{
view_data = ViewData
},
{NewFieldInfo, BytesOther}
end;
%%----------------------------------------------------------------------------------------------------------------------
internal_parse_field_from_bytes(FieldInfo, _Bytes) ->
{error, {'Not parsed field', FieldInfo}}.
%%----------------------------------------------------------------------------------------------------------------------
%% Получить размер реальных данных в поле
%%----------------------------------------------------------------------------------------------------------------------
internal_get_valid_message_size(#iso_field{header = 0, size = Size, type = Type}, Bytes) when Type == d ->
internal_check_size(internal_get_size_align(Size), Bytes);
internal_get_valid_message_size(#iso_field{header = 0, size = Size, type = Type}, Bytes) when Type == b ->
internal_check_size(Size, Bytes);
internal_get_valid_message_size(#iso_field{header = 0, size = Size}, Bytes) ->
internal_check_size(Size, Bytes);
internal_get_valid_message_size(#iso_field{header = Header, type = Type}, Bytes) when Type == d ->
RealDataSize = bytes_extension:bcd_int(binary:part(Bytes, 0, Header)),
internal_check_size(internal_get_size_align(RealDataSize), Bytes);
internal_get_valid_message_size(#iso_field{header = Header, type = Type}, Bytes) when Type == b ->
RealDataSize = bytes_extension:bcd_int(binary:part(Bytes, 0, Header)),
internal_check_size(RealDataSize, Bytes);
internal_get_valid_message_size(#iso_field{header = Header}, Bytes) ->
RealDataSize = string:to_integer(binary_to_list(binary:part(Bytes, 0, Header))),
internal_check_size(internal_get_size_align(RealDataSize), Bytes).
%%----------------------------------------------------------------------------------------------------------------------
%% Получить данные
%%----------------------------------------------------------------------------------------------------------------------
internal_check_size(Size, Bytes) ->
case Size > byte_size(Bytes) of
true ->
{error, {not_enough_data, {size, Size}}};
false ->
Size
end.
%%----------------------------------------------------------------------------------------------------------------------
%% Получить данные
%%----------------------------------------------------------------------------------------------------------------------
internal_get_view_data(#iso_field{type = Type, raw_data = Bytes}) when Type == d ->
bytes_extension:bcd_string(Bytes);
internal_get_view_data(#iso_field{raw_data = Bytes}) ->
Bytes.
%%----------------------------------------------------------------------------------------------------------------------
%% Размер, кратный 2
%%----------------------------------------------------------------------------------------------------------------------
-spec(internal_get_size_align(any()) -> integer() | {error, _}).
internal_get_size_align(Size) when is_integer(Size) ->
Size div 2 + Size rem 2;
internal_get_size_align(Size) ->
{error, {invalid_size_input, Size}}.
%%----------------------------------------------------------------------------------------------------------------------
%% Описание одного поля протокола
%%----------------------------------------------------------------------------------------------------------------------
get_field_description(0 = Pos) ->
#iso_field{
pos = Pos,
size = 8,
header = 0,
type = b,
info = "Primary Bit Map"
};
get_field_description(2 = Pos) ->
#iso_field{
pos = Pos,
size = 19,
header = 1,
type = d,
info = "Primary Acct. Num."
};
get_field_description(3 = Pos) ->
#iso_field{
pos = Pos,
size = 6,
header = 0,
type = d,
info = "Processing Code"
};
get_field_description(4 = Pos) ->
#iso_field{
pos = Pos,
size = 12,
header = 0,
type = d,
info = "Amount, Trans."
};
get_field_description(11 = Pos) ->
#iso_field{
pos = Pos,
size = 6,
header = 0,
type = d,
info = "Systems Trace No"
};
get_field_description(12 = Pos) ->
#iso_field{
pos = Pos,
size = 6,
header = 0,
type = d,
info = "Time, Local Trans."
};
get_field_description(13 = Pos) ->
#iso_field{
pos = Pos,
size = 4,
header = 0,
type = d,
info = "Date, Local Trans."
};
get_field_description(14 = Pos) ->
#iso_field{
pos = Pos,
size = 4,
header = 0,
type = d,
info = "Date, Expiration"
};
get_field_description(22 = Pos) ->
#iso_field{
pos = Pos,
size = 3,
header = 0,
type = d,
info = "POS Entry Mode"
};
get_field_description(23 = Pos) ->
#iso_field{
pos = Pos,
size = 3,
header = 0,
type = d,
info = "Card Seq. Number"
};
get_field_description(24 = Pos) ->
#iso_field{
pos = Pos,
size = 3,
header = 0,
type = d,
info = "NII"
};
get_field_description(25 = Pos) ->
#iso_field{
pos = Pos,
size = 2,
header = 0,
type = d,
info = "POS Condition Code"
};
get_field_description(35 = Pos) ->
#iso_field{
pos = Pos,
size = 37,
header = 1,
type = d,
info = "Track 2 Data"
};
get_field_description(37 = Pos) ->
#iso_field{
pos = Pos,
size = 12,
header = 0,
type = s,
info = "Retrieval Ref. No."
};
get_field_description(38 = Pos) ->
#iso_field{
pos = Pos,
size = 6,
header = 0,
type = s,
info = "Auth. Id. Response"
};
get_field_description(39 = Pos) ->
#iso_field{
pos = Pos,
size = 2,
header = 0,
type = s,
info = "Response Code"
};
get_field_description(41 = Pos) ->
#iso_field{
pos = Pos,
size = 8,
header = 0,
type = s,
info = "Terminal Id"
};
get_field_description(42 = Pos) ->
#iso_field{
pos = Pos,
size = 15,
header = 0,
type = s,
info = "Card Acq. Id"
};
get_field_description(43 = Pos) ->
#iso_field{
pos = Pos,
size = 40,
header = 0,
type = s,
info = "Card Acq. Name"
};
get_field_description(45 = Pos) ->
#iso_field{
pos = Pos,
size = 76,
header = 1,
type = s,
info = "Track 1 Data"
};
get_field_description(48 = Pos) ->
#iso_field{
pos = Pos,
size = 999,
header = 2,
type = b,
info = "Add. Data - Private"
};
get_field_description(49 = Pos) ->
#iso_field{
pos = Pos,
size = 3,
header = 0,
type = s,
info = "Currency Code, Trans."
};
get_field_description(52 = Pos) ->
#iso_field{
pos = Pos,
size = 8,
header = 0,
type = b,
info = "PIN Data"
};
get_field_description(53 = Pos) ->
#iso_field{
pos = Pos,
size = 16,
header = 0,
type = d,
info = "Security Control Info"
};
get_field_description(54 = Pos) ->
#iso_field{
pos = Pos,
size = 120,
header = 2,
type = b,
info = "Additional Amounts"
};
get_field_description(55 = Pos) ->
#iso_field{
pos = Pos,
size = 255,
header = 2,
type = b,
info = "ICC Sys Related Data"
};
get_field_description(57 = Pos) ->
#iso_field{
pos = Pos,
size = 999,
header = 2,
type = b,
info = "Field 57 (Compass+)"
};
get_field_description(60 = Pos) ->
#iso_field{
pos = Pos,
size = 999,
header = 2,
type = b,
info = "Private Use"
};
get_field_description(61 = Pos) ->
#iso_field{
pos = Pos,
size = 999,
header = 2,
type = b,
info = "Private Use"
};
get_field_description(62 = Pos) ->
#iso_field{
pos = Pos,
size = 999,
header = 2,
type = b,
info = "Private Use"
};
get_field_description(63 = Pos) ->
#iso_field{
pos = Pos,
size = 999,
header = 2,
type = b,
info = "Private Use"
};
get_field_description(64 = Pos) ->
#iso_field{
pos = Pos,
size = 8,
header = 0,
type = b,
info = "Message Auth. Code"
};
get_field_description(_Pos) ->
undefined.
-spec(pack(#parsed_iso_message{}) -> binary()).
pack(#parsed_iso_message{fields = Fields, header = Header, mti = Mti}) ->
BytesMTI = <<(Mti div 100):8, (Mti rem 100):8>>,
BytesBitmap = internal_pack_bitmap(Fields, 1, <<>>),
BytesFields = internal_pack_fields(Fields, <<>>),
BytesAll = <<Header/binary, BytesMTI/binary, BytesBitmap/binary, BytesFields/binary>>,
DataSize = bytes_extension:binary_length(BytesAll),
<<(DataSize div 256):8, (DataSize rem 256):8, BytesAll/binary>>.
-spec(internal_pack_bitmap([#iso_field{}], integer(), binary()) -> binary()).
internal_pack_bitmap([#iso_field{pos = Idx} | Tail], Idx, Bitmaps) ->
NewBitmap = <<Bitmaps/bitstring, 1:1>>,
internal_pack_bitmap(Tail, Idx + 1, NewBitmap);
internal_pack_bitmap(_Fields, 65, Bitmaps) ->
Bitmaps;
internal_pack_bitmap(Fields, Idx, Bitmaps) ->
NewBitmap = <<Bitmaps/bitstring, 0:1>>,
internal_pack_bitmap(Fields, Idx + 1, NewBitmap).
-spec(internal_pack_fields([#iso_field{}], binary()) -> binary()).
internal_pack_fields([], Res) ->
Res;
internal_pack_fields([#iso_field{pos = Pos} = Field | Tail], Res) ->
Bytes = internal_pack_field(Field),
logger_Cheese:simple_message("Field_~w: ~p, |||| ~w", [Pos, Field, Bytes]),
internal_pack_fields(Tail, <<Res/binary, Bytes/binary>>).
-spec(internal_pack_field(#iso_field{}) -> binary()).
internal_pack_field(#iso_field{raw_data = Data} = Field) ->
BytesHeader = internal_pack_field_header(Field),
<<BytesHeader/bytes, Data/bytes>>.
-spec(internal_pack_field_header(#iso_field{}) -> binary()).
internal_pack_field_header(#iso_field{header = 0}) ->
<<>>;
internal_pack_field_header(#iso_field{type = Type, header = Header, raw_data = Data}) when Type =:= b ->
BytesCountHeadLen = Header,
BytesCountData = bytes_extension:binary_length(Data),
bytes_extension:int_to_bcd(BytesCountData, BytesCountHeadLen);
internal_pack_field_header(#iso_field{type = Type, header = Header, raw_data = Data}) when Type =:= d ->
BytesCountHeadLen = Header,
BytesCountData = case bytes_extension:last_byte(Data) rem 16 of
15 ->
bytes_extension:binary_length(Data) * 2 - 1;
_ ->
bytes_extension:binary_length(Data) * 2
end,
bytes_extension:int_to_bcd(BytesCountData, BytesCountHeadLen);
internal_pack_field_header(#iso_field{type = Type, raw_data = Data}) ->
error({error, {internal_pack_header, not_realized_for_type, {type, Type}, {raw_data, Data}}}).
create_field_as_string(Idx, Data) ->
case get_field_description(Idx) of
undefined ->
error({error, {undefined_field_index, Idx}});
#iso_field{type = d} = Field ->
Field#iso_field{
view_data = Data,
raw_data = protocol_iso_utilites:prepare_data_string_to_bcd(Data)
};
#iso_field{type = s} = Field ->
Field#iso_field{
view_data = Data,
raw_data = <<Data>>
};
#iso_field{type = b} = Field ->
Field#iso_field{
view_data = Data,
raw_data = list_to_binary(Data)
};
Field ->
error({error, {unsupported_field_for_setting, Field}})
end.
protocol_info_string(#parsed_iso_message{mti = Mti} = Titp) ->
MtiBytes = integer_to_binary(Mti),
FiledsBytes = internal_protocol_info_string(Titp#parsed_iso_message.fields, <<>>),
<<"[MTI: ", MtiBytes/binary, "]", FiledsBytes/bytes>>.
internal_protocol_info_string([], Res) ->
Res;
internal_protocol_info_string([#iso_field{pos = Pos} = Field | Tail], Res) ->
Data = field_info_string(Field),
IdxBytes = integer_to_binary(Pos),
internal_protocol_info_string(Tail, <<Res/binary, " [F", IdxBytes/binary, ": ", Data/binary, "]">>).
field_info_string(#iso_field{view_data = Data}) ->
Data.