-
Notifications
You must be signed in to change notification settings - Fork 7.6k
Bluetooth: Classic: Add role change event cb #90126
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Bluetooth: Classic: Add role change event cb #90126
Conversation
43ed4cc
to
2009ed9
Compare
|
||
if (!strcmp(action, "central")) { | ||
/* 0 - Change own Role to Central for this BD_ADDR. */ | ||
role = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is not readable. I suggest defining two marcos.
#define BT_HCI_SWITCH_ROLE_CENTRAL 0
#define BT_HCI_SWITCH_ROLE_PERIPHERAL 1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
err = bt_conn_get_info(default_conn, &info); | ||
if (err) { | ||
shell_error(sh, "Failed to get info (err %d)", err); | ||
return err; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a function bt_conn_get_dst_br()
can be used to get the peer address.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
if (buf != NULL) { | ||
cp = net_buf_add(buf, sizeof(*cp)); | ||
memcpy(&cp->bdaddr, &info.br.dst->val[0], sizeof(cp->bdaddr)); | ||
cp->role = role; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What if the new role is the same as the old one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From my test, the controller gives error for the result.
buf = bt_hci_cmd_create(BT_HCI_OP_SWITCH_ROLE, sizeof(*cp)); | ||
if (buf != NULL) { | ||
cp = net_buf_add(buf, sizeof(*cp)); | ||
memcpy(&cp->bdaddr, &info.br.dst->val[0], sizeof(cp->bdaddr)); | ||
cp->role = role; | ||
err = bt_hci_cmd_send_sync(BT_HCI_OP_SWITCH_ROLE, buf, NULL); | ||
if (err) { | ||
shell_print(sh, "fail to send hci cmd (err %d)", err); | ||
} | ||
} else { | ||
shell_error(sh, "hi cmd fail to create"); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If can we add an API for BR role switch function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is better to add an API. I think another pr for the API is better because the current pr is mainly for adding new callback.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well. I suggest removing this shell command. And adding it when the API is added.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, Even I don't agree it, but I still removed the added shell test codes.
@@ -1041,6 +1116,7 @@ SHELL_STATIC_SUBCMD_SET_CREATE(br_cmds, | |||
SHELL_CMD_ARG(oob, NULL, NULL, cmd_oob, 1, 0), | |||
SHELL_CMD_ARG(pscan, NULL, "<value: on, off>", cmd_connectable, 2, 0), | |||
SHELL_CMD_ARG(sdp-find, NULL, "<HFPAG, HFPHF>", cmd_sdp_find_record, 2, 0), | |||
SHELL_CMD_ARG(switch-role, NULL, "<central, peripheral", cmd_switch_role, 2, 0), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
>
is missing in <central, peripheral
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
@@ -478,6 +478,10 @@ void bt_conn_set_state(struct bt_conn *conn, bt_conn_state_t state); | |||
|
|||
void bt_conn_connected(struct bt_conn *conn); | |||
|
|||
#if defined(CONFIG_BT_CLASSIC) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As my understand, function declarations do not need to be controlled by conditional compilation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@MarkWangChinese thanks! @lylezhu2012 is correct. If you have the time, please submit a PR to remove those other #ifdefs too. It's a bad idea to have that in header files since it eliminates the possibility of using IS_ENABLED()
in the calling code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the explain. I will do it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed this PR.
2009ed9
to
7c6719d
Compare
include/zephyr/bluetooth/conn.h
Outdated
* connection has changed. | ||
* | ||
* @param conn Connection object. | ||
* @param status The HCI_Role_Change event's Status. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* @param status The HCI_Role_Change event's Status. | |
* @param status HCI status of role change event. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
include/zephyr/bluetooth/conn.h
Outdated
/** @brief The role of the connection has changed. | ||
* | ||
* This callback notifies the application that the role of the | ||
* connection has changed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggest changing to This callback notifies the application that the role switch procedure has completed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
7c6719d
to
f60b13c
Compare
* @param conn Connection object. | ||
* @param status HCI status of role change event. | ||
*/ | ||
void (*role_changed)(struct bt_conn *conn, uint8_t status); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like it has limited usability. Why not at least include the new role as a parameter of the callback?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That said, do we even have an API to query the current role of a connection?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
bt_conn_get_info
can get the current role.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, maybe that's sufficient then. Another question: why do you bother including a status parameter? If a role change fails then then role didn't change, so why would you call the callback then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the role switch is initiated by the DUT, the DUT needs to know the result whether it success or fail. If the role switch is initiated by peer side, this callback can give the indication that the peer tries to switch role even status
is fail. So this callback is defined as HCI status of role change event
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I said that I fully agree to add one API. But I am afraid that I don't think the callback can only make sense when the new API exist. Because the role switch can be initialized from the peer (it can run any bluetooth stack), then DUT (run zephyr stack) needs the callback to know the role is changed (when role switch success, the DUT host receive the HCI event from controller). Without the callback, the DUT application can only poll the conn info to know the role is changed if DUT application want to know it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I said that I fully agree to add one API. But I am afraid that I don't think the callback can only make sense when the new API exist. Because the role switch can be initialized from the pee
I meant the status
parameter, not the callback as a whole.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, let me summary. Sorry that I may not get your point.
- Case1. DUT is the initiator of the role switch: DUT use the new API/hci_cmd to send the hci cmd to let controller do the role switch. Controller will give the result of role switch no matter it success or fail. DUT application needs the callback to know the result no matter success or fail.
@jhedberg Do you mean that we don't have the new API, so the case1 is invalid, so only the follow Case2 is valid case, then thestatus
is not needed? If yes, I will create the new API pr later, could we let this pr merged? - Case2. The peer is the initiator of the role switch: Controller will give the HCI event to host if the role switch success, DUT application needs the callback to know the role is changed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@MarkWangChinese I mean that the callback as it's currently defined in this PR is fine (makes sense) as long as it's combined with an API to initiate the role switch from our side, i.e. I'd propose to add a new commit here to introduce bt_conn_br_change_role()
or similar.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @jhedberg I have added the new API. I prefer the API as bt_conn_br_switch_role(const struct bt_conn *conn, uint8_t role)
because the application want to switch as dedicated role not change the current role. For example: application wants to switch as central after connected by peer, give the dedicated role to stack/controller in avoid that the peer initiate the role switch too at the same time, I think the controller can handle the corner case.
f60b13c
to
07bd0f8
Compare
ab7bb7d
to
9190f88
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A couple of initial comments. I'll do a more thorough review in the next iteration.
include/zephyr/bluetooth/hci_types.h
Outdated
struct bt_hci_rp_read_link_policy_settings { | ||
uint8_t status; | ||
uint16_t handle; | ||
uint16_t link_policy_settings; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be just one space between uint16_t
and variable name
include/zephyr/bluetooth/hci_types.h
Outdated
#define BT_HCI_OP_WRITE_LINK_POLICY_SETTINGS BT_OP(BT_OGF_LINK_POLICY, 0x000d) | ||
struct bt_hci_cp_write_link_policy_settings { | ||
uint16_t handle; | ||
uint16_t link_policy_settings; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here
include/zephyr/bluetooth/hci_types.h
Outdated
#define BT_HCI_OP_READ_DEFAULT_LINK_POLICY_SETTINGS BT_OP(BT_OGF_LINK_POLICY, 0x000e) | ||
struct bt_hci_rp_read_default_link_policy_settings { | ||
uint8_t status; | ||
uint16_t default_link_policy_settings; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And here
include/zephyr/bluetooth/hci_types.h
Outdated
|
||
#define BT_HCI_OP_WRITE_DEFAULT_LINK_POLICY_SETTINGS BT_OP(BT_OGF_LINK_POLICY, 0x000f) | ||
struct bt_hci_cp_write_default_link_policy_settings { | ||
uint16_t default_link_policy_settings; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And here
config BT_DEFAULT_ROLE_SWITCHABLE | ||
bool "Default Bluetooth Role Switch Enable/Disable State" | ||
help | ||
This option sets the controller's default link policy to enable/disable the role switch. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use similar line width as for help texts for other options, like BT_COD
above.
} | ||
|
||
cp = net_buf_add(buf, sizeof(*cp)); | ||
cp->handle = conn->handle; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing sys_cpu_to_le16()
is_enabled = link_policy_settings & BT_HCI_LINK_POLICY_SETTINGS_ENABLE_ROLE_SWITCH; | ||
|
||
if (enable == is_enabled) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To make it clear that you mean &
and not &&
I think it's better to put the operation inside parenthesis. Also, no empty line between the assignment and the test, please (this is also inconsistent with yourself, since you don't do it e.g. on line 261/262 either).
err = bt_conn_br_write_link_policy_settings(conn, link_policy_settings); | ||
|
||
return err; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd just replace this with return bt_conn_br_write_...();
subsys/bluetooth/host/classic/br.c
Outdated
bool is_enabled = default_link_policy_settings & | ||
BT_HCI_LINK_POLICY_SETTINGS_ENABLE_ROLE_SWITCH; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use ()
here. Added benefit is that editors will do the split line alignment more correctly.
subsys/bluetooth/host/classic/br.c
Outdated
@@ -801,7 +801,11 @@ int bt_br_init(void) | |||
struct bt_hci_cp_write_inquiry_mode *inq_cp; | |||
struct bt_hci_write_local_name *name_cp; | |||
struct bt_hci_cp_write_class_of_device *cod; | |||
struct bt_hci_rp_read_default_link_policy_settings *rp; | |||
struct bt_hci_cp_write_default_link_policy_settings *policy_cp; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move this into the if-branch where it's actually used (variables should always be declared in the smallest possible scope)
9190f88
to
0dacc61
Compare
Hi @jhedberg Thanks, all are resolved. please help to review again. |
subsys/bluetooth/host/classic/br.c
Outdated
conn->role = BT_CONN_ROLE_PERIPHERAL; | ||
} else { | ||
conn->role = BT_CONN_ROLE_CENTRAL; | ||
if (!evt->status) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (!evt->status) { | |
if (evt->status == 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
subsys/bluetooth/host/classic/br.c
Outdated
} else { | ||
conn->role = BT_CONN_ROLE_CENTRAL; | ||
if (!evt->status) { | ||
if (evt->role) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest adding the following macros for event BT_HCI_EVT_ROLE_CHANGE
,
#define BT_ROLE_CHANGE_CENTRAL 0
#define BT_ROLE_CHANGE_PERIPHERAL 1
And
if (evt->role) { | |
if (evt->role == BT_ROLE_CHANGE_PERIPHERAL) { |
It is useful for reading.
Or, we may use the macros BT_HCI_ROLE_CENTRAL
and BT_HCI_ROLE_PERIPHERAL
. But I do not make sure it is reasonable. At lest the value of the BT_HCI_ROLE_PERIPHERAL
is 1. And the value of BT_HCI_ROLE_CENTRAL
is 0.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated with the HCI role MACRO.
return bt_hci_cmd_send_sync(BT_HCI_OP_WRITE_LINK_POLICY_SETTINGS, buf, NULL); | ||
} | ||
|
||
int bt_conn_br_set_role_switch_enable(const struct bt_conn *conn, bool enable) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whether is it better to change function name to bt_conn_br_role_switch
?
int bt_conn_br_set_role_switch_enable(const struct bt_conn *conn, bool enable) | |
int bt_conn_br_role_switch(const struct bt_conn *conn, bool enable) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is talked here #90126 (comment) and it is more aligned with the other bluetooth APIs.
if (!strcmp(action, "enable")) { | ||
enable = true; | ||
} else if (!strcmp(action, "disable")) { | ||
enable = false; | ||
} else { | ||
shell_help(sh); | ||
return SHELL_CMD_HELP_PRINTED; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a function shell_strtobool()
. It can be used to parse the argument from string to bool.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated.
add `role_changed` to `struct bt_conn_cb` to notify the HCI_Role_Change event to application. Signed-off-by: Mark Wang <[email protected]>
0dacc61
to
dd4c6ff
Compare
add bt_conn_br_switch_role and bt_conn_br_set_role_switchable to control the role switch, add DEFAULT_ROLE_SWITCHABLE Kconfig to control the default role switch state. Signed-off-by: Mark Wang <[email protected]>
dd4c6ff
to
ebe2c91
Compare
|
add
role_changed
tostruct bt_conn_cb
to notify the HCI_Role_Change event to application.add BT_HCI_OP_SWITCH_ROLE and struct bt_hci_cp_switch_role.
add br switch-role shell cmd and test the role_changed callback.