📄 ag_connect.c
字号:
/* connects to the remote device */
#include "ag_private.h"
#include "ag_types.h"
#include "ag.h"
#include <sched.h>
#include <stdlib.h>
#include <message.h>
#include <print.h>
/*
connectStatus
Translates between the CCM_status flag and its equivalent AG connection status
flag. This is so the Connection Manager is completely transparent to the client
*/
static ag_connection_status_t connectStatus(connect_status_t cm_status)
{
switch(cm_status)
{
case CmConnectComplete:
return AgConnectComplete;
case CmConnectTimeout:
return AgConnectTimeout;
case CmConnectCancelled:
return AgConnectCancelled;
case CmConnectDisconnect:
return AgConnectDisconnect;
case CmConnectDisconnectAbnormal:
return AgConnectDisconnectAbnormal;
case CmConnectFailed:
return AgConnectFailed;
case CmConnectRemoteRefusal:
return AgConnectRemoteRefusal;
case CmConnectServiceNotSupported:
return AgConnectServiceNotSupported;
default:
PRINT(("ag_connect: Unknown connection status %d\n", cm_status));
break;
}
return (ag_connection_status_t) cm_status;
}
/*
sendConnectionHandle
Send the allocated handle to the client.
*/
static void sendConnectionHandle(ag_handle_t hdl, bd_addr_t addr)
{
/* Pass these to the interface to do with as it pleases */
handleConnectionHandleMap(hdl, addr);
}
/*
allocHandleFromAddress
Takes a dvice address and returns an ag_handle for it. Only one device connection at a time supported
so only one handle returned.
*/
static ag_handle_t allocHandleFromAddress(bd_addr_t addr)
{
addr = addr;
return ONLY_ONE_HANDLE;
}
/*
removeAddressFromHandleMap
Removes a handle from the address map once a connection has been
disconnected.
*/
static void removeAddressFromHandleMap(ag_handle_t hdl)
{
hdl = hdl;
/* Reset the stored addr to zeros */
createAddressHandleMap();
}
static void copy_auth(cm_auth_config_t *out, ag_auth_config_t in)
{
out->authentication = in.authentication;
out->encryption = in.encryption;
}
static void copy_addr(BD_ADDR_T *out, bd_addr_t in)
{
out->nap = in.nap;
out->uap = in.uap;
out->lap = in.lap;
}
static void copy_park(cm_park_config_t *out, ag_park_config_t in)
{
out->max_intval = in.max_intval;
out->min_intval = in.min_intval;
}
static void copy_sniff(cm_sniff_config_t *out, ag_sniff_config_t in)
{
out->max_intval = in.max_intval;
out->min_intval = in.min_intval;
out->attempt = in.attempt;
out->timeout = in.timeout;
}
static uint16 connect_setup(uint16 target, bd_addr_t address)
{
uint16 return_target;
/* Initialise some state */
agSetCurrentState(AgConnecting);
/* indicator status updates are disabled to start with */
AGState.hfIndicatorUpdateEnabled = 0;
/* Set service indicator to true and ongoing call indicator to false */
AGState.hfServiceIndicator = 1;
AGState.hfCallIndicator = 0;
/* Voice recognition is disabled */
AGState.hfVoiceRecogEnable = 0;
/* Check what profile we should be using to connect */
if (target == HANDSFREE_TARGET)
{
/* Check the GUI registered the HF as supported and if so OK else send error and default to HS */
if (agIsHandsFreeSupported())
{
return_target = HANDSFREE_TARGET;
agSetCurrentProfile(agHandsFreeProfile);
}
else
{
return_target = HEADSET_TARGET;
agSetCurrentProfile(agHeadsetProfile);
}
AGState.roles_tried = return_target;
}
else if (target == HEADSET_TARGET)
{
/* Check the app supports the headset profile if not it must support the HF as there's nothing else */
if (agIsHeadsetSupported())
{
return_target = HEADSET_TARGET;
agSetCurrentProfile(agHeadsetProfile);
}
else
{
return_target = HANDSFREE_TARGET;
agSetCurrentProfile(agHandsFreeProfile);
}
AGState.roles_tried = return_target;
}
else
{
/*
If target not set by the GUI to a valid value see supported profiles.
If possible try HF first then HS. This way the GUI can say just connect
in the most suitable mode and let the AG decide which profiles the
other end supports.
*/
if (agIsHeadsetSupported() && agIsHandsFreeSupported())
{
/* The AG supports both so try connecting as hf first */
return_target = HANDSFREE_TARGET;
agSetCurrentProfile(agHandsFreeProfile);
}
else if (agIsHandsFreeSupported())
{
/* Only HF supported so use that */
return_target = HANDSFREE_TARGET;
agSetCurrentProfile(agHandsFreeProfile);
}
else
{
/* Default to the headset profile */
return_target = HEADSET_TARGET;
agSetCurrentProfile(agHeadsetProfile);
}
AGState.roles_tried = UNSPECIFIED_TARGET;
}
/* Allocate a connection handle for that device address */
sendConnectionHandle(allocHandleFromAddress(address), address);
return return_target;
}
/* Public functions */
/*
agConnectAsMasterReqAction
Request to create an RFCOMM connection as master.
*/
void agConnectAsMasterReqAction(bd_addr_t addr, const ag_auth_config_t *use, const ag_park_config_t *park, const ag_sniff_config_t *sniff, uint16 target, timeout_t timeout)
{
if (agIdleQuery())
{
MAKE_MSG(CM_CONNECT_AS_MASTER_REQ);
copy_auth(&msg->use, *use);
copy_addr(&msg->bd_addr, addr);
copy_park(&msg->park, *park);
copy_sniff(&msg->sniff, *sniff);
/* Init the connection related state - set the target to what is returned */
msg->target = connect_setup(target, addr);
/* user specifies the timeout in seconds ... zero means never expire */
msg->timeout = timeout ? D_SEC(timeout) : D_NEVER;
/* Set the server channel depending on the profile role */
if (msg->target == HANDSFREE_TARGET)
msg->profile_server_chan = AGState.agHfServerChan;
else
msg->profile_server_chan = AGState.agHsServerChan;
agPutCmMsg(msg);
/* TODO Store the connect params in case the connect attempt fails */
}
else
{
/* AG is not in an idle state so cannot enter connact mode */
agSendErrorToClient(AgErrorConnectRequestWhenNotIdle, (BD_ADDR_T *)&addr);
}
}
/*
AGconnectAsSlaveReq
Request to create an RFCOMM connection as slave.
*/
void agConnectAsSlaveReqAction(bd_addr_t addr, const ag_auth_config_t *use, const ag_park_config_t *park, const ag_sniff_config_t *sniff, timeout_t timeout, uint16 ps_ival, uint16 ps_win)
{
if (agIdleQuery())
{
MAKE_MSG(CM_CONNECT_AS_SLAVE_REQ);
copy_auth(&msg->use, *use);
copy_addr(&msg->bd_addr, addr);
copy_park(&msg->park, *park);
copy_sniff(&msg->sniff, *sniff);
/* Enable page scan but disable inquiry scan for power efficiency */
msg->ps_interval = ps_ival;
msg->ps_window = ps_win;
msg->is_interval = 0x400;
msg->is_window = 0x200;
/* user specifies the timeout in seconds ... zero means never expire */
msg->timeout = timeout ? D_SEC(timeout) : D_NEVER;
agPutCmMsg(msg);
/* Init the connection related state - ignore the target returned as we're slave */
(void) connect_setup(agProfileNotSet, addr);
}
else
{
/* AG is not in an idle state so cannot enter connact mode */
agSendErrorToClient(AgErrorConnectRequestWhenNotIdle, (BD_ADDR_T *)&addr);
}
}
/*
agUnsupportedServiceInd
The service the AG tried to connect to is not suported by the remote device
*/
void agUnsupportedServiceInd(CM_UNSUPPORTED_SERVICE_IND_T *ind)
{
MAKE_MSG(CM_UNSUPPORTED_SERVICE_RES);
if (AGState.roles_tried == UNSPECIFIED_TARGET)
{
/* User did not specify so we're trying hf and now we can try hs */
if (ind->target == HANDSFREE_TARGET)
{
/* Did not connect to HF so try HS */
msg->srch_continue = 1;
msg->new_target = HEADSET_TARGET;
msg->new_conn_server_chan = AGState.agHsServerChan;
AGState.roles_tried = HEADSET_TARGET;
}
else if (ind->target == HEADSET_TARGET)
{
/* Did not connect to HS so try HF */
msg->srch_continue = 1;
msg->new_target = HANDSFREE_TARGET;
msg->new_conn_server_chan = AGState.agHfServerChan;
AGState.roles_tried = HANDSFREE_TARGET;
}
else
{
/* No idea what we tried to connect to so just stop */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -