Hoang NhuTriet Pham
Created October 14, 2017 © GPL3+

Alexa/Google-Assistant Voice/Sensor-Based IoT Automation

Via SensorTile's microphone & sensor, users can tap to send voice command to Alexa/Google-Assistant servers to control IoT appliances

AdvancedFull instructions providedOver 1 day617

Things used in this project

Hardware components

STEVAL-STLKT01V1
STMicroelectronics STEVAL-STLKT01V1
×1
iPhone
Apple iPhone
×1
Android device
Android device
×1
STM32 Nucleo-64 Board
STMicroelectronics STM32 Nucleo-64 Board
×1
NousLogic - Smart Power Plug
×1

Software apps and online services

IoT Voice Assistant (Android)
IoT Voice Assistant (iOS)
STMicroelectronics FP-SNS-ALLMEMS1
STMicroelectronics FP-AUD-BVLINK1

Story

Read more

Schematics

System Block Diagram

Interaction between Android App (IoT Voice Assistant) and SensorTile

Interaction between iOS App (IoT Voice Assistant) and SensorTile

Code

main.c

C/C++
Main file, full source code can be obtained from ST AUD-BVLINK main page
/**
 ******************************************************************************
 * @file    main.c
 * @author  Central Labs
 * @version V2.0.0
 * @date    13-Jun-2016
 * @brief   This software provides an application running on STM32 to
 *          demonstrate half-duplex speech transmission over Bluetooth Low Energy.
 *          It is based on OSXBlueVoice library v2.0.0 (under OSX-LLA License),
 *          configured as PERIPHERAL.
 ******************************************************************************
 * @attention
 *
 * <h2><center>&copy; COPYRIGHT(c) 2015 STMicroelectronics</center></h2>
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *   1. Redistributions of source code must retain the above copyright notice,
 *      this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright notice,
 *      this list of conditions and the following disclaimer in the documentation
 *      and/or other materials provided with the distribution.
 *   3. Neither the name of STMicroelectronics nor the names of its contributors
 *      may be used to endorse or promote products derived from this software
 *      without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ******************************************************************************
 */

/**
 * @mainpage Documentation for FP-AUD-BVLINK1 Software for STM32, BlueNRG-MS and digital MEMS microphone
 *
 * @image html st_logo.png
 *
 * <b>Introduction</b>
 *
 * This software is based on the STM32CubeHAL, the hardware abstraction layer for
 * the STM32 microcontroller. The package extends STM32Cube by providing a
 * Board Support Package (BSP) for BlueNRG-MS, MEMS Microphone 
 * expansion boards, SensorTile and BlueCoin. Middleware components for 
 * communication with other Bluetooth LE devices and a dedicated profile 
 * for voice communication
 *
 * <b>Example Application</b>
 *
 * BlueVoice applications (Central and Peripheral) show speech acquisition,
 * compression and transmission over Bluetooth Low Energy of speech data in a
 * bidirectional system. Both module can act as transmitter or receiver of
 * speech according to the selected channel. The module acting as transmitter is
 * responsible for audio acquisition, compression and streaming over BLE according
 * to BlueVoice Profile specification. The module acting as receiver is responsible
 * for audio decompression and USB streaming of audio data via USB.
 */

/* Includes ------------------------------------------------------------------*/

#include "bluevoice_application_peripheral.h"

/* Private defines -----------------------------------------------------------*/
/* Private macros ------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/


/* Private function prototypes -----------------------------------------------*/

/**
 * @brief  Main program.
 * @param  None.
 * @retval None.
 */
int main(void)
{
  /* STM32Cube HAL library initialization:
   *  - Configure the Flash prefetch, Flash preread and Buffer caches
   *  - Systick timer is configured by default as source of time base, but user
   *    can eventually implement his proper time base source (a general purpose
   *    timer for example or other time source), keeping in mind that Time base
   *    duration should be kept 1ms since PPP_TIMEOUT_VALUEs are defined and
   *    handled in milliseconds basis.
   *  - Low Level Initialization
   */
  HAL_Init();

#ifdef STM32L476xx
  /* Enable Power Clock*/
  __HAL_RCC_PWR_CLK_ENABLE();
  /* enable USB power on Pwrctrl CR2 register */
  HAL_PWREx_EnableVddUSB();  
#endif
  
  /* Configure the system clock */
  SystemClock_Config();
 
  BV_APP_Status status;
  
  /* Peripherals Initialization*/
  status = BVL_APP_PER_HWinitialization();
  if(status != BV_APP_SUCCESS)
  {
    BV_APP_PER_Error_Handler();
  } 
 
  /*BLE Initialization*/
  status = BVL_APP_PER_Init_BLE();
  if(status != BV_APP_SUCCESS)
  {
    BV_APP_PER_Error_Handler();
  }
  
  /*BlueVoice profile Initialization*/
  status = BV_APP_PER_ProfileInit();
  if(status != BV_APP_SUCCESS)
  {
    BV_APP_PER_Error_Handler();
  }
 
  /*Audio Start Acquisition*/
  status = BVL_APP_PER_Start_Acquisition();
  if(status != BV_APP_SUCCESS)
  {
    BV_APP_PER_Error_Handler();
  }
  
  /*Set module in advertise mode*/
  status = BVL_APP_PER_Advertise(); 
  if(status != BV_APP_SUCCESS)
  {
    BV_APP_PER_Error_Handler();
  }
  
  while (1)
  {
    HCI_Process();
    BVL_APP_PER_Process();
  }
}


/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

bluevoice_app_per_sensortile.c

C/C++
peripheral functionalities
/**
 ******************************************************************************
 * @file    bluevoice_app_per_sensortile.c
 * @author  Central Labs
 * @version V 1.0.0
 * @date    13-Jun-2016
 * @brief   This file contains definitions for BlueVoice peripheral application.
 *******************************************************************************
 * @attention
 *
 * <h2><center>&copy; COPYRIGHT(c) 2015 STMicroelectronics</center></h2>
 *
 * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
 * You may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *        http://www.st.com/software_license_agreement_liberty_v2
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *   1. Redistributions of source code must retain the above copyright notice,
 *      this list of conditions and the following disclaimer.
 *   2. Redistributions in binary form must reproduce the above copyright notice,
 *      this list of conditions and the following disclaimer in the documentation
 *      and/or other materials provided with the distribution.
 *   3. Neither the name of STMicroelectronics nor the names of its contributors
 *      may be used to endorse or promote products derived from this software
 *      without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ********************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "bluevoice_application_peripheral.h"

/** @addtogroup BLUEVOICELINK_APP
 * @{
 */

/** @defgroup BLUEVOICELINK_APP_PERIPHERAL BLUEVOICELINK_APP_PERIPHERAL
 * @{
 */

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/

/** @defgroup BLUEVOICELINK_APP_PERIPHERAL_Private_Defines BLUEVOICELINK_APP_PERIPHERAL_Private_Defines
 * @{
 */

#define LED_TOGGLE_ADVERTISEMENT                         300000
#define LED_TOGGLE_CONNECTED                             80000
#define LED_TOGGLE_STREAMING                             15000


#define AUDIO_CHANNELS_IN                               (uint16_t) (IN_CHANNELS_1)                      /*!< Input channels number.*/
#define AUDIO_CHANNELS_OUT                              (uint16_t) (OUT_CHANNELS_1)                     /*!< Output channels number.*/
#define AUDIO_IN_SAMPLING_FREQUENCY                     (uint16_t) (SAMPLING_FREQ_8000)                /*!< Audio acquisition sampling frequency.*/
#define AUDIO_OUT_SAMPLING_FREQUENCY                    (uint16_t) (SAMPLING_FREQ_8000)                /*!< Audio output sampling frequency.*/

#define PCM_IN_SAMPLES_PER_MS                           (AUDIO_IN_SAMPLING_FREQUENCY/1000)              /*!< Number of PCM samples for each ms of audio acquired.*/
#define PCM_OUT_SAMPLES_PER_MS                          (AUDIO_OUT_SAMPLING_FREQUENCY/1000)             /*!< Number of PCM samples for each ms of audio given as output.*/
   
#define AUDIO_IN_MS                                     (1)                                             /*!< Number of ms of Audio given as input to the BlueVoice library.*/            
#define PCM_AUDIO_IN_SAMPLES                            (PCM_IN_SAMPLES_PER_MS * AUDIO_IN_MS)           /*!< Number of PCM samples input total.*/
#define AUDIO_OUT_MS                                    (10)                                            /*!< Number of ms of Audio buffered in Rx before out stream.*/
#define PCM_BUFFER_OUT_LEN                              (PCM_OUT_SAMPLES_PER_MS * AUDIO_OUT_MS * 20)    /*!< Number of PCM samples output total.*/

#define NAME_WEAR 'B', 'V', '-', 'L', 'I', 'N', 'K'   
   
#define BV_APP_STATUS_ADVERTISEMENT                     (0x10)          /*!< BlueVoice Peripheral device is in advertisement mode.*/
#define BV_APP_STATUS_HANDLE_DISC                       (0x20)          /*!< Service and characteristics discovery procedure active.*/  
#define BV_APP_SERVICE_DISC                             (0x21)          /*!< Service discovery procedure.*/  
#define BV_APP_CHAR_AUDIO_DISC                          (0x22)          /*!< Audio characteristic discovery procedure.*/ 
#define BV_APP_CHAR_SYNC_DISC                           (0x23)          /*!< Audio sync characteristic discovery procedure.*/ 
#define BV_APP_STATUS_RECEIVER_ACTIVATION               (0x30)          /*!< Discovered handle setting and enable notifications.*/
#define BV_APP_STATUS_READY                             (0x40)          /*!< BlueVoice Peripheral device ready to stream or receive audio.*/

