anchor.diff:  
   -behaviour(ranch_protocol).
   
  +-include("em_records.hrl").
  +
   %% API
   -export([start_link/4]).
   -export([init/4]).
  
positive.code: parse_gprmc(Data) ->
    case em_regexp:match(Data, ?GPRMC_PATTERN) of
      {match, [_, Hour, Minute, Second, Validity, LatDD, LatMM_MMMM, LatType, LonDD, LonMM_MMMM, LonType, Speed, Course, Day, Month, Year|_]} ->
        #{
          <<"deviceTime">> => parse_date(Year, Month, Day, Hour, Minute, Second),
          <<"latitude">> => parse_coord(LatDD, LatMM_MMMM, LatType),
          <<"longitude">> => parse_coord(LonDD, LonMM_MMMM, LonType),
          <<"speed">> => parse_speed(Speed),
          <<"course">> => parse_course(Course),
          <<"valid">> => parse_valid(Validity)
        };
      _ ->
        null
    end.
  
  
  parse_gpgga(Data) ->
    case em_regexp:match(Data, ?GPGGA_PATTERN) of
      {match, [_, _Hour, _Minute, _Second, LatDD, LatMM_MMMM, LatType, LonDD, LonMM_MMMM, LonType|_]} ->
        #{
          %%time => parse_date(Year, Month, Day, Hour, Minute, Second),
          <<"latitude">> => parse_coord(LatDD, LatMM_MMMM, LatType),
          <<"longitude">> => parse_coord(LonDD, LonMM_MMMM, LonType)
        };
      _ ->
        null
    end.
  
  parse_gprma(Data) ->
    case em_regexp:match(Data, ?GPRMA_PATTERN) of
      {match, [_, Validity, LatDD, LatMM_MMMM, LatType, LonDD, LonMM_MMMM, LonType, Speed, Course|_]} ->
        #{
          %%time => parse_date(Year, Month, Day, Hour, Minute, Second),
          <<"latitude">> => parse_coord(LatDD, LatMM_MMMM, LatType),
          <<"longitude">> => parse_coord(LonDD, LonMM_MMMM, LonType),
          <<"speed">> => parse_speed(Speed),
          <<"course">> => parse_course(Course),
          <<"valid">> => parse_valid(Validity)
        };
      _ ->
        null
    end.
  
  parse_trccr(Data) ->
      %% $TRCCR,20150727040136.279,A,53.897743,27.442885,0.00,0.00,0.00,34,*34
    case em_regexp:match(Data, ?TRCCR_PATTERN) of
      {match, [_, Year, Month, Day, Hour, Minute, Second, Validity, Lat, Lon, Speed, Course, Altitude, Battery|_]} ->
        #{
          <<"deviceTime">> => trccr_parse_date(Year, Month, Day, Hour, Minute, Second),
          <<"latitude">> => list_to_float(binary_to_list(Lat)),
          <<"longitude">> => list_to_float(binary_to_list(Lon)),
          <<"speed">> => parse_speed(Speed),
          <<"course">> => parse_course(Course),
          <<"valid">> => parse_valid(Validity),
          <<"altitude">> => parse_altitude(Altitude),
          <<"battery">> => parse_battery(Battery)
        };
      _ ->
        null
    end.
  
  parse_battery(Battery) ->
  
