Ryan Malloy ab699bbca3 Add HFP (Hands-Free Profile) support
Implement HFP client (Hands-Free Unit role) for the ESP32 test harness:

Firmware:
- bt_hfp.c/h: Full HFP client with call control, audio, volume, DTMF,
  voice recognition
- Enable HFP in sdkconfig.defaults with Wide Band Speech support
- Add HFP commands/events to protocol.h and cmd_dispatcher.c

Python MCP tools:
- 15 new tools: enable, connect, audio_connect, answer, reject, dial,
  send_dtmf, volume, voice_recognition_start/stop, query_calls, status
- Full protocol constants in protocol.py

Tested: HFP enable returns role='hands_free_unit', ready for AG pairing
2026-02-03 14:34:13 -07:00

123 lines
2.8 KiB
C

/**
* @file bt_hfp.h
* @brief HFP (Hands-Free Profile) Client module for ESP32 test harness.
*
* Implements HFP Hands-Free Unit (HF) role - acts as a Bluetooth headset.
* Connects to phones/computers (Audio Gateways) for call control and audio.
*/
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include "cJSON.h"
/**
* @brief Initialize HFP module (register callbacks, but don't init stack yet).
*/
void bt_hfp_init(void);
/* Command handlers (dispatched from cmd_dispatcher) */
/**
* @brief Enable HFP Client (Hands-Free Unit).
*
* Initializes the HFP client stack and registers the device as a headset.
* Classic Bluetooth must be enabled first.
*/
void cmd_hfp_enable(const char *id, cJSON *params);
/**
* @brief Disable HFP Client.
*
* Disconnects any active connection and deinitializes the HFP stack.
*/
void cmd_hfp_disable(const char *id, cJSON *params);
/**
* @brief Connect to an Audio Gateway (phone/computer).
*
* Params:
* - address: Bluetooth address of the AG (required)
*/
void cmd_hfp_connect(const char *id, cJSON *params);
/**
* @brief Disconnect from the current Audio Gateway.
*/
void cmd_hfp_disconnect(const char *id, cJSON *params);
/**
* @brief Connect SCO audio channel.
*
* Opens the audio link for voice. Requires an active SLC connection.
*/
void cmd_hfp_audio_connect(const char *id, cJSON *params);
/**
* @brief Disconnect SCO audio channel.
*
* Closes the audio link but keeps the control connection open.
*/
void cmd_hfp_audio_disconnect(const char *id, cJSON *params);
/**
* @brief Answer an incoming call.
*/
void cmd_hfp_answer(const char *id, cJSON *params);
/**
* @brief Reject an incoming call or hang up an active call.
*/
void cmd_hfp_reject(const char *id, cJSON *params);
/**
* @brief Dial a phone number.
*
* Params:
* - number: Phone number to dial (required)
*/
void cmd_hfp_dial(const char *id, cJSON *params);
/**
* @brief Send DTMF tone during an active call.
*
* Params:
* - code: Single DTMF character (0-9, *, #, A-D)
*/
void cmd_hfp_send_dtmf(const char *id, cJSON *params);
/**
* @brief Adjust speaker or microphone volume.
*
* Params:
* - type: "speaker" or "microphone"
* - volume: 0-15
*/
void cmd_hfp_volume(const char *id, cJSON *params);
/**
* @brief Start voice recognition (Siri/Google Assistant).
*/
void cmd_hfp_voice_recognition_start(const char *id, cJSON *params);
/**
* @brief Stop voice recognition.
*/
void cmd_hfp_voice_recognition_stop(const char *id, cJSON *params);
/**
* @brief Query current call list from AG.
*/
void cmd_hfp_query_calls(const char *id, cJSON *params);
/**
* @brief Get HFP status (enabled, connected, audio state, call info).
*/
void cmd_hfp_status(const char *id, cJSON *params);
/* State query functions */
bool bt_hfp_is_enabled(void);
bool bt_hfp_is_connected(void);
bool bt_hfp_is_audio_connected(void);