/**
 * @}
 */

/** @defgroup BLUEVOICELINK_APP_PERIPHERAL_Private_Variables BLUEVOICELINK_APP_PERIPHERAL_Private_Variables
 * @{
 */

uint16_t PDM_Buffer[AUDIO_CHANNELS_IN * PCM_AUDIO_IN_SAMPLES * 64 / 8];         /*!< PDM data is stored here.*/
uint16_t PCM_Buffer[AUDIO_CHANNELS_IN * PCM_AUDIO_IN_SAMPLES];                  /*!< PCM data is stored here.*/

static uint16_t PCM_Buffer_Temp[BV_ADPCM_PCM_SAMPLES_PER_PACKET];               /*!< PCM parsed data are stored here.*/
static uint16_t PCM_Buffer_OUT[PCM_BUFFER_OUT_LEN];                             /*!< PCM data to be streamed via Audio OUT are stored here.*/
static void *PCM1774_X_0_handle = NULL;
static void *LSM6DSM_X_0_handle = NULL;
static uint32_t AudioOutActive = 0;
static uint32_t led_toggle_count = 0;                                           /*!< Variable used to handle led toggling.*/

BV_ADPCM_ProfileHandle_t tx_handle;                                             /*!< Peripheral service and characteristics handles.*/
BV_ADPCM_ProfileHandle_t rx_handle;                                             /*!< Central service and characteristics handles.*/
BV_ADPCM_uuid_t uuid;
 
uint16_t service_handle, dev_name_char_handle, appearance_char_handle;
uint16_t conn_handle = 0;

volatile uint8_t BV_APP_PER_state = BV_APP_STATUS_ADVERTISEMENT;                /*!< BlueVoice peripheral application state.*/
volatile uint8_t BV_APP_PER_handle_disc_state = BV_APP_SERVICE_DISC;            /*!< BlueVoice central serv and char discovery state.*/
volatile uint8_t ready = 0;                                                     /*!< Flag used to request stream data when they're ready.*/

volatile uint8_t wait_end_procedure = 0;
volatile uint8_t service_discovered = 0;
volatile uint8_t char_discovered = 0;
uint16_t num_byte_sent = 0;                                             

const uint8_t CENTRAL_BDADDR[] = { 0x55, 0x11, 0x07, 0x01, 0x16, 0xE1 };        /*!< BLE CENTRAL address.*/
const uint8_t PERIPHERAL_BDADDR[] = { 0x55, 0x11, 0x07, 0x01, 0x16, 0xE2 };     /*!< BLE PERIPHERAL address.*/

static const uint8_t audio_adpcm_serv_uuid[16] =
{
  0x1b,0xc5,0xd5,0xa5,0x02,0x00,0xb4,0x9a,0xe1,0x11,0x01,0x00,0x00,0x00,0x00,0x00
};                                                                              /*!< Audio service uuid.*/

static const uint8_t audio_adpcm_char_uuid[16] =
{
  0x1b,0xc5,0xd5,0xa5,0x02,0x00,0x36,0xac,0xe1,0x11,0x01,0x00,0x00,0x00,0x00,0x08
};                                                                              /*!< Audio characteristic uuid.*/

static const uint8_t audio_adpcm_sync_char_uuid[16] =
{
  0x1b,0xc5,0xd5,0xa5,0x02,0x00,0x36,0xac,0xe1,0x11,0x01,0x00,0x00,0x00,0x00,0x40
};                                                                              /*!< Audio synchronization uuid.*/

/**
 * @}
 */

BV_APP_Status BVL_APP_PER_Init_Acquisition_Peripherals(uint32_t AudioFreq, uint32_t ChnlNbrIn);
void BVL_APP_PER_AttributeModified_CB(uint16_t attr_handle, uint8_t attr_len, uint8_t *attr_value);
void BVL_APP_PER_GAPConnectionComplete_CB(uint8_t *addr, uint16_t handle);
void BVL_APP_PER_GAPDisconnectionComplete_CB(void);
void BVL_APP_PER_GATTNotification_CB(uint16_t attr_handle, uint8_t attr_len, uint8_t *attr_value);
void BVL_APP_PER_Stream_Handler(void);
void BVL_APP_PER_AudioProcess(void);


/** @defgroup BLUEVOICELINK_APP_PERIPHERAL_Exported_Functions BLUEVOICELINK_APP_PERIPHERAL_Exported_Functions
 * @{
 */

/**
  * @brief  Hardware Initializes depending on the board.
  * @param  None.
  * @retval BV_APP_Status: BV_APP_SUCCESS if the configuration is ok, BV_APP_ERROR otherwise..
  */
