diff options
Diffstat (limited to 'components/dlink_bt/src/bt_connection.erl')
-rw-r--r-- | components/dlink_bt/src/bt_connection.erl | 144 |
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). |