negative.code:         {<<"PGID">>, Imei} ->
            em_logger:info("[packet] unit: ip = '~s' imei = '~s'", [em_hardware:resolve(Socket), Imei]),
            case em_data_manager:get_device_by_uid(Imei) of
              {error, _Reason} ->
                    em_logger:info("[packet] unit: ip = '~s' unknown device with imei = '~s'", [em_hardware:resolve(Socket), Imei]),
                    Transport:close(Socket);
              {ok, Object} ->
                    loop(State#state{device = Object})
            end;
          {<<"PCPTI">>, Imei} ->
            em_logger:info("[packet] unit: ip = '~s' imei = '~s'", [em_hardware:resolve(Socket), Imei]),
            case em_data_manager:get_device_by_uid(Imei) of
              {error, _Reason} ->
                    em_logger:info("[packet] unit: ip = '~s' unknown device with imei = '~s'", [em_hardware:resolve(Socket), Imei]),
                    Transport:close(Socket);
              {ok, Object} ->
                    loop(State#state{device = Object})
            end;
          {<<"GPFID">>, Imei} ->
            em_logger:info("[packet] unit: ip = '~s' imei = '~s'", [em_hardware:resolve(Socket), Imei]),
            case em_data_manager:get_device_by_uid(Imei) of
              {error, _Reason} ->
                    em_logger:info("[packet] unit: ip = '~s' unknown device with imei = '~s'", [em_hardware:resolve(Socket), Imei]),
                    Transport:close(Socket);
              {ok, Object} ->
                    loop(State#state{device = Object})
            end;
          {<<"IMEI">>, Imei} ->
            em_logger:info("[packet] unit: ip = '~s' imei = '~s'", [em_hardware:resolve(Socket), Imei]),
            case em_data_manager:get_device_by_uid(Imei) of
              {error, _Reason} ->
                    em_logger:info("[packet] unit: ip = '~s' unknown device with imei = '~s'", [em_hardware:resolve(Socket), Imei]),
                    Transport:close(Socket);
              {ok, Object} ->
                    loop(State#state{device = Object})
            end;
          {<<"GPRMC">>, {ok, PositionModel}} ->
            Position = PositionModel#position{
              deviceId = Device#device.id,
              protocol = atom_to_binary(Protocol, utf8),
              attributes = maps:merge(PositionModel#position.attributes, #{
                ?KEY_IP => em_hardware:resolve(Socket)
              })
            },
            em_logger:info("save message => unit: ip = '~s' id = '~w' imei = '~s' position: ~w", [em_hardware:resolve(Socket), Device#device.id, Device#device.uniqueId, Position]),
            em_data_manager:create_position(Device, Position),
            Transport:send(Socket, <<"OK1\r\n">>),
            loop(State);
          {<<"GPGGA">>, {ok, PositionModel}} ->
            Position = PositionModel#position{
              deviceId = Device#device.id,
              protocol = atom_to_binary(Protocol, utf8),
              attributes = maps:merge(PositionModel#position.attributes, #{
                ?KEY_IP => em_hardware:resolve(Socket)
              })
            },
            em_logger:info("save message => unit: ip = '~s' id = '~w' imei = '~s' position: ~w", [em_hardware:resolve(Socket), Device#device.id, Device#device.uniqueId, Position]),
            em_data_manager:create_position(Device, Position),
            Transport:send(Socket, <<"OK1\r\n">>),
            loop(State);
          {<<"GPRMA">>, {ok, PositionModel}} ->
            Position = PositionModel#position{
              deviceId = Device#device.id,
              protocol = atom_to_binary(Protocol, utf8),
              attributes = maps:merge(PositionModel#position.attributes, #{
                ?KEY_IP => em_hardware:resolve(Socket)
              })
            },
            em_logger:info("save message => unit: ip = '~s' id = '~w' imei = '~s' position: ~w", [em_hardware:resolve(Socket), Device#device.id, Device#device.uniqueId, Position]),
            em_data_manager:create_position(Device, Position),
            Transport:send(Socket, <<"OK1\r\n">>),
            loop(State);
          {<<"TRCCR">>, {ok, PositionModel}} ->
            Position = PositionModel#position{
              deviceId = Device#device.id,
              protocol = atom_to_binary(Protocol, utf8),
              attributes = maps:merge(PositionModel#position.attributes, #{
                ?KEY_IP => em_hardware:resolve(Socket)
              })
            },
            em_logger:info("save message => unit: ip = '~s' id = '~w' imei = '~s' position: ~w", [em_hardware:resolve(Socket), Device#device.id, Device#device.uniqueId, Position]),
            em_data_manager:create_position(Device, Position),
            Transport:send(Socket, <<"OK1\r\n">>),
            loop(State);
          _ ->
            Transport:close(Socket)
        end;
      _ ->
        Transport:close(Socket)
  