BV_APP_Status BVL_APP_PER_HWinitialization(void)
{
  BV_APP_Status status;
    
  /* Configure LED1 */
  BSP_LED_Init(LED1);
   
  /* Initialize the BlueNRG SPI driver */
  BNRG_SPI_Init(); 
  /* Initialize the BlueNRG HCI */
  HCI_Init(); 
  /* Reset BlueNRG hardware */
  BlueNRG_RST();

  /* Initialize Acquisition Peripherals */
  status = BVL_APP_PER_Init_Acquisition_Peripherals(AUDIO_IN_SAMPLING_FREQUENCY, AUDIO_CHANNELS_IN);
  if(status != BV_APP_SUCCESS)
  {
    BV_APP_PER_Error_Handler();
  }
  
  /* Accelerometer initialization */
  if(BSP_ACCELERO_Init( LSM6DSM_X_0, &LSM6DSM_X_0_handle ) == COMPONENT_ERROR)
  {
    BV_APP_PER_Error_Handler();
  } 
  BSP_ACCELERO_Sensor_Enable( LSM6DSM_X_0_handle );
  
  /* Enable duoble tap detection */
  if(BSP_ACCELERO_Enable_Double_Tap_Detection_Ext(LSM6DSM_X_0_handle, INT2_PIN)==COMPONENT_ERROR)
  {
    BV_APP_PER_Error_Handler();
  }
  
  return BV_APP_SUCCESS;
}

/**
 * @brief  Initializes Gatt and Gap; sets the authentication requirements and the tx output power level.
 * @param  None.
 * @retval BV_APP_Status: BV_APP_SUCCESS if the configuration is ok, BV_APP_ERROR otherwise.
 */
BV_APP_Status BVL_APP_PER_Init_BLE(void)
{
  uint8_t ret = 0;

  ret = aci_hal_write_config_data(CONFIG_DATA_PUBADDR_OFFSET, CONFIG_DATA_PUBADDR_LEN, PERIPHERAL_BDADDR);
  
  if (ret != BLE_STATUS_SUCCESS)
  {
    return BV_APP_ERROR;
  }
  
  ret = aci_gatt_init();
  
  if (ret != BLE_STATUS_SUCCESS)
  {
    return BV_APP_ERROR;
  }

  ret = aci_gap_init_IDB05A1(GAP_PERIPHERAL_ROLE_IDB05A1, 0, 0x07, &service_handle, &dev_name_char_handle,  &appearance_char_handle);

  if (ret != BLE_STATUS_SUCCESS)
  {
    return BV_APP_ERROR;
  }

  /* Set auth requirement*/
  aci_gap_set_auth_requirement(MITM_PROTECTION_REQUIRED,
                               OOB_AUTH_DATA_ABSENT,
                               NULL, 7, 16,
                               USE_FIXED_PIN_FOR_PAIRING, 123456,
                               BONDING);
                               
  /* Set output power level */
  aci_hal_set_tx_power_level(1, 5);
  
  return BV_APP_SUCCESS;
}
  
/**
 * @brief  This function is called to initialize BlueVoice Profile.
 * @param  None.
 * @retval BV_APP_Status: BV_APP_SUCCESS if the configuration is ok, BV_APP_ERROR otherwise.
 */
BV_APP_Status BV_APP_PER_ProfileInit(void)
{     
  BV_ADPCM_Status status;
  
  /* Enable CRC peripheral to unlock BlueVoice library */
  __CRC_CLK_ENABLE();
  /* BlueVoice ADPCM library initialization*/
  BluevoiceADPCM_Initialize();
 
  BV_ADPCM_Config_t BV_ADPCM_Config;
  BV_ADPCM_Config.sampling_frequency = FR_8000;
  BV_ADPCM_Config.channel_in = 1;
  BV_ADPCM_Config.channel_tot = 1;
  status = BluevoiceADPCM_SetConfig(&BV_ADPCM_Config);

  if(status != BV_ADPCM_SUCCESS)
  {
    BV_APP_PER_Error_Handler();
  }
  
  memcpy(uuid.ServiceUUID,
              audio_adpcm_serv_uuid,
              sizeof(audio_adpcm_serv_uuid));                 
  memcpy(uuid.CharAudioUUID,
              audio_adpcm_char_uuid,
              sizeof(audio_adpcm_char_uuid));
  memcpy(uuid.CharAudioSyncUUID,
              audio_adpcm_sync_char_uuid,
              sizeof(audio_adpcm_sync_char_uuid));
  
  /*BlueVoice Service and characteristics creation*/
  status = BluevoiceADPCM_AddService(uuid.ServiceUUID, &tx_handle.ServiceHandle);
  
  if(status != BV_ADPCM_SUCCESS)
  {
    BV_APP_PER_Error_Handler();
  }
  
  status = BluevoiceADPCM_AddChar(uuid, tx_handle.ServiceHandle, &tx_handle);

  if(status != BV_ADPCM_SUCCESS)
  {
    BV_APP_PER_Error_Handler();
  }
  
  return BV_APP_SUCCESS;
}

