diff --git a/extmod/modbluetooth.c b/extmod/modbluetooth.c index caaf872e7d..8870a21c4d 100644 --- a/extmod/modbluetooth.c +++ b/extmod/modbluetooth.c @@ -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); diff --git a/extmod/modbluetooth.h b/extmod/modbluetooth.h index f14033de30..c96427fcb4 100644 --- a/extmod/modbluetooth.h +++ b/extmod/modbluetooth.h @@ -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): diff --git a/extmod/nimble/modbluetooth_nimble.c b/extmod/nimble/modbluetooth_nimble.c index 9ceeab7d7b..8bead890d8 100644 --- a/extmod/nimble/modbluetooth_nimble.c +++ b/extmod/nimble/modbluetooth_nimble.c @@ -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) {