Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: SimpleBLE-ObCP_ENSMM_V2019_Test_BLE_S SimpleBLE-ObCp_test-BLE_envoi SimpleBLE-ObCp_test-BLE Roller_catcher_Envoi ... more
source/BlueNRGDevice.cpp
- Committer:
- jimbaud
- Date:
- 2019-12-17
- Revision:
- 308:8886c0252544
- Parent:
- 293:5a1f577bf92f
File content as of revision 308:8886c0252544:
/* 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();
}