/**
 * @brief  This function is called from the server in order to go in advertisement mode.
 * @param  None
 * @retval BV_APP_Status: BV_APP_SUCCESS if the configuration is ok, BV_APP_ERROR otherwise.
 */
BV_APP_Status BVL_APP_PER_Advertise(void)
{
  uint8_t ret = 0;
  
  const char local_name[] =
  {
    AD_TYPE_COMPLETE_LOCAL_NAME, NAME_WEAR
  };

  uint8_t manuf_data[20] = {
  2,0x0A,0x00 /* 0 dBm */, // Trasmission Power
  8,0x09,NAME_WEAR, // Complete Name
  7,0xFF,0x01 /* SDK version */,
         0x02 /* NUCLEO-Board */,
         0x48 /* AudioSync+AudioData */,
         0x00,
         0x00,
         0x00
  };

  /* disable scan response */
  ret = hci_le_set_scan_resp_data(0, NULL);

  ret = aci_gap_set_discoverable(ADV_IND, 0, 0, PUBLIC_ADDR, NO_WHITE_LIST_USE,
                           sizeof(local_name), local_name, 0, NULL, 0, 0);

  /* Send Advertising data */
  ret = aci_gap_update_adv_data(20, manuf_data);

  if (ret != BLE_STATUS_SUCCESS)
  {
    return BV_APP_ERROR;
  }
  
  return BV_APP_SUCCESS;
}

/**
 * @brief  Initializes the required peripherals using BSP_AUDIO_IN_Init function.
 * @param  AudioFreq: Audio frequency to be configured for the peripherals.
 * @param  ChnlNbrIn: Input channel number, used to configure the right peripherals.
 * @retval BV_APP_Status: BV_APP_SUCCESS if the configuration is ok, BV_APP_ERROR otherwise.
 */
BV_APP_Status BVL_APP_PER_Init_Acquisition_Peripherals(uint32_t AudioFreq, uint32_t ChnlNbrIn)
{
  uint8_t ret = 0;
  
  ret = BSP_AUDIO_IN_Init(AudioFreq, 16, ChnlNbrIn);
  
  if(ret != AUDIO_OK)
  {
    return BV_APP_ERROR;
  }
  
  return BV_APP_SUCCESS;
}

/**
 * @brief  Starts audio acquisition engine and then it pauses it.
 * @param  None.
 * @retval BV_APP_Status: BV_APP_SUCCESS if the configuration is ok, BV_APP_ERROR otherwise.
 */
BV_APP_Status BVL_APP_PER_Start_Acquisition(void)
{
  uint8_t ret = 0;
#ifdef STM32L476xx
  ret = BSP_AUDIO_IN_Record(PCM_Buffer,0);
#else  
  ret = BSP_AUDIO_IN_Record(PDM_Buffer, 0);
#endif  
  ret = BSP_AUDIO_IN_Pause();
  
  if(ret != AUDIO_OK)
  {
    return BV_APP_ERROR;
  }
  
  return BV_APP_SUCCESS;
}

/**
 * @brief  Process user input.
 * @param  None.
 * @retval None.
 */
void BVL_APP_PER_Process(void)
{
  BV_ADPCM_Status status;
  
  switch (BV_APP_PER_state)
  {
  case BV_APP_STATUS_ADVERTISEMENT:
    {
      if (led_toggle_count++ >= LED_TOGGLE_ADVERTISEMENT)
      {
        led_toggle_count = 0;
        BSP_LED_Toggle(LED1);
      }
    }
    break;
  case BV_APP_STATUS_HANDLE_DISC:
    {
      switch(BV_APP_PER_handle_disc_state)
      {
      case BV_APP_SERVICE_DISC:
        {
          if(!wait_end_procedure)
          {
            if(aci_gatt_disc_prim_service_by_uuid(conn_handle, UUID_TYPE_128, (uint8_t*)&uuid.ServiceUUID) == BLE_STATUS_SUCCESS)
            {
              service_discovered = 0;
              wait_end_procedure = 1;
            }
          }
        }
        break;
      case BV_APP_CHAR_AUDIO_DISC:
        {
          if(!wait_end_procedure)
          {
            if(aci_gatt_disc_charac_by_uuid(conn_handle, 0x0001, 0xFFFF, UUID_TYPE_128, (uint8_t*)&uuid.CharAudioUUID) == BLE_STATUS_SUCCESS)
            {
              char_discovered = 0;
              wait_end_procedure = 1;
            }
          }
        }
        break;
      case BV_APP_CHAR_SYNC_DISC:
        {
          if(!wait_end_procedure)
          {
            if(aci_gatt_disc_charac_by_uuid(conn_handle, 0x0001, 0xFFFF, UUID_TYPE_128, (uint8_t*)&uuid.CharAudioSyncUUID) == BLE_STATUS_SUCCESS)
            {
              char_discovered = 0;
              wait_end_procedure = 1;
            }
          }
        } 
        break;
      default:
        {       
        }
        break;
      }
    }
    break;
  case BV_APP_STATUS_RECEIVER_ACTIVATION:
    { 
      if(service_discovered)
      {
        status = BluevoiceADPCM_SetRxHandle(&rx_handle);
        
        if(status != BV_ADPCM_SUCCESS)
        {
          BV_APP_PER_Error_Handler();
        }
        
        status = BluevoiceADPCM_EnableNotification();
        
        if(status != BV_ADPCM_SUCCESS)
        {
          BV_APP_PER_Error_Handler();
        }
      }
      BV_APP_PER_state = BV_APP_STATUS_READY;
    }
    break;
  case BV_APP_STATUS_READY:
    {   
      switch(BluevoiceADPCM_GetStatus())
      {
      case BV_ADPCM_STATUS_READY:
        {
          if(AudioOutActive)
          {
            AudioOutActive = 0;
            BSP_AUDIO_OUT_Stop(PCM1774_X_0_handle, 0);
            /* Configure LED1 */
            BSP_LED_Init(LED1);
          }
          if (led_toggle_count++ >= LED_TOGGLE_CONNECTED)
          {
            led_toggle_count = 0;
            BSP_LED_Toggle(LED1);
          }    
        }
        break;
      case BV_ADPCM_STATUS_STREAMING:
        {
          if (led_toggle_count++ >= LED_TOGGLE_STREAMING)
          {
            led_toggle_count = 0;
            BSP_LED_Toggle(LED1);
          }
          if(ready)
          {
            status = BluevoiceADPCM_SendData(&num_byte_sent);
            
            if(status != BV_ADPCM_SUCCESS)
            {
              BV_APP_PER_Error_Handler();
            }
            
            ready = 0;
          }
        }
        break;
      case BV_ADPCM_STATUS_RECEIVING:
        {         
          BSP_LED_On(LED1);
        }
        break;
      default:
        {
        
        }
        break;
      }
    }
    break;   
  }
}

/**
* @}
*/

/** @defgroup BLUEVOICELINK_APP_PERIPHERAL_Callbacks BLUEVOICELINK_APP_PERIPHERAL_Callbacks
* @{
*/

/**
 * @brief  Half Transfer user callback, called by BSP functions.
 * @param  None
 * @retval None
 */
void BSP_AUDIO_IN_HalfTransfer_CallBack(void)
{
  BVL_APP_PER_AudioProcess();
}

/**
 * @brief  Complete Transfer user callback, called by BSP functions.
 * @param  None
 * @retval None
 */
void BSP_AUDIO_IN_TransferComplete_CallBack(void)
{
  BVL_APP_PER_AudioProcess();
}

/**
 * @brief  EXTI line detection callback.
 * @param  GPIO_Pin: Specifies the pins connected EXTI line
 * @retval None.
 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  if (GPIO_Pin == BNRG_SPI_EXTI_PIN)
  {
    HCI_Isr();
  }
  else if (GPIO_Pin == LSM6DSM_INT2_PIN)
  {
    uint8_t stat = 0;
    
    BSP_ACCELERO_Get_Double_Tap_Detection_Status_Ext(LSM6DSM_X_0_handle,&stat);
    if(stat)
    {
      BVL_APP_PER_Stream_Handler();
    }
  }
}

/**
* @brief  This function is called whenever there is an ACI event to be processed.
* @note   Inside this function each event must be identified and correctly
*         parsed.
* @param  pckt:  Pointer to the ACI packet
* @retval None
*/
void HCI_Event_CB(void *pckt)
{
  hci_uart_pckt *hci_pckt = pckt;
  hci_event_pckt *event_pckt = (hci_event_pckt*) hci_pckt->data;
  
  if (hci_pckt->type != HCI_EVENT_PKT)
    return;
    
  switch (event_pckt->evt)
  {
    case EVT_DISCONN_COMPLETE:
    {
      BVL_APP_PER_GAPDisconnectionComplete_CB();
    }
    break;
    
    case EVT_LE_META_EVENT:
    {
      evt_le_meta_event *evt = (void *) event_pckt->data;
      
      switch (evt->subevent)
      {
        case EVT_LE_CONN_COMPLETE:
        {
          evt_le_connection_complete *cc = (void *) evt->data;
          BVL_APP_PER_GAPConnectionComplete_CB(cc->peer_bdaddr, cc->handle);
        }
        break;
      }
    }
    break;
    
    case EVT_VENDOR:
    {
      evt_blue_aci *blue_evt = (void*) event_pckt->data;
      switch (blue_evt->ecode)
      {
        case EVT_BLUE_GATT_PROCEDURE_COMPLETE:
          {
            wait_end_procedure = 0;
            if(BV_APP_PER_handle_disc_state == BV_APP_SERVICE_DISC)
            {
              if(service_discovered)
              {
                BV_APP_PER_handle_disc_state = BV_APP_CHAR_AUDIO_DISC;
              }
              else
              {
                BV_APP_PER_state = BV_APP_STATUS_RECEIVER_ACTIVATION;
              }
            }
            else if(BV_APP_PER_handle_disc_state == BV_APP_CHAR_AUDIO_DISC)
            {
              if(char_discovered)
              {
                char_discovered = 0;
                BV_APP_PER_handle_disc_state = BV_APP_CHAR_SYNC_DISC;
              }
            }
            else if(BV_APP_PER_handle_disc_state == BV_APP_CHAR_SYNC_DISC)
            {
              if(char_discovered)
              {
                char_discovered = 0;
                BV_APP_PER_state = BV_APP_STATUS_RECEIVER_ACTIVATION;
              }
            }
          }
          break;
        case EVT_BLUE_ATT_FIND_BY_TYPE_VAL_RESP:
          {
            evt_att_find_by_type_val_resp *evt_serv = (evt_att_find_by_type_val_resp*)blue_evt->data;
            rx_handle.ServiceHandle = (evt_serv->handles_info_list[1]<<8) + evt_serv->handles_info_list[0];            
            service_discovered = 1;
          }
          break;
        case EVT_BLUE_GATT_DISC_READ_CHAR_BY_UUID_RESP:
          {
            evt_gatt_disc_read_char_by_uuid_resp *evt_char = (evt_gatt_disc_read_char_by_uuid_resp*)blue_evt->data;
            if(BV_APP_PER_handle_disc_state == BV_APP_CHAR_AUDIO_DISC)
            {
               rx_handle.CharAudioHandle = evt_char->attr_handle;
               char_discovered = 1;
            }
            else if(BV_APP_PER_handle_disc_state == BV_APP_CHAR_SYNC_DISC)
            {
              rx_handle.CharAudioSyncHandle = evt_char->attr_handle;
              char_discovered = 1;
            }      
          }
          break;  
        case EVT_BLUE_GATT_ATTRIBUTE_MODIFIED:
        {
          evt_gatt_attr_modified_IDB05A1 *evt = (evt_gatt_attr_modified_IDB05A1*) blue_evt->data;            
          BVL_APP_PER_AttributeModified_CB(evt->attr_handle, evt->data_length, evt->att_data);
        }
        break;
        case EVT_BLUE_GATT_NOTIFICATION:
        {
          evt_gatt_attr_notification *evt = (evt_gatt_attr_notification*) blue_evt->data;
          BVL_APP_PER_GATTNotification_CB(evt->attr_handle, evt->event_data_length - 2, evt->attr_value);
        }
        break;
      }
    }
    break;
  }
}

/**
 * @}
 */

/** @defgroup BLUEVOICELINK_APP_PERIPHERAL_Private_Functions BLUEVOICELINK_APP_PERIPHERAL_Private_Functions
* @{
*/

/**
 * @brief  This function is called when an attribute gets modified
 * @param  handle: Handle of the attribute
 * @param  attr_len: Size of the modified attribute data
 * @param  attr_value: Pointer to the modified attribute data
 * @retval None.
 */
void BVL_APP_PER_AttributeModified_CB(uint16_t attr_handle, uint8_t attr_len, uint8_t *attr_value)
{ 
  if((attr_handle == tx_handle.CharAudioHandle+2) || (attr_handle == tx_handle.CharAudioSyncHandle+2))
  {
    BluevoiceADPCM_AttributeModified_CB(attr_handle, attr_len, attr_value);
  }
}

/**
 * @brief  This function is called when there is a LE Connection Complete event.
 * @param  addr: Address of peer device
 * @param  handle: Connection handle
 * @retval None.
 */
void BVL_APP_PER_GAPConnectionComplete_CB(uint8_t *addr, uint16_t handle)
{
  /* Connection completed */
  BluevoiceADPCM_ConnectionComplete_CB(handle);

  /* Connection interval parameters update request in order to be compatible with Android and iOS*/
  int ret = aci_l2cap_connection_parameter_update_request(handle,
                                                8 /* interval_min*/,
                                                17 /* interval_max */,
                                                0   /* slave_latency */,
                                                400 /*timeout_multiplier*/);
  if (ret != BLE_STATUS_SUCCESS) 
  {
    while (1);
  }
  
  conn_handle = handle;

  BV_APP_PER_state = BV_APP_STATUS_HANDLE_DISC;
}

/**
 * @brief  This function is called when the peer device get disconnected.
 * @param  None.
 * @retval None.
 */
