summaryrefslogtreecommitdiff
path: root/components/dlink_bt/src/bt_connection.erl
diff options
context:
space:
mode:
Diffstat (limited to 'components/dlink_bt/src/bt_connection.erl')
-rw-r--r--components/dlink_bt/src/bt_connection.erl144
1 files changed, 103 insertions, 41 deletions
diff --git a/components/dlink_bt/src/bt_connection.erl b/components/dlink_bt/src/bt_connection.erl
index 85a8663..6b3a64e 100644
--- a/components/dlink_bt/src/bt_connection.erl
+++ b/components/dlink_bt/src/bt_connection.erl
@@ -36,16 +36,20 @@
-define(SERVER, ?MODULE).
+-define(PACKET_MOD, dlink_data_json).
-record(st, {
remote_addr = "00:00:00:00:00:00",
channel = 0,
- rfcomm_ref = undefined,
- listen_ref = undefined,
+ rfcomm_ref,
+ listen_ref,
+ accept_ref,
mode = bt,
- mod = undefined,
- func = undefined,
- args = undefined
+ packet_mod = ?PACKET_MOD,
+ packet_st = [],
+ mod,
+ func,
+ args
}).
%%%===================================================================
@@ -124,11 +128,15 @@ is_connection_up(Addr, Channel) ->
%% MFA used to handle socket closed, socket error and received data
%% When data is received, a separate process is spawned to handle
%% the MFA invocation.
-init({connect, BTAddr, Channel, Mode, Mod, Fun, Arg}) ->
+init({connect, BTAddr, Channel, Mode, Mod, Fun, CS}) ->
%% connect will block on rfcomm:open, so cast to self
%% in order to let init return.
+ ?debug("init({connect, ~p, ~p, ~p, ~p, ~p, CS})",
+ [BTAddr, Channel, Mode, Mod, Fun]),
gen_server:cast(self(), connect),
+ {ok, PktMod} = get_module_config(packet_mod, ?PACKET_MOD, CS),
+ PktSt = PktMod:init(CS),
{ok, #st{
remote_addr = BTAddr,
channel = Channel,
@@ -136,36 +144,47 @@ init({connect, BTAddr, Channel, Mode, Mod, Fun, Arg}) ->
mode = Mode,
mod = Mod,
func = Fun,
- args = Arg
+ args = CS,
+ packet_mod = PktMod,
+ packet_st = PktSt
}};
-init({accept, Channel, ListenRef, Mode, Mod, Fun, Arg}) ->
- ARef = case Mode of
- tcp ->
- {ok, R} = exo_socket:async_accept(ListenRef),
- R;
- bt ->
- {ok, R} = rfcomm:accept(ListenRef, infinity, self()),
- R
- end,
+init({accept, Channel, ListenRef, Mode, Mod, Fun, CS}) ->
+ ?debug("init({accept, ~p, ~p, ~p, ~p, ~p, CS})",
+ [Channel, ListenRef, Mode, Mod, Fun]),
?debug("bt_connection:init(accept): self(): ~p", [self()]),
?debug("bt_connection:init(accept): Channel: ~p", [Channel]),
?debug("bt_connection:init(accept): ListenRef: ~p", [ListenRef]),
- ?debug("bt_connection:init(accept): AcceptRef: ~p", [ARef]),
?debug("bt_connection:init(accept): Module: ~p", [Mod]),
?debug("bt_connection:init(accept): Function: ~p", [Fun]),
- ?debug("bt_connection:init(accept): Arg: ~p", [Arg]),
-
+ ?debug("bt_connection:init(accept): Arg: ~p", [CS]),
+ {ok, PktMod} = get_module_config(packet_mod, ?PACKET_MOD, CS),
+ PktSt = PktMod:init(CS),
+ ARef = case Mode of
+ bt ->
+ %% Expected message is
+ %% {rfcomm, ARef, {accept, Addr, Chan}}
+ {ok, R} = rfcomm:accept(ListenRef, infinity, self()),
+ R;
+ tcp ->
+ %% -1 represents infinity
+ %% Expected message is
+ %% {inet_async,LSock,Ref,{ok,Socket}}
+ {ok, R} = prim_inet:async_accept(ListenRef, -1),
+ R
+ end,
{ok, #st{
channel = Channel,
- rfcomm_ref = ARef,
- listen_ref = ListenRef,
+ rfcomm_ref = undefined,
+ accept_ref = ARef,
mode = Mode,
mod = Mod,
func = Fun,
- args = Arg
+ args = CS,
+ packet_mod = PktMod,
+ packet_st = PktSt
}}.
@@ -219,7 +238,7 @@ handle_cast(connect, #st {
bt ->
rfcomm:open(BTAddr, Channel);
tcp ->
- exo_socket:connect(BTAddr, Channel)
+ gen_tcp:connect(BTAddr, Channel, bt_listener:sock_opts())
end,
case ConnRes of
{ok, ConnRef} ->
@@ -246,13 +265,18 @@ handle_cast(connect, #st {
{ stop, { connect_failed, Error}, St }
end;
-handle_cast({send, Data}, St) ->
- ?debug("~p:handle_call(send): Sending: ~p",
- [ ?MODULE, Data]),
-
- rfcomm:send(St#st.rfcomm_ref, Data),
-
- {noreply, St};
+handle_cast({send, Data}, #st{mode = Mode,
+ rfcomm_ref = Sock,
+ packet_mod = PMod, packet_st = PSt} = St) ->
+ ?debug("handle_cast(send): Sending: ~p", [Data]),
+ {ok, Encoded, PSt1} = PMod:encode(Data, PSt),
+ ?debug("Encoded = ~p", [Encoded]),
+ Res = case Mode of
+ bt -> rfcomm:send(Sock, Encoded);
+ tcp -> gen_tcp:send(Sock, Encoded)
+ end,
+ ?debug("send Res = ~p", [Res]),
+ {noreply, St#st{packet_st = PSt1}};
handle_cast(_Msg, State) ->
?warning("~p:handle_cast(): Unknown call: ~p", [ ?MODULE, _Msg]),
@@ -271,35 +295,43 @@ handle_cast(_Msg, State) ->
%% An accept reference we've setup now has accetpted an
%% incoming connection.
-handle_info({rfcomm, _ARef, { accept, BTAddr, _ } },
+handle_info({rfcomm, ARef, { accept, BTAddr, _ } },
#st { mod = Mod,
func = Fun,
args = Arg,
+ listen_ref = LRef,
+ accept_ref = ARef,
channel = Channel } = St) ->
?info("~p:handle_info(): bt_connection from ~w:~w\n",
[?MODULE, BTAddr,Channel]),
-
+ bt_listener:accept_ack(ok, LRef, BTAddr, Channel),
Mod:Fun(self(), BTAddr, Channel, accepted, Arg),
{ noreply, St#st { remote_addr = BTAddr,
- channel = Channel } };
+ channel = Channel,
+ accept_ref = undefined} };
handle_info({rfcomm, _ConnRef, {data, Data}},
#st { remote_addr = BTAddr,
channel = Channel,
+ packet_mod = PMod,
+ packet_st = PSt,
mod = Mod,
- func = Fun,
- args = Arg } = State) ->
+ func = Fun } = State) ->
?debug("~p:handle_info(data): Data: ~p", [ ?MODULE, Data]),
?info("~p:handle_info(data): From: ~p:~p ", [ ?MODULE, BTAddr, Channel]),
?info("~p:handle_info(data): ~p:~p -> ~p:~p",
[ ?MODULE, BTAddr, Channel, Mod, Fun]),
- Self = self(),
- spawn(fun() -> Mod:Fun(Self, BTAddr, Channel,
- data, Data, Arg) end),
-
- {noreply, State};
+ case PMod:decode(Data, fun(Elems) ->
+ handle_elements(Elems, State)
+ end, PSt) of
+ {ok, PSt1} ->
+ {noreply, State#st{packet_st = PSt1}};
+ {error, Reason} ->
+ ?error("decode failed: ~p", [Reason]),
+ {stop, Reason, State}
+ end;
handle_info({rfcomm, ConnRef, closed},
@@ -339,13 +371,32 @@ handle_info({rfcomm, ConnRef, error},
bt_connection_manager:delete_connection_by_pid(self()),
{stop, normal, State};
+handle_info({tcp, Sock, Data}, #st{remote_addr = IP,
+ channel = Port,
+ rfcomm_ref = Sock,
+ packet_mod = PMod,
+ packet_st = PSt} = St) ->
+ ?debug("handle_info(data): From: ~p:~p", [IP, Port]),
+ case PMod:decode(Data, fun(Elems) ->
+ handle_elements(Elems, St)
+ end, PSt) of
+ {ok, PSt1} ->
+ inet:setopts(Sock, [{active, once}]),
+ {noreply, St#st{packet_st = PSt1}};
+ {error, Reason} ->
+ ?error("decode failed, Reason = ~p", [Reason]),
+ {stop, Reason, St}
+ end;
handle_info({inet_async, _L, _Ref, {ok, Sock}} = Msg, #st{mod = Mod,
func = Fun,
args = Arg} = St) ->
?debug("~p:handle_info(~p)", [?MODULE, Msg]),
+ inet_db:register_socket(Sock, inet_tcp),
+ inet:setopts(Sock, [{active, once}]),
{ok, {BTAddr, Channel}} = inet:peername(Sock),
Mod:Fun(self(), BTAddr, Channel, accepted, Arg),
- {noreply, St};
+ {noreply, St#st{rfcomm_ref = Sock,
+ remote_addr = BTAddr}};
handle_info(_Info, State) ->
?warning("~p:handle_info(): Unknown info: ~p", [ ?MODULE, _Info]),
@@ -380,3 +431,14 @@ code_change(_OldVsn, State, _Extra) ->
%%%===================================================================
%%% Internal functions
%%%===================================================================
+get_module_config(Key, Default, CS) ->
+ rvi_common:get_module_config(dlink_tcp, dlink_tcp_rpc, Key, Default, CS).
+
+handle_elements(Elements, #st{remote_addr = BTAddr,
+ channel = Channel,
+ mod = Mod,
+ func = Fun,
+ args = Arg}) ->
+ ?debug("data complete; processed: ~p",
+ [authorize_keys:abbrev(Elements)]),
+ Mod:Fun(self(), BTAddr, Channel, data, Elements, Arg).