extmod/modbluetooth: Add ble.hci_cmd(ogf, ocf, req, resp) function.

This allows sending arbitrary HCI commands and getting the response.  The
return value of the function is the status of the command.

This is intended for debugging and not to be a part of the public API, and
must be enabled via mpconfigboard.h.  It's currently only implemented for
NimBLE bindings.

Signed-off-by: Jim Mussared <jim.mussared@gmail.com>
This commit is contained in:
Jim Mussared 2021-01-22 17:30:25 +11:00 committed by Damien George
parent 49dd9ba1a5
commit aa136b4d78
3 changed files with 52 additions and 1 deletions

View File

@ -884,6 +884,23 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_l2cap_recvinto_obj, 4,
#endif // MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS
#if MICROPY_PY_BLUETOOTH_ENABLE_HCI_CMD
STATIC mp_obj_t bluetooth_ble_hci_cmd(size_t n_args, const mp_obj_t *args) {
mp_int_t ogf = mp_obj_get_int(args[1]);
mp_int_t ocf = mp_obj_get_int(args[2]);
mp_buffer_info_t bufinfo_request = {0};
mp_buffer_info_t bufinfo_response = {0};
mp_get_buffer_raise(args[3], &bufinfo_request, MP_BUFFER_READ);
mp_get_buffer_raise(args[4], &bufinfo_response, MP_BUFFER_WRITE);
uint8_t status = 0;
bluetooth_handle_errno(mp_bluetooth_hci_cmd(ogf, ocf, bufinfo_request.buf, bufinfo_request.len, bufinfo_response.buf, bufinfo_response.len, &status));
return MP_OBJ_NEW_SMALL_INT(status);
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(bluetooth_ble_hci_cmd_obj, 5, 5, bluetooth_ble_hci_cmd);
#endif // MICROPY_PY_BLUETOOTH_ENABLE_HCI_CMD
// ----------------------------------------------------------------------------
// Bluetooth object: Definition
// ----------------------------------------------------------------------------
@ -927,6 +944,9 @@ STATIC const mp_rom_map_elem_t bluetooth_ble_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_l2cap_send), MP_ROM_PTR(&bluetooth_ble_l2cap_send_obj) },
{ MP_ROM_QSTR(MP_QSTR_l2cap_recvinto), MP_ROM_PTR(&bluetooth_ble_l2cap_recvinto_obj) },
#endif
#if MICROPY_PY_BLUETOOTH_ENABLE_HCI_CMD
{ MP_ROM_QSTR(MP_QSTR_hci_cmd), MP_ROM_PTR(&bluetooth_ble_hci_cmd_obj) },
#endif
};
STATIC MP_DEFINE_CONST_DICT(bluetooth_ble_locals_dict, bluetooth_ble_locals_dict_table);

View File

@ -60,6 +60,12 @@
#define MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING (0)
#endif
// Optionally enable support for the `hci_cmd` function allowing
// Python to directly low-level HCI commands.
#ifndef MICROPY_PY_BLUETOOTH_ENABLE_HCI_CMD
#define MICROPY_PY_BLUETOOTH_ENABLE_HCI_CMD (0)
#endif
// This is used to protect the ringbuffer.
// A port may no-op this if MICROPY_PY_BLUETOOTH_USE_SYNC_EVENTS is enabled.
#ifndef MICROPY_PY_BLUETOOTH_ENTER
@ -387,6 +393,10 @@ int mp_bluetooth_l2cap_send(uint16_t conn_handle, uint16_t cid, const uint8_t *b
int mp_bluetooth_l2cap_recvinto(uint16_t conn_handle, uint16_t cid, uint8_t *buf, size_t *len);
#endif // MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS
#if MICROPY_PY_BLUETOOTH_ENABLE_HCI_CMD
int mp_bluetooth_hci_cmd(uint16_t ogf, uint16_t ocf, const uint8_t *req, size_t req_len, uint8_t *resp, size_t resp_len, uint8_t *status);
#endif // MICROPY_PY_BLUETOOTH_ENABLE_HCI_CMD
/////////////////////////////////////////////////////////////////////////////
// API implemented by modbluetooth (called by port-specific implementations):

View File

@ -81,9 +81,11 @@ STATIC int ble_hs_err_to_errno(int err) {
return 0;
}
if (err >= 0 && (unsigned)err < MP_ARRAY_SIZE(ble_hs_err_to_errno_table) && ble_hs_err_to_errno_table[err]) {
// Return an MP_Exxx error code.
return ble_hs_err_to_errno_table[err];
} else {
return MP_EIO;
// Pass through the BLE error code.
return -err;
}
}
@ -1660,6 +1662,25 @@ int mp_bluetooth_l2cap_recvinto(uint16_t conn_handle, uint16_t cid, uint8_t *buf
#endif // MICROPY_PY_BLUETOOTH_ENABLE_L2CAP_CHANNELS
#if MICROPY_PY_BLUETOOTH_ENABLE_HCI_CMD
// For ble_hs_hci_cmd_tx
#include "nimble/host/src/ble_hs_hci_priv.h"
int mp_bluetooth_hci_cmd(uint16_t ogf, uint16_t ocf, const uint8_t *req, size_t req_len, uint8_t *resp, size_t resp_len, uint8_t *status) {
int rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(ogf, ocf), req, req_len, resp, resp_len);
if (rc < BLE_HS_ERR_HCI_BASE || rc >= BLE_HS_ERR_HCI_BASE + 0x100) {
// The controller didn't handle the command (e.g. HCI timeout).
return ble_hs_err_to_errno(rc);
} else {
// The command executed, but had an error (i.e. invalid parameter).
*status = rc - BLE_HS_ERR_HCI_BASE;
return 0;
}
}
#endif // MICROPY_PY_BLUETOOTH_ENABLE_HCI_CMD
#if MICROPY_PY_BLUETOOTH_ENABLE_PAIRING_BONDING
STATIC int ble_store_ram_read(int obj_type, const union ble_store_key *key, union ble_store_value *value) {