void BVL_APP_PER_GAPDisconnectionComplete_CB(void)
{
  BluevoiceADPCM_DisconnectionComplete_CB();
    
  BSP_AUDIO_IN_Pause();
  
  BV_APP_PER_state = BV_APP_STATUS_ADVERTISEMENT;
  
  BV_APP_Status status;
  
  /*Set module in advertise mode*/
  status = BVL_APP_PER_Advertise();
  if(status != BV_APP_SUCCESS)
  {
    BV_APP_PER_Error_Handler();
  }
  
  wait_end_procedure = 0;
}

/**
 * @brief  This function is called when there is a notification from the Central Server.
 * @param  attr_handle: Handle of the attribute.
 * @param  attr_len:  Length of attribute value in the notification.
 * @param  attr_value: Attribute value in the notification.
 * @retval None.
 */
void BVL_APP_PER_GATTNotification_CB(uint16_t attr_handle, uint8_t attr_len, uint8_t *attr_value)
{
  BV_ADPCM_Status status;
  
  uint8_t PCMsample = 0;
  static uint32_t IndexOut = 0;
  static uint32_t IndexIn = 0;
 
  /* Data parsing. */
  status = BluevoiceADPCM_ParseData(attr_value, attr_len, attr_handle, (uint8_t *) PCM_Buffer_Temp, &PCMsample);

  if(status != BV_ADPCM_SUCCESS)
  {
    BV_APP_PER_Error_Handler();
  }
  
  if (PCMsample > 0)
  {   
    for(IndexIn=0;IndexIn<PCMsample;IndexIn++)
    {
      PCM_Buffer_OUT[IndexOut++] = PCM_Buffer_Temp[IndexIn];
      PCM_Buffer_OUT[IndexOut++] = PCM_Buffer_Temp[IndexIn];
    }

    if (!AudioOutActive && IndexOut==PCM_BUFFER_OUT_LEN/2)
    {
      /* Configure Audio Output peripheral (SAI) and external DAC */
      BSP_AUDIO_OUT_Init(PCM1774_0, &PCM1774_X_0_handle, NULL, 20, AUDIO_OUT_SAMPLING_FREQUENCY); 
      BSP_AUDIO_OUT_SetVolume(PCM1774_X_0_handle, 20);
      /* start audio streaming */
      BSP_AUDIO_OUT_Play(PCM1774_X_0_handle,(uint16_t*)PCM_Buffer_OUT, PCM_BUFFER_OUT_LEN);
      AudioOutActive=1;
    }
    if(IndexOut==PCM_BUFFER_OUT_LEN)
    {
      IndexOut = 0;
    }
  }  
}

/**
* @brief  Audio Process function: PDM to PCM conversion and BlueVoice buffer filling.
* @param  None.
* @retval None.
*/
void BVL_APP_PER_AudioProcess(void)
{   
  BV_ADPCM_Status status;
  
  /* for L4 PDM to PCM conversion is performed in hardware by DFSDM peripheral */
#ifndef STM32L476xx 
  /*PDM to PCM conversion*/
  BSP_AUDIO_IN_PDMToPCM((uint16_t *) PDM_Buffer, PCM_Buffer);
#endif  
  
  if (BluevoiceADPCM_IsProfileConfigured())
  {
    /*BlueVoice data filling*/
    status = BluevoiceADPCM_AudioIn((uint16_t*) PCM_Buffer, PCM_AUDIO_IN_SAMPLES);
    if(status==BV_ADPCM_OUT_BUF_READY)
    {
      ready=1;
    }
  }
}

/**
 * @brief  This function is called when user button is pressed.
 * @param  None.
 * @retval None.
 */
void BVL_APP_PER_Stream_Handler(void)
{
  BV_ADPCM_Profile_Status Status;
  BV_ADPCM_Mode Mode;
  Status = BluevoiceADPCM_GetStatus();
  Mode = BluevoiceADPCM_GetMode();

  if (Status == BV_ADPCM_STATUS_READY)
  {   
    if((Mode == TRANSMITTER) || (Mode == HALF_DUPLEX))
    {
      /* Audio acquisition is resumed */
      BSP_AUDIO_IN_Resume();
    }
  }
  else if (Status == BV_ADPCM_STATUS_STREAMING)
  {
    /* Audio acquisition is paused */
    BSP_AUDIO_IN_Pause();
  }
  else if (Status == BV_ADPCM_STATUS_RECEIVING)
  {
    /*Nothing to be done*/
  }
}

/**
 * @brief  Error handler.
 * @param  None.
 * @retval None.
 */
void BV_APP_PER_Error_Handler(void)
{
  while(1)
  {
  }
}    
       
/**
 * @}
 */

/**
* @}
*/

/**
 * @}
 */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

STBlueMS_iOS

For iOS App starting point

AVS Sample App

Alexa Sample App for reference

Credits

Hoang Nhu

Hoang Nhu

1 project • 2 followers
Embedded System Architect
Triet Pham

Triet Pham

0 projects • 0 followers

Comments