From ff2d7b76bf4878f47a2df1261219c9d9e14f8c9e Mon Sep 17 00:00:00 2001 From: Dylan Van Assche Date: Wed, 13 Apr 2022 19:56:41 +0200 Subject: [PATCH 08/26] bluetooth: support AT+CMEE AT+CMEE is now supported and extended error messages are returned when an ERROR occurs. By default, these error codes are disabled, the HF must enable them explicitely with AT+CMEE=1 (numeric mode). --- src/modules/bluetooth/backend-native.c | 71 +++++++++++++++++++++----- src/modules/bluetooth/bluez5-util.h | 6 +++ 2 files changed, 65 insertions(+), 12 deletions(-) diff --git a/src/modules/bluetooth/backend-native.c b/src/modules/bluetooth/backend-native.c index 77792146a..3110c5ef2 100644 --- a/src/modules/bluetooth/backend-native.c +++ b/src/modules/bluetooth/backend-native.c @@ -57,6 +57,7 @@ struct pa_bluetooth_backend { bool enable_hsp_hs; bool enable_hfp_hf; bool cmer_indicator_reporting_enabled; + bool cmee_extended_error_reporting_enabled; uint32_t cind_enabled_indicators; PA_LLIST_HEAD(pa_dbus_pending, pending); @@ -125,7 +126,7 @@ typedef enum pa_bluetooth_ag_to_hf_indicators { /* gateway features we support, which is as little as we can get away with */ static uint32_t hfp_features = /* HFP 1.6 requires this */ - (1 << HFP_AG_ESTATUS ) | (1 << HFP_AG_CODECS) | (1 << HFP_AG_INDICATORS); + (1 << HFP_AG_ESTATUS ) | (1 << HFP_AG_CODECS) | (1 << HFP_AG_INDICATORS) | (1 << HFP_AG_EERR); #define HSP_AG_PROFILE "/Profile/HSPAGProfile" #define HFP_AG_PROFILE "/Profile/HFPAGProfile" @@ -256,6 +257,14 @@ static void rfcomm_write_response(int fd, const char *fmt, ...) va_end(ap); } +/* Send Extended Error messages if enabled */ +static void rfcomm_write_error(pa_bluetooth_backend *b, int fd, unsigned int error) { + if (b->cmee_extended_error_reporting_enabled) + rfcomm_write_response(fd, "+CME ERROR: %d", error); + else + rfcomm_write_response(fd, "ERROR"); +} + static int sco_setsockopt_enable_bt_voice(pa_bluetooth_transport *t, int fd) { /* the mSBC codec requires a special transparent eSCO connection */ struct bt_voice voice; @@ -621,6 +630,30 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf size_t len; const char *state; + /* Extended error reporting. Described in Bluetooth HFP 1.8 spec. */ + if (sscanf(buf, "AT+CMEE=%d", &val) == 1) { + switch(val) { + /* Disable extended error reporting */ + case 0: + discovery->native_backend->cmee_extended_error_reporting_enabled = false; + return true; + /* Enable extend error reporting in numeric mode */ + case 1: + discovery->native_backend->cmee_extended_error_reporting_enabled = true; + return true; + /* Enable extend error reporting in verbose mode */ + case 2: + pa_log_warn("Extended Error Reporting verbose mode is unsupported by Bluetooth HFP 1.8"); + rfcomm_write_error(discovery->native_backend, fd, CMEE_OPERATION_NOT_SUPPORTED); + return false; + default: + pa_log_warn("Unknown AT+CMEE value: %d", val); + rfcomm_write_error(discovery->native_backend, fd, CMEE_AG_FAILURE); + return false; + } + pa_assert_not_reached(); + } + /* first-time initialize selected codec to CVSD */ if (c->selected_codec == 0) c->selected_codec = 1; @@ -655,7 +688,7 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf discovery->native_backend->cind_enabled_indicators &= ~(1 << indicator); else { pa_log_error("Unable to parse indicator of AT+BIA command: %s", buf); - rfcomm_write_response(fd, "ERROR"); + rfcomm_write_error(discovery->native_backend, fd, CMEE_AG_FAILURE); return false; } @@ -741,7 +774,7 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf } else { pa_log_error("Unable to parse AT+CMER command: %s", buf); - rfcomm_write_response(fd, "ERROR"); + rfcomm_write_error(discovery->native_backend, fd, CMEE_AG_FAILURE); return false; } @@ -767,7 +800,7 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf pa_bluetooth_transport_reconfigure(t, pa_bluetooth_get_hf_codec("mSBC"), sco_transport_write, sco_setsockopt_enable_bt_voice); } else { pa_assert_fp(val != 1 && val != 2); - rfcomm_write_response(fd, "ERROR"); + rfcomm_write_error(discovery->native_backend, fd, CMEE_AG_FAILURE); return false; } @@ -798,14 +831,14 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf pa_log_notice("Battery Level: %d%%", val); if (val < 0 || val > 100) { pa_log_error("Battery HF indicator %d out of [0, 100] range", val); - rfcomm_write_response(fd, "ERROR"); + rfcomm_write_error(discovery->native_backend, fd, CMEE_AG_FAILURE); return false; } pa_bluetooth_device_report_battery_level(t->device, val, "HFP 1.7 HF indicator"); break; default: pa_log_error("Unknown HF indicator %u", indicator); - rfcomm_write_response(fd, "ERROR"); + rfcomm_write_error(discovery->native_backend, fd, CMEE_OPERATION_NOT_SUPPORTED); return false; } return true; @@ -819,12 +852,23 @@ static bool hfp_rfcomm_handle(int fd, pa_bluetooth_transport *t, const char *buf if (c->state != 5) { pa_log_error("HFP negotiation failed in state %d with inbound %s\n", c->state, buf); - rfcomm_write_response(fd, "ERROR"); + rfcomm_write_error(discovery->native_backend, fd, CMEE_AG_FAILURE); return false; } - /* Unsupported commands return ERROR */ - return false + /* + * Unsupported commands return ERROR. + * Unsupported AT commands from HFP 1.8: + * - AT+BINP + * - AT+BLDN + * - ATD> + * - AT+BVRA + * - AT+BTRH + * - AT+CHLD + * - AT+CCWA + */ + rfcomm_write_error(discovery->native_backend, fd, CMEE_OPERATION_NOT_SUPPORTED); + return false; } static int get_rfcomm_fd (pa_bluetooth_discovery *discovery) { @@ -996,12 +1040,13 @@ static void rfcomm_io_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_i break; } } - if (!do_reply) - rfcomm_write_response(fd, "ERROR"); + if (!do_reply) { + rfcomm_write_error(discovery->native_backend, fd, CMEE_AG_FAILURE); + } } else if (t->config) { /* t->config is only non-null for hfp profile */ do_reply = hfp_rfcomm_handle(fd, t, buf); } else { - rfcomm_write_response(fd, "ERROR"); + rfcomm_write_error(discovery->native_backend, fd, CMEE_AG_FAILURE); do_reply = false; } @@ -1391,6 +1436,8 @@ pa_bluetooth_backend *pa_bluetooth_native_backend_new(pa_core *c, pa_bluetooth_d /* While all CIND indicators are enabled, event reporting is not enabled by default */ backend->cmer_indicator_reporting_enabled = false; + /* CMEE is disabled by default */ + backend->cmee_extended_error_reporting_enabled = false; return backend; } diff --git a/src/modules/bluetooth/bluez5-util.h b/src/modules/bluetooth/bluez5-util.h index f69176425..4cc5c2882 100644 --- a/src/modules/bluetooth/bluez5-util.h +++ b/src/modules/bluetooth/bluez5-util.h @@ -211,6 +211,12 @@ struct pa_bluetooth_adapter { bool battery_provider_registered; }; +/* extended error reporting values, described in Bluetooth HFP 1.8 spec */ +typedef enum pa_bluetooth_cmee { + CMEE_AG_FAILURE = 0, + CMEE_OPERATION_NOT_SUPPORTED = 4, +} pa_bluetooth_cmee_t; + #ifdef HAVE_BLUEZ_5_OFONO_HEADSET pa_bluetooth_backend *pa_bluetooth_ofono_backend_new(pa_core *c, pa_bluetooth_discovery *y); void pa_bluetooth_ofono_backend_free(pa_bluetooth_backend *b); -- 2.35.1