HW layer for the Nucleo board, it only work with old BLE_API

Dependents:   Hello_BLE F446RE-BLE

Fork of X_NUCLEO_IDB0XA1 by ST

BlueNRGDevice.cpp

Committer:
Wolfgang Betz
Date:
2015-07-23
Revision:
91:97c0c21046b4
Parent:
90:26c0c9807ab4
Child:
92:709d44dc869a

File content as of revision 91:97c0c21046b4:

/* 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>&copy; COPYRIGHT 2013 STMicroelectronics</center></h2>
  */

/** @defgroup BlueNRGDevice
 *  @brief BlueNRG BLE_API Device Adaptation
 *  @{
 */

#include "mbed.h"
#include "BlueNRGDevice.h"
#include "BlueNRGGap.h"
#include "BlueNRGGattServer.h"

#include "btle.h"
#include "Utils.h"
#include "osal.h"

extern "C" {
#include "hci.h"
}

#define HEADER_SIZE 5
#define MAX_BUFFER_SIZE 255

/**
* The singleton which represents the BlueNRG transport for the BLEDevice.
* FIXME: find a better way to create the BlueNRG device instance so that 
* the pin names can be chosen by the users of this class
*
* This is using Arduino pins as follows:
* D11: MOSI line of SPI interface
* D12: MISO line of SPI interface
* D3 : SCK line of SPI interface
* A1 : nCS line of SPI interface
* D7 : BlueNRG reset
* A0 : BlueNRG IRQ pin
*/
BlueNRGDevice bluenrgDeviceInstance(D11, D12, D3, A1, D7, A0);

/**
* 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) : spi_(mosi, miso, sck), nCS_(cs), rst_(rst), irq_(irq)
{
    isInitialized = false;

    // 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);
}

/**************************************************************************/
/**
    @brief  Destructor
*/
/**************************************************************************/
BlueNRGDevice::~BlueNRGDevice(void)
{
}


/**
    @brief  Initialises anything required to start using BLE
    @param[in] void
    @returns    ble_error_t
*/
ble_error_t BlueNRGDevice::init(void)
{
    // Set the interrupt handler for the device
    irq_.rise(&HCI_Isr);

    /* ToDo: Clear memory contents, reset the SD, etc. */
    btle_init(BlueNRGGap::getInstance().getIsSetAddress());

    isInitialized = true;
    
    return BLE_ERROR_NONE;
}


/**
    @brief  Resets the BLE HW, removing any existing services and
            characteristics
    @param[in] void
    @returns    ble_error_t
*/
ble_error_t 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);
    
    isInitialized = false;

    return BLE_ERROR_NONE;
}


/*!
    @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 {
        HCI_Process();

        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
    @param[in] void
    @returns    char *
*/
const char *BlueNRGDevice::getVersion(void)
{
    char *version = new char[6];
    memcpy((void *)version, "1.0.0", 5);
    return version;
}

/**************************************************************************/
/*!
    @brief  get init state
    @param[in] void
    @returns    bool
*/
/**************************************************************************/
bool BlueNRGDevice::getIsInitialized(void)
{
    return isInitialized;
}

/**************************************************************************/
/*!
    @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();
}

//FIXME: TBI (by now just placeholders to let build
GattClient& BlueNRGDevice::getGattClient() {}
SecurityManager& BlueNRGDevice::getSecurityManager(){}
const SecurityManager& BlueNRGDevice::getSecurityManager() const {}

/**************************************************************************/
/*!
    @brief  shut down the the BLE device
    @param[out] error if any
*/
/**************************************************************************/
ble_error_t  BlueNRGDevice::shutdown(void) {
    return reset();
}

/**
 * @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 read_char;
    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};

    //unsigned char read_char_buf[MAX_BUFFER_SIZE];

    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++) {
                read_char = spi_.write(*(data1 + i));
            }
            for (i = 0; i < Nb_bytes2; i++) {
                read_char = 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();
}