This is an example of BLE GATT Client, which receives broadcast data from BLE_Server_BME280 ( a GATT server) , then transfers values up to mbed Device Connector (cloud).
Please refer details about BLEClient_mbedDevConn below. https://github.com/soramame21/BLEClient_mbedDevConn
The location of required BLE GATT server, BLE_Server_BME280, is at here. https://developer.mbed.org/users/edamame22/code/BLE_Server_BME280/
Diff: shields/TARGET_ST_BLUENRG/source/BlueNRGDevice.cpp
- Revision:
- 0:29983394c6b6
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/shields/TARGET_ST_BLUENRG/source/BlueNRGDevice.cpp Thu Apr 13 04:48:11 2017 +0000 @@ -0,0 +1,475 @@ +/* mbed Microcontroller Library +* Copyright (c) 2006-2013 ARM Limited +* +* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +/** + ****************************************************************************** + * @file BlueNRGDevice.cpp + * @author STMicroelectronics + * @brief Implementation of BLEDeviceInstanceBase + ****************************************************************************** + * @copy + * + * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS + * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE + * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY + * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING + * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE + * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + * <h2><center>© COPYRIGHT 2013 STMicroelectronics</center></h2> + */ + +/** @defgroup BlueNRGDevice + * @brief BlueNRG BLE_API Device Adaptation + * @{ + */ + +#ifdef YOTTA_CFG_MBED_OS + #include "mbed-drivers/mbed.h" +#else + #include "mbed.h" +#endif +#include "BlueNRGDevice.h" +#include "BlueNRGGap.h" +#include "BlueNRGGattServer.h" + +#include "btle.h" +#include "ble_utils.h" +#include "ble_osal.h" + +#include "ble_debug.h" +#include "stm32_bluenrg_ble.h" + +extern "C" { + #include "ble_hci.h" + #include "bluenrg_utils.h" +} + +#define HEADER_SIZE 5 +#define MAX_BUFFER_SIZE 255 + +/** + * The singleton which represents the BlueNRG transport for the BLEDevice. + * + * See file 'x_nucleo_idb0xa1_targets.h' for details regarding the peripheral pins used! + */ +#include "x_nucleo_idb0xa1_targets.h" + +BlueNRGDevice bluenrgDeviceInstance(IDB0XA1_PIN_SPI_MOSI, + IDB0XA1_PIN_SPI_MISO, + IDB0XA1_PIN_SPI_SCK, + IDB0XA1_PIN_SPI_nCS, + IDB0XA1_PIN_SPI_RESET, + IDB0XA1_PIN_SPI_IRQ); + +/** +* BLE-API requires an implementation of the following function in order to +* obtain its transport handle. +*/ +BLEInstanceBase * +createBLEInstance(void) +{ + return (&bluenrgDeviceInstance); +} + +/**************************************************************************/ +/** + @brief Constructor + * @param mosi mbed pin to use for MOSI line of SPI interface + * @param miso mbed pin to use for MISO line of SPI interface + * @param sck mbed pin to use for SCK line of SPI interface + * @param cs mbed pin to use for not chip select line of SPI interface + * @param rst mbed pin to use for BlueNRG reset + * @param irq mbed pin for BlueNRG IRQ +*/ +/**************************************************************************/ +BlueNRGDevice::BlueNRGDevice(PinName mosi, + PinName miso, + PinName sck, + PinName cs, + PinName rst, + PinName irq) : + isInitialized(false), spi_(mosi, miso, sck), nCS_(cs), rst_(rst), irq_(irq) +{ + // Setup the spi for 8 bit data, low clock polarity, + // 1-edge phase, with an 8MHz clock rate + spi_.format(8, 0); + spi_.frequency(8000000); + + // Deselect the BlueNRG chip by keeping its nCS signal high + nCS_ = 1; + + wait_us(500); + + // Prepare communication between the host and the BlueNRG SPI interface + HCI_Init(); + + // Set the interrupt handler for the device + irq_.mode(PullDown); // set irq mode + irq_.rise(&HCI_Isr); +} + +/**************************************************************************/ +/** + @brief Destructor +*/ +/**************************************************************************/ +BlueNRGDevice::~BlueNRGDevice(void) +{ +} + +/** + * @brief Get BlueNRG HW version in bootloader mode + * @param hw_version The HW version is written to this parameter + * @retval It returns BLE_STATUS_SUCCESS on success or an error code otherwise + */ +uint8_t BlueNRGDevice::getUpdaterHardwareVersion(uint8_t *hw_version) +{ + uint8_t status; + + status = getBlueNRGUpdaterHWVersion(hw_version); + + return (status); +} + +/** + * @brief Flash a new firmware using internal bootloader. + * @param fw_image Pointer to the firmware image (raw binary data, + * little-endian). + * @param fw_size Size of the firmware image. The firmware image size shall + * be multiple of 4 bytes. + * @retval int It returns BLE_STATUS_SUCCESS on success, or a number + * not equal to 0 in case of error + * (ACI_ERROR, UNSUPPORTED_VERSION, WRONG_IMAGE_SIZE, CRC_ERROR) + */ +int BlueNRGDevice::updateFirmware(const uint8_t *fw_image, uint32_t fw_size) +{ + int status = program_device(fw_image, fw_size); + + return (status); +} + + +/** + * @brief Initialises anything required to start using BLE + * @param[in] instanceID + * The ID of the instance to initialize. + * @param[in] callback + * A callback for when initialization completes for a BLE + * instance. This is an optional parameter set to NULL when not + * supplied. + * + * @return BLE_ERROR_NONE if the initialization procedure was started + * successfully. + */ +ble_error_t BlueNRGDevice::init(BLE::InstanceID_t instanceID, FunctionPointerWithContext<BLE::InitializationCompleteCallbackContext *> callback) +{ + if (isInitialized) { + BLE::InitializationCompleteCallbackContext context = { + BLE::Instance(instanceID), + BLE_ERROR_ALREADY_INITIALIZED + }; + callback.call(&context); + return BLE_ERROR_ALREADY_INITIALIZED; + } + + // Init the BlueNRG/BlueNRG-MS stack + btleInit(); + + isInitialized = true; + BLE::InitializationCompleteCallbackContext context = { + BLE::Instance(instanceID), + BLE_ERROR_NONE + }; + callback.call(&context); + + return BLE_ERROR_NONE; +} + + +/** + @brief Resets the BLE HW, removing any existing services and + characteristics + @param[in] void + @returns void +*/ +void BlueNRGDevice::reset(void) +{ + wait_us(500); + + /* Reset BlueNRG SPI interface */ + rst_ = 0; + wait_us(5); + rst_ = 1; + wait_us(5); + + /* Wait for the radio to come back up */ + wait_us(500); + +} + +/*! + @brief Wait for any BLE Event like BLE Connection, Read Request etc. + @param[in] void + @returns char * +*/ +void BlueNRGDevice::waitForEvent(void) +{ + bool must_return = false; + + do { + bluenrgDeviceInstance.processEvents(); + + if(must_return) return; + + __WFE(); /* it is recommended that SEVONPEND in the + System Control Register is NOT set */ + must_return = true; /* after returning from WFE we must guarantee + that conrol is given back to main loop before next WFE */ + } while(true); + +} + +/*! + @brief get GAP version + @brief Get the BLE stack version information + @param[in] void + @returns char * + @returns char * +*/ +const char *BlueNRGDevice::getVersion(void) +{ + return getVersionString(); +} + +/**************************************************************************/ +/*! + @brief get reference to GAP object + @param[in] void + @returns Gap& +*/ +/**************************************************************************/ +Gap &BlueNRGDevice::getGap() +{ + return BlueNRGGap::getInstance(); +} + +const Gap &BlueNRGDevice::getGap() const +{ + return BlueNRGGap::getInstance(); +} + +/**************************************************************************/ +/*! + @brief get reference to GATT server object + @param[in] void + @returns GattServer& +*/ +/**************************************************************************/ +GattServer &BlueNRGDevice::getGattServer() +{ + return BlueNRGGattServer::getInstance(); +} + +const GattServer &BlueNRGDevice::getGattServer() const +{ + return BlueNRGGattServer::getInstance(); +} + +/**************************************************************************/ +/*! + @brief shut down the BLE device + @param[out] error if any +*/ +/**************************************************************************/ +ble_error_t BlueNRGDevice::shutdown(void) { + if (!isInitialized) { + return BLE_ERROR_INITIALIZATION_INCOMPLETE; + } + + /* Reset the BlueNRG device first */ + reset(); + + /* Shutdown the BLE API and BlueNRG glue code */ + ble_error_t error; + + /* GattServer instance */ + error = BlueNRGGattServer::getInstance().reset(); + if (error != BLE_ERROR_NONE) { + return error; + } + + /* GattClient instance */ + error = BlueNRGGattClient::getInstance().reset(); + if (error != BLE_ERROR_NONE) { + return error; + } + + /* Gap instance */ + error = BlueNRGGap::getInstance().reset(); + if (error != BLE_ERROR_NONE) { + return error; + } + + isInitialized = false; + + return BLE_ERROR_NONE; + +} + +/** + * @brief Reads from BlueNRG SPI buffer and store data into local buffer. + * @param buffer : Buffer where data from SPI are stored + * @param buff_size: Buffer size + * @retval int32_t : Number of read bytes + */ +int32_t BlueNRGDevice::spiRead(uint8_t *buffer, uint8_t buff_size) +{ + uint16_t byte_count; + uint8_t len = 0; + uint8_t char_ff = 0xff; + volatile uint8_t read_char; + + uint8_t i = 0; + volatile uint8_t tmpreg; + + uint8_t header_master[HEADER_SIZE] = {0x0b, 0x00, 0x00, 0x00, 0x00}; + uint8_t header_slave[HEADER_SIZE]; + + /* Select the chip */ + nCS_ = 0; + + /* Read the header */ + for (i = 0; i < 5; i++) + { + tmpreg = spi_.write(header_master[i]); + header_slave[i] = (uint8_t)(tmpreg); + } + + if (header_slave[0] == 0x02) { + /* device is ready */ + byte_count = (header_slave[4]<<8)|header_slave[3]; + + if (byte_count > 0) { + + /* avoid to read more data that size of the buffer */ + if (byte_count > buff_size){ + byte_count = buff_size; + } + + for (len = 0; len < byte_count; len++){ + read_char = spi_.write(char_ff); + buffer[len] = read_char; + } + } + } + /* Release CS line to deselect the chip */ + nCS_ = 1; + + // Add a small delay to give time to the BlueNRG to set the IRQ pin low + // to avoid a useless SPI read at the end of the transaction + for(volatile int i = 0; i < 2; i++)__NOP(); + +#ifdef PRINT_CSV_FORMAT + if (len > 0) { + print_csv_time(); + for (int i=0; i<len; i++) { + PRINT_CSV(" %02x", buffer[i]); + } + PRINT_CSV("\n"); + } +#endif + + return len; +} + +/** + * @brief Writes data from local buffer to SPI. + * @param data1 : First data buffer to be written + * @param data2 : Second data buffer to be written + * @param Nb_bytes1: Size of first data buffer to be written + * @param Nb_bytes2: Size of second data buffer to be written + * @retval Number of read bytes + */ +int32_t BlueNRGDevice::spiWrite(uint8_t* data1, + uint8_t* data2, uint8_t Nb_bytes1, uint8_t Nb_bytes2) +{ + int32_t result = 0; + uint32_t i; + volatile uint8_t tmpreg; + + unsigned char header_master[HEADER_SIZE] = {0x0a, 0x00, 0x00, 0x00, 0x00}; + unsigned char header_slave[HEADER_SIZE] = {0xaa, 0x00, 0x00, 0x00, 0x00}; + + disable_irq(); + + /* CS reset */ + nCS_ = 0; + + /* Exchange header */ + for (i = 0; i < 5; i++) + { + tmpreg = spi_.write(header_master[i]); + header_slave[i] = tmpreg; + } + + if (header_slave[0] == 0x02) { + /* SPI is ready */ + if (header_slave[1] >= (Nb_bytes1+Nb_bytes2)) { + + /* Buffer is big enough */ + for (i = 0; i < Nb_bytes1; i++) { + spi_.write(*(data1 + i)); + } + for (i = 0; i < Nb_bytes2; i++) { + spi_.write(*(data2 + i)); + } + } else { + /* Buffer is too small */ + result = -2; + } + } else { + /* SPI is not ready */ + result = -1; + } + + /* Release CS line */ + //HAL_GPIO_WritePin(BNRG_SPI_CS_PORT, BNRG_SPI_CS_PIN, GPIO_PIN_SET); + nCS_ = 1; + + enable_irq(); + + return result; +} + +bool BlueNRGDevice::dataPresent() +{ + return (irq_ == 1); +} + +void BlueNRGDevice::disable_irq() +{ + irq_.disable_irq(); +} + +void BlueNRGDevice::enable_irq() +{ + irq_.enable_irq(); +} + +void BlueNRGDevice::processEvents() { + btle_handler(); +}