diff options
author | Magnus Feuer <mfeuer@jaguarlandrover.com> | 2015-05-22 16:30:34 -0700 |
---|---|---|
committer | Magnus Feuer <mfeuer@jaguarlandrover.com> | 2015-06-09 13:51:45 -0700 |
commit | 618aab876be2c248046fec367c3c62c9584be78f (patch) | |
tree | 310e452f279c3e8fceb5475001dfe1017dd5c0f0 /components/dlink_bt | |
parent | adaea0388918bf1c196a4faa6e181c704307caff (diff) | |
download | rvi_core-618aab876be2c248046fec367c3c62c9584be78f.tar.gz |
Now receives incoming calls, connects to remote servers, and reports services.
Diffstat (limited to 'components/dlink_bt')
-rw-r--r-- | components/dlink_bt/src/bt_connection.erl | 134 | ||||
-rw-r--r-- | components/dlink_bt/src/bt_gen_nb_server.erl | 205 | ||||
-rw-r--r-- | components/dlink_bt/src/bt_listener.erl | 54 | ||||
-rw-r--r-- | components/dlink_bt/src/dlink_bt_rpc.erl | 278 |
4 files changed, 296 insertions, 375 deletions
diff --git a/components/dlink_bt/src/bt_connection.erl b/components/dlink_bt/src/bt_connection.erl index c57b108..ab6d5da 100644 --- a/components/dlink_bt/src/bt_connection.erl +++ b/components/dlink_bt/src/bt_connection.erl @@ -25,8 +25,8 @@ -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]). --export([setup/6]). --export([accept/6]). +-export([connect/5]). +-export([accept/5]). -export([send/2]). -export([send/3]). -export([is_connection_up/1]). @@ -40,7 +40,6 @@ -record(st, { remote_addr = "00:00:00:00:00:00", channel = 0, - parent_pid = undefined, rfcomm_ref = undefined, mod = undefined, func = undefined, @@ -52,16 +51,15 @@ %%%=================================================================== %% MFA is to deliver data received on the socket. -setup(Addr, Channel, Ref, Mod, Fun, Arg) -> +connect(Addr, Channel, Mod, Fun, Arg) -> gen_server:start_link(?MODULE, - {connect, Addr, Channel, Ref, Mod, Fun, Arg }, + {connect, Addr, Channel, Mod, Fun, Arg }, []). -accept(Channel, ListenRef, ParentPid, Mod, Fun, Arg) -> +accept(Channel, ListenRef, Mod, Fun, Arg) -> gen_server:start_link(?MODULE, {accept, Channel, ListenRef, - ParentPid, Mod, Fun, Arg},[]). @@ -70,7 +68,7 @@ send(Pid, Data) when is_pid(Pid) -> gen_server:cast(Pid, {send, Data}). send(Addr, Channel, Data) -> - case connection_manager:find_connection_by_address(Addr, Channel) of + case bt_connection_manager:find_connection_by_address(Addr, Channel) of {ok, Pid} -> gen_server:cast(Pid, {send, Data}); @@ -85,7 +83,7 @@ terminate_connection(Pid) when is_pid(Pid) -> gen_server:call(Pid, terminate_connection). terminate_connection(Addr, Channel) -> - case connection_manager:find_connection_by_address(Addr, Channel) of + case bt_connection_manager:find_connection_by_address(Addr, Channel) of {ok, Pid} -> gen_server:call(Pid, terminate_connection); @@ -97,7 +95,7 @@ is_connection_up(Pid) when is_pid(Pid) -> is_process_alive(Pid). is_connection_up(Addr, Channel) -> - case connection_manager:find_connection_by_address(Addr, Channel) of + case bt_connection_manager:find_connection_by_address(Addr, Channel) of {ok, Pid} -> is_connection_up(Pid); @@ -123,22 +121,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, ConnRef, Mod, Fun, Arg}) -> - connection_manager:add_connection(BTAddr, Channel, self()), - - ?debug("connection:init(): self(): ~p", [self()]), - ?debug("connection:init(): BTAddr: ~p", [BTAddr]), - ?debug("connection:init(): Channel: ~p", [Channel]), - ?debug("connection:init(): Ref: ~p", [ConnRef]), - ?debug("connection:init(): Module: ~p", [Mod]), - ?debug("connection:init(): Function: ~p", [Fun]), - ?debug("connection:init(): Arg: ~p", [Arg]), - - %% Grab socket control +init({connect, BTAddr, Channel, Mod, Fun, Arg}) -> + + %% connect will block on rfcomm:open, so cast to self + %% in order to let init return. + gen_server:cast(self(), connect), {ok, #st{ remote_addr = BTAddr, channel = Channel, - rfcomm_ref = ConnRef, + rfcomm_ref = undefined, mod = Mod, func = Fun, args = Arg @@ -146,18 +137,18 @@ init({connect, BTAddr, Channel, ConnRef, Mod, Fun, Arg}) -> -init({accept, Channel, ListenRef, ParentPid, Mod, Fun, Arg}) -> +init({accept, Channel, ListenRef, Mod, Fun, Arg}) -> { ok, ARef } = rfcomm:accept(ListenRef, infinity, self()), - ?debug("bt_connection:init(): self(): ~p", [self()]), - ?debug("bt_connection:init(): Channel: ~p", [Channel]), - ?debug("bt_connection:init(): ParentPid: ~p", [ParentPid]), - ?debug("bt_connection:init(): Module: ~p", [Mod]), - ?debug("bt_connection:init(): Function: ~p", [Fun]), - ?debug("bt_connection:init(): Arg: ~p", [Arg]), + ?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]), {ok, #st{ channel = Channel, - parent_pid = ParentPid, rfcomm_ref = ARef, mod = Mod, func = Fun, @@ -201,11 +192,45 @@ handle_call(_Request, _From, State) -> %% {stop, Reason, State} %% @end %%-------------------------------------------------------------------- +handle_cast(connect, #st { + remote_addr = BTAddr, + channel = Channel, + mod = Mod, + func = Fun, + args = Arg + } = St) -> + + %% Looong call that blocks for ever. + case rfcomm:open(BTAddr, Channel) of + {ok, ConnRef} -> + ?debug("bt_connection:init(connect): self(): ~p", [self()]), + ?debug("bt_connection:init(connect): BTAddr: ~p", [BTAddr]), + ?debug("bt_connection:init(connect): Channel: ~p", [Channel]), + ?debug("bt_connection:init(connect): Ref: ~p", [ConnRef]), + ?debug("bt_connection:init(connect): Module: ~p", [Mod]), + ?debug("bt_connection:init(connect): Function: ~p", [Fun]), + ?debug("bt_connection:init(connect): Arg: ~p", [Arg]), + + %% Add to managed connections, + bt_connection_manager:add_connection(BTAddr, Channel, self()), + + Mod:Fun(self(), BTAddr, Channel, connected, Arg), + + %% Update state with new connection + {noreply, St#st{ + rfcomm_ref = ConnRef + }}; + + { err, Error } -> + ?info("Failed to connect to ~p-~p", [ BTAddr, Channel]), + { stop, { connect_failed, Error}, St } + end; + handle_cast({send, Data}, St) -> ?debug("~p:handle_call(send): Sending: ~p", [ ?MODULE, Data]), -%% gen_tcp:send(St#st.sock, term_to_binary(Data)), + rfcomm:send(St#st.rfcomm_ref, Data), {noreply, St}; @@ -226,37 +251,34 @@ handle_cast(_Msg, State) -> %% An accept reference we've setup now has accetpted an %% incoming connection. -handle_info({ARef, {accept, BTAddr, Channel} }, - #st { rfcomm_ref = ConnRef, - parent_pid = PPid } = St) - when ConnRef =:= ARef -> - io:format("bt_connection from ~w:~w\n", [BTAddr,Channel]), - PPid ! {accept, ARef, Channel, ok}, +handle_info({rfcomm, _ARef, { accept, BTAddr, _ } }, + #st { mod = Mod, + func = Fun, + args = Arg, + channel = Channel } = St) -> + + ?info("~p:handle_info(): bt_connection from ~w:~w\n", + [?MODULE, BTAddr,Channel]), + + Mod:Fun(self(), BTAddr, Channel, accepted, Arg), { noreply, St#st { remote_addr = BTAddr, channel = Channel } }; -handle_info({tcp, _ConnRef, Data}, + +handle_info({rfcomm, _ConnRef, {data, Data}}, #st { remote_addr = BTAddr, channel = Channel, mod = Mod, func = Fun, args = Arg } = State) -> ?debug("~p:handle_info(data): Data: ~p", [ ?MODULE, Data]), - ?debug("~p:handle_info(data): From: ~p:~p ", [ ?MODULE, BTAddr, Channel]), - - try binary_to_term(Data) of - Term -> - ?debug("~p:handle_info(data): Term: ~p", [ ?MODULE, Term]), - FromPid = self(), - spawn(fun() -> Mod:Fun(FromPid, BTAddr, Channel, - data, Term, Arg) end) - catch - _:_ -> - ?warning("~p:handle_info(data): Data could not be decoded: ~pp", - [ ?MODULE, Data]) - - end, -%% inet:setopts(Sock, [{active, once}]), + ?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}; @@ -268,7 +290,7 @@ handle_info({rfcomm_closed, ConnRef}, args = Arg } = State) -> ?debug("~p:handle_info(tcp_closed): BTAddr: ~p:~p ", [ ?MODULE, BTAddr, Channel]), Mod:Fun(self(), BTAddr, Channel, closed, Arg), - connection_manager:delete_connection_by_pid(self()), + bt_connection_manager:delete_connection_by_pid(self()), rfcomm_close:close(ConnRef), {stop, normal, State}; @@ -283,7 +305,7 @@ handle_info({rfcomm_error, ConnRef}, ?debug("~p:handle_info(tcp_error): BTAddr: ~p:~p ", [ ?MODULE, BTAddr, Channel]), Mod:Fun(self(), BTAddr, Channel, error, Arg), rfcomm:close(ConnRef), - connection_manager:delete_connection_by_pid(self()), + bt_connection_manager:delete_connection_by_pid(self()), {stop, normal, State}; diff --git a/components/dlink_bt/src/bt_gen_nb_server.erl b/components/dlink_bt/src/bt_gen_nb_server.erl deleted file mode 100644 index 4a9a630..0000000 --- a/components/dlink_bt/src/bt_gen_nb_server.erl +++ /dev/null @@ -1,205 +0,0 @@ -%% Copyright (c) 2009 Hypothetical Labs, Inc. - -%% Permission is hereby granted, free of charge, to any person obtaining a copy -%% of this software and associated documentation files (the "Software"), to deal -%% in the Software without restriction, including without limitation the rights -%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -%% copies of the Software, and to permit persons to whom the Software is -%% furnished to do so, subject to the following conditions: -%% -%% The above copyright notice and this permission notice shall be included in -%% all copies or substantial portions of the Software. -%% -%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -%% THE SOFTWARE. - --module(bt_gen_nb_server). - --author('kevin@hypotheticalabs.com'). - --behaviour(gen_server). - -%% API --export([start_link/2, - start_link/3, - get_cb_state/1, - store_cb_state/2, - add_listen_socket/2, - remove_listen_socket/2]). - -%% Behavior callbacks --export([behaviour_info/1]). - -%% gen_server callbacks --export([init/1, - handle_call/3, - handle_cast/2, - handle_info/2, - terminate/2, - code_change/3]). - --define(SERVER, ?MODULE). - --record(state, {cb, - addrs=dict:new(), - socks=dict:new(), - server_state}). - -%% @hidden -behaviour_info(callbacks) -> - [{init, 2}, - {handle_call, 3}, - {handle_cast, 2}, - {handle_info, 2}, - {terminate, 2}, - {sock_opts, 0}, - {new_connection, 4}]; - -behaviour_info(_) -> - undefined. - -%% @doc Start server listening on BTAddr:Channel --spec start_link(atom(), [any()]) -> ok | ignore | {error, any()}. -start_link(CallbackModule, InitParams) -> - gen_server:start_link(?MODULE, [CallbackModule, InitParams], [{fullsweep_after, 0}]). - - -%% @doc Start server listening on BTAddr:Channel registered as Name --spec start_link(atom(), atom(), [any()]) -> ok | ignore | {error, any()}. -start_link(Name, CallbackModule, InitParams) -> - gen_server:start_link(Name, ?MODULE, [CallbackModule, InitParams], [{fullsweep_after, 0}]). - -%% @doc Extracts the callback module's state from the server's overall state -%% NOTE: Should only be called by the submodule --spec get_cb_state(#state{}) -> any(). -get_cb_state(#state{server_state=SState}) -> - SState. - -%% @doc Stores the callback module's state into the server's state -%% NOTE: Should only be called by the submodule --spec store_cb_state(any(), #state{}) -> #state{}. -store_cb_state(CBState, State) when is_record(State, state) -> - State#state{server_state=CBState}. - -%% @doc Adds a new listener socket to be managed by gen_nb_server -%% NOTE: Should only be called by the submodule --spec add_listen_socket({string(), integer()}, #state{}) -> {ok, #state{}} | {error, any()}. -add_listen_socket({BTAddr, Channel}, #state{cb=Callback, addrs=Addrs, socks=Socks}=State) -> - Key = {BTAddr, Channel}, - case dict:find(Key, Socks) of - {ok, _} -> - {error, already_listening}; - error -> - case rfcomm:listen(Channel) of - {ok, Sock} -> - {ok, State#state{socks=dict:store(Key, Sock, Socks), - addrs=dict:store(Sock, Key, Addrs)}}; - Error -> - Error - end - end. - -%% @doc Removes a new listener socket to be managed by gen_nb_server -%% NOTE: Should only be called by the submodule --spec remove_listen_socket({string(), integer()}, #state{}) -> {error, not_listening} | {ok, #state{}}. -remove_listen_socket({BTAddr, Channel}, #state{socks=Socks, addrs=Addrs}=State) -> - Key = {BTAddr, Channel}, - case dict:find(Key, Socks) of - error -> - {error, not_listening}; - {ok, Sock} -> - rfcomm:close(Sock), - {ok, State#state{socks=dict:erase(Key, Socks), - addrs=dict:erase(Sock, Addrs)}} - end. - -%% @doc Returns the callback module's state --spec init([atom()|any()]) -> {ok, #state{}} | {error, bad_init_state} | {error, any()}. - -init([CallbackModule, InitParams]) -> - process_flag(trap_exit, true), - State = #state{cb=CallbackModule}, - case CallbackModule:init(InitParams, State) of - {ok, ServerState} when is_record(ServerState, state) -> - {ok, ServerState}; - {ok, _State} -> - {error, bad_init_state}; - Err -> - Err - end. - -%% @hidden -handle_call(Request, From, #state{cb=Callback}=State) -> - case Callback:handle_call(Request, From, State) of - {reply, Reply, NewServerState} -> - {reply, Reply, NewServerState}; - {reply, Reply, NewServerState, Arg} when Arg =:= hibernate orelse is_number(Arg) -> - {reply, Reply, NewServerState, Arg}; - {noreply, NewServerState} -> - {noreply, NewServerState}; - {noreply, NewServerState, Arg} when Arg =:= hibernate orelse is_number(Arg) -> - {noreply, NewServerState, Arg}; - {stop, Reason, NewServerState} -> - {stop, Reason, NewServerState}; - {stop, Reason, Reply, NewServerState} -> - {stop, Reason, Reply, NewServerState} - end. - -%% @hidden -handle_cast(Msg, #state{cb=Callback}=State) -> - case Callback:handle_cast(Msg, State) of - {noreply, NewServerState} -> - {noreply, NewServerState}; - {noreply, NewServerState, Arg} when Arg =:= hibernate orelse is_number(Arg) -> - {noreply, NewServerState, Arg}; - {stop, Reason, NewServerState} -> - {stop, Reason, NewServerState} - end. - -%% @hidden -handle_info({inet_async, ListSock, _Ref, {ok, CliSocket}}, #state{cb=Callback, addrs=Addrs}=State) -> - inet_db:register_socket(CliSocket, inet_tcp), - {BTAddr, Channel} = dict:fetch(ListSock, Addrs), - case Callback:new_connection(BTAddr, Channel, CliSocket, State) of - {ok, NewServerState} -> - prim_inet:async_accept(ListSock, -1), - {noreply, NewServerState}; - {stop, Reason, NewServerState} -> - {stop, Reason, NewServerState} - end; - -handle_info(Info, #state{cb=Callback}=State) -> - case Callback:handle_info(Info, State) of - {noreply, NewServerState} -> - {noreply, NewServerState}; - {noreply, NewServerState, Arg} when Arg =:= hibernate orelse is_number(Arg) -> - {noreply, NewServerState, Arg}; - {stop, Reason, NewServerState} -> - {stop, Reason, NewServerState} - end. - -%% @hidden -terminate(Reason, #state{cb=Callback, addrs=Addrs}=State) -> - [gen_tcp:close(Sock) || Sock <- dict:fetch_keys(Addrs)], - State1 = State#state{addrs=dict:new(), socks=dict:new()}, - Callback:terminate(Reason, State1), - ok. - -%% @hidden -code_change(_OldVsn, State, _Extra) -> - {ok, State}. - - -%% @hidden -%% @spec convert(Addr) -> Result -%% Addr = string() -%% Result = {integer(), integer(), integer(), integer()} -%% @doc Converts text IP addresses "0.0.0.0" to tuples {0, 0, 0, 0} -convert(Addr) -> - T = string:tokens(Addr, "."), - list_to_tuple([list_to_integer(X) || X <- T]). diff --git a/components/dlink_bt/src/bt_listener.erl b/components/dlink_bt/src/bt_listener.erl index 2ec3c39..b0c08ab 100644 --- a/components/dlink_bt/src/bt_listener.erl +++ b/components/dlink_bt/src/bt_listener.erl @@ -11,7 +11,7 @@ -module(bt_listener). -include_lib("lager/include/log.hrl"). - +-include_lib("rvi_common/include/rvi_common.hrl"). -export([start_link/0, add_listener/1, remove_listener/1]). @@ -20,7 +20,9 @@ -export([terminate/2]). -record(st, {listeners = [], - acceptors = []}). + acceptors = [], + cs = #component_spec{} + }). start_link() -> @@ -33,27 +35,42 @@ remove_listener(Channel) -> gen_server:call(?MODULE, {remove_listener, Channel}). init([]) -> - {ok, #st { listeners = [] }}. + + {ok, #st { + listeners = [], + acceptors = [], + cs = rvi_common:get_component_specification() + } + }. -handle_call({add_listener, Channel}, _From, State) -> +handle_call({add_listener, Channel}, _From, St) -> ?info("bt_listener:add_listener(): Setting up listener on channel ~p", [ Channel]), case rfcomm:listen(Channel) of {ok, ListenRef} -> ?info("bt_listener:add_listener(): ListenRef: ~p", [ ListenRef]), - { noreply, NSt} = handle_info({accept, ListenRef, Channel, ok}, State), + {ok, ConnPid} = bt_connection:accept(Channel, + ListenRef, + dlink_bt_rpc, + handle_socket, + St#st.cs), + + + + %%{ noreply, NSt} = handle_info({accept, ListenRef, Channel, ok}, St), { reply, ok, - NSt#st { - listeners = [ { ListenRef, Channel } | NSt#st.listeners ] + St#st { + acceptors = [ { Channel, ConnPid } | St#st.acceptors ], + listeners = [ { ListenRef, Channel } | St#st.listeners ] } }; Err -> ?info("bt_listener:add_listener(): Failed: ~p", [ Err]), - {reply, Err, State} + {reply, Err, St} end; @@ -67,22 +84,25 @@ handle_call(_Msg, _From, State) -> handle_cast(_Msg, State) -> {noreply, State}. -handle_info({accept, ListenRef, Channel, ok} , St) -> +handle_info({accept, ListenRef, BTAddr, Channel, ok} , St) -> %% Fire up a new process to handle the %% future incoming connection. ?info("bt_listener:accept(): ListenRef: ~p", [ ListenRef]), - - {ok, ConnPid} = bt_connection:accept(Channel, - ListenRef, - self(), - dlink_bt_rpc, - handle_socket, - nil), + ?info("bt_listener:accept(): Remote: ~p-~p", [BTAddr, Channel ]), + + %% Must fix multiple acceptors in bt_linux_drv.c + %% {ok, ConnPid} = bt_connection:accept(Channel, + %% ListenRef, + %% dlink_bt_rpc, + %% handle_socket, + %% []), - {noreply, St#st {acceptors = [ { Channel, ConnPid } | St#st.acceptors ]}}; + %% {noreply, St#st {acceptors = [ { Channel, ConnPid } | St#st.acceptors ]}}; + {noreply, St }; handle_info(_Msg, State) -> + ?info("bt_listener:handle_info(): Unknown: ~p", [ _Msg]), {noreply, State}. diff --git a/components/dlink_bt/src/dlink_bt_rpc.erl b/components/dlink_bt/src/dlink_bt_rpc.erl index ddcd34b..745dd9d 100644 --- a/components/dlink_bt/src/dlink_bt_rpc.erl +++ b/components/dlink_bt/src/dlink_bt_rpc.erl @@ -35,6 +35,7 @@ -include_lib("lager/include/log.hrl"). -include_lib("rvi_common/include/rvi_common.hrl"). +-define(PERSISTENT_CONNECTIONS, persistent_connections). -define(DEFAULT_BT_CHANNEL, 1). -define(DEFAULT_RECONNECT_INTERVAL, 1000). -define(DEFAULT_PING_INTERVAL, 300000). %% Five minutes @@ -63,6 +64,21 @@ start_link() -> gen_server:start_link({local, ?SERVER}, ?MODULE, [], []). +tohex(V) when V < 16 -> + "0" ++ integer_to_list(V, 16); + +tohex(V) -> + integer_to_list(V, 16). + +bt_address_to_string({A1, A2, A3, A4, A5, A6}) -> + tohex(A1) ++ ":" ++ + tohex(A2) ++ ":" ++ + tohex(A3) ++ ":" ++ + tohex(A4) ++ ":" ++ + tohex(A5) ++ ":" ++ + tohex(A6). + + init([]) -> ?info("dlink_bt:init(): Called"), %% Dig out the bert rpc server setup @@ -115,8 +131,28 @@ start_connection_manager() -> ok end, + {ok, PersistentConnections } = rvi_common:get_module_config(data_link, + ?MODULE, + ?PERSISTENT_CONNECTIONS, + [], + CompSpec), + + setup_persistent_connections_(PersistentConnections, CompSpec), + ok. + + +setup_persistent_connections_([ ], _CompSpec) -> + ok; + + +setup_persistent_connections_([ BTAddress | T], CompSpec) -> + ?debug("~p: Will persistently connect connect : ~p", [self(), BTAddress]), + [ BTAddr, Channel] = string:tokens(BTAddress, "-"), + connect_and_retry_remote(BTAddr, Channel, CompSpec), + setup_persistent_connections_(T, CompSpec), ok. + service_available(CompSpec, SvcName, DataLinkModule) -> rvi_common:notification(data_link, ?MODULE, service_available, @@ -170,21 +206,13 @@ connect_remote(BTAddr, Channel, CompSpec) -> [BTAddr, Channel]), %%FIXME - case rfcomm:open(BTAddr, Channel) of - { ok, Ref } -> - ?info("dlink_bt:connect_remote(): Connected ~p:~p", - [BTAddr, Channel]), - - %% Setup a genserver around the new connection. - {ok, Pid } = connection:setup(BTAddr, Channel, Ref, - ?MODULE, handle_socket, CompSpec ), - - %% Send authorize - { LocalBTAddr, LocalChannel} = rvi_common:node_address_tuple(), - connection:send(Pid, - { authorize, - 1, LocalBTAddr, LocalChannel, rvi_binary, - { certificate, {}}, { signature, {}} }), + %% Setup a genserver around the new connection. + case bt_connection:connect(BTAddr, Channel, + ?MODULE, handle_socket, CompSpec ) of + { ok, Pid } -> + ?info("dlink_bt:connect_remote(): Connection in progress ~p:~p - Proc ~p", + [BTAddr, Channel, Pid]), + ok; {error, Err } -> @@ -222,9 +250,9 @@ announce_local_service_(CompSpec, [ConnPid | T], Service, Availability) -> - Res = connection:send(ConnPid, - {service_announce, 3, Availability, - [Service], { signature, {}}}), + Res = bt_connection:send(ConnPid, + term_to_binary({service_announce, 3, Availability, + [Service], { signature, {}}})), ?debug("dlink_bt:announce_local_service(~p: ~p) -> ~p Res: ~p", [ Availability, Service, ConnPid, Res]), @@ -235,30 +263,78 @@ announce_local_service_(CompSpec, Service, Availability). announce_local_service_(CompSpec, Service, Availability) -> + ?debug("dlink_bt:announce_local_service(~p, ~p)", + [ Service, Availability]), + announce_local_service_(CompSpec, get_connections(), Service, Availability). -handle_socket(_FromPid, PeerBTAddr, PeerChannel, data, ping, [_CompSpec]) -> - ?info("dlink_bt:ping(): Pinged from: ~p:~p", [ PeerBTAddr, PeerChannel]), +process_data(_FromPid, RemoteBTAddr, RemoteChannel, ProtocolMod, Data, CompSpec) -> + ?debug("dlink_bt:receive_data(): SetupAddress: {~p, ~p}", [ RemoteBTAddr, RemoteChannel ]), + ProtocolMod:receive_message(CompSpec, Data), + ok. + + +process_announce(FromPid, RemoteBTAddr, RemoteChannel, + TransactionID, available, Services, + Signature, CompSpec) -> + ?debug("dlink_bt:service_announce(available): Address: ~p-~p", [ RemoteBTAddr, RemoteChannel ]), + ?debug("dlink_bt:service_announce(available): TransactionID: ~p", [ TransactionID ]), + ?debug("dlink_bt:service_announce(available): Signature: ~p", [ Signature ]), + ?debug("dlink_bt:service_announce(available): Service: ~p", [ Services ]), + + + %% Register the received services with all relevant components + + add_services(Services, FromPid), + + service_discovery_rpc:register_services(CompSpec, Services, ?MODULE), ok; -handle_socket(FromPid, PeerBTAddr, PeerChannel, data, - { authorize, - TransactionID, - RemoteAddress, - RemoteChannel, - Protocol, - Certificate, - Signature}, [CompSpec]) -> - - ?info("dlink_bt:authorize(): Peer Address: ~p:~p", [PeerBTAddr, PeerChannel ]), + +process_announce(FromPid, + RemoteBTAddr, + RemoteChannel, + TransactionID, + unavailable, + Services, + Signature , + CompSpec) -> + ?debug("dlink_bt:service_announce(unavailable): Address: ~p-~p", + [ RemoteBTAddr, RemoteChannel ]), + ?debug("dlink_bt:service_announce(unavailable): TransactionID: ~p", + [ TransactionID ]), + ?debug("dlink_bt:service_announce(unavailable): Signature: ~p", + [ Signature ]), + ?debug("dlink_bt:service_announce(unavailable): Service: ~p", + [ Services ]), + + + %% Delete from our own tables. + + delete_services(FromPid, Services), + service_discovery_rpc:unregister_services(CompSpec, Services, ?MODULE), + ok. + +process_authorize(FromPid, + PeerBTAddr, + PeerBTChannel, + TransactionID, + RemoteAddress, + RemoteChannel, + Protocol, + Certificate, + Signature, + CompSpec) -> + + ?info("dlink_bt:authorize(): Peer Address: ~p:~p", [PeerBTAddr, PeerBTChannel ]), ?info("dlink_bt:authorize(): Remote Address: ~p~p", [ RemoteAddress, RemoteChannel ]), - ?info("dlink_bt:authorize(): Protocol: ~p", [ Protocol ]), - ?debug("dlink_bt:authorize(): TransactionID: ~p", [ TransactionID ]), - ?debug("dlink_bt:authorize(): Certificate: ~p", [ Certificate ]), - ?debug("dlink_bt:authorize(): Signature: ~p", [ Signature ]), + ?info("dlink_bt:authorize(): Protocol: ~p", [ Protocol ]), + ?debug("dlink_bt:authorize(): TransactionID: ~p", [ TransactionID ]), + ?debug("dlink_bt:authorize(): Certificate: ~p", [ Certificate ]), + ?debug("dlink_bt:authorize(): Signature: ~p", [ Signature ]), { LocalAddress, LocalChannel } = rvi_common:node_address_tuple(), @@ -269,15 +345,16 @@ handle_socket(FromPid, PeerBTAddr, PeerChannel, data, %% a service announce %% FIXME: Validate certificate and signature before continuing. - case connection_manager:find_connection_by_pid(FromPid) of + case bt_connection_manager:find_connection_by_pid(FromPid) of not_found -> ?info("dlink_bt:authorize(): New connection!"), - connection_manager:add_connection(RemoteAddress, RemoteChannel, FromPid), + bt_connection_manager:add_connection(RemoteAddress, RemoteChannel, FromPid), ?debug("dlink_bt:authorize(): Sending authorize."), - Res = connection:send(FromPid, - { authorize, - 1, LocalAddress, LocalChannel, rvi_binary, - {certificate, {}}, { signature, {}}}), + Res = bt_connection:send(FromPid, + term_to_binary( + { authorize, + 1, LocalAddress, LocalChannel, rvi_json, + {certificate, {}}, { signature, {}}})), ?debug("dlink_bt:authorize(): Sending authorize: ~p", [ Res]), ok; _ -> ok @@ -292,72 +369,55 @@ handle_socket(FromPid, PeerBTAddr, PeerChannel, data, ?info("dlink_bt:authorize(): Announcing local services: ~p to remote ~p:~p", [LocalServices, RemoteAddress, RemoteChannel]), - connection:send(FromPid, - { service_announce, 2, available, - LocalServices, { signature, {}}}), + bt_connection:send(FromPid, + term_to_binary( + { service_announce, 2, available, + LocalServices, { signature, {}}})), %% Setup ping interval gen_server:call(?SERVER, { setup_initial_ping, RemoteAddress, RemoteChannel, FromPid }), - ok; - -handle_socket(FromPid, RemoteBTAddr, RemoteChannel, data, - { service_announce, - TransactionID, - available, - Services, - Signature }, [CompSpec]) -> - ?debug("dlink_bt:service_announce(available): Address: ~p:~p", [ RemoteBTAddr, RemoteChannel ]), - ?debug("dlink_bt:service_announce(available): Remote Channel: ~p", [ RemoteChannel ]), - ?debug("dlink_bt:service_announce(available): TransactionID: ~p", [ TransactionID ]), - ?debug("dlink_bt:service_announce(available): Signature: ~p", [ Signature ]), - ?debug("dlink_bt:service_announce(available): Service: ~p", [ Services ]), - - - add_services(Services, FromPid), - - service_discovery_rpc:register_services(CompSpec, Services, ?MODULE), - ok; - + ok. -handle_socket(FromPid, RemoteBTAddr, RemoteChannel, data, - { service_announce, - TransactionID, - unavailable, - Services, - Signature}, [CompSpec]) -> - ?debug("dlink_bt:service_announce(unavailable): Address: ~p:~p", [ RemoteBTAddr, RemoteChannel ]), - ?debug("dlink_bt:service_announce(unavailable): Remote Channel: ~p", [ RemoteChannel ]), - ?debug("dlink_bt:service_announce(unavailable): TransactionID: ~p", [ TransactionID ]), - ?debug("dlink_bt:service_announce(unavailable): Signature: ~p", [ Signature ]), - ?debug("dlink_bt:service_announce(unavailable): Service: ~p", [ Services ]), - %% Register the received services with all relevant components - - - %% Delete from our own tables. - - delete_services(FromPid, Services), - service_discovery_rpc:unregister_services(CompSpec, Services, ?MODULE), - ok; +handle_socket(FromPid, PeerBTAddr, PeerChannel, data, + Data, CompSpec) -> + + try binary_to_term(Data) of + { authorize, TransactionID, RemoteAddress, RemoteChannel, + Protocol, Certificate, Signature} -> + process_authorize(FromPid, PeerBTAddr, RemoteChannel, + TransactionID, RemoteAddress, RemoteChannel, + Protocol, Certificate, Signature, CompSpec); + + { service_announce, TransactionID, Available, Services, Signature } -> + process_announce(FromPid, PeerBTAddr, PeerChannel, + TransactionID, Available, Services, + Signature, CompSpec); + + { receive_data, ProtocolMod, Data } -> + process_data(FromPid, PeerBTAddr, PeerChannel, + ProtocolMod, Data, CompSpec); + ping -> + ?info("dlink_bt:ping(): Pinged from: ~p:~p", [ PeerBTAddr, PeerChannel]), + ok; -handle_socket(_FromPid, SetupBTAddr, SetupChannel, data, - { receive_data, ProtocolMod, Data}, [CompSpec]) -> -%% ?info("dlink_bt:receive_data(): ~p", [ Data ]), - ?debug("dlink_bt:receive_data(): SetupAddress: {~p, ~p}", [ SetupBTAddr, SetupChannel ]), - ProtocolMod:receive_message(CompSpec, Data), - ok; + Unknown -> + ?warning("dlink_bt:handle_socket(): Unknown data: ~p", [ Unknown]), + ok + catch + _:_ -> + ?warning("dlink_bt:handle_socket(data): Data could not be decoded: ~p", + [ Data]), + ok + end. -handle_socket(_FromPid, SetupBTAddr, SetupChannel, data, Data, [_CompSpec]) -> - ?warning("dlink_bt:unknown_data(): SetupAddress: {~p, ~p}", [ SetupBTAddr, SetupChannel ]), - ?warning("dlink_bt:unknown_data(): Unknown data: ~p", [ Data]), - ok. %% We lost the socket connection. %% Unregister all services that were routed to the remote end that just died. -handle_socket(FromPid, SetupBTAddr, SetupChannel, closed, [CompSpec]) -> +handle_socket(FromPid, SetupBTAddr, SetupChannel, closed, CompSpec) -> ?info("dlink_bt:closed(): SetupAddress: {~p, ~p}", [ SetupBTAddr, SetupChannel ]), NetworkAddress = SetupBTAddr ++ "-" ++ integer_to_list(SetupChannel), @@ -398,11 +458,33 @@ handle_socket(FromPid, SetupBTAddr, SetupChannel, closed, [CompSpec]) -> end, ok; +handle_socket(FromPid, SetupBTAddr, SetupChannel, connected, _ExtraArgs) -> + ?info("dlink_bt:handle_socket(connected): {~p, ~p}", [ SetupBTAddr, SetupChannel ]), + + {ok,[{address, Address }]} = bt_drv:local_info([address]), + + bt_connection:send(FromPid, + term_to_binary( + { authorize, + 1, + bt_address_to_string(Address), + SetupChannel, rvi_json, + { certificate, {}}, { signature, {}} })), + ok; + + +handle_socket(_FromPid, SetupBTAddr, SetupChannel, accepted, _ExtraArgs) -> + ?info("dlink_bt:handle_socket(accepted): {~p, ~p}", [ SetupBTAddr, SetupChannel ]), + ok; + handle_socket(_FromPid, SetupBTAddr, SetupChannel, error, _ExtraArgs) -> ?info("dlink_bt:socket_error(): SetupAddress: {~p, ~p}", [ SetupBTAddr, SetupChannel ]), ok. + + + %% JSON-RPC entry point %% CAlled by local exo http server handle_notification("service_available", Args) -> @@ -517,7 +599,7 @@ handle_call({rvi, setup_data_link, [ Service, Opts ]}, _From, St) -> handle_call({rvi, disconnect_data_link, [NetworkAddress] }, _From, St) -> [ Address, Channel] = string:tokens(NetworkAddress, "-"), - Res = connection:terminate_connection(Address,Channel), + Res = bt_connection:terminate_connection(Address,Channel), { reply, [ Res ], St }; @@ -530,7 +612,9 @@ handle_call({rvi, send_data, [ProtoMod, Service, Data, _DataLinkOpts]}, _From, S %% FIXME: What to do if we have multiple connections to the same service? [ConnPid | _T] -> - Res = connection:send(ConnPid, {receive_data, ProtoMod, Data}), + Res = bt_connection:send(ConnPid, + term_to_binary( + {receive_data, ProtoMod, Data})), { reply, [ Res ], St} end; @@ -562,10 +646,10 @@ handle_call(Other, _From, St) -> handle_info({ rvi_ping, Pid, Address, Channel, Timeout}, St) -> %% Check that connection is up - case connection:is_connection_up(Pid) of + case bt_connection:is_connection_up(Pid) of true -> ?info("dlink_bt:ping(): Pinging: ~p:~p", [Address, Channel]), - connection:send(Pid, ping), + bt_connection:send(Pid, term_to_binary(ping)), erlang:send_after(Timeout, self(), { rvi_ping, Pid, Address, Channel, Timeout }); |