服务 (service) 是具体产品功能在软件层面上的实现,如输入按键、网络配置管理、电池检测等功能。例如,想要在做的蓝牙耳机上加按键 调整音量、切歌的功能,就得使用蓝牙 service 配置。更具体的是 Bluetooth service 中的音视频远程控制规范 (Audio Video Remote Control Profile, AVRCP)。
在 ADF 框架中 AVRCP 是和 A2DP stream 封装在一起的。触发相应的服务控制,直接调用 api 即可。当然也可调用 bluetooth_service.h 中的 api 去实现 AVRCP 服务。
switch (event) { case ESP_A2D_CONNECTION_STATE_EVT: my_a2d_sink_cb(event, param); // the callback added to change the bd_add. ... }
对应的 a2dp_stream.h 文件添加以下接口的声明:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/** * @brief return the mac address of the last connected device. * */ esp_bd_addr_t* get_remote_ba_addr_last( void );
/** * @brief return the mac address of remembered devices. The maximum number of devices is 6. * * @param[in] before_index The before_index of the address. * For example, if the last index is 5 and the before_index is 1, it will return the address of index-4. */ esp_bd_addr_t* get_remote_ba_addr_before(uint8_t before_index);
“The ESP32 HID device set the SDP attribute HIDReconnectInitiate to True, it indicates that the HID device will be primarily responsible for connection re-establishment.”
“It seems this is not done in the ESP firmware, it is done in the phone application code instead. I’m not sure if this is the correct way to do it or if there are more optimal ways, but here’s what I did. In your Android phone application, in the line of code that starts the GATT connection from the Android side (Android Studio or whatever you’re using) set it to auto-connect.”
windows 是有蓝牙自动连接设置的,一些业余的解决蓝牙自动连接的答案也都是依靠 PC 端来做的:
ES8388 支持 SPI 模式和 I2C 模式,通过 CE 引脚来控制。SPI 需要三线,片选信号下降沿有效;在原理图中直接把 CE 拉低,默认 I2C 模式。400 kbps
The first byte transferred is the slave address. It is a seven-bit chip address followed by a RW bit. The chip address must be 001000x, where x equals AD0.
设备地址 0010001/0 AD0,也就是 CE 模拟的。在画图时该引脚拉低,所以地址是 0010000;0x20
*/** * @brief Start/stop codec driver * * @param audio_hal reference function pointer for selected audio codec * @param mode select media hal codec mode either encode/decode/or both to start from audio_hal_codec_mode_t * @param audio_hal_ctrl select start stop state for specific mode * * @return int, 0--success, others--fail */ *esp_err_t audio_hal_ctrl_codec(audio_hal_handle_t*audio_hal*, audio_hal_codec_mode_t*mode*, audio_hal_ctrl_t*audio_hal_ctrl*);
/* mute DAC during setup, power up all systems, slave mode */ res &= write_reg(ES8388_ADDR, ES8388_DACCONTROL3, 0x04); res &= write_reg(ES8388_ADDR, ES8388_CONTROL2, 0x50); res &= write_reg(ES8388_ADDR, ES8388_CHIPPOWER, 0x00); res &= write_reg(ES8388_ADDR, ES8388_MASTERMODE, 0x00);
/* power up DAC and enable LOUT1+2 / ROUT1+2, ADC sample rate = DAC sample rate */ res &= write_reg(ES8388_ADDR, ES8388_DACPOWER, 0x3e); res &= write_reg(ES8388_ADDR, ES8388_CONTROL1, 0x12);
/* DAC I2S setup: 16 bit word length, I2S format; MCLK / Fs = 256*/ res &= write_reg(ES8388_ADDR, ES8388_DACCONTROL1, 0x18); res &= write_reg(ES8388_ADDR, ES8388_DACCONTROL2, 0x02);
/* DAC to output route mixer configuration: ADC MIX TO OUTPUT */ res &= write_reg(ES8388_ADDR, ES8388_DACCONTROL16, 0x1B); res &= write_reg(ES8388_ADDR, ES8388_DACCONTROL17, 0x90); res &= write_reg(ES8388_ADDR, ES8388_DACCONTROL20, 0x90);
/* DAC and ADC use same LRCK, enable MCLK input; output resistance setup */ res &= write_reg(ES8388_ADDR, ES8388_DACCONTROL21, 0x80); res &= write_reg(ES8388_ADDR, ES8388_DACCONTROL23, 0x00);
/* DAC volume control: 0dB (maximum, unattenuated) */ res &= write_reg(ES8388_ADDR, ES8388_DACCONTROL5, 0x00); res &= write_reg(ES8388_ADDR, ES8388_DACCONTROL4, 0x00);
/* power down ADC while configuring; volume: +9dB for both channels */ res &= write_reg(ES8388_ADDR, ES8388_ADCPOWER, 0xff); res &= write_reg(ES8388_ADDR, ES8388_ADCCONTROL1, 0x88); // +24db
/* select LINPUT2 / RINPUT2 as ADC input; stereo; 16 bit word length, format right-justified, MCLK / Fs = 256 */ res &= write_reg(ES8388_ADDR, ES8388_ADCCONTROL2, 0xf0); // 50 res &= write_reg(ES8388_ADDR, ES8388_ADCCONTROL3, 0x80); // 00 res &= write_reg(ES8388_ADDR, ES8388_ADCCONTROL4, 0x0e); res &= write_reg(ES8388_ADDR, ES8388_ADCCONTROL5, 0x02);
/* set ADC volume */ res &= write_reg(ES8388_ADDR, ES8388_ADCCONTROL8, 0x20); res &= write_reg(ES8388_ADDR, ES8388_ADCCONTROL9, 0x20);
/* set LOUT1 / ROUT1 volume: 0dB (unattenuated) */ res &= write_reg(ES8388_ADDR, ES8388_DACCONTROL24, 0x1e); res &= write_reg(ES8388_ADDR, ES8388_DACCONTROL25, 0x1e);
/* set LOUT2 / ROUT2 volume: 0dB (unattenuated) */ res &= write_reg(ES8388_ADDR, ES8388_DACCONTROL26, 0x1e); res &= write_reg(ES8388_ADDR, ES8388_DACCONTROL27, 0x1e);
/* power up and enable DAC; power up ADC (no MIC bias) */ res &= write_reg(ES8388_ADDR, ES8388_DACPOWER, 0x3c); res &= write_reg(ES8388_ADDR, ES8388_DACCONTROL3, 0x00); res &= write_reg(ES8388_ADDR, ES8388_ADCPOWER, 0x00);
/* set up MCLK) */ PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0_CLK_OUT1); WRITE_PERI_REG(PIN_CTRL, 0xFFF0); }
/** * @brief Test if device with I2C address for ES8388 is connected to the I2C bus * * @param sda which pin to use for I2C SDA * @param scl which pin to use for I2C SCL * @param frequency which frequency to use as I2C bus frequency * @return true device was found * @return false device was not found */ bool ES8388::identify(int sda, int scl, uint32_t frequency) { Wire.begin(sda, scl, frequency); Wire.beginTransmission(ES8388_ADDR); return Wire.endTransmission() == 0; }
esp_err_t es8388_init(es8388_handle_t *dev*, const es8388_clock_config_t *const *clk_cfg*) { int res = 0;
res = i2c_init();* // ESP32 in master mode * char ES8388_ADDR = *dev->addr;*
res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL3, 0x04);* //0x04 mute/0x00 unmute&ramp;DAC unmute and disabled digital volume control soft ramp /* Chip Control and Power Management */ * res |= es_write_reg(ES8388_ADDR, ES8388_CONTROL2, 0x50); res |= es_write_reg(ES8388_ADDR, ES8388_CHIPPOWER, 0x00);* //normal all and power up all * *// Disable the internal DLL to improve 8K sample rate * res |= es_write_reg(ES8388_ADDR, 0x35, 0xA0); res |= es_write_reg(ES8388_ADDR, 0x37, 0xD0); res |= es_write_reg(ES8388_ADDR, 0x39, 0xD0);
res |= es_write_reg(ES8388_ADDR, ES8388_MASTERMODE, cfg->i2s_iface.mode);* //CODEC IN I2S SLAVE MODE * * /* dac */ * res |= es_write_reg(ES8388_ADDR, ES8388_DACPOWER, 0xC0);* //disable DAC and disable Lout/Rout/1/2 * res |= es_write_reg(ES8388_ADDR, ES8388_CONTROL1, 0x12);* //Enfr=0,Play&Record Mode,(0x17-both of mic&paly) // res |= es_write_reg(ES8388_ADDR, ES8388_CONTROL2, 0); //LPVrefBuf=0,Pdn_ana=0 * res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL1, 0x18);*//1a 0x18:16bit iis , 0x00:24 * res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL2, 0x02);* //DACFsMode,SINGLE SPEED; DACFsRatio,256 * res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL16, 0x00);* //0x00 audio on LIN1&RIN1, 0x09 LIN2&RIN2 * res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL17, 0x90);* // only left DAC to left mixer enable 0db * res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL20, 0x90);* // only right DAC to right mixer enable 0db * res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL21, 0x80);* //set internal ADC and DAC use the same LRCK clock, ADC LRCK as internal LRCK * res |= es_write_reg(ES8388_ADDR, ES8388_DACCONTROL23, 0x00);* //vroi=0 * res |= es8388_set_adc_dac_volume(ES_MODULE_DAC, 0, 0);* //0db * res |= es_write_reg(ES8388_ADDR, ES8388_DACPOWER, tmp);* //0x3c Enable DAC and Enable Lout/Rout/1/2 /* adc */ * res |= es_write_reg(ES8388_ADDR, ES8388_ADCPOWER, 0xFF); res |= es_write_reg(ES8388_ADDR, ES8388_ADCCONTROL1, 0xbb);* // MIC Left and Right channel PGA gain * res |= es_write_reg(ES8388_ADDR, ES8388_ADCCONTROL2, tmp);* //0x00 LINSEL & RINSEL, LIN1/RIN1 as ADC Input; DSSEL,use one DS Reg11; DSR, LINPUT1-RINPUT1 * res |= es_write_reg(ES8388_ADDR, ES8388_ADCCONTROL3, 0x02); res |= es_write_reg(ES8388_ADDR, ES8388_ADCCONTROL4, 0x0c);* //16 Bits length and I2S serial audio data format * res |= es_write_reg(ES8388_ADDR, ES8388_ADCCONTROL5, 0x02);* //ADCFsMode,singel SPEED,RATIO=256 * *//ALC for Microphone * res |= es8388_set_adc_dac_volume(ES_MODULE_ADC, 0, 0);* //0db * res |= es_write_reg(ES8388_ADDR, ES8388_ADCPOWER, 0x09);* //Power on ADC, Enable LIN&RIN, Power off MICBIAS, set int1lp to low power mode * return res; }