Initial commit of NRF52840 target as the copy of NRF52832 and NRF52_DK.

pull/3841/head
Andrzej Puzdrowski 2016-12-09 12:21:52 +01:00
parent cc58a7fb0c
commit cd44b58d11
240 changed files with 103075 additions and 0 deletions

View File

@ -0,0 +1,97 @@
# LF Clock configuration using mbed configuration system
In order to provide the configuration for a low frequency (LF) clock, add a description of the LF clock inside a mbed configuration JSON file.
For example at application level the description might be added in a mbed_app.json file and on target level the description might be added in the hal/target.json file.
LF clock source configuration is used for MCU startup initialization and the BLE SoftDevice LF clock configuration (if BLE libraries is used). Advanced configurations are used only for the BLE SoftDevice LF clock configuration.
## Usage:
1. Clock source
Default clock source is XTAL oscillator. It is defined at the target level configuration as the target.lf_clock_src key.
There are three options that can be configured as the clock source:
- NRF_LF_SRC_XTAL
- NRF_LF_SRC_RC
- NRF_LF_SRC_SYNTH
In order to override this configuration use targed_override section in configuration file (e.g mbed_app.json)
```json
{
"target_overrides": {
"*": {
"target.lf_clock_src": "NRF_LF_SRC_XTAL"
}
}
}
```
2a. Advanced configuration of the LFCLK RC oscillator:
```json
{
"config": {
"lf_clock_rc_calib_timer_interval": {
"value": 16,
"macro_name": "MBED_CONF_NORDIC_NRF_LF_CLOCK_CALIB_TIMER_INTERVAL"
},
"lf_clock_rc_calib_mode_config": {
"value": 1,
"macro_name": "MBED_CONF_NORDIC_NRF_LF_CLOCK_CALIB_MODE_CONFIG"
}
}
}
```
"lf_clock_rc_calib_timer_interval" - Calibration timer interval in 250 ms. It is equivalent to nrf_clock_lf_cfg_t::rc_ctiv.
This item generates macro MBED_CONF_NORDIC_NRF_LF_CLOCK_CALIB_TIMER_INTERVAL.
By default, such configuration is set to 16.
"lf_clock_rc_calib_mode_config" - This value configures how often the RC oscillator will be calibrated, in number of calibration intervals.
It is equivalent to nrf_clock_lf_cfg_t::rc_temp_ctiv.
For further information, see the documentation for the [API of a SoftDevice 13x version 2.0.0](http://infocenter.nordicsemi.com/topic/com.nordic.infocenter.s132.api.v2.0.0/structnrf__clock__lf__cfg__t.html)
This item generates macro MBED_CONF_NORDIC_NRF_LF_CLOCK_CALIB_MODE_CONFIG.
By default, such configuration is set to 1.
2b. Advanced configuration of the LFCLK XTAL oscillator:
Accuracy of the clock source can be set. In order to do so macro MBED_CONF_NORDIC_LF_CLOCK_XTAL_ACCURACY should been provided (e.g. in mbed_app.json).
By default such configuration is set to NRF_CLOCK_LF_XTAL_ACCURACY_20_PPM.
For further information, see the documentation for the [API of a SoftDevice 13x version 2.0.0](https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.s132.api.v2.0.0%2Fgroup___n_r_f___s_d_m___d_e_f_i_n_e_s.html)
```json
{
"config": {
"lf_clock_xtal_accuracy": {
"value": "NRF_CLOCK_LF_XTAL_ACCURACY_250_PPM",
"macro_name": "MBED_CONF_NORDIC_LF_CLOCK_XTAL_ACCURACY"
}
}
}
```
2c. Advance configuration of the LFCLK Synthesized from HFCLK:
Accuracy of the clock source can be set. In order to do so macro MBED_CONF_NORDIC_LF_CLOCK_SYNTH_ACCURACY should been provided (e.g. in mbed_app.json).
By default, such configuration is set to NRF_CLOCK_LF_XTAL_ACCURACY_20_PPM.
For further information, see the documentation for the [API of a SoftDevice 13x version 2.0.0](https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.s132.api.v2.0.0%2Fgroup___n_r_f___s_d_m___d_e_f_i_n_e_s.html)
```json
{
"config": {
"lf_clock_synth_accuracy": {
"value": "NRF_CLOCK_LF_SYNTH_ACCURACY_250_PPM",
"macro_name": "MBED_CONF_NORDIC_LF_CLOCK_XTAL_ACCURACY"
}
}
}
```

View File

@ -0,0 +1,81 @@
/*
* Copyright (c) 2013 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#ifndef MBED_PERIPHERALNAMES_H
#define MBED_PERIPHERALNAMES_H
#include "cmsis.h"
#ifdef __cplusplus
extern "C" {
#endif
#define STDIO_UART_TX TX_PIN_NUMBER
#define STDIO_UART_RX RX_PIN_NUMBER
#define STDIO_UART UART_0
typedef enum {
UART_0 = (int)NRF_UART0_BASE
} UARTName;
typedef enum {
SPI_0 = (int)NRF_SPI0_BASE,
SPI_1 = (int)NRF_SPI1_BASE,
SPIS = (int)NRF_SPIS1_BASE
} SPIName;
typedef enum {
PWM_1 = 0,
PWM_2
} PWMName;
typedef enum {
I2C_0 = (int)NRF_TWI0_BASE,
I2C_1 = (int)NRF_TWI1_BASE
} I2CName;
typedef enum {
ADC0_0 = (int)0
} ADCName;
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,53 @@
/*
* Copyright (c) 2013 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#ifndef MBED_PORTNAMES_H
#define MBED_PORTNAMES_H
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
Port0 = 0 //GPIO pins 0-31
} PortName;
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,203 @@
/*
* Copyright (c) 2016 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#ifndef MBED_PINNAMES_H
#define MBED_PINNAMES_H
#include "cmsis.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
PIN_INPUT,
PIN_OUTPUT
} PinDirection;
#define PORT_SHIFT 3
typedef enum {
p0 = 0,
p1 = 1,
p2 = 2,
p3 = 3,
p4 = 4,
p5 = 5,
p6 = 6,
p7 = 7,
p8 = 8,
p9 = 9,
p10 = 10,
p11 = 11,
p12 = 12,
p13 = 13,
p14 = 14,
p15 = 15,
p16 = 16,
p17 = 17,
p18 = 18,
p19 = 19,
p20 = 20,
p21 = 21,
p22 = 22,
p23 = 23,
p24 = 24,
p25 = 25,
p26 = 26,
p27 = 27,
p28 = 28,
p29 = 29,
p30 = 30,
p31 = 31,
P0_0 = p0,
P0_1 = p1,
P0_2 = p2,
P0_3 = p3,
P0_4 = p4,
P0_5 = p5,
P0_6 = p6,
P0_7 = p7,
P0_8 = p8,
P0_9 = p9,
P0_10 = p10,
P0_11 = p11,
P0_12 = p12,
P0_13 = p13,
P0_14 = p14,
P0_15 = p15,
P0_16 = p16,
P0_17 = p17,
P0_18 = p18,
P0_19 = p19,
P0_20 = p20,
P0_21 = p21,
P0_22 = p22,
P0_23 = p23,
P0_24 = p24,
P0_25 = p25,
P0_26 = p26,
P0_27 = p27,
P0_28 = p28,
P0_29 = p29,
P0_30 = p30,
P0_31 = p31,
LED1 = p17,
LED2 = p18,
LED3 = p19,
LED4 = p20,
BUTTON1 = p13,
BUTTON2 = p14,
BUTTON3 = p15,
BUTTON4 = p16,
RX_PIN_NUMBER = p8,
TX_PIN_NUMBER = p6,
CTS_PIN_NUMBER = p7,
RTS_PIN_NUMBER = p5,
// mBed interface Pins
USBTX = TX_PIN_NUMBER,
USBRX = RX_PIN_NUMBER,
SPI_PSELMOSI0 = p23,
SPI_PSELMISO0 = p24,
SPI_PSELSS0 = p22,
SPI_PSELSCK0 = p25,
SPI_PSELMOSI1 = p12,
SPI_PSELMISO1 = p13,
SPI_PSELSS1 = p11,
SPI_PSELSCK1 = p14,
SPIS_PSELMOSI = p12,
SPIS_PSELMISO = p13,
SPIS_PSELSS = p11,
SPIS_PSELSCK = p14,
I2C_SDA0 = p26,
I2C_SCL0 = p27,
D0 = p11,
D1 = p12,
D2 = p13,
D3 = p14,
D4 = p15,
D5 = p16,
D6 = p17,
D7 = p18,
D8 = p19,
D9 = p20,
D10 = p22,
D11 = p23,
D12 = p24,
D13 = p25,
D14 = p26,
D15 = p27,
A0 = p3,
A1 = p4,
A2 = p28,
A3 = p29,
A4 = p30,
A5 = p31,
// Not connected
NC = (int)0xFFFFFFFF
} PinName;
typedef enum {
PullNone = 0,
PullDown = 1,
PullUp = 3,
PullDefault = PullUp
} PinMode;
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,38 @@
// The 'features' section in 'target.json' is now used to create the device's hardware preprocessor switches.
// Check the 'features' section of the target description in 'targets.json' for more details.
/* 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.
*/
#ifndef MBED_DEVICE_H
#define MBED_DEVICE_H
#include "objects.h"
#endif

View File

@ -0,0 +1,91 @@
/* 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.
*/
#include "mbed_assert.h"
#include "analogin_api.h"
#include "cmsis.h"
#include "pinmap.h"
#include "app_util_platform.h"
#include "nrf_drv_saadc.h"
#ifdef DEVICE_ANALOGIN
#define ADC_12BIT_RANGE 0xFFF
#define ADC_RANGE ADC_12BIT_RANGE
static void analog_in_event_handler(nrf_drv_saadc_evt_t const *p_event)// type of nrf_drv_saadc_event_handler_t
{
(void) p_event;
}
static const nrf_drv_saadc_config_t saadc_config =
{
.resolution = NRF_SAADC_RESOLUTION_12BIT,
.oversample = NRF_SAADC_OVERSAMPLE_DISABLED,
.interrupt_priority = SAADC_CONFIG_IRQ_PRIORITY
};
void SAADC_IRQHandler(void);
void analogin_init(analogin_t *obj, PinName pin)
{
ret_code_t ret_code;
NVIC_SetVector(SAADC_IRQn, (uint32_t)SAADC_IRQHandler);
ret_code = nrf_drv_saadc_init(&saadc_config, analog_in_event_handler);
MBED_ASSERT(((ret_code == NRF_SUCCESS) || (ret_code == NRF_ERROR_INVALID_STATE))); //NRF_ERROR_INVALID_STATE expected for multiple channels used.
uint8_t saadcIn = nrf_drv_saadc_gpio_to_ain(pin);
MBED_ASSERT(saadcIn != NRF_SAADC_INPUT_DISABLED);
obj->adc = ADC0_0; // only one instance of ADC in nRF52 SoC
obj->adc_pin = saadcIn - 1;
nrf_saadc_channel_config_t channel_config =
NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(saadcIn); //Single ended, negative input to ADC shorted to GND.
ret_code = nrf_drv_saadc_channel_init(obj->adc_pin, &channel_config);
MBED_ASSERT(ret_code == NRF_SUCCESS);
}
uint16_t analogin_read_u16(analogin_t *obj)
{
int16_t adc_value;
ret_code_t ret_code;
ret_code = nrf_drv_saadc_sample_convert(obj->adc_pin, &adc_value);
MBED_ASSERT(ret_code == NRF_SUCCESS);
if (adc_value < 0)
{
// Even in the single ended mode measured value can be {-0}. Saturation for avoid casting to a big integer.
return 0;
}
else
{
return (uint16_t) adc_value;
}
}
float analogin_read(analogin_t *obj)
{
uint16_t value = analogin_read_u16(obj);
return (float)value * (1.0f / (float)ADC_RANGE);
}
#endif // DEVICE_ANALOGIN

View File

@ -0,0 +1,27 @@
;WITHOUT SOFTDEVICE:
;LR_IROM1 0x00000000 0x00040000 {
; ER_IROM1 0x00000000 0x00040000 {
; *.o (RESET, +First)
; *(InRoot$$Sections)
; .ANY (+RO)
; }
; RW_IRAM1 0x20000000 0x00004000 {
; .ANY (+RW +ZI)
; }
;}
;
;WITH SOFTDEVICE:
LR_IROM1 0x1C000 0x0064000 {
ER_IROM1 0x1C000 0x0064000 {
*.o (RESET, +First)
*(InRoot$$Sections)
.ANY (+RO)
}
RW_IRAM0 0x20002EF8 UNINIT 0x000000D8 { ;no init section
*(noinit)
}
RW_IRAM1 0x20002FD0 0x0000D030 {
.ANY (+RW +ZI)
}
}

View File

@ -0,0 +1,245 @@
;/* Copyright (c) 2012 ARM LIMITED
;
; All rights reserved.
; Redistribution and use in source and binary forms, with or without
; modification, are permitted provided that the following conditions are met:
; - Redistributions of source code must retain the above copyright
; notice, this list of conditions and the following disclaimer.
; - 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.
; - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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.
; ---------------------------------------------------------------------------*/
__initial_sp EQU 0x20010000
PRESERVE8
THUMB
; Vector Table Mapped to Address 0 at Reset
AREA RESET, DATA, READONLY
EXPORT __Vectors
EXPORT __Vectors_End
EXPORT __Vectors_Size
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler
DCD NMI_Handler
DCD HardFault_Handler
DCD MemoryManagement_Handler
DCD BusFault_Handler
DCD UsageFault_Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVC_Handler
DCD DebugMonitor_Handler
DCD 0 ; Reserved
DCD PendSV_Handler
DCD SysTick_Handler
; External Interrupts
DCD POWER_CLOCK_IRQHandler
DCD RADIO_IRQHandler
DCD UARTE0_UART0_IRQHandler_v
DCD SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler_v
DCD SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler_v
DCD NFCT_IRQHandler_v
DCD GPIOTE_IRQHandler_v
DCD SAADC_IRQHandler_v
DCD TIMER0_IRQHandler_v
DCD TIMER1_IRQHandler_v
DCD TIMER2_IRQHandler_v
DCD RTC0_IRQHandler
DCD TEMP_IRQHandler_v
DCD RNG_IRQHandler
DCD ECB_IRQHandler
DCD CCM_AAR_IRQHandler
DCD WDT_IRQHandler_v
DCD RTC1_IRQHandler_v
DCD QDEC_IRQHandler_v
DCD COMP_LPCOMP_IRQHandler_v
DCD SWI0_EGU0_IRQHandler_v
DCD SWI1_EGU1_IRQHandler_v
DCD SWI2_EGU2_IRQHandler_v
DCD SWI3_EGU3_IRQHandler_v
DCD SWI4_EGU4_IRQHandler
DCD SWI5_EGU5_IRQHandler
DCD TIMER3_IRQHandler_v
DCD TIMER4_IRQHandler_v
DCD PWM0_IRQHandler_v
DCD PDM_IRQHandler_v
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD MWU_IRQHandler
DCD PWM1_IRQHandler_v
DCD PWM2_IRQHandler_v
DCD SPIM2_SPIS2_SPI2_IRQHandler_v
DCD RTC2_IRQHandler_v
DCD I2S_IRQHandler_v
DCD FPU_IRQHandler_v
__Vectors_End
__Vectors_Size EQU __Vectors_End - __Vectors
AREA |.text|, CODE, READONLY
; Reset Handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
IMPORT nrf_reloc_vector_table
LDR R0, =SystemInit
BLX R0
LDR R0, =nrf_reloc_vector_table
BLX R0
LDR R0, =__main
BX R0
ENDP
; Dummy Exception Handlers (infinite loops which can be modified)
NMI_Handler PROC
EXPORT NMI_Handler [WEAK]
B .
ENDP
HardFault_Handler\
PROC
EXPORT HardFault_Handler [WEAK]
B .
ENDP
MemoryManagement_Handler\
PROC
EXPORT MemoryManagement_Handler [WEAK]
B .
ENDP
BusFault_Handler\
PROC
EXPORT BusFault_Handler [WEAK]
B .
ENDP
UsageFault_Handler\
PROC
EXPORT UsageFault_Handler [WEAK]
B .
ENDP
SVC_Handler PROC
EXPORT SVC_Handler [WEAK]
B .
ENDP
DebugMonitor_Handler\
PROC
EXPORT DebugMonitor_Handler [WEAK]
B .
ENDP
PendSV_Handler PROC
EXPORT PendSV_Handler [WEAK]
B .
ENDP
SysTick_Handler PROC
EXPORT SysTick_Handler [WEAK]
B .
ENDP
Default_Handler PROC
EXPORT POWER_CLOCK_IRQHandler [WEAK]
EXPORT RADIO_IRQHandler [WEAK]
EXPORT UARTE0_UART0_IRQHandler_v [WEAK]
EXPORT SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler_v [WEAK]
EXPORT SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler_v [WEAK]
EXPORT NFCT_IRQHandler_v [WEAK]
EXPORT GPIOTE_IRQHandler_v [WEAK]
EXPORT SAADC_IRQHandler_v [WEAK]
EXPORT TIMER0_IRQHandler_v [WEAK]
EXPORT TIMER1_IRQHandler_v [WEAK]
EXPORT TIMER2_IRQHandler_v [WEAK]
EXPORT RTC0_IRQHandler [WEAK]
EXPORT TEMP_IRQHandler_v [WEAK]
EXPORT RNG_IRQHandler [WEAK]
EXPORT ECB_IRQHandler [WEAK]
EXPORT CCM_AAR_IRQHandler [WEAK]
EXPORT WDT_IRQHandler_v [WEAK]
EXPORT RTC1_IRQHandler_v [WEAK]
EXPORT QDEC_IRQHandler_v [WEAK]
EXPORT COMP_LPCOMP_IRQHandler_v [WEAK]
EXPORT SWI0_EGU0_IRQHandler_v [WEAK]
EXPORT SWI1_EGU1_IRQHandler_v [WEAK]
EXPORT SWI2_EGU2_IRQHandler_v [WEAK]
EXPORT SWI3_EGU3_IRQHandler_v [WEAK]
EXPORT SWI4_EGU4_IRQHandler [WEAK]
EXPORT SWI5_EGU5_IRQHandler [WEAK]
EXPORT TIMER3_IRQHandler_v [WEAK]
EXPORT TIMER4_IRQHandler_v [WEAK]
EXPORT PWM0_IRQHandler_v [WEAK]
EXPORT PDM_IRQHandler_v [WEAK]
EXPORT MWU_IRQHandler [WEAK]
EXPORT PWM1_IRQHandler_v [WEAK]
EXPORT PWM2_IRQHandler_v [WEAK]
EXPORT SPIM2_SPIS2_SPI2_IRQHandler_v [WEAK]
EXPORT RTC2_IRQHandler_v [WEAK]
EXPORT I2S_IRQHandler_v [WEAK]
EXPORT FPU_IRQHandler_v [WEAK]
POWER_CLOCK_IRQHandler
RADIO_IRQHandler
UARTE0_UART0_IRQHandler_v
SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler_v
SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler_v
NFCT_IRQHandler_v
GPIOTE_IRQHandler_v
SAADC_IRQHandler_v
TIMER0_IRQHandler_v
TIMER1_IRQHandler_v
TIMER2_IRQHandler_v
RTC0_IRQHandler
TEMP_IRQHandler_v
RNG_IRQHandler
ECB_IRQHandler
CCM_AAR_IRQHandler
WDT_IRQHandler_v
RTC1_IRQHandler_v
QDEC_IRQHandler_v
COMP_LPCOMP_IRQHandler_v
SWI0_EGU0_IRQHandler_v
SWI1_EGU1_IRQHandler_v
SWI2_EGU2_IRQHandler_v
SWI3_EGU3_IRQHandler_v
SWI4_EGU4_IRQHandler
SWI5_EGU5_IRQHandler
TIMER3_IRQHandler_v
TIMER4_IRQHandler_v
PWM0_IRQHandler_v
PDM_IRQHandler_v
MWU_IRQHandler
PWM1_IRQHandler_v
PWM2_IRQHandler_v
SPIM2_SPIS2_SPI2_IRQHandler_v
RTC2_IRQHandler_v
I2S_IRQHandler_v
FPU_IRQHandler_v
B .
ENDP
ALIGN
END

View File

@ -0,0 +1,31 @@
/* mbed Microcontroller Library - stackheap
* Copyright (C) 2009-2011 ARM Limited. All rights reserved.
*
* Setup a fixed single stack/heap memory model,
* between the top of the RW/ZI region and the stackpointer
*/
#ifdef __cplusplus
extern "C" {
#endif
#include <rt_misc.h>
#include <stdint.h>
extern char Image$$RW_IRAM1$$ZI$$Limit[];
extern __value_in_regs struct __initial_stackheap __user_setup_stackheap(uint32_t R0, uint32_t R1, uint32_t R2, uint32_t R3) {
uint32_t zi_limit = (uint32_t)Image$$RW_IRAM1$$ZI$$Limit;
uint32_t sp_limit = __current_sp();
zi_limit = (zi_limit + 7) & ~0x7; // ensure zi_limit is 8-byte aligned
struct __initial_stackheap r;
r.heap_base = zi_limit;
r.heap_limit = sp_limit;
return r;
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,190 @@
/*
* Copyright (c) 2015 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.
*/
/* Linker script to configure memory regions. */
MEMORY
{
FLASH (rx) : ORIGIN = 0x1C000, LENGTH = 0x64000
RAM (rwx) : ORIGIN = 0x20002ef8, LENGTH = 0xd108
}
OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
/* Linker script to place sections and symbol values. Should be used together
* with the other linker script that defines memory regions FLASH and RAM.
* It references the following symbols that must be defined in code:
* Reset_Handler : Entry of reset handler
*
* It defines the following symbols that the code can use without definition:
* __exidx_start
* __exidx_end
* __etext
* __data_start__
* __preinit_array_start
* __preinit_array_end
* __init_array_start
* __init_array_end
* __fini_array_start
* __fini_array_end
* __data_end__
* __bss_start__
* __bss_end__
* __end__
* end
* __HeapLimit
* __StackLimit
* __StackTop
* __stack
*/
ENTRY(Reset_Handler)
SECTIONS
{
.text :
{
KEEP(*(.Vectors))
*(.text*)
KEEP(*(.init))
KEEP(*(.fini))
/* .ctors */
*crtbegin.o(.ctors)
*crtbegin?.o(.ctors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
*(SORT(.ctors.*))
*(.ctors)
/* .dtors */
*crtbegin.o(.dtors)
*crtbegin?.o(.dtors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
*(SORT(.dtors.*))
*(.dtors)
*(.rodata*)
KEEP(*(.eh_frame*))
} > FLASH
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
. = ALIGN(4);
} > FLASH
__exidx_start = .;
.ARM.exidx :
{
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
. = ALIGN(4);
} > FLASH
__exidx_end = .;
__etext = .;
.data : AT (__etext)
{
__data_start__ = .;
*(vtable)
*(.data*)
. = ALIGN(4);
/* preinit data */
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP(*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
. = ALIGN(4);
/* init data */
PROVIDE_HIDDEN (__init_array_start = .);
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
PROVIDE_HIDDEN (__init_array_end = .);
. = ALIGN(4);
/* finit data */
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP(*(SORT(.fini_array.*)))
KEEP(*(.fini_array))
PROVIDE_HIDDEN (__fini_array_end = .);
. = ALIGN(4);
PROVIDE(__start_fs_data = .);
KEEP(*(.fs_data))
PROVIDE(__stop_fs_data = .);
*(.jcr)
. = ALIGN(4);
/* All data end */
__data_end__ = .;
} > RAM
__edata = .;
.noinit :
{
PROVIDE(__start_noinit = .);
KEEP(*(.noinit))
PROVIDE(__stop_noinit = .);
} > RAM
.bss :
{
. = ALIGN(4);
__bss_start__ = .;
*(.bss*)
*(COMMON)
. = ALIGN(4);
__bss_end__ = .;
} > RAM
.heap (NOLOAD):
{
__end__ = .;
end = __end__;
*(.heap*);
/* Expand the heap to reach the stack boundary. */
ASSERT(. <= (ORIGIN(RAM) + LENGTH(RAM) - 0x800), "heap region overflowed into stack");
. += (ORIGIN(RAM) + LENGTH(RAM) - 0x800) - .;
} > RAM
PROVIDE(__heap_start = ADDR(.heap));
PROVIDE(__heap_size = SIZEOF(.heap));
PROVIDE(__mbed_sbrk_start = ADDR(.heap));
PROVIDE(__mbed_krbs_start = ADDR(.heap) + SIZEOF(.heap));
/* .stack_dummy section does not contain any symbols. It is only
* used for the linker script to calculate the size of stack sections
* and assign values to stack symbols later. */
.stack (NOLOAD):
{
__StackLimit = .;
*(.stack*)
. += (ORIGIN(RAM) + LENGTH(RAM) - .);
} > RAM
/* Set the stack top to the end of RAM and move down the stack limit by
* the size of the stack_dummy section. */
__StackTop = ORIGIN(RAM) + LENGTH(RAM);
__StackLimit = __StackTop - SIZEOF(.stack);
PROVIDE(__stack = __StackTop);
}

View File

@ -0,0 +1,270 @@
/*
* Copyright (c) 2013 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/*
NOTE: Template files (including this one) are application specific and therefore
expected to be copied into the application project folder prior to its use!
*/
.syntax unified
.arch armv7e-m
.section .Vectors
.align 2
.globl __Vectors
__Vectors:
.long __StackTop /* Top of Stack */
.long Reset_Handler
.long NMI_Handler
.long HardFault_Handler
.long MemoryManagement_Handler
.long BusFault_Handler
.long UsageFault_Handler
.long 0 /*Reserved */
.long 0 /*Reserved */
.long 0 /*Reserved */
.long 0 /*Reserved */
.long SVC_Handler
.long 0 /*Reserved */
.long 0 /*Reserved */
.long PendSV_Handler
.long SysTick_Handler
/* External Interrupts */
.long POWER_CLOCK_IRQHandler
.long RADIO_IRQHandler
.long UARTE0_UART0_IRQHandler_v
.long SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler_v
.long SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler_v
.long NFCT_IRQHandler_v
.long GPIOTE_IRQHandler_v
.long SAADC_IRQHandler_v
.long TIMER0_IRQHandler_v
.long TIMER1_IRQHandler_v
.long TIMER2_IRQHandler_v
.long RTC0_IRQHandler
.long TEMP_IRQHandler_v
.long RNG_IRQHandler
.long ECB_IRQHandler
.long CCM_AAR_IRQHandler
.long WDT_IRQHandler_v
.long RTC1_IRQHandler_v
.long QDEC_IRQHandler_v
.long COMP_LPCOMP_IRQHandler_v
.long SWI0_EGU0_IRQHandler_v
.long SWI1_EGU1_IRQHandler_v
.long SWI2_EGU2_IRQHandler_v
.long SWI3_EGU3_IRQHandler_v
.long SWI4_EGU4_IRQHandler
.long SWI5_EGU5_IRQHandler
.long TIMER3_IRQHandler_v
.long TIMER4_IRQHandler_v
.long PWM0_IRQHandler_v
.long PDM_IRQHandler_v
.long 0 /*Reserved */
.long 0 /*Reserved */
.long MWU_IRQHandler
.long PWM1_IRQHandler_v
.long PWM2_IRQHandler_v
.long SPIM2_SPIS2_SPI2_IRQHandler_v
.long RTC2_IRQHandler_v
.long I2S_IRQHandler_v
.long FPU_IRQHandler_v
.size __Vectors, . - __Vectors
/* Reset Handler */
.text
.thumb
.thumb_func
.align 1
.globl Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
.fnstart
/* Loop to copy data from read only memory to RAM. The ranges
* of copy from/to are specified by following symbols evaluated in
* linker script.
* __etext: End of code section, i.e., begin of data sections to copy from.
* __data_start__/__data_end__: RAM address range that data should be
* copied to. Both must be aligned to 4 bytes boundary. */
ldr r1, =__etext
ldr r2, =__data_start__
ldr r3, =__data_end__
subs r3, r2
ble .LC0
.LC1:
subs r3, 4
ldr r0, [r1,r3]
str r0, [r2,r3]
bgt .LC1
.LC0:
LDR R0, =SystemInit
BLX R0
LDR R0, =nrf_reloc_vector_table
BLX R0
LDR R0, =_start
BX R0
.pool
.cantunwind
.fnend
.size Reset_Handler,.-Reset_Handler
.section ".text"
/* Dummy Exception Handlers (infinite loops which can be modified) */
.weak NMI_Handler
.type NMI_Handler, %function
NMI_Handler:
B .
.size NMI_Handler, . - NMI_Handler
.weak HardFault_Handler
.type HardFault_Handler, %function
HardFault_Handler:
B .
.size HardFault_Handler, . - HardFault_Handler
.weak MemoryManagement_Handler
.type MemoryManagement_Handler, %function
MemoryManagement_Handler:
B .
.size MemoryManagement_Handler, . - MemoryManagement_Handler
.weak BusFault_Handler
.type BusFault_Handler, %function
BusFault_Handler:
B .
.size BusFault_Handler, . - BusFault_Handler
.weak UsageFault_Handler
.type UsageFault_Handler, %function
UsageFault_Handler:
B .
.size UsageFault_Handler, . - UsageFault_Handler
.weak SVC_Handler
.type SVC_Handler, %function
SVC_Handler:
B .
.size SVC_Handler, . - SVC_Handler
.weak PendSV_Handler
.type PendSV_Handler, %function
PendSV_Handler:
B .
.size PendSV_Handler, . - PendSV_Handler
.weak SysTick_Handler
.type SysTick_Handler, %function
SysTick_Handler:
B .
.size SysTick_Handler, . - SysTick_Handler
/* IRQ Handlers */
.globl Default_Handler
.type Default_Handler, %function
Default_Handler:
B .
.size Default_Handler, . - Default_Handler
.macro IRQ handler
.weak \handler
.set \handler, Default_Handler
.endm
IRQ POWER_CLOCK_IRQHandler /* restricted */
IRQ RADIO_IRQHandler /* blocked */
IRQ UARTE0_UART0_IRQHandler_v
IRQ SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler_v
IRQ SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler_v
IRQ NFCT_IRQHandler_v
IRQ GPIOTE_IRQHandler_v
IRQ SAADC_IRQHandler_v
IRQ TIMER0_IRQHandler_v
IRQ TIMER1_IRQHandler_v
IRQ TIMER2_IRQHandler_v
IRQ RTC0_IRQHandler /* blocked */
IRQ TEMP_IRQHandler_v
IRQ RNG_IRQHandler /* restricted */
IRQ ECB_IRQHandler /* restricted */
IRQ CCM_AAR_IRQHandler /* blocked */
IRQ WDT_IRQHandler_v
IRQ RTC1_IRQHandler_v
IRQ QDEC_IRQHandler_v
IRQ COMP_LPCOMP_IRQHandler_v
IRQ SWI0_EGU0_IRQHandler_v
IRQ SWI1_EGU1_IRQHandler_v /* restricted for Radio Notification */
IRQ SWI2_EGU2_IRQHandler_v /* blocked for SoftDevice Event */
IRQ SWI3_EGU3_IRQHandler_v
IRQ SWI4_EGU4_IRQHandler /* blocked */
IRQ SWI5_EGU5_IRQHandler /* blocked */
IRQ TIMER3_IRQHandler_v
IRQ TIMER4_IRQHandler_v
IRQ PWM0_IRQHandler_v
IRQ PDM_IRQHandler_v
IRQ MWU_IRQHandler /* restricted */
IRQ PWM1_IRQHandler_v
IRQ PWM2_IRQHandler_v
IRQ SPIM2_SPIS2_SPI2_IRQHandler_v
IRQ RTC2_IRQHandler_v
IRQ I2S_IRQHandler_v
IRQ FPU_IRQHandler_v
.end

View File

@ -0,0 +1,46 @@
/*###ICF### Section handled by ICF editor, don't touch! ****/
/*-Editor annotation file-*/
/* IcfEditorFile="$TOOLKIT_DIR$\config\ide\IcfEditor\cortex_v1_0.xml" */
/*-Specials-*/
define symbol __ICFEDIT_intvec_start__ = 0x1c000;
/*-Memory Regions-*/
define symbol __ICFEDIT_region_ROM_start__ = 0x1c000;
define symbol __ICFEDIT_region_ROM_end__ = 0x7ffff;
define symbol __ICFEDIT_region_RAM_start__ = 0x20002ef8;
define symbol __ICFEDIT_region_RAM_end__ = 0x2000ffff;
export symbol __ICFEDIT_region_RAM_start__;
export symbol __ICFEDIT_region_RAM_end__;
/*-Sizes-*/
/*Heap 1/4 of ram and stack 1/8*/
define symbol __ICFEDIT_size_cstack__ = 0x800;
define symbol __ICFEDIT_size_heap__ = 0x1800;
/**** End of ICF editor section. ###ICF###*/
define symbol __code_start_soft_device__ = 0x0;
define memory mem with size = 4G;
define region ROM_region = mem:[from __ICFEDIT_region_ROM_start__ to __ICFEDIT_region_ROM_end__];
define region RAM_region = mem:[from __ICFEDIT_region_RAM_start__ to __ICFEDIT_region_RAM_end__];
define block CSTACK with alignment = 8, size = __ICFEDIT_size_cstack__ { };
define block HEAP with alignment = 8, size = __ICFEDIT_size_heap__ { };
initialize by copy { readwrite };
do not initialize { section .noinit };
keep { section .intvec };
place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec };
place in ROM_region { readonly };
place in RAM_region { readwrite,
block HEAP,
block CSTACK };
/*This is used for mbed applications build inside the Embedded workbench
Applications build with the python scritps use a hex merge so need to merge it
inside the linker. The linker can only use binary files so the hex merge is not possible
through the linker. That is why a binary is used instead of a hex image for the embedded project.
*/
if(isdefinedsymbol(SOFT_DEVICE_BIN))
{
place at address mem:__code_start_soft_device__ { section .noinit_softdevice };
}

View File

@ -0,0 +1,381 @@
;/* Copyright (c) 2012 ARM LIMITED
;
; All rights reserved.
; Redistribution and use in source and binary forms, with or without
; modification, are permitted provided that the following conditions are met:
; - Redistributions of source code must retain the above copyright
; notice, this list of conditions and the following disclaimer.
; - 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.
; - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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.
; ---------------------------------------------------------------------------*/
; The modules in this file are included in the libraries, and may be replaced
; by any user-defined modules that define the PUBLIC symbol _program_start or
; a user defined start symbol.
; To override the cstartup defined in the library, simply add your modified
; version to the workbench project.
;
; The vector table is normally located at address 0.
; When debugging in RAM, it can be located in RAM, aligned to at least 2^6.
; The name "__vector_table" has special meaning for C-SPY:
; it is where the SP start value is found, and the NVIC vector
; table register (VTOR) is initialized to this address if != 0.
MODULE ?cstartup
;; Stack size default : Defined in *.icf (linker file). Can be modified inside EW.
;; Heap size default : Defined in *.icf (linker file). Can be modified inside EW.
;; Forward declaration of sections.
SECTION CSTACK:DATA:NOROOT(3)
SECTION .intvec:CODE:NOROOT(2)
EXTERN __iar_program_start
EXTERN SystemInit
EXTERN nrf_reloc_vector_table
PUBLIC __vector_table
PUBLIC __Vectors
PUBLIC __Vectors_End
PUBLIC __Vectors_Size
DATA
__vector_table
DCD sfe(CSTACK)
DCD Reset_Handler
DCD NMI_Handler
DCD HardFault_Handler
DCD MemoryManagement_Handler
DCD BusFault_Handler
DCD UsageFault_Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVC_Handler
DCD DebugMonitor_Handler
DCD 0 ; Reserved
DCD PendSV_Handler
DCD SysTick_Handler
; External Interrupts
DCD POWER_CLOCK_IRQHandler
DCD RADIO_IRQHandler
DCD UARTE0_UART0_IRQHandler_v
DCD SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler_v
DCD SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler_v
DCD NFCT_IRQHandler_v
DCD GPIOTE_IRQHandler_v
DCD SAADC_IRQHandler_v
DCD TIMER0_IRQHandler_v
DCD TIMER1_IRQHandler_v
DCD TIMER2_IRQHandler_v
DCD RTC0_IRQHandler
DCD TEMP_IRQHandler_v
DCD RNG_IRQHandler
DCD ECB_IRQHandler
DCD CCM_AAR_IRQHandler
DCD WDT_IRQHandler_v
DCD RTC1_IRQHandler_v
DCD QDEC_IRQHandler_v
DCD COMP_LPCOMP_IRQHandler_v
DCD SWI0_EGU0_IRQHandler_v
DCD SWI1_EGU1_IRQHandler_v
DCD SWI2_EGU2_IRQHandler_v
DCD SWI3_EGU3_IRQHandler_v
DCD SWI4_EGU4_IRQHandler
DCD SWI5_EGU5_IRQHandler
DCD TIMER3_IRQHandler_v
DCD TIMER4_IRQHandler_v
DCD PWM0_IRQHandler_v
DCD PDM_IRQHandler_v
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD MWU_IRQHandler
DCD PWM1_IRQHandler_v
DCD PWM2_IRQHandler_v
DCD SPIM2_SPIS2_SPI2_IRQHandler_v
DCD RTC2_IRQHandler_v
DCD I2S_IRQHandler_v
DCD FPU_IRQHandler_v
__Vectors_End
__Vectors EQU __vector_table
__Vectors_Size EQU __Vectors_End - __Vectors
; Default handlers.
THUMB
PUBWEAK Reset_Handler
SECTION .text:CODE:NOROOT(2)
Reset_Handler
LDR R0, =SystemInit
BLX R0
LDR R0, =nrf_reloc_vector_table
BLX R0
LDR R0, =__iar_program_start
BX R0
; Dummy exception handlers
PUBWEAK NMI_Handler
SECTION .text:CODE:NOROOT(1)
NMI_Handler
B .
PUBWEAK HardFault_Handler
SECTION .text:CODE:NOROOT(1)
HardFault_Handler
B .
PUBWEAK MemoryManagement_Handler
SECTION .text:CODE:NOROOT(1)
MemoryManagement_Handler
B .
PUBWEAK BusFault_Handler
SECTION .text:CODE:NOROOT(1)
BusFault_Handler
B .
PUBWEAK UsageFault_Handler
SECTION .text:CODE:NOROOT(1)
UsageFault_Handler
B .
PUBWEAK SVC_Handler
SECTION .text:CODE:NOROOT(1)
SVC_Handler
B .
PUBWEAK DebugMonitor_Handler
SECTION .text:CODE:NOROOT(1)
DebugMonitor_Handler
B .
PUBWEAK PendSV_Handler
SECTION .text:CODE:NOROOT(1)
PendSV_Handler
B .
PUBWEAK SysTick_Handler
SECTION .text:CODE:NOROOT(1)
SysTick_Handler
B .
; Dummy interrupt handlers
PUBWEAK POWER_CLOCK_IRQHandler
SECTION .text:CODE:NOROOT(1)
POWER_CLOCK_IRQHandler
B .
PUBWEAK RADIO_IRQHandler
SECTION .text:CODE:NOROOT(1)
RADIO_IRQHandler
B .
PUBWEAK UARTE0_UART0_IRQHandler_v
SECTION .text:CODE:NOROOT(1)
UARTE0_UART0_IRQHandler_v
B .
PUBWEAK SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler_v
SECTION .text:CODE:NOROOT(1)
SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQHandler_v
B .
PUBWEAK SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler_v
SECTION .text:CODE:NOROOT(1)
SPIM1_SPIS1_TWIM1_TWIS1_SPI1_TWI1_IRQHandler_v
B .
PUBWEAK NFCT_IRQHandler_v
SECTION .text:CODE:NOROOT(1)
NFCT_IRQHandler_v
B .
PUBWEAK GPIOTE_IRQHandler_v
SECTION .text:CODE:NOROOT(1)
GPIOTE_IRQHandler_v
B .
PUBWEAK SAADC_IRQHandler_v
SECTION .text:CODE:NOROOT(1)
SAADC_IRQHandler_v
B .
PUBWEAK TIMER0_IRQHandler_v
SECTION .text:CODE:NOROOT(1)
TIMER0_IRQHandler_v
B .
PUBWEAK TIMER1_IRQHandler_v
SECTION .text:CODE:NOROOT(1)
TIMER1_IRQHandler_v
B .
PUBWEAK TIMER2_IRQHandler_v
SECTION .text:CODE:NOROOT(1)
TIMER2_IRQHandler_v
B .
PUBWEAK RTC0_IRQHandler
SECTION .text:CODE:NOROOT(1)
RTC0_IRQHandler
B .
PUBWEAK TEMP_IRQHandler_v
SECTION .text:CODE:NOROOT(1)
TEMP_IRQHandler_v
B .
PUBWEAK RNG_IRQHandler
SECTION .text:CODE:NOROOT(1)
RNG_IRQHandler
B .
PUBWEAK ECB_IRQHandler
SECTION .text:CODE:NOROOT(1)
ECB_IRQHandler
B .
PUBWEAK CCM_AAR_IRQHandler
SECTION .text:CODE:NOROOT(1)
CCM_AAR_IRQHandler
B .
PUBWEAK WDT_IRQHandler_v
SECTION .text:CODE:NOROOT(1)
WDT_IRQHandler_v
B .
PUBWEAK RTC1_IRQHandler_v
SECTION .text:CODE:NOROOT(1)
RTC1_IRQHandler_v
B .
PUBWEAK QDEC_IRQHandler_v
SECTION .text:CODE:NOROOT(1)
QDEC_IRQHandler_v
B .
PUBWEAK COMP_LPCOMP_IRQHandler_v
SECTION .text:CODE:NOROOT(1)
COMP_LPCOMP_IRQHandler_v
B .
PUBWEAK SWI0_EGU0_IRQHandler_v
SECTION .text:CODE:NOROOT(1)
SWI0_EGU0_IRQHandler_v
B .
PUBWEAK SWI1_EGU1_IRQHandler_v
SECTION .text:CODE:NOROOT(1)
SWI1_EGU1_IRQHandler_v
B .
PUBWEAK SWI2_EGU2_IRQHandler_v
SECTION .text:CODE:NOROOT(1)
SWI2_EGU2_IRQHandler_v
B .
PUBWEAK SWI3_EGU3_IRQHandler_v
SECTION .text:CODE:NOROOT(1)
SWI3_EGU3_IRQHandler_v
B .
PUBWEAK SWI4_EGU4_IRQHandler
SECTION .text:CODE:NOROOT(1)
SWI4_EGU4_IRQHandler
B .
PUBWEAK SWI5_EGU5_IRQHandler
SECTION .text:CODE:NOROOT(1)
SWI5_EGU5_IRQHandler
B .
PUBWEAK TIMER3_IRQHandler_v
SECTION .text:CODE:NOROOT(1)
TIMER3_IRQHandler_v
B .
PUBWEAK TIMER4_IRQHandler_v
SECTION .text:CODE:NOROOT(1)
TIMER4_IRQHandler_v
B .
PUBWEAK PWM0_IRQHandler_v
SECTION .text:CODE:NOROOT(1)
PWM0_IRQHandler_v
B .
PUBWEAK PDM_IRQHandler_v
SECTION .text:CODE:NOROOT(1)
PDM_IRQHandler_v
B .
PUBWEAK MWU_IRQHandler
SECTION .text:CODE:NOROOT(1)
MWU_IRQHandler
B .
PUBWEAK PWM1_IRQHandler_v
SECTION .text:CODE:NOROOT(1)
PWM1_IRQHandler_v
B .
PUBWEAK PWM2_IRQHandler_v
SECTION .text:CODE:NOROOT(1)
PWM2_IRQHandler_v
B .
PUBWEAK SPIM2_SPIS2_SPI2_IRQHandler_v
SECTION .text:CODE:NOROOT(1)
SPIM2_SPIS2_SPI2_IRQHandler_v
B .
PUBWEAK RTC2_IRQHandler_v
SECTION .text:CODE:NOROOT(1)
RTC2_IRQHandler_v
B .
PUBWEAK I2S_IRQHandler_v
SECTION .text:CODE:NOROOT(1)
I2S_IRQHandler_v
B .
PUBWEAK FPU_IRQHandler_v
SECTION .text:CODE:NOROOT(1)
FPU_IRQHandler_v
B .
END

View File

@ -0,0 +1,24 @@
/*
* PackageLicenseDeclared: Apache-2.0
* Copyright (c) 2016 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.
*/
#ifndef MBED_CMSIS_H
#define MBED_CMSIS_H
#include "nrf.h"
#include "cmsis_nvic.h"
#endif

View File

@ -0,0 +1,43 @@
/* mbed Microcontroller Library
* CMSIS-style functionality to support dynamic vectors
*******************************************************************************
* Copyright (c) 2016 ARM Limited. All rights reserved.
* All rights reserved.
*
* 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 ARM Limited 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.
*******************************************************************************
*/
#include "cmsis_nvic.h"
extern uint32_t nrf_dispatch_vector[NVIC_NUM_VECTORS];
void NVIC_SetVector(IRQn_Type IRQn, uint32_t vector)
{
nrf_dispatch_vector[IRQn + NVIC_USER_IRQ_OFFSET] = vector;
}
uint32_t NVIC_GetVector(IRQn_Type IRQn)
{
return nrf_dispatch_vector[IRQn + NVIC_USER_IRQ_OFFSET];
}

View File

@ -0,0 +1,53 @@
/* mbed Microcontroller Library
* CMSIS-style functionality to support dynamic vectors
*******************************************************************************
* Copyright (c) 2016 ARM Limited. All rights reserved.
* All rights reserved.
*
* 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 ARM Limited 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.
*******************************************************************************
*/
#ifndef MBED_CMSIS_NVIC_H
#define MBED_CMSIS_NVIC_H
#define NVIC_NUM_VECTORS (16 + 38) // CORE + MCU Peripherals
#define NVIC_USER_IRQ_OFFSET 16
#include "nrf52.h"
#include "cmsis.h"
#ifdef __cplusplus
extern "C" {
#endif
void NVIC_SetVector(IRQn_Type IRQn, uint32_t vector);
uint32_t NVIC_GetVector(IRQn_Type IRQn);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,321 @@
/*
* Copyright (c) 2015 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#include <stdint.h>
#include <stdbool.h>
#include "nrf.h"
#include "system_nrf52.h"
#include "nrf5x_lf_clk_helper.h"
/*lint ++flb "Enter library region" */
#define __SYSTEM_CLOCK_64M (64000000UL)
static bool errata_16(void);
static bool errata_31(void);
static bool errata_32(void);
static bool errata_36(void);
static bool errata_37(void);
static bool errata_57(void);
static bool errata_66(void);
#if defined ( __CC_ARM )
uint32_t SystemCoreClock __attribute__((used)) = __SYSTEM_CLOCK_64M;
#elif defined ( __ICCARM__ )
__root uint32_t SystemCoreClock = __SYSTEM_CLOCK_64M;
#elif defined ( __GNUC__ )
uint32_t SystemCoreClock __attribute__((used)) = __SYSTEM_CLOCK_64M;
#endif
void SystemCoreClockUpdate(void)
{
SystemCoreClock = __SYSTEM_CLOCK_64M;
}
void SystemInit(void)
{
/* Workaround for Errata 16 "System: RAM may be corrupt on wakeup from CPU IDLE" found at the Errata document
for your device located at https://infocenter.nordicsemi.com/ */
if (errata_16()){
*(volatile uint32_t *)0x4007C074 = 3131961357ul;
}
/* Workaround for Errata 31 "CLOCK: Calibration values are not correctly loaded from FICR at reset" found at the Errata document
for your device located at https://infocenter.nordicsemi.com/ */
if (errata_31()){
*(volatile uint32_t *)0x4000053C = ((*(volatile uint32_t *)0x10000244) & 0x0000E000) >> 13;
}
/* Workaround for Errata 32 "DIF: Debug session automatically enables TracePort pins" found at the Errata document
for your device located at https://infocenter.nordicsemi.com/ */
if (errata_32()){
CoreDebug->DEMCR &= ~CoreDebug_DEMCR_TRCENA_Msk;
}
/* Workaround for Errata 36 "CLOCK: Some registers are not reset when expected" found at the Errata document
for your device located at https://infocenter.nordicsemi.com/ */
if (errata_36()){
NRF_CLOCK->EVENTS_DONE = 0;
NRF_CLOCK->EVENTS_CTTO = 0;
NRF_CLOCK->CTIV = 0;
}
/* Workaround for Errata 37 "RADIO: Encryption engine is slow by default" found at the Errata document
for your device located at https://infocenter.nordicsemi.com/ */
if (errata_37()){
*(volatile uint32_t *)0x400005A0 = 0x3;
}
/* Workaround for Errata 57 "NFCT: NFC Modulation amplitude" found at the Errata document
for your device located at https://infocenter.nordicsemi.com/ */
if (errata_57()){
*(volatile uint32_t *)0x40005610 = 0x00000005;
*(volatile uint32_t *)0x40005688 = 0x00000001;
*(volatile uint32_t *)0x40005618 = 0x00000000;
*(volatile uint32_t *)0x40005614 = 0x0000003F;
}
/* Workaround for Errata 66 "TEMP: Linearity specification not met with default settings" found at the Errata document
for your device located at https://infocenter.nordicsemi.com/ */
if (errata_66()){
NRF_TEMP->A0 = NRF_FICR->TEMP.A0;
NRF_TEMP->A1 = NRF_FICR->TEMP.A1;
NRF_TEMP->A2 = NRF_FICR->TEMP.A2;
NRF_TEMP->A3 = NRF_FICR->TEMP.A3;
NRF_TEMP->A4 = NRF_FICR->TEMP.A4;
NRF_TEMP->A5 = NRF_FICR->TEMP.A5;
NRF_TEMP->B0 = NRF_FICR->TEMP.B0;
NRF_TEMP->B1 = NRF_FICR->TEMP.B1;
NRF_TEMP->B2 = NRF_FICR->TEMP.B2;
NRF_TEMP->B3 = NRF_FICR->TEMP.B3;
NRF_TEMP->B4 = NRF_FICR->TEMP.B4;
NRF_TEMP->B5 = NRF_FICR->TEMP.B5;
NRF_TEMP->T0 = NRF_FICR->TEMP.T0;
NRF_TEMP->T1 = NRF_FICR->TEMP.T1;
NRF_TEMP->T2 = NRF_FICR->TEMP.T2;
NRF_TEMP->T3 = NRF_FICR->TEMP.T3;
NRF_TEMP->T4 = NRF_FICR->TEMP.T4;
}
/* Enable the FPU if the compiler used floating point unit instructions. __FPU_USED is a MACRO defined by the
* compiler. Since the FPU consumes energy, remember to disable FPU use in the compiler if floating point unit
* operations are not used in your code. */
#if (__FPU_USED == 1)
SCB->CPACR |= (3UL << 20) | (3UL << 22);
__DSB();
__ISB();
#endif
/* Configure NFCT pins as GPIOs if NFCT is not to be used in your code. If CONFIG_NFCT_PINS_AS_GPIOS is not defined,
two GPIOs (see Product Specification to see which ones) will be reserved for NFC and will not be available as
normal GPIOs. */
#if defined (CONFIG_NFCT_PINS_AS_GPIOS)
if ((NRF_UICR->NFCPINS & UICR_NFCPINS_PROTECT_Msk) == (UICR_NFCPINS_PROTECT_NFC << UICR_NFCPINS_PROTECT_Pos)){
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
NRF_UICR->NFCPINS &= ~UICR_NFCPINS_PROTECT_Msk;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
NVIC_SystemReset();
}
#endif
/* Configure GPIO pads as pPin Reset pin if Pin Reset capabilities desired. If CONFIG_GPIO_AS_PINRESET is not
defined, pin reset will not be available. One GPIO (see Product Specification to see which one) will then be
reserved for PinReset and not available as normal GPIO. */
#if defined (CONFIG_GPIO_AS_PINRESET)
if (((NRF_UICR->PSELRESET[0] & UICR_PSELRESET_CONNECT_Msk) != (UICR_PSELRESET_CONNECT_Connected << UICR_PSELRESET_CONNECT_Pos)) ||
((NRF_UICR->PSELRESET[1] & UICR_PSELRESET_CONNECT_Msk) != (UICR_PSELRESET_CONNECT_Connected << UICR_PSELRESET_CONNECT_Pos))){
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
NRF_UICR->PSELRESET[0] = 21;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
NRF_UICR->PSELRESET[1] = 21;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos;
while (NRF_NVMC->READY == NVMC_READY_READY_Busy){}
NVIC_SystemReset();
}
#endif
/* Enable SWO trace functionality. If ENABLE_SWO is not defined, SWO pin will be used as GPIO (see Product
Specification to see which one). */
#if defined (ENABLE_SWO)
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
NRF_CLOCK->TRACECONFIG |= CLOCK_TRACECONFIG_TRACEMUX_Serial << CLOCK_TRACECONFIG_TRACEMUX_Pos;
NRF_P0->PIN_CNF[18] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
#endif
/* Enable Trace functionality. If ENABLE_TRACE is not defined, TRACE pins will be used as GPIOs (see Product
Specification to see which ones). */
#if defined (ENABLE_TRACE)
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
NRF_CLOCK->TRACECONFIG |= CLOCK_TRACECONFIG_TRACEMUX_Parallel << CLOCK_TRACECONFIG_TRACEMUX_Pos;
NRF_P0->PIN_CNF[14] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
NRF_P0->PIN_CNF[15] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
NRF_P0->PIN_CNF[16] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
NRF_P0->PIN_CNF[18] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
NRF_P0->PIN_CNF[20] = (GPIO_PIN_CNF_DRIVE_H0H1 << GPIO_PIN_CNF_DRIVE_Pos) | (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) | (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
#endif
SystemCoreClockUpdate();
// Start the LF oscilator according to the mbed configuration (over the nrf5x_lf_clk_helper.h file)
NRF_CLOCK->LFCLKSRC = (CLOCK_LFCLKSRC_SRC_TO_USE << CLOCK_LFCLKSRC_SRC_Pos);
NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
NRF_CLOCK->TASKS_LFCLKSTART = 1;
// Wait for the external oscillator to start up.
while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0) {
// Do nothing.
}
}
static bool errata_16(void)
{
if ((((*(uint32_t *)0xF0000FE0) & 0x000000FF) == 0x6) && (((*(uint32_t *)0xF0000FE4) & 0x0000000F) == 0x0))
{
if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x30)
{
return true;
}
}
return false;
}
static bool errata_31(void)
{
if ((((*(uint32_t *)0xF0000FE0) & 0x000000FF) == 0x6) && (((*(uint32_t *)0xF0000FE4) & 0x0000000F) == 0x0))
{
if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x30)
{
return true;
}
if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x40)
{
return true;
}
if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x50)
{
return true;
}
}
return false;
}
static bool errata_32(void)
{
if ((((*(uint32_t *)0xF0000FE0) & 0x000000FF) == 0x6) && (((*(uint32_t *)0xF0000FE4) & 0x0000000F) == 0x0))
{
if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x30)
{
return true;
}
}
return false;
}
static bool errata_36(void)
{
if ((((*(uint32_t *)0xF0000FE0) & 0x000000FF) == 0x6) && (((*(uint32_t *)0xF0000FE4) & 0x0000000F) == 0x0))
{
if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x30)
{
return true;
}
if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x40)
{
return true;
}
if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x50)
{
return true;
}
}
return false;
}
static bool errata_37(void)
{
if ((((*(uint32_t *)0xF0000FE0) & 0x000000FF) == 0x6) && (((*(uint32_t *)0xF0000FE4) & 0x0000000F) == 0x0))
{
if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x30)
{
return true;
}
}
return false;
}
static bool errata_57(void)
{
if ((((*(uint32_t *)0xF0000FE0) & 0x000000FF) == 0x6) && (((*(uint32_t *)0xF0000FE4) & 0x0000000F) == 0x0))
{
if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x30)
{
return true;
}
}
return false;
}
static bool errata_66(void)
{
if ((((*(uint32_t *)0xF0000FE0) & 0x000000FF) == 0x6) && (((*(uint32_t *)0xF0000FE4) & 0x0000000F) == 0x0))
{
if (((*(uint32_t *)0xF0000FE8) & 0x000000F0) == 0x50)
{
return true;
}
}
return false;
}
/*lint --flb "Leave library region" */

View File

@ -0,0 +1,78 @@
/*
* Copyright (c) 2015 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#ifndef SYSTEM_NRF52_H
#define SYSTEM_NRF52_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */
/**
* Initialize the system
*
* @param none
* @return none
*
* @brief Setup the microcontroller system.
* Initialize the System and update the SystemCoreClock variable.
*/
extern void SystemInit (void);
/**
* Update SystemCoreClock variable
*
* @param none
* @return none
*
* @brief Updates the SystemCoreClock with current core Clock
* retrieved from cpu registers.
*/
extern void SystemCoreClockUpdate (void);
#ifdef __cplusplus
}
#endif
#endif /* SYSTEM_NRF52_H */

View File

@ -0,0 +1,399 @@
/*
* Copyright (c) 2013 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#include "mbed_assert.h"
#include "mbed_error.h"
#include "pwmout_api.h"
#include "cmsis.h"
#include "pinmap.h"
#if DEVICE_PWMOUT
#include "app_util_platform.h"
#include "nrf_drv_pwm.h"
#define MAX_PWM_COUNTERTOP (0x7FFF) // 0x7FFF is the max of COUNTERTOP value for the PWM peripherial of the nRF52.
#define MAX_PWM_PERIOD_US (MAX_PWM_COUNTERTOP * 8) // PWM hw is driven by 16 MHz clock, hence the tick is 1_us/16,
// and 128 is the max prescaler value.
#define MAX_PWM_PERIOD_MS ((MAX_PWM_PERIOD_US / 1000) + 1) // approximations advance
#define MAX_PWM_PERIOD_S ((MAX_PWM_PERIOD_US / 1000000) + 1) // approximations advance
#define PWM_INSTANCE_COUNT (PWM_COUNT) // import from the nrf_drv_config.h file
///> instances of nRF52 PWM driver
static const nrf_drv_pwm_t m_pwm_driver[PWM_INSTANCE_COUNT] =
{
#if PWM0_ENABLED
NRF_DRV_PWM_INSTANCE(0),
#endif
#if PWM1_ENABLED
NRF_DRV_PWM_INSTANCE(1),
#endif
#if PWM2_ENABLED
NRF_DRV_PWM_INSTANCE(2)
#endif
};
typedef struct
{
uint32_t period_us;
uint32_t duty_us;
float duty;
} pwm_signal_t; /// PWM signal description type
typedef struct
{
nrf_drv_pwm_t * p_pwm_driver;
pwm_signal_t signal;
volatile nrf_pwm_values_common_t seq_values[1];
} pwm_t; /// internal PWM instance support type
static pwm_t m_pwm[PWM_INSTANCE_COUNT] =
{
#if PWM0_ENABLED
{.p_pwm_driver = NULL},
#endif
#if PWM1_ENABLED
{.p_pwm_driver = NULL},
#endif
#if PWM2_ENABLED
{.p_pwm_driver = NULL}
#endif
}; /// Array of internal PWM instances.
typedef struct
{
uint16_t period_hwu; // unit related to pwm_clk
uint16_t duty_hwu; // unit related to pwm_clk
nrf_pwm_clk_t pwm_clk;
} pulsewidth_set_t; /// helper type for timing calculations
static void internal_pwmout_exe(pwmout_t *obj, bool new_period, bool initialization);
// extern PWM nIRQ handler implementations
void PWM0_IRQHandler(void);
void PWM1_IRQHandler(void);
void PWM2_IRQHandler(void);
static const peripheral_handler_desc_t pwm_handlers[PWM_INSTANCE_COUNT] =
{
{
PWM0_IRQn,
(uint32_t)PWM0_IRQHandler
},
{
PWM1_IRQn,
(uint32_t)PWM1_IRQHandler
},
{
PWM2_IRQn,
(uint32_t)PWM2_IRQHandler
}
};
void pwmout_init(pwmout_t *obj, PinName pin)
{
uint32_t i;
for (i = 0; PWM_INSTANCE_COUNT; i++)
{
if (m_pwm[i].p_pwm_driver == NULL) // a driver instance not assigned to the obj?
{
NVIC_SetVector(pwm_handlers[i].IRQn, pwm_handlers[i].vector);
obj->pin = pin;
obj->pwm_channel = i;
m_pwm[i].p_pwm_driver = (nrf_drv_pwm_t *) &m_pwm_driver[i];
m_pwm[i].signal.period_us = 200000; // 0.02 s
m_pwm[i].signal.duty_us = 100000;
m_pwm[i].signal.duty = 0.5f;
obj->pwm_struct = &m_pwm[i];
internal_pwmout_exe(obj, true, true);
break;
}
}
MBED_ASSERT(i != PWM_INSTANCE_COUNT); // assert if free instance was not found.
}
void pwmout_free(pwmout_t *obj)
{
nrf_drv_pwm_uninit( (nrf_drv_pwm_t*) obj->pwm_struct );
m_pwm[obj->pwm_channel].p_pwm_driver = NULL;
}
void pwmout_write(pwmout_t *obj, float percent)
{
if (percent < 0)
{
percent = 0;
}
else if (percent > 1)
{
percent = 1;
}
pwm_signal_t * p_pwm_signal = &(((pwm_t*)obj->pwm_struct)->signal);
p_pwm_signal->duty = percent;
int us = (((int)p_pwm_signal->period_us) * percent);
pwmout_pulsewidth_us(obj, us);
}
float pwmout_read(pwmout_t *obj)
{
pwm_signal_t * p_pwm_signal = &(((pwm_t*)obj->pwm_struct)->signal);
return (float)p_pwm_signal->duty_us / (float)p_pwm_signal->period_us;
}
void pwmout_period(pwmout_t *obj, float seconds)
{
// raught saturation < 0, quasi-max>
if (seconds > MAX_PWM_PERIOD_S)
{
seconds = MAX_PWM_PERIOD_S;
}
else if (seconds < 0)
{
seconds = 0; // f. pwmout_period_us will set period to min. value
}
int us = seconds * 1000000;
pwmout_period_us(obj, us);
}
void pwmout_period_ms(pwmout_t *obj, int ms)
{
// reught saturation < 0, quasi-max>
if (ms > MAX_PWM_PERIOD_MS)
{
ms = MAX_PWM_PERIOD_MS;
}
else if (ms < 0)
{
ms = 0; // f. pwmout_period_us will set period to min. value
}
int us = ms * 1000;
pwmout_period_us(obj, us);
}
void pwmout_period_us(pwmout_t *obj, int us)
{
pwm_signal_t * p_pwm_signal = &(((pwm_t*)obj->pwm_struct)->signal);
// saturation <1, real-max>
if (us > MAX_PWM_PERIOD_US)
{
us = MAX_PWM_PERIOD_US;
}
else if (us < 1)
{
us = 1;
}
p_pwm_signal->duty_us = (int)((float)us * p_pwm_signal->duty);
p_pwm_signal->period_us = us;
internal_pwmout_exe(obj, true, false);
}
void pwmout_pulsewidth(pwmout_t *obj, float seconds)
{
// raught saturation < 0, quasi-max>
if (seconds > MAX_PWM_PERIOD_S)
{
seconds = MAX_PWM_PERIOD_S;
}
else if (seconds < 0)
{
seconds = 0;
}
int us = seconds * 1000000;
pwmout_pulsewidth_us(obj,us);
}
void pwmout_pulsewidth_ms(pwmout_t *obj, int ms)
{
// raught saturation < 0, quasi-max>
if (ms > MAX_PWM_PERIOD_MS)
{
ms = MAX_PWM_PERIOD_MS;
}
else if (ms < 0)
{
ms = 0;
}
int us = ms * 1000;
pwmout_pulsewidth_us(obj, us);
}
void pwmout_pulsewidth_us(pwmout_t *obj, int us)
{
// saturation <0, real-max>
if (us > MAX_PWM_PERIOD_US)
{
us = MAX_PWM_PERIOD_US;
}
else if (us < 0)
{
us = 0;
}
pwm_signal_t * p_pwm_signal = &(((pwm_t*)obj->pwm_struct)->signal);
p_pwm_signal->duty_us = us;
p_pwm_signal->duty = us / p_pwm_signal->period_us;
internal_pwmout_exe(obj, false, false);
}
static ret_code_t pulsewidth_us_set_get(int period_hwu, int duty_hwu, pulsewidth_set_t * p_settings)
{
uint16_t div;
nrf_pwm_clk_t pwm_clk = NRF_PWM_CLK_16MHz;
for(div = 1; div <= 128 ; div <<= 1) // 128 is the maximum of clock prescaler for PWM peripherial
{
if (MAX_PWM_COUNTERTOP >= period_hwu)
{
p_settings->period_hwu = period_hwu; // unit [us/16 * div]
p_settings->duty_hwu = duty_hwu; // unit [us/16 * div]
p_settings->pwm_clk = pwm_clk;
return NRF_SUCCESS;
}
period_hwu >>= 1;
duty_hwu >>= 1;
pwm_clk++;
}
return NRF_ERROR_INVALID_PARAM;
}
static void internal_pwmout_exe(pwmout_t *obj, bool new_period, bool initialization)
{
pulsewidth_set_t pulsewidth_set;
pwm_signal_t * p_pwm_signal;
nrf_drv_pwm_t * p_pwm_driver;
ret_code_t ret_code;
p_pwm_signal = &(((pwm_t*)obj->pwm_struct)->signal);
if (NRF_SUCCESS == pulsewidth_us_set_get(p_pwm_signal->period_us * 16, // base clk for PWM is 16 MHz
p_pwm_signal->duty_us * 16, // base clk for PWM is 16 MHz
&pulsewidth_set))
{
p_pwm_driver = (((pwm_t*)obj->pwm_struct)->p_pwm_driver);
const nrf_pwm_sequence_t seq =
{
.values.p_common = (nrf_pwm_values_common_t*) (((pwm_t*)obj->pwm_struct)->seq_values),
.length = 1,
.repeats = 0,
.end_delay = 0
};
(((pwm_t*)obj->pwm_struct)->seq_values)[0] = pulsewidth_set.duty_hwu | 0x8000;
if (new_period)
{
nrf_drv_pwm_config_t config0 =
{
.output_pins =
{
obj->pin | NRF_DRV_PWM_PIN_INVERTED, // channel 0
NRF_DRV_PWM_PIN_NOT_USED, // channel 1
NRF_DRV_PWM_PIN_NOT_USED, // channel 2
NRF_DRV_PWM_PIN_NOT_USED, // channel 3
},
.irq_priority = PWM0_CONFIG_IRQ_PRIORITY,
.base_clock = pulsewidth_set.pwm_clk,
.count_mode = NRF_PWM_MODE_UP,
.top_value = pulsewidth_set.period_hwu,
.load_mode = NRF_PWM_LOAD_COMMON,
.step_mode = NRF_PWM_STEP_AUTO
};
if (!initialization)
{
nrf_drv_pwm_uninit(p_pwm_driver);
}
ret_code = nrf_drv_pwm_init( p_pwm_driver, &config0, NULL);
MBED_ASSERT(ret_code == NRF_SUCCESS); // assert if free instance was not found.
}
nrf_drv_pwm_simple_playback(p_pwm_driver, &seq, 0, NRF_DRV_PWM_FLAG_LOOP);
}
else
{
MBED_ASSERT(0); // force assertion
}
}
#endif // DEVICE_PWMOUT

View File

@ -0,0 +1,350 @@
/* Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved.
*
* The information contained herein is property of Nordic Semiconductor ASA.
* Terms and conditions of usage are described in detail in NORDIC
* SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
*
* Licensees are granted free, non-transferable use of the information. NO
* WARRANTY of ANY KIND is provided. This heading must NOT be removed from
* the file.
*
*/
#include <string.h>
#include "nrf_drv_pwm.h"
#include "nrf_drv_common.h"
#include "nrf_gpio.h"
#include "app_util_platform.h"
#if (PWM_COUNT == 0)
#error "No PWM instances enabled in the driver configuration file."
#endif
// Control block - driver instance local data.
typedef struct
{
nrf_drv_pwm_handler_t handler;
nrf_drv_state_t volatile state;
} pwm_control_block_t;
static pwm_control_block_t m_cb[PWM_COUNT];
static nrf_drv_pwm_config_t const m_default_config[PWM_COUNT] = {
#if PWM0_ENABLED
NRF_DRV_PWM_DEFAULT_CONFIG(0),
#endif
#if PWM1_ENABLED
NRF_DRV_PWM_DEFAULT_CONFIG(1),
#endif
#if PWM2_ENABLED
NRF_DRV_PWM_DEFAULT_CONFIG(2),
#endif
};
static void configure_pins(nrf_drv_pwm_t const * const p_instance,
nrf_drv_pwm_config_t const * p_config)
{
uint32_t out_pins[NRF_PWM_CHANNEL_COUNT];
uint8_t i;
for (i = 0; i < NRF_PWM_CHANNEL_COUNT; ++i)
{
uint8_t output_pin = p_config->output_pins[i];
if (output_pin != NRF_DRV_PWM_PIN_NOT_USED)
{
bool inverted = output_pin & NRF_DRV_PWM_PIN_INVERTED;
out_pins[i] = output_pin & ~NRF_DRV_PWM_PIN_INVERTED;
if (inverted)
{
nrf_gpio_pin_set(out_pins[i]);
}
else
{
nrf_gpio_pin_clear(out_pins[i]);
}
nrf_gpio_cfg_output(out_pins[i]);
}
else
{
out_pins[i] = NRF_PWM_PIN_NOT_CONNECTED;
}
}
nrf_pwm_pins_set(p_instance->p_registers, out_pins);
}
ret_code_t nrf_drv_pwm_init(nrf_drv_pwm_t const * const p_instance,
nrf_drv_pwm_config_t const * p_config,
nrf_drv_pwm_handler_t handler)
{
pwm_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
if (p_cb->state != NRF_DRV_STATE_UNINITIALIZED)
{
return NRF_ERROR_INVALID_STATE;
}
if (p_config == NULL)
{
p_config = &m_default_config[p_instance->drv_inst_idx];
}
p_cb->handler = handler;
configure_pins(p_instance, p_config);
nrf_pwm_enable(p_instance->p_registers);
nrf_pwm_configure(p_instance->p_registers,
p_config->base_clock, p_config->count_mode, p_config->top_value);
nrf_pwm_decoder_set(p_instance->p_registers,
p_config->load_mode, p_config->step_mode);
nrf_pwm_shorts_set(p_instance->p_registers, 0);
nrf_pwm_int_set(p_instance->p_registers, 0);
nrf_pwm_event_clear(p_instance->p_registers, NRF_PWM_EVENT_LOOPSDONE);
nrf_pwm_event_clear(p_instance->p_registers, NRF_PWM_EVENT_SEQEND0);
nrf_pwm_event_clear(p_instance->p_registers, NRF_PWM_EVENT_SEQEND1);
nrf_pwm_event_clear(p_instance->p_registers, NRF_PWM_EVENT_STOPPED);
if (p_cb->handler)
{
nrf_drv_common_irq_enable(nrf_drv_get_IRQn(p_instance->p_registers),
p_config->irq_priority);
}
p_cb->state = NRF_DRV_STATE_INITIALIZED;
return NRF_SUCCESS;
}
void nrf_drv_pwm_uninit(nrf_drv_pwm_t const * const p_instance)
{
pwm_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
ASSERT(p_cb->state != NRF_DRV_STATE_UNINITIALIZED);
nrf_drv_common_irq_disable(nrf_drv_get_IRQn(p_instance->p_registers));
nrf_pwm_disable(p_instance->p_registers);
p_cb->state = NRF_DRV_STATE_UNINITIALIZED;
}
static void start_playback(nrf_drv_pwm_t const * const p_instance,
pwm_control_block_t * p_cb,
uint8_t flags,
nrf_pwm_task_t starting_task)
{
p_cb->state = NRF_DRV_STATE_POWERED_ON;
if (p_cb->handler)
{
// The notification about finished playback is by default enabled, but
// this can be suppressed. The notification that the peripheral has been
// stopped is always enable.
uint32_t int_mask = NRF_PWM_INT_LOOPSDONE_MASK |
NRF_PWM_INT_STOPPED_MASK;
if (flags & NRF_DRV_PWM_FLAG_SIGNAL_END_SEQ0)
{
int_mask |= NRF_PWM_INT_SEQEND0_MASK;
}
if (flags & NRF_DRV_PWM_FLAG_SIGNAL_END_SEQ1)
{
int_mask |= NRF_PWM_INT_SEQEND1_MASK;
}
if (flags & NRF_DRV_PWM_FLAG_NO_EVT_FINISHED)
{
int_mask &= ~NRF_PWM_INT_LOOPSDONE_MASK;
}
nrf_pwm_int_set(p_instance->p_registers, int_mask);
}
nrf_pwm_event_clear(p_instance->p_registers, NRF_PWM_EVENT_STOPPED);
nrf_pwm_task_trigger(p_instance->p_registers, starting_task);
}
void nrf_drv_pwm_simple_playback(nrf_drv_pwm_t const * const p_instance,
nrf_pwm_sequence_t const * p_sequence,
uint16_t playback_count,
uint32_t flags)
{
pwm_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
ASSERT(p_cb->state != NRF_DRV_STATE_UNINITIALIZED);
ASSERT(playback_count > 0);
ASSERT(nrf_drv_is_in_RAM(p_sequence->values.p_raw));
// To take advantage of the looping mechanism, we need to use both sequences
// (single sequence can be played back only once).
nrf_pwm_sequence_set(p_instance->p_registers, 0, p_sequence);
nrf_pwm_sequence_set(p_instance->p_registers, 1, p_sequence);
bool odd = (playback_count & 1);
nrf_pwm_loop_set(p_instance->p_registers, playback_count/2 + (odd ? 1 : 0));
uint32_t shorts_mask;
if (flags & NRF_DRV_PWM_FLAG_STOP)
{
shorts_mask = NRF_PWM_SHORT_LOOPSDONE_STOP_MASK;
}
else if (flags & NRF_DRV_PWM_FLAG_LOOP)
{
shorts_mask = odd ? NRF_PWM_SHORT_LOOPSDONE_SEQSTART1_MASK
: NRF_PWM_SHORT_LOOPSDONE_SEQSTART0_MASK;
}
else
{
shorts_mask = 0;
}
nrf_pwm_shorts_set(p_instance->p_registers, shorts_mask);
start_playback(p_instance, p_cb, flags, odd ? NRF_PWM_TASK_SEQSTART1
: NRF_PWM_TASK_SEQSTART0);
}
void nrf_drv_pwm_complex_playback(nrf_drv_pwm_t const * const p_instance,
nrf_pwm_sequence_t const * p_sequence_0,
nrf_pwm_sequence_t const * p_sequence_1,
uint16_t playback_count,
uint32_t flags)
{
pwm_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
ASSERT(p_cb->state != NRF_DRV_STATE_UNINITIALIZED);
ASSERT(playback_count > 0);
ASSERT(nrf_drv_is_in_RAM(p_sequence_0->values.p_raw));
ASSERT(nrf_drv_is_in_RAM(p_sequence_1->values.p_raw));
nrf_pwm_sequence_set(p_instance->p_registers, 0, p_sequence_0);
nrf_pwm_sequence_set(p_instance->p_registers, 1, p_sequence_1);
nrf_pwm_loop_set(p_instance->p_registers, playback_count);
uint32_t shorts_mask;
if (flags & NRF_DRV_PWM_FLAG_STOP)
{
shorts_mask = NRF_PWM_SHORT_LOOPSDONE_STOP_MASK;
}
else if (flags & NRF_DRV_PWM_FLAG_LOOP)
{
shorts_mask = NRF_PWM_SHORT_LOOPSDONE_SEQSTART0_MASK;
}
else
{
shorts_mask = 0;
}
nrf_pwm_shorts_set(p_instance->p_registers, shorts_mask);
start_playback(p_instance, p_cb, flags, NRF_PWM_TASK_SEQSTART0);
}
bool nrf_drv_pwm_stop(nrf_drv_pwm_t const * const p_instance,
bool wait_until_stopped)
{
ASSERT(m_cb[p_instance->drv_inst_idx].state != NRF_DRV_STATE_UNINITIALIZED);
if (nrf_drv_pwm_is_stopped(p_instance))
{
return true;
}
nrf_pwm_task_trigger(p_instance->p_registers, NRF_PWM_TASK_STOP);
do {
if (nrf_drv_pwm_is_stopped(p_instance))
{
return true;
}
} while (wait_until_stopped);
return false;
}
bool nrf_drv_pwm_is_stopped(nrf_drv_pwm_t const * const p_instance)
{
pwm_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
ASSERT(p_cb->state != NRF_DRV_STATE_UNINITIALIZED);
// If the event handler is used (interrupts are enabled), the state will
// be changed in interrupt handler when the STOPPED event occurs.
if (p_cb->state != NRF_DRV_STATE_POWERED_ON)
{
return true;
}
// If interrupts are disabled, we must check the STOPPED event here.
if (nrf_pwm_event_check(p_instance->p_registers, NRF_PWM_EVENT_STOPPED))
{
p_cb->state = NRF_DRV_STATE_INITIALIZED;
return true;
}
return false;
}
static void irq_handler(NRF_PWM_Type * p_pwm, pwm_control_block_t * p_cb)
{
ASSERT(p_cb->handler);
// The SEQEND0 and SEQEND1 events are only handled when the user asked for
// it (by setting proper flags when starting the playback).
if (nrf_pwm_int_enable_check(p_pwm, NRF_PWM_INT_SEQEND0_MASK) &&
nrf_pwm_event_check(p_pwm, NRF_PWM_EVENT_SEQEND0))
{
nrf_pwm_event_clear(p_pwm, NRF_PWM_EVENT_SEQEND0);
p_cb->handler(NRF_DRV_PWM_EVT_END_SEQ0);
}
if (nrf_pwm_int_enable_check(p_pwm, NRF_PWM_INT_SEQEND1_MASK) &&
nrf_pwm_event_check(p_pwm, NRF_PWM_EVENT_SEQEND1))
{
nrf_pwm_event_clear(p_pwm, NRF_PWM_EVENT_SEQEND1);
p_cb->handler(NRF_DRV_PWM_EVT_END_SEQ1);
}
// The LOOPSDONE event is handled by default, but this can be disabled.
if (nrf_pwm_int_enable_check(p_pwm, NRF_PWM_INT_LOOPSDONE_MASK) &&
nrf_pwm_event_check(p_pwm, NRF_PWM_EVENT_LOOPSDONE))
{
nrf_pwm_event_clear(p_pwm, NRF_PWM_EVENT_LOOPSDONE);
p_cb->handler(NRF_DRV_PWM_EVT_FINISHED);
}
if (nrf_pwm_event_check(p_pwm, NRF_PWM_EVENT_STOPPED))
{
nrf_pwm_event_clear(p_pwm, NRF_PWM_EVENT_STOPPED);
p_cb->state = NRF_DRV_STATE_INITIALIZED;
p_cb->handler(NRF_DRV_PWM_EVT_STOPPED);
}
}
#if PWM0_ENABLED
void PWM0_IRQHandler(void)
{
irq_handler(NRF_PWM0, &m_cb[PWM0_INSTANCE_INDEX]);
}
#endif
#if PWM1_ENABLED
void PWM1_IRQHandler(void)
{
irq_handler(NRF_PWM1, &m_cb[PWM1_INSTANCE_INDEX]);
}
#endif
#if PWM2_ENABLED
void PWM2_IRQHandler(void)
{
irq_handler(NRF_PWM2, &m_cb[PWM2_INSTANCE_INDEX]);
}
#endif

View File

@ -0,0 +1,426 @@
/* Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved.
*
* The information contained herein is property of Nordic Semiconductor ASA.
* Terms and conditions of usage are described in detail in NORDIC
* SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
*
* Licensees are granted free, non-transferable use of the information. NO
* WARRANTY of ANY KIND is provided. This heading must NOT be removed from
* the file.
*
*/
/**@file
* @addtogroup nrf_pwm PWM HAL and driver
* @ingroup nrf_drivers
* @brief @tagAPI52 Pulse Width Modulation (PWM) module APIs.
*
* @defgroup nrf_drv_pwm PWM driver
* @{
* @ingroup nrf_pwm
* @brief @tagAPI52 Pulse Width Modulation (PWM) module driver.
*/
#ifndef NRF_DRV_PWM_H__
#define NRF_DRV_PWM_H__
#include "nordic_common.h"
#include "nrf_drv_config.h"
#include "nrf_pwm.h"
#include "sdk_errors.h"
/**
* @brief PWM driver instance data structure.
*/
typedef struct
{
NRF_PWM_Type * p_registers; ///< Pointer to the structure with PWM peripheral instance registers.
uint8_t drv_inst_idx; ///< Driver instance index.
} nrf_drv_pwm_t;
/**
* @brief Macro for creating a PWM driver instance.
*/
#define NRF_DRV_PWM_INSTANCE(id) \
{ \
.p_registers = CONCAT_2(NRF_PWM, id), \
.drv_inst_idx = CONCAT_3(PWM, id, _INSTANCE_INDEX), \
}
/**
* @brief This value can be provided instead of a pin number for any channel
* to specify that its output is not used and therefore does not need
* to be connected to a pin.
*/
#define NRF_DRV_PWM_PIN_NOT_USED 0xFF
/**
* @brief This value can be added to a pin number to inverse its polarity
* (set idle state = 1).
*/
#define NRF_DRV_PWM_PIN_INVERTED 0x80
/**
* @brief PWM driver configuration structure.
*/
typedef struct
{
uint8_t output_pins[NRF_PWM_CHANNEL_COUNT]; ///< Pin numbers for individual output channels (optional).
/**< Use @ref NRF_DRV_PWM_PIN_NOT_USED
* if a given output channel is not needed. */
uint8_t irq_priority; ///< Interrupt priority.
nrf_pwm_clk_t base_clock; ///< Base clock frequency.
nrf_pwm_mode_t count_mode; ///< Operating mode of the pulse generator counter.
uint16_t top_value; ///< Value up to which the pulse generator counter counts.
nrf_pwm_dec_load_t load_mode; ///< Mode of loading sequence data from RAM.
nrf_pwm_dec_step_t step_mode; ///< Mode of advancing the active sequence.
} nrf_drv_pwm_config_t;
/**
* @brief PWM driver default configuration.
*/
#define NRF_DRV_PWM_DEFAULT_CONFIG(id) \
{ \
.output_pins = { CONCAT_3(PWM, id, _CONFIG_OUT0_PIN), \
CONCAT_3(PWM, id, _CONFIG_OUT1_PIN), \
CONCAT_3(PWM, id, _CONFIG_OUT2_PIN), \
CONCAT_3(PWM, id, _CONFIG_OUT3_PIN) }, \
.irq_priority = CONCAT_3(PWM, id, _CONFIG_IRQ_PRIORITY), \
.base_clock = CONCAT_3(PWM, id, _CONFIG_BASE_CLOCK), \
.count_mode = CONCAT_3(PWM, id, _CONFIG_COUNT_MODE), \
.top_value = CONCAT_3(PWM, id, _CONFIG_TOP_VALUE), \
.load_mode = CONCAT_3(PWM, id, _CONFIG_LOAD_MODE), \
.step_mode = CONCAT_3(PWM, id, _CONFIG_STEP_MODE), \
}
/**
* @brief PWM flags providing additional playback options.
*/
typedef enum
{
NRF_DRV_PWM_FLAG_STOP = 0x01, /**< When the requested playback is finished,
the peripheral should be stopped.
@note The STOP task is triggered when
the last value of the final sequence is
loaded from RAM, and the peripheral stops
at the end of the current PWM period.
For sequences with configured repeating
of duty cycle values, this might result in
less than the requested number of repeats
of the last value. */
NRF_DRV_PWM_FLAG_LOOP = 0x02, /**< When the requested playback is finished,
it should be started from the beginning.
This flag is ignored if used together
with @ref NRF_DRV_PWM_FLAG_STOP. */
NRF_DRV_PWM_FLAG_SIGNAL_END_SEQ0 = 0x04, /**< The event handler should be
called when the last value
from sequence 0 is loaded. */
NRF_DRV_PWM_FLAG_SIGNAL_END_SEQ1 = 0x08, /**< The event handler should be
called when the last value
from sequence 1 is loaded. */
NRF_DRV_PWM_FLAG_NO_EVT_FINISHED = 0x10, /**< The playback finished event
(enabled by default) should be
suppressed. */
} nrf_drv_pwm_flag_t;
/**
* @brief PWM driver event type.
*/
typedef enum
{
NRF_DRV_PWM_EVT_FINISHED, ///< Sequence playback finished.
NRF_DRV_PWM_EVT_END_SEQ0, /**< End of sequence 0 reached. Its data can be
safely modified now. */
NRF_DRV_PWM_EVT_END_SEQ1, /**< End of sequence 1 reached. Its data can be
safely modified now. */
NRF_DRV_PWM_EVT_STOPPED, ///< The PWM peripheral has been stopped.
} nrf_drv_pwm_evt_type_t;
/**
* @brief PWM driver event handler type.
*/
typedef void (* nrf_drv_pwm_handler_t)(nrf_drv_pwm_evt_type_t event_type);
/**
* @brief Function for initializing the PWM driver.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] p_config Pointer to the structure with initial configuration.
* If NULL, the default configuration is used.
* @param[in] handler Event handler provided by the user. If NULL is passed
* instead, event notifications are not done and PWM
* interrupts are disabled.
*
* @retval NRF_SUCCESS If initialization was successful.
* @retval NRF_ERROR_INVALID_STATE If the driver was already initialized.
*/
ret_code_t nrf_drv_pwm_init(nrf_drv_pwm_t const * const p_instance,
nrf_drv_pwm_config_t const * p_config,
nrf_drv_pwm_handler_t handler);
/**
* @brief Function for uninitializing the PWM driver.
*
* If any sequence playback is in progress, it is stopped immediately.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
void nrf_drv_pwm_uninit(nrf_drv_pwm_t const * const p_instance);
/**
* @brief Function for starting a single sequence playback.
*
* To take advantage of the looping mechanism in the PWM peripheral, both
* sequences must be used (single sequence can be played back only once by
* the peripheral). Therefore, the provided sequence is internally set and
* played back as both sequence 0 and sequence 1. Consequently, if end of
* sequence notifications are required, events for both sequences should be
* used (that means that both the @ref NRF_DRV_PWM_FLAG_SIGNAL_END_SEQ0 flag
* and the @ref NRF_DRV_PWM_FLAG_SIGNAL_END_SEQ1 flag should be specified and
* the @ref NRF_DRV_PWM_EVT_END_SEQ0 event and the @ref NRF_DRV_PWM_EVT_END_SEQ1
* event should be handled in the same way).
*
* @note The array containing the duty cycle values for the specified sequence
* must be in RAM and cannot be allocated on stack.
* For detailed information, see @ref nrf_pwm_sequence_t.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] p_sequence Sequence to be played back.
* @param[in] playback_count Number of playbacks to be performed (must not be 0).
* @param[in] flags Additional options. Pass any combination of
* @ref nrf_drv_pwm_flag_t "playback flags", or 0
* for default settings.
*/
void nrf_drv_pwm_simple_playback(nrf_drv_pwm_t const * const p_instance,
nrf_pwm_sequence_t const * p_sequence,
uint16_t playback_count,
uint32_t flags);
/**
* @brief Function for starting a two-sequence playback.
*
* @note The array containing the duty cycle values for the specified sequence
* must be in RAM and cannot be allocated on stack.
* For detailed information, see @ref nrf_pwm_sequence_t.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] p_sequence_0 First sequence to be played back.
* @param[in] p_sequence_1 Second sequence to be played back.
* @param[in] playback_count Number of playbacks to be performed (must not be 0).
* @param[in] flags Additional options. Pass any combination of
* @ref nrf_drv_pwm_flag_t "playback flags", or 0
* for default settings.
*/
void nrf_drv_pwm_complex_playback(nrf_drv_pwm_t const * const p_instance,
nrf_pwm_sequence_t const * p_sequence_0,
nrf_pwm_sequence_t const * p_sequence_1,
uint16_t playback_count,
uint32_t flags);
/**
* @brief Function for advancing the active sequence.
*
* This function only applies to @ref NRF_PWM_STEP_TRIGGERED mode.
*
* @param[in] p_instance Pointer to the driver instance structure.
*/
__STATIC_INLINE void nrf_drv_pwm_step(nrf_drv_pwm_t const * const p_instance);
/**
* @brief Function for stopping the sequence playback.
*
* The playback is stopped at the end of the current PWM period.
* This means that if the active sequence is configured to repeat each duty
* cycle value for a certain number of PWM periods, the last played value
* might appear on the output less times than requested.
*
* @note This function can be instructed to wait until the playback is stopped
* (by setting @p wait_until_stopped to true). Note that, depending on
* the length of the PMW period, this might take a significant amount of
* time. Alternatively, the @ref nrf_drv_pwm_is_stopped function can be
* used to poll the status, or the @ref NRF_DRV_PWM_EVT_STOPPED event can
* be used to get the notification when the playback is stopped, provided
* the event handler is defined.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] wait_until_stopped If true, the function will not return until
* the playback is stopped.
*
* @retval true If the PWM peripheral is stopped.
* @retval false If the PWM peripheral is not stopped.
*/
bool nrf_drv_pwm_stop(nrf_drv_pwm_t const * const p_instance,
bool wait_until_stopped);
/**
* @brief Function for checking the status of the PWM peripheral.
*
* @param[in] p_instance Pointer to the driver instance structure.
*
* @retval true If the PWM peripheral is stopped.
* @retval false If the PWM peripheral is not stopped.
*/
bool nrf_drv_pwm_is_stopped(nrf_drv_pwm_t const * const p_instance);
/**
* @brief Function for updating the sequence data during playback.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] seq_id Identifier of the sequence (0 or 1).
* @param[in] p_sequence Pointer to the new sequence definition.
*/
__STATIC_INLINE void nrf_drv_pwm_sequence_update(
nrf_drv_pwm_t const * const p_instance,
uint8_t seq_id,
nrf_pwm_sequence_t const * p_sequence);
/**
* @brief Function for updating the pointer to the duty cycle values
* in the specified sequence during playback.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] seq_id Identifier of the sequence (0 or 1).
* @param[in] values New pointer to the duty cycle values.
*/
__STATIC_INLINE void nrf_drv_pwm_sequence_values_update(
nrf_drv_pwm_t const * const p_instance,
uint8_t seq_id,
nrf_pwm_values_t values);
/**
* @brief Function for updating the number of duty cycle values
* in the specified sequence during playback.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] seq_id Identifier of the sequence (0 or 1).
* @param[in] length New number of the duty cycle values.
*/
__STATIC_INLINE void nrf_drv_pwm_sequence_length_update(
nrf_drv_pwm_t const * const p_instance,
uint8_t seq_id,
uint16_t length);
/**
* @brief Function for updating the number of repeats for duty cycle values
* in specified sequence during playback.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] seq_id Identifier of the sequence (0 or 1).
* @param[in] repeats New number of repeats.
*/
__STATIC_INLINE void nrf_drv_pwm_sequence_repeats_update(
nrf_drv_pwm_t const * const p_instance,
uint8_t seq_id,
uint32_t repeats);
/**
* @brief Function for updating the additional delay after the specified
* sequence during playback.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] seq_id Identifier of the sequence (0 or 1).
* @param[in] end_delay New end delay value (in PWM periods).
*/
__STATIC_INLINE void nrf_drv_pwm_sequence_end_delay_update(
nrf_drv_pwm_t const * const p_instance,
uint8_t seq_id,
uint32_t end_delay);
/**
* @brief Function for returning the address of a specified PWM task that can
* be used in PPI module.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] task Requested task.
*
* @return Task address.
*/
__STATIC_INLINE uint32_t nrf_drv_pwm_task_address_get(
nrf_drv_pwm_t const * const p_instance,
nrf_pwm_task_t task);
/**@brief Function for returning the address of a specified PWM event that can
* be used in PPI module.
*
* @param[in] p_instance Pointer to the driver instance structure.
* @param[in] event Requested event.
*
* @return Event address.
*/
__STATIC_INLINE uint32_t nrf_drv_pwm_event_address_get(
nrf_drv_pwm_t const * const p_instance,
nrf_pwm_event_t event);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE void nrf_drv_pwm_step(nrf_drv_pwm_t const * const p_instance)
{
nrf_pwm_task_trigger(p_instance->p_registers, NRF_PWM_TASK_NEXTSTEP);
}
__STATIC_INLINE void nrf_drv_pwm_sequence_update(
nrf_drv_pwm_t const * const p_instance,
uint8_t seq_id,
nrf_pwm_sequence_t const * p_sequence)
{
nrf_pwm_sequence_set(p_instance->p_registers, seq_id, p_sequence);
}
__STATIC_INLINE void nrf_drv_pwm_sequence_values_update(
nrf_drv_pwm_t const * const p_instance,
uint8_t seq_id,
nrf_pwm_values_t values)
{
nrf_pwm_seq_ptr_set(p_instance->p_registers, seq_id, values.p_raw);
}
__STATIC_INLINE void nrf_drv_pwm_sequence_length_update(
nrf_drv_pwm_t const * const p_instance,
uint8_t seq_id,
uint16_t length)
{
nrf_pwm_seq_cnt_set(p_instance->p_registers, seq_id, length);
}
__STATIC_INLINE void nrf_drv_pwm_sequence_repeats_update(
nrf_drv_pwm_t const * const p_instance,
uint8_t seq_id,
uint32_t repeats)
{
nrf_pwm_seq_refresh_set(p_instance->p_registers, seq_id, repeats);
}
__STATIC_INLINE void nrf_drv_pwm_sequence_end_delay_update(
nrf_drv_pwm_t const * const p_instance,
uint8_t seq_id,
uint32_t end_delay)
{
nrf_pwm_seq_end_delay_set(p_instance->p_registers, seq_id, end_delay);
}
__STATIC_INLINE uint32_t nrf_drv_pwm_task_address_get(
nrf_drv_pwm_t const * const p_instance,
nrf_pwm_task_t task)
{
return nrf_pwm_task_address_get(p_instance->p_registers, task);
}
__STATIC_INLINE uint32_t nrf_drv_pwm_event_address_get(
nrf_drv_pwm_t const * const p_instance,
nrf_pwm_event_t event)
{
return nrf_pwm_event_address_get(p_instance->p_registers, event);
}
#endif // SUPPRESS_INLINE_IMPLEMENTATION
#endif // NRF_DRV_PWM_H__
/** @} */

View File

@ -0,0 +1,536 @@
/*
* Copyright (c) 2015 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#include "nrf_drv_saadc.h"
#include "nrf_assert.h"
#include "nordic_common.h"
#include "nrf_drv_common.h"
#include "app_util_platform.h"
typedef enum
{
NRF_SAADC_STATE_IDLE = 0,
NRF_SAADC_STATE_BUSY = 1
} nrf_saadc_state_t;
typedef struct
{
nrf_saadc_input_t pselp;
nrf_saadc_input_t pseln;
} nrf_saadc_psel_buffer;
static const nrf_drv_saadc_config_t m_default_config = NRF_DRV_SAADC_DEFAULT_CONFIG;
/** @brief SAADC control block.*/
typedef struct
{
nrf_drv_saadc_event_handler_t event_handler; ///< Event handler function pointer.
volatile nrf_saadc_value_t * p_buffer; ///< Sample buffer.
volatile uint16_t buffer_size; ///< Size of the sample buffer.
#ifdef NRF52_PAN_28
volatile uint16_t buffer_pos; ///< Current sample buffer position.
#endif
volatile nrf_saadc_value_t * p_secondary_buffer; ///< Secondary sample buffer.
uint32_t limits_enabled_flags; ///< Enabled limits flags.
uint16_t secondary_buffer_size; ///< Size of the secondary buffer.
nrf_saadc_psel_buffer psel[NRF_SAADC_CHANNEL_COUNT]; ///< Pin configurations of SAADC channels.
nrf_drv_state_t state; ///< Driver initialization state.
nrf_saadc_state_t adc_state; ///< State of the SAADC.
#ifdef NRF52_PAN_28
uint8_t scan_pos; ///< Current channel scanning position.
#endif
uint8_t active_channels; ///< Number of enabled SAADC channels.
} nrf_drv_saadc_cb_t;
static nrf_drv_saadc_cb_t m_cb;
#define LOW_LIMIT_TO_FLAG(channel) ((2*channel+1))
#define HIGH_LIMIT_TO_FLAG(channel) ((2*channel))
#define FLAG_IDX_TO_EVENT(idx) ((nrf_saadc_event_t)((uint32_t)NRF_SAADC_EVENT_CH0_LIMITH+4*idx))
#define LIMIT_EVENT_TO_CHANNEL(event)(uint8_t)(((uint32_t)event-(uint32_t)NRF_SAADC_EVENT_CH0_LIMITH)/8)
#define LIMIT_EVENT_TO_LIMIT_TYPE(event)((((uint32_t)event-(uint32_t)NRF_SAADC_EVENT_CH0_LIMITH) & 4) ? \
NRF_SAADC_LIMIT_LOW : NRF_SAADC_LIMIT_HIGH)
#define HW_TIMEOUT 10000
void SAADC_IRQHandler(void)
{
if (nrf_saadc_event_check(NRF_SAADC_EVENT_END))
{
nrf_saadc_event_clear(NRF_SAADC_EVENT_END);
#ifdef NRF52_PAN_28
if (m_cb.active_channels == 1)
{
#endif
nrf_drv_saadc_evt_t evt;
evt.type = NRF_DRV_SAADC_EVT_DONE;
evt.data.done.p_buffer = (nrf_saadc_value_t *)m_cb.p_buffer;
evt.data.done.size = nrf_saadc_amount_get();
if (m_cb.p_secondary_buffer == NULL)
{
m_cb.adc_state = NRF_SAADC_STATE_IDLE;
}
else
{
m_cb.p_buffer = m_cb.p_secondary_buffer;
m_cb.buffer_size = m_cb.secondary_buffer_size;
m_cb.p_secondary_buffer = NULL;
nrf_saadc_task_trigger(NRF_SAADC_TASK_START);
}
m_cb.event_handler(&evt);
#ifdef NRF52_PAN_28
}
else
{
//PAN-28: scan mode is not working correctly, emulated by interrupts
++(m_cb.buffer_pos);
uint16_t buffer_pos = m_cb.buffer_pos;
if (buffer_pos == m_cb.buffer_size)
{
nrf_drv_saadc_evt_t evt;
evt.type = NRF_DRV_SAADC_EVT_DONE;
evt.data.done.p_buffer = (nrf_saadc_value_t *)(m_cb.p_buffer);
evt.data.done.size = m_cb.buffer_size;
m_cb.adc_state = NRF_SAADC_STATE_IDLE;
if (m_cb.p_secondary_buffer == NULL)
{
m_cb.adc_state = NRF_SAADC_STATE_IDLE;
}
else
{
(void)nrf_drv_saadc_buffer_convert((nrf_saadc_value_t *)m_cb.p_secondary_buffer, (uint16_t)m_cb.secondary_buffer_size);
}
m_cb.event_handler(&evt);
}
else
{
uint8_t current_scan_pos = m_cb.scan_pos;
nrf_saadc_channel_input_set(current_scan_pos,
NRF_SAADC_INPUT_DISABLED, NRF_SAADC_INPUT_DISABLED);
nrf_saadc_buffer_init((nrf_saadc_value_t *)(m_cb.p_buffer + m_cb.buffer_pos), 1);
// Find the next enabled channel.
for (++m_cb.scan_pos; m_cb.scan_pos < NRF_SAADC_CHANNEL_COUNT; ++m_cb.scan_pos)
{
if (m_cb.psel[m_cb.scan_pos].pselp)
{
nrf_saadc_channel_input_set(m_cb.scan_pos,
m_cb.psel[m_cb.scan_pos].pselp, m_cb.psel[m_cb.scan_pos].pseln);
nrf_saadc_task_trigger(NRF_SAADC_TASK_START);
nrf_saadc_task_trigger(NRF_SAADC_TASK_SAMPLE);
return;
}
}
//if scanning is done prepare for next round.
for (uint8_t i = 0; i < NRF_SAADC_CHANNEL_COUNT; ++i)
{
if (m_cb.psel[i].pselp)
{
m_cb.scan_pos = i;
break;
}
}
nrf_saadc_channel_input_set(m_cb.scan_pos,
m_cb.psel[m_cb.scan_pos].pselp, m_cb.psel[m_cb.scan_pos].pseln);
nrf_saadc_task_trigger(NRF_SAADC_TASK_START);
}
}
#endif
}
if (nrf_saadc_event_check(NRF_SAADC_EVENT_STOPPED))
{
nrf_saadc_event_clear(NRF_SAADC_EVENT_STOPPED);
m_cb.adc_state = NRF_SAADC_STATE_IDLE;
}
else
{
uint32_t limit_flags = m_cb.limits_enabled_flags;
uint32_t flag_idx;
nrf_saadc_event_t event;
while (limit_flags)
{
flag_idx = __CLZ(limit_flags);
limit_flags &= ~((1UL<<31) >> flag_idx);
event = FLAG_IDX_TO_EVENT(flag_idx);
if (nrf_saadc_event_check(event))
{
nrf_saadc_event_clear(event);
nrf_drv_saadc_evt_t evt;
evt.type = NRF_DRV_SAADC_EVT_LIMIT;
evt.data.limit.channel = LIMIT_EVENT_TO_CHANNEL(event);
evt.data.limit.limit_type = LIMIT_EVENT_TO_LIMIT_TYPE(event);
m_cb.event_handler(&evt);
}
}
}
}
ret_code_t nrf_drv_saadc_init(nrf_drv_saadc_config_t const * p_config,
nrf_drv_saadc_event_handler_t event_handler)
{
if (m_cb.state != NRF_DRV_STATE_UNINITIALIZED)
{
return NRF_ERROR_INVALID_STATE;
}
if (event_handler == NULL)
{
return NRF_ERROR_INVALID_PARAM;
}
if (p_config == NULL)
{
p_config = &m_default_config;
}
m_cb.event_handler = event_handler;
nrf_saadc_resolution_set(p_config->resolution);
nrf_saadc_oversample_set(p_config->oversample);
m_cb.state = NRF_DRV_STATE_INITIALIZED;
m_cb.adc_state = NRF_SAADC_STATE_IDLE;
m_cb.active_channels = 0;
m_cb.limits_enabled_flags = 0;
#ifdef NRF52_PAN_28
m_cb.buffer_pos = 0;
#endif
nrf_saadc_int_disable(NRF_SAADC_INT_ALL);
nrf_saadc_event_clear(NRF_SAADC_EVENT_END);
nrf_drv_common_irq_enable(SAADC_IRQn, p_config->interrupt_priority);
nrf_saadc_int_enable(NRF_SAADC_INT_END);
nrf_saadc_enable();
return NRF_SUCCESS;
}
void nrf_drv_saadc_uninit(void)
{
ASSERT(m_cb.state != NRF_DRV_STATE_UNINITIALIZED);
nrf_drv_common_irq_disable(SAADC_IRQn);
nrf_saadc_task_trigger(NRF_SAADC_TASK_STOP);
// Wait for ADC being stopped.
uint32_t timeout = HW_TIMEOUT;
while (nrf_saadc_event_check(NRF_SAADC_EVENT_STOPPED) == 0 && timeout > 0)
{
--timeout;
}
ASSERT(timeout > 0);
nrf_saadc_disable();
nrf_saadc_int_disable(NRF_SAADC_INT_ALL);
m_cb.adc_state = NRF_SAADC_STATE_IDLE;
for (uint8_t channel = 0; channel < NRF_SAADC_CHANNEL_COUNT; ++channel)
{
if (m_cb.psel[channel].pselp != NRF_SAADC_INPUT_DISABLED)
{
(void)nrf_drv_saadc_channel_uninit(channel);
}
}
m_cb.state = NRF_DRV_STATE_UNINITIALIZED;
}
ret_code_t nrf_drv_saadc_channel_init(uint8_t channel,
nrf_saadc_channel_config_t const * const p_config)
{
ASSERT(m_cb.state != NRF_DRV_STATE_UNINITIALIZED);
ASSERT(channel < NRF_SAADC_CHANNEL_COUNT);
//Oversampling can be used only with one channel.
ASSERT((nrf_saadc_oversample_get()==NRF_SAADC_OVERSAMPLE_DISABLED) || (m_cb.active_channels == 0));
ASSERT((p_config->pin_p <= NRF_SAADC_INPUT_VDD) && (p_config->pin_p > NRF_SAADC_INPUT_DISABLED));
ASSERT(p_config->pin_n <= NRF_SAADC_INPUT_VDD);
// A channel can only be initialized if the driver is in the idle state.
if (m_cb.adc_state == NRF_SAADC_STATE_BUSY)
{
return NRF_ERROR_BUSY;
}
if (!m_cb.psel[channel].pselp)
{
++m_cb.active_channels;
}
m_cb.psel[channel].pselp = p_config->pin_p;
m_cb.psel[channel].pseln = p_config->pin_n;
nrf_saadc_channel_init(channel, p_config);
#ifdef NRF52_PAN_28
nrf_saadc_channel_input_set(channel, NRF_SAADC_INPUT_DISABLED, NRF_SAADC_INPUT_DISABLED);
#else
nrf_saadc_channel_input_set(channel, p_config->pin_p, p_config->pin_n);
#endif
return NRF_SUCCESS;
}
ret_code_t nrf_drv_saadc_channel_uninit(uint8_t channel)
{
ASSERT(channel <= NRF_SAADC_CHANNEL_COUNT)
ASSERT(m_cb.state != NRF_DRV_STATE_UNINITIALIZED);
// A channel can only be uninitialized if the driver is in the idle state.
if (m_cb.adc_state == NRF_SAADC_STATE_BUSY)
{
return NRF_ERROR_BUSY;
}
if (m_cb.psel[channel].pselp)
{
--m_cb.active_channels;
}
m_cb.psel[channel].pselp = NRF_SAADC_INPUT_DISABLED;
m_cb.psel[channel].pseln = NRF_SAADC_INPUT_DISABLED;
nrf_saadc_channel_input_set(channel, NRF_SAADC_INPUT_DISABLED, NRF_SAADC_INPUT_DISABLED);
nrf_drv_saadc_limits_set(channel, NRF_DRV_SAADC_LIMITL_DISABLED, NRF_DRV_SAADC_LIMITH_DISABLED);
return NRF_SUCCESS;
}
ret_code_t nrf_drv_saadc_sample_convert(uint8_t channel, nrf_saadc_value_t * p_value)
{
if (m_cb.adc_state != NRF_SAADC_STATE_IDLE)
{
return NRF_ERROR_BUSY;
}
m_cb.adc_state = NRF_SAADC_STATE_BUSY;
nrf_saadc_int_disable(NRF_SAADC_INT_END);
nrf_saadc_buffer_init(p_value, 1);
#ifndef NRF52_PAN_28
if (m_cb.active_channels > 1)
{
for (uint8_t i = 0; i < NRF_SAADC_CHANNEL_COUNT; ++i)
{
nrf_saadc_channel_input_set(i, NRF_SAADC_INPUT_DISABLED, NRF_SAADC_INPUT_DISABLED);
}
}
#endif
nrf_saadc_channel_input_set(channel,
m_cb.psel[channel].pselp, m_cb.psel[channel].pseln);
nrf_saadc_task_trigger(NRF_SAADC_TASK_START);
nrf_saadc_task_trigger(NRF_SAADC_TASK_SAMPLE);
uint32_t timeout = HW_TIMEOUT;
while (0 == nrf_saadc_event_check(NRF_SAADC_EVENT_END) && timeout > 0)
{
timeout--;
}
nrf_saadc_event_clear(NRF_SAADC_EVENT_END);
#ifdef NRF52_PAN_28
nrf_saadc_channel_input_set(channel, NRF_SAADC_INPUT_DISABLED, NRF_SAADC_INPUT_DISABLED);
#else
if (m_cb.active_channels > 1)
{
for (uint8_t i = 0; i < NRF_SAADC_CHANNEL_COUNT; ++i)
{
nrf_saadc_channel_input_set(i, m_cb.psel[i].pselp, m_cb.psel[i].pseln);
}
}
#endif
nrf_saadc_int_enable(NRF_SAADC_INT_END);
m_cb.adc_state = NRF_SAADC_STATE_IDLE;
return NRF_SUCCESS;
}
ret_code_t nrf_drv_saadc_buffer_convert(nrf_saadc_value_t * p_buffer, uint16_t size)
{
ASSERT(m_cb.state != NRF_DRV_STATE_UNINITIALIZED);
nrf_saadc_int_disable(NRF_SAADC_INT_END);
if (m_cb.adc_state == NRF_SAADC_STATE_BUSY)
{
if ( m_cb.p_secondary_buffer)
{
nrf_saadc_int_enable(NRF_SAADC_INT_END);
return NRF_ERROR_BUSY;
}
else
{
m_cb.p_secondary_buffer = p_buffer;
m_cb.secondary_buffer_size = size;
#ifdef NRF52_PAN_28
if (m_cb.active_channels == 1)
#endif
{
while (nrf_saadc_event_check(NRF_SAADC_EVENT_STARTED) == 0);
nrf_saadc_event_clear(NRF_SAADC_EVENT_STARTED);
nrf_saadc_buffer_init(p_buffer, size);
}
nrf_saadc_int_enable(NRF_SAADC_INT_END);
return NRF_SUCCESS;
}
}
nrf_saadc_int_enable(NRF_SAADC_INT_END);
m_cb.adc_state = NRF_SAADC_STATE_BUSY;
#ifdef NRF52_PAN_28
m_cb.scan_pos = NRF_SAADC_CHANNEL_COUNT;
for (uint8_t i = 0; i < NRF_SAADC_CHANNEL_COUNT; ++i)
{
if (m_cb.psel[i].pselp)
{
m_cb.scan_pos = i;
break;
}
}
// Find the first enabled channel.
if (m_cb.scan_pos >= NRF_SAADC_CHANNEL_COUNT)
{
return NRF_ERROR_INVALID_STATE;
}
m_cb.buffer_pos = 0;
#endif
m_cb.p_buffer = p_buffer;
m_cb.buffer_size = size;
m_cb.p_secondary_buffer = NULL;
#ifdef NRF52_PAN_28
nrf_saadc_channel_input_set(m_cb.scan_pos,
m_cb.psel[m_cb.scan_pos].pselp, m_cb.psel[m_cb.scan_pos].pseln);
if (m_cb.active_channels == 1)
{
nrf_saadc_buffer_init(p_buffer, size);
}
else
{
nrf_saadc_buffer_init(p_buffer, 1);
}
#else
nrf_saadc_buffer_init(p_buffer, size);
#endif
nrf_saadc_event_clear(NRF_SAADC_EVENT_STARTED);
nrf_saadc_task_trigger(NRF_SAADC_TASK_START);
return NRF_SUCCESS;
}
ret_code_t nrf_drv_saadc_sample()
{
ASSERT(m_cb.state != NRF_DRV_STATE_UNINITIALIZED);
ret_code_t err_code = NRF_SUCCESS;
if (m_cb.adc_state == NRF_SAADC_STATE_IDLE)
{
err_code = NRF_ERROR_BUSY;
}
else
{
nrf_saadc_task_trigger(NRF_SAADC_TASK_SAMPLE);
}
return err_code;
}
bool nrf_drv_saadc_is_busy(void)
{
return (m_cb.adc_state == NRF_SAADC_STATE_BUSY);
}
void nrf_drv_saadc_abort(void)
{
if (nrf_drv_saadc_is_busy())
{
nrf_saadc_event_clear(NRF_SAADC_EVENT_STOPPED);
nrf_saadc_task_trigger(NRF_SAADC_TASK_STOP);
// Wait for ADC being stopped.
uint32_t timeout = HW_TIMEOUT;
while ((m_cb.adc_state != NRF_SAADC_STATE_IDLE) && (timeout > 0))
{
--timeout;
}
ASSERT(timeout > 0);
m_cb.p_buffer = 0;
m_cb.p_secondary_buffer = 0;
}
}
void nrf_drv_saadc_limits_set(uint8_t channel, int16_t limit_low, int16_t limit_high)
{
ASSERT(m_cb.state != NRF_DRV_STATE_UNINITIALIZED);
ASSERT(m_cb.event_handler); // only non blocking mode supported
ASSERT(limit_low>=NRF_DRV_SAADC_LIMITL_DISABLED);
ASSERT(limit_high<=NRF_DRV_SAADC_LIMITH_DISABLED);
ASSERT(limit_low<limit_high);
nrf_saadc_channel_limits_set(channel, limit_low, limit_high);
uint32_t int_mask = nrf_saadc_limit_int_get(channel, NRF_SAADC_LIMIT_LOW);
if (limit_low == NRF_DRV_SAADC_LIMITL_DISABLED)
{
m_cb.limits_enabled_flags &= ~(0x80000000 >> LOW_LIMIT_TO_FLAG(channel));
nrf_saadc_int_disable(int_mask);
}
else
{
m_cb.limits_enabled_flags |= (0x80000000 >> LOW_LIMIT_TO_FLAG(channel));
nrf_saadc_int_enable(int_mask);
}
int_mask = nrf_saadc_limit_int_get(channel, NRF_SAADC_LIMIT_HIGH);
if (limit_high == NRF_DRV_SAADC_LIMITH_DISABLED)
{
m_cb.limits_enabled_flags &= ~(0x80000000 >> HIGH_LIMIT_TO_FLAG(channel));
nrf_saadc_int_disable(int_mask);
}
else
{
m_cb.limits_enabled_flags |= (0x80000000 >> HIGH_LIMIT_TO_FLAG(channel));
nrf_saadc_int_enable(int_mask);
}
}

View File

@ -0,0 +1,330 @@
/*
* Copyright (c) 2015 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/**
* @addtogroup nrf_saadc SAADC HAL and driver
* @ingroup nrf_drivers
* @brief @tagAPI52 Successive Approximation Analog-to-Digital Converter (SAADC) APIs.
* @details The SAADC HAL provides basic APIs for accessing the registers of the SAADC peripheral.
* The SAADC driver provides APIs on a higher level.
*
* @defgroup nrf_drv_saadc SAADC driver
* @{
* @ingroup nrf_saadc
*
* @brief @tagAPI52 Successive Approximation Analog-to-Digital Converter (SAADC) driver.
*/
#ifndef NRF_DRV_SAADC_H__
#define NRF_DRV_SAADC_H__
#include "nrf_drv_config.h"
#include "nrf_saadc.h"
#include "sdk_errors.h"
/**
* @brief Value that should be set as high limit to disable limit detection.
*/
#define NRF_DRV_SAADC_LIMITH_DISABLED (2047)
/**
* @brief Value that should be set as low limit to disable limit detection.
*/
#define NRF_DRV_SAADC_LIMITL_DISABLED (-2048)
/**
* @brief Macro for setting @ref nrf_drv_saadc_config_t to default settings.
*/
#define NRF_DRV_SAADC_DEFAULT_CONFIG \
{ \
.resolution = SAADC_CONFIG_RESOLUTION, \
.oversample = SAADC_CONFIG_OVERSAMPLE, \
.interrupt_priority = SAADC_CONFIG_IRQ_PRIORITY \
}
/**
* @brief Macro for setting @ref nrf_saadc_channel_config_t to default settings
* in single ended mode.
*
* @param PIN_P Analog input.
*/
#define NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(PIN_P) \
{ \
.resistor_p = NRF_SAADC_RESISTOR_DISABLED, \
.resistor_n = NRF_SAADC_RESISTOR_DISABLED, \
.gain = NRF_SAADC_GAIN1_6, \
.reference = NRF_SAADC_REFERENCE_INTERNAL, \
.acq_time = NRF_SAADC_ACQTIME_10US, \
.mode = NRF_SAADC_MODE_SINGLE_ENDED, \
.pin_p = (nrf_saadc_input_t)(PIN_P), \
.pin_n = NRF_SAADC_INPUT_DISABLED \
}
/**
* @brief Macro for setting @ref nrf_saadc_channel_config_t to default settings
* in differential mode.
*
* @param PIN_P Positive analog input.
* @param PIN_N Negative analog input.
*/
#define NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_DIFFERENTIAL(PIN_P, PIN_N) \
{ \
.resistor_p = NRF_SAADC_RESISTOR_DISABLED, \
.resistor_n = NRF_SAADC_RESISTOR_DISABLED, \
.gain = NRF_SAADC_GAIN1_6, \
.reference = NRF_SAADC_REFERENCE_INTERNAL, \
.acq_time = NRF_SAADC_ACQTIME_10US, \
.mode = NRF_SAADC_MODE_DIFFERENTIAL, \
.pin_p = (nrf_saadc_input_t)(PIN_P), \
.pin_n = (nrf_saadc_input_t)(PIN_N) \
}
/**
* @brief Analog-to-digital converter driver configuration structure.
*/
typedef struct
{
nrf_saadc_resolution_t resolution; ///< Resolution configuration.
nrf_saadc_oversample_t oversample; ///< Oversampling configuration.
uint8_t interrupt_priority; ///< Interrupt priority.
} nrf_drv_saadc_config_t;
/**
* @brief Driver event types.
*/
typedef enum
{
NRF_DRV_SAADC_EVT_DONE, ///< Event generated when the buffer is filled with samples.
NRF_DRV_SAADC_EVT_LIMIT, ///< Event generated after one of the limits is reached.
} nrf_drv_saadc_evt_type_t;
/**
* @brief Analog-to-digital converter driver done event data.
*/
typedef struct
{
nrf_saadc_value_t * p_buffer; ///< Pointer to buffer with converted samples.
uint16_t size; ///< Number of samples in the buffer.
} nrf_drv_saadc_done_evt_t;
/**
* @brief Analog-to-digital converter driver limit event data.
*/
typedef struct
{
uint8_t channel; ///< Channel on which the limit was detected.
nrf_saadc_limit_t limit_type; ///< Type of limit detected.
} nrf_drv_saadc_limit_evt_t;
/**
* @brief Analog-to-digital converter driver event structure.
*/
typedef struct
{
nrf_drv_saadc_evt_type_t type; ///< Event type.
union
{
nrf_drv_saadc_done_evt_t done; ///< Data for @ref NRF_DRV_SAADC_EVT_DONE event.
nrf_drv_saadc_limit_evt_t limit;///< Data for @ref NRF_DRV_SAADC_EVT_LIMIT event.
} data;
} nrf_drv_saadc_evt_t;
/**
* @brief ADC event handler.
*
* @param[in] p_event Pointer to an ADC event. The event structure is allocated on
* the stack, so it is valid only within the context of
* the event handler.
*/
typedef void (*nrf_drv_saadc_event_handler_t)(nrf_drv_saadc_evt_t const * p_event);
/**
* @brief Function for initializing the SAADC.
*
* @param[in] p_config Pointer to a configuration structure. If NULL, the default one is used.
* @param[in] event_handler Event handler provided by the user.
*
* @retval NRF_SUCCESS If initialization was successful.
* @retval NRF_ERROR_INVALID_STATE If the driver is already initialized.
* @retval NRF_ERROR_INVALID_PARAM If event_handler is NULL.
*/
ret_code_t nrf_drv_saadc_init(nrf_drv_saadc_config_t const * p_config,
nrf_drv_saadc_event_handler_t event_handler);
/**
* @brief Function for uninitializing the SAADC.
*
* This function stops all ongoing conversions and disables all channels.
*/
void nrf_drv_saadc_uninit(void);
/**
* @brief Function for getting the address of a SAMPLE SAADC task.
*
* @return Task address.
*/
__STATIC_INLINE uint32_t nrf_drv_saadc_sample_task_get(void)
{
return nrf_saadc_task_address_get(NRF_SAADC_TASK_SAMPLE);
}
/**
* @brief Function for initializing an SAADC channel.
*
* This function configures and enables the channel.
*
* @retval NRF_SUCCESS If initialization was successful.
* @retval NRF_ERROR_INVALID_STATE If the ADC was not initialized.
* @retval NRF_ERROR_NO_MEM If the specified channel was already allocated.
*/
ret_code_t nrf_drv_saadc_channel_init(uint8_t channel,
nrf_saadc_channel_config_t const * const p_config);
/**
* @brief Function for uninitializing an SAADC channel.
*
* @retval NRF_SUCCESS If uninitialization was successful.
* @retval NRF_ERROR_BUSY If the ADC is busy.
*/
ret_code_t nrf_drv_saadc_channel_uninit(uint8_t channel);
/**
* @brief Function for starting SAADC sampling.
*
* @retval NRF_SUCCESS If ADC sampling was triggered.
* @retval NRF_ERROR_BUSY If ADC is in idle state.
*/
ret_code_t nrf_drv_saadc_sample(void);
/**
* @brief Blocking function for executing a single ADC conversion.
*
* This function selects the desired input, starts a single conversion,
* waits for it to finish, and returns the result.
*
* The function will fail if ADC is busy.
*
* @param[in] channel Channel.
* @param[out] p_value Pointer to the location where the result should be placed.
*
* @retval NRF_SUCCESS If conversion was successful.
* @retval NRF_ERROR_BUSY If the ADC driver is busy.
*/
ret_code_t nrf_drv_saadc_sample_convert(uint8_t channel, nrf_saadc_value_t * p_value);
/**
* @brief Function for issuing conversion of data to the buffer.
*
* This function is non-blocking. The application is notified about filling the buffer by the event handler.
* Conversion will be done on all enabled channels. If the ADC is in idle state, the function will set up Easy
* DMA for the conversion. The ADC will be ready for sampling and wait for the SAMPLE task. It can be
* triggered manually by the @ref nrf_drv_saadc_sample function or by PPI using the @ref NRF_SAADC_TASK_SAMPLE
* task. If one buffer is already set and the conversion is ongoing, calling this function will
* result in queuing the given buffer. The driver will start filling the issued buffer when the first one is
* completed. If the function is called again before the first buffer is filled, it will return with error.
*
* @param[in] buffer Result buffer.
* @param[in] size Buffer size in words.
*
* @retval NRF_SUCCESS If conversion was successful.
* @retval NRF_ERROR_BUSY If the driver already has two buffers set.
*/
ret_code_t nrf_drv_saadc_buffer_convert(nrf_saadc_value_t * buffer, uint16_t size);
/**
* @brief Function for retrieving the SAADC state.
*
* @retval true If the ADC is busy.
* @retval false If the ADC is ready.
*/
bool nrf_drv_saadc_is_busy(void);
/**
* @brief Function for aborting ongoing and buffered conversions.
* @note @ref NRF_DRV_SAADC_EVT_DONE event will be generated if there is a conversion in progress.
* Event will contain number of words in the sample buffer.
*/
void nrf_drv_saadc_abort(void);
/**
* @brief Function for setting the SAADC channel limits.
* When limits are enabled and the result exceeds the defined bounds, the limit handler function is called.
*
* @param[in] channel SAADC channel number.
* @param[in] limit_low Lower limit (valid values from @ref NRF_DRV_SAADC_LIMITL_DISABLED to
* @ref NRF_DRV_SAADC_LIMITH_DISABLED). Conversion results below this value will trigger
* the handler function. Set to @ref NRF_DRV_SAADC_LIMITL_DISABLED to disable this limit.
* @param[in] limit_high Upper limit (valid values from @ref NRF_DRV_SAADC_LIMITL_DISABLED to
* @ref NRF_DRV_SAADC_LIMITH_DISABLED). Conversion results above this value will trigger
* the handler function. Set to @ref NRF_DRV_SAADC_LIMITH_DISABLED to disable this limit.
*/
void nrf_drv_saadc_limits_set(uint8_t channel, int16_t limit_low, int16_t limit_high);
/**
* @brief Function for converting a GPIO pin number to an analog input pin number used in the channel
* configuration.
*
* @param[in] pin GPIO pin.
*
* @return Value representing an analog input pin. The function returns @ref NRF_SAADC_INPUT_DISABLED
* if the specified pin is not an analog input.
*/
__STATIC_INLINE nrf_saadc_input_t nrf_drv_saadc_gpio_to_ain(uint32_t pin)
{
// AIN0 - AIN3
if (pin >= 2 && pin <= 5)
{
//0 means "not connected", hence this "+ 1"
return (nrf_saadc_input_t)(pin - 2 + 1);
}
// AIN4 - AIN7
else if (pin >= 28 && pin <= 31)
{
return (nrf_saadc_input_t)(pin - 24 + 1);
}
else
{
return NRF_SAADC_INPUT_DISABLED;
}
}
#endif // NRF_DRV_SAADC_H__
/** @} */

View File

@ -0,0 +1,495 @@
/*
* Copyright (c) 2015 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#ifndef NRF_DRV_CONFIG_H
#define NRF_DRV_CONFIG_H
/**
* Provide a non-zero value here in applications that need to use several
* peripherals with the same ID that are sharing certain resources
* (for example, SPI0 and TWI0). Obviously, such peripherals cannot be used
* simultaneously. Therefore, this definition allows to initialize the driver
* for another peripheral from a given group only after the previously used one
* is uninitialized. Normally, this is not possible, because interrupt handlers
* are implemented in individual drivers.
* This functionality requires a more complicated interrupt handling and driver
* initialization, hence it is not always desirable to use it.
*/
#define PERIPHERAL_RESOURCE_SHARING_ENABLED 1
/* CLOCK */
#define CLOCK_ENABLED 1
#if (CLOCK_ENABLED == 1)
#define CLOCK_CONFIG_XTAL_FREQ NRF_CLOCK_XTALFREQ_Default
#define CLOCK_CONFIG_LF_SRC NRF_CLOCK_LFCLK_Xtal
#define CLOCK_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOWEST
#endif
/* GPIOTE */
#define GPIOTE_ENABLED 1
#if (GPIOTE_ENABLED == 1)
#define GPIOTE_CONFIG_USE_SWI_EGU false
#define GPIOTE_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOWEST
#define GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS 8
#endif
/* TIMER */
#ifdef SOFTDEVICE_PRESENT
#define TIMER0_ENABLED 0
#else
#define TIMER0_ENABLED 1
#endif
#if (TIMER0_ENABLED == 1)
#define TIMER0_CONFIG_FREQUENCY NRF_TIMER_FREQ_16MHz
#define TIMER0_CONFIG_MODE TIMER_MODE_MODE_Timer
#define TIMER0_CONFIG_BIT_WIDTH TIMER_BITMODE_BITMODE_32Bit
#define TIMER0_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOWEST
#define TIMER0_INSTANCE_INDEX 0
#endif
#define TIMER1_ENABLED 1
#if (TIMER1_ENABLED == 1)
#define TIMER1_CONFIG_FREQUENCY NRF_TIMER_FREQ_16MHz
#define TIMER1_CONFIG_MODE TIMER_MODE_MODE_Timer
#define TIMER1_CONFIG_BIT_WIDTH TIMER_BITMODE_BITMODE_16Bit
#define TIMER1_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOWEST
#define TIMER1_INSTANCE_INDEX (TIMER0_ENABLED)
#endif
#define TIMER2_ENABLED 1
#if (TIMER2_ENABLED == 1)
#define TIMER2_CONFIG_FREQUENCY NRF_TIMER_FREQ_16MHz
#define TIMER2_CONFIG_MODE TIMER_MODE_MODE_Timer
#define TIMER2_CONFIG_BIT_WIDTH TIMER_BITMODE_BITMODE_16Bit
#define TIMER2_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOWEST
#define TIMER2_INSTANCE_INDEX (TIMER1_ENABLED+TIMER0_ENABLED)
#endif
#define TIMER3_ENABLED 0
#if (TIMER3_ENABLED == 1)
#define TIMER3_CONFIG_FREQUENCY NRF_TIMER_FREQ_16MHz
#define TIMER3_CONFIG_MODE TIMER_MODE_MODE_Timer
#define TIMER3_CONFIG_BIT_WIDTH TIMER_BITMODE_BITMODE_16Bit
#define TIMER3_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOWEST
#define TIMER3_INSTANCE_INDEX (TIMER2_ENABLED+TIMER1_ENABLED+TIMER0_ENABLED)
#endif
#define TIMER4_ENABLED 0
#if (TIMER4_ENABLED == 1)
#define TIMER4_CONFIG_FREQUENCY NRF_TIMER_FREQ_16MHz
#define TIMER4_CONFIG_MODE TIMER_MODE_MODE_Timer
#define TIMER4_CONFIG_BIT_WIDTH TIMER_BITMODE_BITMODE_16Bit
#define TIMER4_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOWEST
#define TIMER4_INSTANCE_INDEX (TIMER3_ENABLED+TIMER2_ENABLED+TIMER1_ENABLED+TIMER0_ENABLED)
#endif
#define TIMER_COUNT (TIMER0_ENABLED + TIMER1_ENABLED + TIMER2_ENABLED + TIMER3_ENABLED + TIMER4_ENABLED)
/* RTC */
#define RTC0_ENABLED 0
#if (RTC0_ENABLED == 1)
#define RTC0_CONFIG_FREQUENCY 32678
#define RTC0_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOWEST
#define RTC0_CONFIG_RELIABLE false
#define RTC0_INSTANCE_INDEX 0
#endif
#define RTC1_ENABLED 0
#if (RTC1_ENABLED == 1)
#define RTC1_CONFIG_FREQUENCY 32768
#define RTC1_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOWEST
#define RTC1_CONFIG_RELIABLE false
#define RTC1_INSTANCE_INDEX (RTC0_ENABLED)
#endif
#define RTC2_ENABLED 0
#if (RTC2_ENABLED == 1)
#define RTC2_CONFIG_FREQUENCY 32768
#define RTC2_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOWEST
#define RTC2_CONFIG_RELIABLE false
#define RTC2_INSTANCE_INDEX (RTC0_ENABLED+RTC1_ENABLED)
#endif
#define RTC_COUNT (RTC0_ENABLED+RTC1_ENABLED+RTC2_ENABLED)
#define NRF_MAXIMUM_LATENCY_US 2000
/* RNG */
#define RNG_ENABLED 0
#if (RNG_ENABLED == 1)
#define RNG_CONFIG_ERROR_CORRECTION true
#define RNG_CONFIG_POOL_SIZE 8
#define RNG_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOWEST
#endif
/* PWM */
#define PWM0_ENABLED 1
#if (PWM0_ENABLED == 1)
#define PWM0_CONFIG_OUT0_PIN 2
#define PWM0_CONFIG_OUT1_PIN 3
#define PWM0_CONFIG_OUT2_PIN 4
#define PWM0_CONFIG_OUT3_PIN 5
#define PWM0_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOWEST
#define PWM0_CONFIG_BASE_CLOCK NRF_PWM_CLK_1MHz
#define PWM0_CONFIG_COUNT_MODE NRF_PWM_MODE_UP
#define PWM0_CONFIG_TOP_VALUE 1000
#define PWM0_CONFIG_LOAD_MODE NRF_PWM_LOAD_COMMON
#define PWM0_CONFIG_STEP_MODE NRF_PWM_STEP_AUTO
#define PWM0_INSTANCE_INDEX 0
#endif
#define PWM1_ENABLED 1
#if (PWM1_ENABLED == 1)
#define PWM1_CONFIG_OUT0_PIN 2
#define PWM1_CONFIG_OUT1_PIN 3
#define PWM1_CONFIG_OUT2_PIN 4
#define PWM1_CONFIG_OUT3_PIN 5
#define PWM1_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOWEST
#define PWM1_CONFIG_BASE_CLOCK NRF_PWM_CLK_1MHz
#define PWM1_CONFIG_COUNT_MODE NRF_PWM_MODE_UP
#define PWM1_CONFIG_TOP_VALUE 1000
#define PWM1_CONFIG_LOAD_MODE NRF_PWM_LOAD_COMMON
#define PWM1_CONFIG_STEP_MODE NRF_PWM_STEP_AUTO
#define PWM1_INSTANCE_INDEX (PWM0_ENABLED)
#endif
#define PWM2_ENABLED 1
#if (PWM2_ENABLED == 1)
#define PWM2_CONFIG_OUT0_PIN 2
#define PWM2_CONFIG_OUT1_PIN 3
#define PWM2_CONFIG_OUT2_PIN 4
#define PWM2_CONFIG_OUT3_PIN 5
#define PWM2_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOWEST
#define PWM2_CONFIG_BASE_CLOCK NRF_PWM_CLK_1MHz
#define PWM2_CONFIG_COUNT_MODE NRF_PWM_MODE_UP
#define PWM2_CONFIG_TOP_VALUE 1000
#define PWM2_CONFIG_LOAD_MODE NRF_PWM_LOAD_COMMON
#define PWM2_CONFIG_STEP_MODE NRF_PWM_STEP_AUTO
#define PWM2_INSTANCE_INDEX (PWM0_ENABLED + PWM1_ENABLED)
#endif
#define PWM_COUNT (PWM0_ENABLED + PWM1_ENABLED + PWM2_ENABLED)
/* SPI */
#define SPI0_ENABLED 1
#if (SPI0_ENABLED == 1)
#define SPI0_USE_EASY_DMA 0
#define SPI0_CONFIG_SCK_PIN 2
#define SPI0_CONFIG_MOSI_PIN 3
#define SPI0_CONFIG_MISO_PIN 4
#define SPI0_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOWEST
#define SPI0_INSTANCE_INDEX 0
#endif
#define SPI1_ENABLED 1
#if (SPI1_ENABLED == 1)
#define SPI1_USE_EASY_DMA 0
#define SPI1_CONFIG_SCK_PIN 2
#define SPI1_CONFIG_MOSI_PIN 3
#define SPI1_CONFIG_MISO_PIN 4
#define SPI1_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOWEST
#define SPI1_INSTANCE_INDEX (SPI0_ENABLED)
#endif
#define SPI2_ENABLED 1
#if (SPI2_ENABLED == 1)
#define SPI2_USE_EASY_DMA 0
#define SPI2_CONFIG_SCK_PIN 2
#define SPI2_CONFIG_MOSI_PIN 3
#define SPI2_CONFIG_MISO_PIN 4
#define SPI2_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOWEST
#define SPI2_INSTANCE_INDEX (SPI0_ENABLED + SPI1_ENABLED)
#endif
#define SPI_COUNT (SPI0_ENABLED + SPI1_ENABLED + SPI2_ENABLED)
/* SPIS */
#define SPIS0_ENABLED 1
#if (SPIS0_ENABLED == 1)
#define SPIS0_CONFIG_SCK_PIN 2
#define SPIS0_CONFIG_MOSI_PIN 3
#define SPIS0_CONFIG_MISO_PIN 4
#define SPIS0_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOWEST
#define SPIS0_INSTANCE_INDEX 0
#endif
#define SPIS1_ENABLED 1
#if (SPIS1_ENABLED == 1)
#define SPIS1_CONFIG_SCK_PIN 2
#define SPIS1_CONFIG_MOSI_PIN 3
#define SPIS1_CONFIG_MISO_PIN 4
#define SPIS1_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOWEST
#define SPIS1_INSTANCE_INDEX SPIS0_ENABLED
#endif
#define SPIS2_ENABLED 1
#if (SPIS2_ENABLED == 1)
#define SPIS2_CONFIG_SCK_PIN 2
#define SPIS2_CONFIG_MOSI_PIN 3
#define SPIS2_CONFIG_MISO_PIN 4
#define SPIS2_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOWEST
#define SPIS2_INSTANCE_INDEX (SPIS0_ENABLED + SPIS1_ENABLED)
#endif
#define SPIS_COUNT (SPIS0_ENABLED + SPIS1_ENABLED + SPIS2_ENABLED)
/* UART */
#define UART0_ENABLED 1
#if (UART0_ENABLED == 1)
#define UART0_CONFIG_HWFC NRF_UART_HWFC_ENABLED
#define UART0_CONFIG_PARITY NRF_UART_PARITY_EXCLUDED
#define UART0_CONFIG_BAUDRATE NRF_UART_BAUDRATE_9600
#define UART0_CONFIG_PSEL_TXD 6
#define UART0_CONFIG_PSEL_RXD 8
#define UART0_CONFIG_PSEL_CTS 7
#define UART0_CONFIG_PSEL_RTS 5
#define UART0_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_HIGH
#ifdef NRF52
#define UART0_CONFIG_USE_EASY_DMA false
//Compile time flag
#define UART_EASY_DMA_SUPPORT 1
#define UART_LEGACY_SUPPORT 1
#endif //NRF52
#endif
#define TWI0_ENABLED 1
#if (TWI0_ENABLED == 1)
#define TWI0_USE_EASY_DMA 0
#define TWI0_CONFIG_FREQUENCY NRF_TWI_FREQ_100K
#define TWI0_CONFIG_SCL 0
#define TWI0_CONFIG_SDA 1
#define TWI0_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOWEST
#define TWI0_INSTANCE_INDEX 0
#endif
#define TWI1_ENABLED 1
#if (TWI1_ENABLED == 1)
#define TWI1_USE_EASY_DMA 0
#define TWI1_CONFIG_FREQUENCY NRF_TWI_FREQ_100K
#define TWI1_CONFIG_SCL 0
#define TWI1_CONFIG_SDA 1
#define TWI1_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOWEST
#define TWI1_INSTANCE_INDEX (TWI0_ENABLED)
#endif
#define TWI_COUNT (TWI0_ENABLED + TWI1_ENABLED)
/* TWIS */
#define TWIS0_ENABLED 0
#if (TWIS0_ENABLED == 1)
#define TWIS0_CONFIG_ADDR0 0
#define TWIS0_CONFIG_ADDR1 0 /* 0: Disabled */
#define TWIS0_CONFIG_SCL 0
#define TWIS0_CONFIG_SDA 1
#define TWIS0_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOWEST
#define TWIS0_INSTANCE_INDEX 0
#endif
#define TWIS1_ENABLED 0
#if (TWIS1_ENABLED == 1)
#define TWIS1_CONFIG_ADDR0 0
#define TWIS1_CONFIG_ADDR1 0 /* 0: Disabled */
#define TWIS1_CONFIG_SCL 0
#define TWIS1_CONFIG_SDA 1
#define TWIS1_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOWEST
#define TWIS1_INSTANCE_INDEX (TWIS0_ENABLED)
#endif
#define TWIS_COUNT (TWIS0_ENABLED + TWIS1_ENABLED)
/* For more documentation see nrf_drv_twis.h file */
#define TWIS_ASSUME_INIT_AFTER_RESET_ONLY 0
/* For more documentation see nrf_drv_twis.h file */
#define TWIS_NO_SYNC_MODE 0
/* QDEC */
#define QDEC_ENABLED 0
#if (QDEC_ENABLED == 1)
#define QDEC_CONFIG_REPORTPER NRF_QDEC_REPORTPER_10
#define QDEC_CONFIG_SAMPLEPER NRF_QDEC_SAMPLEPER_16384us
#define QDEC_CONFIG_PIO_A 1
#define QDEC_CONFIG_PIO_B 2
#define QDEC_CONFIG_PIO_LED 3
#define QDEC_CONFIG_LEDPRE 511
#define QDEC_CONFIG_LEDPOL NRF_QDEC_LEPOL_ACTIVE_HIGH
#define QDEC_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOWEST
#define QDEC_CONFIG_DBFEN false
#define QDEC_CONFIG_SAMPLE_INTEN false
#endif
/* ADC */
#define ADC_ENABLED 0
#if (ADC_ENABLED == 1)
#define ADC_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOWEST
#endif
/* SAADC */
#define SAADC_ENABLED 1
#if (SAADC_ENABLED == 1)
#define SAADC_CONFIG_RESOLUTION NRF_SAADC_RESOLUTION_10BIT
#define SAADC_CONFIG_OVERSAMPLE NRF_SAADC_OVERSAMPLE_DISABLED
#define SAADC_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOWEST
#endif
/* PDM */
#define PDM_ENABLED 0
#if (PDM_ENABLED == 1)
#define PDM_CONFIG_MODE NRF_PDM_MODE_MONO
#define PDM_CONFIG_EDGE NRF_PDM_EDGE_LEFTFALLING
#define PDM_CONFIG_CLOCK_FREQ NRF_PDM_FREQ_1032K
#define PDM_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOWEST
#endif
/* COMP */
#define COMP_ENABLED 0
#if (COMP_ENABLED == 1)
#define COMP_CONFIG_REF NRF_COMP_REF_Int1V8
#define COMP_CONFIG_MAIN_MODE NRF_COMP_MAIN_MODE_SE
#define COMP_CONFIG_SPEED_MODE NRF_COMP_SP_MODE_High
#define COMP_CONFIG_HYST NRF_COMP_HYST_NoHyst
#define COMP_CONFIG_ISOURCE NRF_COMP_ISOURCE_Off
#define COMP_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOWEST
#define COMP_CONFIG_INPUT NRF_COMP_INPUT_0
#endif
/* LPCOMP */
#define LPCOMP_ENABLED 0
#if (LPCOMP_ENABLED == 1)
#define LPCOMP_CONFIG_REFERENCE NRF_LPCOMP_REF_SUPPLY_4_8
#define LPCOMP_CONFIG_DETECTION NRF_LPCOMP_DETECT_DOWN
#define LPCOMP_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_LOWEST
#define LPCOMP_CONFIG_INPUT NRF_LPCOMP_INPUT_0
#endif
/* WDT */
#define WDT_ENABLED 0
#if (WDT_ENABLED == 1)
#define WDT_CONFIG_BEHAVIOUR NRF_WDT_BEHAVIOUR_RUN_SLEEP
#define WDT_CONFIG_RELOAD_VALUE 2000
#define WDT_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_HIGH
#endif
/* SWI EGU */
#ifdef NRF52
#define EGU_ENABLED 0
#endif
/* I2S */
#define I2S_ENABLED 0
#if (I2S_ENABLED == 1)
#define I2S_CONFIG_SCK_PIN 22
#define I2S_CONFIG_LRCK_PIN 23
#define I2S_CONFIG_MCK_PIN NRF_DRV_I2S_PIN_NOT_USED
#define I2S_CONFIG_SDOUT_PIN 24
#define I2S_CONFIG_SDIN_PIN 25
#define I2S_CONFIG_IRQ_PRIORITY APP_IRQ_PRIORITY_HIGH
#define I2S_CONFIG_MASTER NRF_I2S_MODE_MASTER
#define I2S_CONFIG_FORMAT NRF_I2S_FORMAT_I2S
#define I2S_CONFIG_ALIGN NRF_I2S_ALIGN_LEFT
#define I2S_CONFIG_SWIDTH NRF_I2S_SWIDTH_16BIT
#define I2S_CONFIG_CHANNELS NRF_I2S_CHANNELS_STEREO
#define I2S_CONFIG_MCK_SETUP NRF_I2S_MCK_32MDIV8
#define I2S_CONFIG_RATIO NRF_I2S_RATIO_256X
#endif
#include "nrf_drv_config_validation.h"
#endif // NRF_DRV_CONFIG_H

View File

@ -0,0 +1,220 @@
/*
* Copyright (c) 2000 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/**
@defgroup nrf_mbr_api Master Boot Record API
@{
@brief APIs for updating SoftDevice and BootLoader
*/
/* Header guard */
#ifndef NRF_MBR_H__
#define NRF_MBR_H__
#include "nrf_svc.h"
#include <stdint.h>
#ifndef NRF52
#error "This header file shall only be included for nRF52 projects"
#endif
#ifdef __cplusplus
extern "C" {
#endif
/** @addtogroup NRF_MBR_DEFINES Defines
* @{ */
/**@brief MBR SVC Base number. */
#define MBR_SVC_BASE (0x18)
/**@brief Page size in words. */
#define MBR_PAGE_SIZE_IN_WORDS (1024)
/** @brief The size that must be reserved for the MBR when a softdevice is written to flash.
This is the offset where the first byte of the softdevice hex file is written.*/
#define MBR_SIZE (0x1000)
/** @} */
/** @addtogroup NRF_MBR_ENUMS Enumerations
* @{ */
/**@brief nRF Master Boot Record API SVC numbers. */
enum NRF_MBR_SVCS
{
SD_MBR_COMMAND = MBR_SVC_BASE, /**< ::sd_mbr_command */
};
/**@brief Possible values for ::sd_mbr_command_t.command */
enum NRF_MBR_COMMANDS
{
SD_MBR_COMMAND_COPY_BL, /**< Copy a new BootLoader. @see sd_mbr_command_copy_bl_t */
SD_MBR_COMMAND_COPY_SD, /**< Copy a new SoftDevice. @see ::sd_mbr_command_copy_sd_t*/
SD_MBR_COMMAND_INIT_SD, /**< Init forwarding interrupts to SD, and run reset function in SD*/
SD_MBR_COMMAND_COMPARE, /**< This command works like memcmp. @see ::sd_mbr_command_compare_t*/
SD_MBR_COMMAND_VECTOR_TABLE_BASE_SET, /**< Start forwarding all exception to this address @see ::sd_mbr_command_vector_table_base_set_t*/
};
/** @} */
/** @addtogroup NRF_MBR_TYPES Types
* @{ */
/**@brief This command copies part of a new SoftDevice
* The destination area is erased before copying.
* If dst is in the middle of a flash page, that whole flash page will be erased.
* If (dst+len) is in the middle of a flash page, that whole flash page will be erased.
*
* The user of this function is responsible for setting the BPROT registers.
*
* @retval ::NRF_SUCCESS indicates that the contents of the memory blocks where copied correctly.
* @retval ::NRF_ERROR_INTERNAL indicates that the contents of the memory blocks where not verified correctly after copying.
*/
typedef struct
{
uint32_t *src; /**< Pointer to the source of data to be copied.*/
uint32_t *dst; /**< Pointer to the destination where the content is to be copied.*/
uint32_t len; /**< Number of 32 bit words to copy. Must be a multiple of @ref MBR_PAGE_SIZE_IN_WORDS words.*/
} sd_mbr_command_copy_sd_t;
/**@brief This command works like memcmp, but takes the length in words.
*
* @retval ::NRF_SUCCESS indicates that the contents of both memory blocks are equal.
* @retval ::NRF_ERROR_NULL indicates that the contents of the memory blocks are not equal.
*/
typedef struct
{
uint32_t *ptr1; /**< Pointer to block of memory. */
uint32_t *ptr2; /**< Pointer to block of memory. */
uint32_t len; /**< Number of 32 bit words to compare.*/
} sd_mbr_command_compare_t;
/**@brief This command copies a new BootLoader.
* With this command, destination of BootLoader is always the address written in NRF_UICR->BOOTADDR.
*
* Destination is erased by this function.
* If (destination+bl_len) is in the middle of a flash page, that whole flash page will be erased.
*
* This function will use PROTENSET to protect the flash that is not intended to be written.
*
* On Success, this function will not return. It will start the new BootLoader from reset-vector as normal.
*
* @retval ::NRF_ERROR_INTERNAL indicates an internal error that should not happen.
* @retval ::NRF_ERROR_FORBIDDEN if NRF_UICR->BOOTADDR is not set.
* @retval ::NRF_ERROR_INVALID_LENGTH if parameters attempts to read or write outside flash area.
* @retval ::NRF_ERROR_NO_MEM if no parameter page is provided (see sds for more info)
*/
typedef struct
{
uint32_t *bl_src; /**< Pointer to the source of the Bootloader to be be copied.*/
uint32_t bl_len; /**< Number of 32 bit words to copy for BootLoader. */
} sd_mbr_command_copy_bl_t;
/**@brief Sets the base address of the interrupt vector table for interrupts forwarded from the MBR
*
* Once this function has been called, this address is where the MBR will start to forward interrupts to after a reset.
*
* To restore default forwarding this function should be called with @param address set to 0.
* The MBR will then start forwarding to interrupts to the address in NFR_UICR->BOOTADDR or to the SoftDevice if the BOOTADDR is not set.
*
* On Success, this function will not return. It will reset the device.
*
* @retval ::NRF_ERROR_INTERNAL indicates an internal error that should not happen.
* @retval ::NRF_ERROR_INVALID_ADDR if parameter address is outside of the flash size.
* @retval ::NRF_ERROR_NO_MEM if no parameter page is provided (see sds for more info)
*/
typedef struct
{
uint32_t address; /**< The base address of the interrupt vector table for forwarded interrupts.*/
} sd_mbr_command_vector_table_base_set_t;
typedef struct
{
uint32_t command; /**< type of command to be issued see @ref NRF_MBR_COMMANDS. */
union
{
sd_mbr_command_copy_sd_t copy_sd; /**< Parameters for copy SoftDevice.*/
sd_mbr_command_compare_t compare; /**< Parameters for verify.*/
sd_mbr_command_copy_bl_t copy_bl; /**< Parameters for copy BootLoader. Requires parameter page. */
sd_mbr_command_vector_table_base_set_t base_set; /**< Parameters for vector table base set. Requires parameter page.*/
} params;
} sd_mbr_command_t;
/** @} */
/** @addtogroup NRF_MBR_FUNCTIONS Functions
* @{ */
/**@brief Issue Master Boot Record commands
*
* Commands used when updating a SoftDevice and bootloader.
*
* The SD_MBR_COMMAND_COPY_BL and SD_MBR_COMMAND_VECTOR_TABLE_BASE_SET requires parameters to be
* retained by the MBR when resetting the IC. This is done in a separate flash page
* provided by the application. The uicr register UICR.NRFFW[1] must be set
* to an address corresponding to a page in the application flash space. This page will be cleared
* by the MBR and used to store the command before reset. When the UICR.NRFFW[1] field is set
* the page it refers to must not be used by the application. If the UICR.NRFFW[1] is set to
* 0xFFFFFFFF (the default) MBR commands which use flash will be unavailable and return
* NRF_ERROR_NO_MEM.
*
* @param[in] param Pointer to a struct describing the command.
*
* @note for retvals see ::sd_mbr_command_copy_sd_t ::sd_mbr_command_copy_bl_t ::sd_mbr_command_compare_t ::sd_mbr_command_vector_table_base_set_t
*
* @retval NRF_ERROR_NO_MEM if UICR.NRFFW[1] is not set (i.e. is 0xFFFFFFFF).
* @retval NRF_ERROR_INVALID_PARAM if an invalid command is given.
*/
SVCALL(SD_MBR_COMMAND, uint32_t, sd_mbr_command(sd_mbr_command_t* param));
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF_MBR_H__
/**
@}
*/

View File

@ -0,0 +1,635 @@
/*
* Copyright (c) 2000 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/**
@addtogroup BLE_COMMON BLE SoftDevice Common
@{
@defgroup ble_api Events, type definitions and API calls
@{
@brief Module independent events, type definitions and API calls for the BLE SoftDevice.
*/
#ifndef NRF_BLE_H__
#define NRF_BLE_H__
#include "nrf_ble_ranges.h"
#include "nrf_ble_types.h"
#include "nrf_ble_gap.h"
#include "nrf_ble_l2cap.h"
#include "nrf_ble_gatt.h"
#include "nrf_ble_gattc.h"
#include "nrf_ble_gatts.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @addtogroup BLE_COMMON_ENUMERATIONS Enumerations
* @{ */
/**
* @brief Common API SVC numbers.
*/
enum BLE_COMMON_SVCS
{
SD_BLE_ENABLE = BLE_SVC_BASE, /**< Enable and initialize the BLE stack */
SD_BLE_EVT_GET, /**< Get an event from the pending events queue. */
SD_BLE_TX_PACKET_COUNT_GET, /**< Get the total number of available application transmission packets for a particular connection. */
SD_BLE_UUID_VS_ADD, /**< Add a Vendor Specific UUID. */
SD_BLE_UUID_DECODE, /**< Decode UUID bytes. */
SD_BLE_UUID_ENCODE, /**< Encode UUID bytes. */
SD_BLE_VERSION_GET, /**< Get the local version information (company id, Link Layer Version, Link Layer Subversion). */
SD_BLE_USER_MEM_REPLY, /**< User Memory Reply. */
SD_BLE_OPT_SET, /**< Set a BLE option. */
SD_BLE_OPT_GET, /**< Get a BLE option. */
};
/**
* @brief BLE Module Independent Event IDs.
*/
enum BLE_COMMON_EVTS
{
BLE_EVT_TX_COMPLETE = BLE_EVT_BASE, /**< Transmission Complete. @ref ble_evt_tx_complete_t */
BLE_EVT_USER_MEM_REQUEST, /**< User Memory request. @ref ble_evt_user_mem_request_t */
BLE_EVT_USER_MEM_RELEASE /**< User Memory release. @ref ble_evt_user_mem_release_t */
};
/**@brief BLE connection bandwidth types.
* Bandwidth types supported by the SoftDevice in packets per connection interval.
*/
enum BLE_CONN_BWS
{
BLE_CONN_BW_NONE = 0,
BLE_CONN_BW_LOW,
BLE_CONN_BW_MID,
BLE_CONN_BW_HIGH
};
/**@brief Common Option IDs.
* IDs that uniquely identify a common option.
*/
enum BLE_COMMON_OPTS
{
BLE_COMMON_OPT_CONN_BW = BLE_OPT_BASE, /**< Bandwidth configuration @ref ble_common_opt_conn_bw_t */
BLE_COMMON_OPT_PA_LNA /**< PA and LNA options */
};
/** @} */
/** @addtogroup BLE_COMMON_DEFINES Defines
* @{ */
/** @brief Required pointer alignment for BLE Events.
*/
#define BLE_EVTS_PTR_ALIGNMENT 4
/** @defgroup BLE_USER_MEM_TYPES User Memory Types
* @{ */
#define BLE_USER_MEM_TYPE_INVALID 0x00 /**< Invalid User Memory Types. */
#define BLE_USER_MEM_TYPE_GATTS_QUEUED_WRITES 0x01 /**< User Memory for GATTS queued writes. */
/** @} */
/** @defgroup BLE_UUID_VS_COUNTS Vendor Specific UUID counts
* @{
*/
#define BLE_UUID_VS_COUNT_MIN 1 /**< Minimum VS UUID count. */
#define BLE_UUID_VS_COUNT_DEFAULT 0 /**< Use the default VS UUID count (10 for this version of the SoftDevice). */
/** @} */
/** @} */
/** @addtogroup BLE_COMMON_STRUCTURES Structures
* @{ */
/**@brief User Memory Block. */
typedef struct
{
uint8_t *p_mem; /**< Pointer to the start of the user memory block. */
uint16_t len; /**< Length in bytes of the user memory block. */
} ble_user_mem_block_t;
/**
* @brief Event structure for @ref BLE_EVT_TX_COMPLETE.
*/
typedef struct
{
uint8_t count; /**< Number of packets transmitted. */
} ble_evt_tx_complete_t;
/**@brief Event structure for @ref BLE_EVT_USER_MEM_REQUEST. */
typedef struct
{
uint8_t type; /**< User memory type, see @ref BLE_USER_MEM_TYPES. */
} ble_evt_user_mem_request_t;
/**@brief Event structure for @ref BLE_EVT_USER_MEM_RELEASE. */
typedef struct
{
uint8_t type; /**< User memory type, see @ref BLE_USER_MEM_TYPES. */
ble_user_mem_block_t mem_block; /**< User memory block */
} ble_evt_user_mem_release_t;
/**@brief Event structure for events not associated with a specific function module. */
typedef struct
{
uint16_t conn_handle; /**< Connection Handle on which this event occurred. */
union
{
ble_evt_tx_complete_t tx_complete; /**< Transmission Complete. */
ble_evt_user_mem_request_t user_mem_request; /**< User Memory Request Event Parameters. */
ble_evt_user_mem_release_t user_mem_release; /**< User Memory Release Event Parameters. */
} params;
} ble_common_evt_t;
/**@brief BLE Event header. */
typedef struct
{
uint16_t evt_id; /**< Value from a BLE_<module>_EVT series. */
uint16_t evt_len; /**< Length in octets including this header. */
} ble_evt_hdr_t;
/**@brief Common BLE Event type, wrapping the module specific event reports. */
typedef struct
{
ble_evt_hdr_t header; /**< Event header. */
union
{
ble_common_evt_t common_evt; /**< Common Event, evt_id in BLE_EVT_* series. */
ble_gap_evt_t gap_evt; /**< GAP originated event, evt_id in BLE_GAP_EVT_* series. */
ble_l2cap_evt_t l2cap_evt; /**< L2CAP originated event, evt_id in BLE_L2CAP_EVT* series. */
ble_gattc_evt_t gattc_evt; /**< GATT client originated event, evt_id in BLE_GATTC_EVT* series. */
ble_gatts_evt_t gatts_evt; /**< GATT server originated event, evt_id in BLE_GATTS_EVT* series. */
} evt;
} ble_evt_t;
/**
* @brief Version Information.
*/
typedef struct
{
uint8_t version_number; /**< Link Layer Version number for BT 4.1 spec is 7 (https://www.bluetooth.org/en-us/specification/assigned-numbers/link-layer). */
uint16_t company_id; /**< Company ID, Nordic Semiconductor's company ID is 89 (0x0059) (https://www.bluetooth.org/apps/content/Default.aspx?doc_id=49708). */
uint16_t subversion_number; /**< Link Layer Sub Version number, corresponds to the SoftDevice Config ID or Firmware ID (FWID). */
} ble_version_t;
/* @brief: Configuration parameters for the PA and LNA. */
typedef struct
{
uint8_t enable :1; /**< Enable toggling for this amplifier */
uint8_t active_high :1; /**< Set the pin to be active high */
uint8_t gpio_pin :6; /**< The GPIO pin to toggle for this amplifier */
} ble_pa_lna_cfg_t;
/*
* @brief PA & LNA GPIO toggle configuration
*
* This option configures the SoftDevice to toggle pins when the radio is active for use with a power amplifier and/or
* a low noise amplifier.
*
* Toggling the pins is achieved by using two PPI channels and a GPIOTE channel. The hardware channel IDs are provided
* by the application and should be regarded as reserved as long as any PA/LNA toggling is enabled.
*
* @note @ref sd_ble_opt_get is not supported for this option.
* @note This feature is only supported for nRF52, on nRF51 @ref NRF_ERROR_NOT_SUPPORTED will always be returned.
* @note Setting this option while the radio is in use (i.e. any of the roles are active) may have undefined consequences
* and must be avoided by the application.
*
*/
typedef struct
{
ble_pa_lna_cfg_t pa_cfg; /**< Power Amplifier configuration */
ble_pa_lna_cfg_t lna_cfg; /**< Low Noise Amplifier configuration */
uint8_t ppi_ch_id_set; /**< PPI channel used for radio pin setting */
uint8_t ppi_ch_id_clr; /**< PPI channel used for radio pin clearing */
uint8_t gpiote_ch_id; /**< GPIOTE channel used for radio pin toggling */
} ble_common_opt_pa_lna_t;
/**
* @brief BLE connection bandwidth configuration parameters
*/
typedef struct
{
uint8_t conn_bw_tx; /**< Connection bandwidth configuration for transmission, see @ref BLE_CONN_BWS.*/
uint8_t conn_bw_rx; /**< Connection bandwidth configuration for reception, see @ref BLE_CONN_BWS.*/
} ble_conn_bw_t;
/**@brief BLE connection specific bandwidth configuration parameters.
*
* This can be used with @ref sd_ble_opt_set to set the bandwidth configuration to be used when creating connections.
*
* Call @ref sd_ble_opt_set with this option prior to calling @ref sd_ble_gap_adv_start or @ref sd_ble_gap_connect.
*
* The bandwidth configurations set via @ref sd_ble_opt_set are maintained separately for central and peripheral
* connections. The given configurations are used for all future connections of the role indicated in this structure
* unless they are changed by subsequent @ref sd_ble_opt_set calls.
*
* @note When this option is not used, the SoftDevice will use the default options:
* - @ref BLE_CONN_BW_HIGH for @ref BLE_GAP_ROLE_PERIPH connections (both transmission and reception).
* - @ref BLE_CONN_BW_MID for @ref BLE_GAP_ROLE_CENTRAL connections (both transmisison and reception).
* This option allows the application to selectively override these defaults for each role.
*
* @note The global memory pool configuration can be set with the @ref ble_conn_bw_counts_t configuration parameter, which
* is provided to @ref sd_ble_enable.
*
* @note Please refer to SoftDevice Specification for more information on bandwidth configuration.
*
* @mscs
* @mmsc{@ref BLE_COMMON_CONF_BW}
* @endmscs
*
* @retval ::NRF_SUCCESS Set successfully.
* @retval ::BLE_ERROR_INVALID_ROLE The role is invalid.
* @retval ::NRF_ERROR_INVALID_PARAM Invalid bandwidth configuration parameters.
* @retval ::NRF_ERROR_NOT_SUPPORTED If the combination of role and bandwidth configuration is not supported.
*/
typedef struct
{
uint8_t role; /**< BLE role of the connection, see @ref BLE_GAP_ROLES. */
ble_conn_bw_t conn_bw; /**< Bandwidth configuration parameters. */
} ble_common_opt_conn_bw_t;
/**@brief Option structure for common options. */
typedef union
{
ble_common_opt_conn_bw_t conn_bw; /**< Parameters for the connection bandwidth option. */
ble_common_opt_pa_lna_t pa_lna; /**< Parameters for controlling PA and LNA pin toggling. */
} ble_common_opt_t;
/**@brief Common BLE Option type, wrapping the module specific options. */
typedef union
{
ble_common_opt_t common_opt; /**< COMMON options, opt_id in @ref BLE_COMMON_OPTS series. */
ble_gap_opt_t gap_opt; /**< GAP option, opt_id in @ref BLE_GAP_OPTS series. */
} ble_opt_t;
/**
* @brief BLE bandwidth count parameters
*
* These parameters are used to configure the memory pools allocated within the SoftDevice for application packets
* (both transmission and reception) for all connections.
*
* @note The sum of all three counts must add up to the sum of @ref ble_gap_enable_params_t::central_conn_count and
* @ref ble_gap_enable_params_t::periph_conn_count in @ref ble_gap_enable_params_t.
*/
typedef struct {
uint8_t high_count; /**< Total number of high bandwidth TX or RX memory pools available to the application at runtime for all active connections. */
uint8_t mid_count; /**< Total number of medium bandwidth TX or RX memory pools available to the application at runtime for all active connections. */
uint8_t low_count; /**< Total number of low bandwidth TX or RX memory pools available to the application at runtime for all active connections. */
} ble_conn_bw_count_t;
/**
* @brief BLE bandwidth global memory pool configuration parameters
*
* These configuration parameters are used to set the amount of memory dedicated to application packets for
* all connections. The application should specify the most demanding configuration for the intended use.
*
* Please refer to the SoftDevice Specification for more information on bandwidth configuration.
*
* @note Each connection created at runtime requires both a TX and an RX memory pool. By the use of these configuration
* parameters, the application can decide the size and total number of the global memory pools that will be later
* available for connection creation.
*
* @mscs
* @mmsc{@ref BLE_COMMON_CONF_BW}
* @endmscs
*
*/
typedef struct {
ble_conn_bw_count_t tx_counts; /**< Global memory pool configuration for transmission.*/
ble_conn_bw_count_t rx_counts; /**< Global memory pool configuration for reception.*/
} ble_conn_bw_counts_t;
/**
* @brief BLE Common Initialization parameters.
*
* @note If @ref p_conn_bw_counts is NULL the SoftDevice will assume default bandwidth configuration for all connections.
* To fit a custom bandwidth configuration requirement, the application developer may have to specify a custom memory
* pool configuration here. See @ref ble_common_opt_conn_bw_t for bandwidth configuration of individual connections.
* Please refer to the SoftDevice Specification for more information on bandwidth configuration.
*/
typedef struct
{
uint16_t vs_uuid_count; /**< Maximum number of 128-bit, Vendor Specific UUID bases to allocate. */
ble_conn_bw_counts_t *p_conn_bw_counts; /**< Bandwidth configuration parameters or NULL for defaults. */
} ble_common_enable_params_t;
/**
* @brief BLE Initialization parameters.
*/
typedef struct
{
ble_common_enable_params_t common_enable_params; /**< Common init parameters @ref ble_common_enable_params_t. */
ble_gap_enable_params_t gap_enable_params; /**< GAP init parameters @ref ble_gap_enable_params_t. */
ble_gatts_enable_params_t gatts_enable_params; /**< GATTS init parameters @ref ble_gatts_enable_params_t. */
} ble_enable_params_t;
/** @} */
/** @addtogroup BLE_COMMON_FUNCTIONS Functions
* @{ */
/**@brief Enable the BLE stack
*
* @param[in, out] p_ble_enable_params Pointer to ble_enable_params_t
* @param[in, out] p_app_ram_base Pointer to a variable containing the start address of the application RAM region
* (APP_RAM_BASE). On return, this will contain the minimum start address of the application RAM region required by the
* SoftDevice for this configuration. Calling @ref sd_ble_enable() with *p_app_ram_base set to 0 can be used during
* development to find out how much memory a specific configuration will need.
*
* @note The memory requirement for a specific configuration will not increase between SoftDevices with the same major
* version number.
*
* @note At runtime the IC's RAM is split into 2 regions: The SoftDevice RAM region is located between 0x20000000 and
* APP_RAM_BASE-1 and the application's RAM region is located between APP_RAM_BASE and the start of the call stack.
*
* @details This call initializes the BLE stack, no other BLE related function can be called before this one.
*
* @mscs
* @mmsc{@ref BLE_COMMON_ENABLE}
* @endmscs
*
* @retval ::NRF_SUCCESS The BLE stack has been initialized successfully.
* @retval ::NRF_ERROR_INVALID_STATE The BLE stack had already been initialized and cannot be reinitialized.
* @retval ::NRF_ERROR_INVALID_ADDR Invalid or not sufficiently aligned pointer supplied.
* @retval ::NRF_ERROR_INVALID_LENGTH The specified Attribute Table size is either too small or not a multiple of 4.
* The minimum acceptable size is defined by @ref BLE_GATTS_ATTR_TAB_SIZE_MIN.
* @retval ::NRF_ERROR_INVALID_PARAM Incorrectly configured VS UUID count or connection count parameters.
* @retval ::NRF_ERROR_NO_MEM The amount of memory assigned to the SoftDevice by *p_app_ram_base is not
* large enough to fit this configuration's memory requirement. Check *p_app_ram_base
* and set the start address of the application RAM region accordingly.
* @retval ::NRF_ERROR_CONN_COUNT The requested number of connections exceeds the maximum supported by the SoftDevice.
* Please refer to the SoftDevice Specification for more information on role configuration.
*/
SVCALL(SD_BLE_ENABLE, uint32_t, sd_ble_enable(ble_enable_params_t * p_ble_enable_params, uint32_t * p_app_ram_base));
/**@brief Get an event from the pending events queue.
*
* @param[out] p_dest Pointer to buffer to be filled in with an event, or NULL to retrieve the event length.
* This buffer <b>must be 4-byte aligned in memory</b>.
* @param[in, out] p_len Pointer the length of the buffer, on return it is filled with the event length.
*
* @details This call allows the application to pull a BLE event from the BLE stack. The application is signaled that
* an event is available from the BLE stack by the triggering of the SD_EVT_IRQn interrupt.
* The application is free to choose whether to call this function from thread mode (main context) or directly from the
* Interrupt Service Routine that maps to SD_EVT_IRQn. In any case however, and because the BLE stack runs at a higher
* priority than the application, this function should be called in a loop (until @ref NRF_ERROR_NOT_FOUND is returned)
* every time SD_EVT_IRQn is raised to ensure that all available events are pulled from the BLE stack. Failure to do so
* could potentially leave events in the internal queue without the application being aware of this fact. Sizing the
* p_dest buffer is equally important, since the application needs to provide all the memory necessary for the event to
* be copied into application memory. If the buffer provided is not large enough to fit the entire contents of the event,
* @ref NRF_ERROR_DATA_SIZE will be returned and the application can then call again with a larger buffer size.
* Please note that because of the variable length nature of some events, sizeof(ble_evt_t) will not always be large
* enough to fit certain events, and so it is the application's responsibility to provide an amount of memory large
* enough so that the relevant event is copied in full. The application may "peek" the event length by providing p_dest
* as a NULL pointer and inspecting the value of *p_len upon return:
*
* \code
* uint16_t len;
* errcode = sd_ble_evt_get(NULL, &len);
* \endcode
*
* @note The pointer supplied must be aligned to the extend defined by @ref BLE_EVTS_PTR_ALIGNMENT
*
* @mscs
* @mmsc{@ref BLE_COMMON_IRQ_EVT_MSC}
* @mmsc{@ref BLE_COMMON_THREAD_EVT_MSC}
* @endmscs
*
* @retval ::NRF_SUCCESS Event pulled and stored into the supplied buffer.
* @retval ::NRF_ERROR_INVALID_ADDR Invalid or not sufficiently aligned pointer supplied.
* @retval ::NRF_ERROR_NOT_FOUND No events ready to be pulled.
* @retval ::NRF_ERROR_DATA_SIZE Event ready but could not fit into the supplied buffer.
*/
SVCALL(SD_BLE_EVT_GET, uint32_t, sd_ble_evt_get(uint8_t *p_dest, uint16_t *p_len));
/**@brief Get the total number of available guaranteed application transmission packets for a particular connection.
*
* @details This call allows the application to obtain the total number of guaranteed application transmission packets
* available for a connection. Please note that this does not return the number of free packets, but rather the total
* amount of them for that particular connection. The application has two options to handle transmitting application packets:
* - Use a simple arithmetic calculation: after connection creation time the application should use this function to
* find out the total amount of guaranteed packets available to it and store it in a variable.
* Every time a packet is successfully queued for a transmission on this connection using any of the exposed functions in
* this BLE API, the application should decrement that variable. Conversely, whenever a @ref BLE_EVT_TX_COMPLETE event
* with the conn_handle matching the particular connection is received by the application, it should retrieve the count
* field in such event and add that number to the same variable storing the number of available guaranteed packets. This
* mechanism allows the application to be aware at any time of the number of guaranteed application packets available for
* each of the active connections, and therefore it can know with certainty whether it is possible to send more data or
* it has to wait for a @ref BLE_EVT_TX_COMPLETE event before it proceeds.
* The application can still pursue transmissions when the number of guaranteed application packets available is smaller
* than or equal to zero, but successful queuing of the tranmsission is not guaranteed.
* - Choose to simply not keep track of available packets at all, and instead handle the @ref BLE_ERROR_NO_TX_PACKETS error
* by queueing the packet to be transmitted and try again as soon as a @ref BLE_EVT_TX_COMPLETE event arrives.
*
* The API functions that <b>may</b> consume an application packet depending on the parameters supplied to them can be found below:
* - @ref sd_ble_gattc_write (write without response only)
* - @ref sd_ble_gatts_hvx (notifications only)
* - @ref sd_ble_l2cap_tx (all packets)
*
* @param[in] conn_handle Connection handle.
* @param[out] p_count Pointer to a uint8_t which will contain the number of application transmission packets upon
* successful return.
* @mscs
* @mmsc{@ref BLE_COMMON_APP_BUFF_MSC}
* @endmscs
*
* @retval ::NRF_SUCCESS Number of application transmission packets retrieved successfully.
* @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
* @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
*/
SVCALL(SD_BLE_TX_PACKET_COUNT_GET, uint32_t, sd_ble_tx_packet_count_get(uint16_t conn_handle, uint8_t *p_count));
/**@brief Add a Vendor Specific UUID.
*
* @details This call enables the application to add a vendor specific UUID to the BLE stack's table, for later use
* all other modules and APIs. This then allows the application to use the shorter, 24-bit @ref ble_uuid_t format
* when dealing with both 16-bit and 128-bit UUIDs without having to check for lengths and having split code paths.
* The way that this is accomplished is by extending the grouping mechanism that the Bluetooth SIG standard base
* UUID uses for all other 128-bit UUIDs. The type field in the @ref ble_uuid_t structure is an index (relative to
* @ref BLE_UUID_TYPE_VENDOR_BEGIN) to the table populated by multiple calls to this function, and the uuid field
* in the same structure contains the 2 bytes at indices 12 and 13. The number of possible 128-bit UUIDs available to
* the application is therefore the number of Vendor Specific UUIDs added with the help of this function times 65536,
* although restricted to modifying bytes 12 and 13 for each of the entries in the supplied array.
*
* @note Bytes 12 and 13 of the provided UUID will not be used internally, since those are always replaced by
* the 16-bit uuid field in @ref ble_uuid_t.
*
* @note If a UUID is already present in the BLE stack's internal table, the corresponding index will be returned in
* p_uuid_type along with an NRF_SUCCESS error code.
*
* @param[in] p_vs_uuid Pointer to a 16-octet (128-bit) little endian Vendor Specific UUID disregarding
* bytes 12 and 13.
* @param[out] p_uuid_type Pointer to a uint8_t where the type field in @ref ble_uuid_t corresponding to this UUID will be stored.
*
* @retval ::NRF_SUCCESS Successfully added the Vendor Specific UUID.
* @retval ::NRF_ERROR_INVALID_ADDR If p_vs_uuid or p_uuid_type is NULL or invalid.
* @retval ::NRF_ERROR_NO_MEM If there are no more free slots for VS UUIDs.
*/
SVCALL(SD_BLE_UUID_VS_ADD, uint32_t, sd_ble_uuid_vs_add(ble_uuid128_t const *p_vs_uuid, uint8_t *p_uuid_type));
/** @brief Decode little endian raw UUID bytes (16-bit or 128-bit) into a 24 bit @ref ble_uuid_t structure.
*
* @details The raw UUID bytes excluding bytes 12 and 13 (i.e. bytes 0-11 and 14-15) of p_uuid_le are compared
* to the corresponding ones in each entry of the table of vendor specific UUIDs populated with @ref sd_ble_uuid_vs_add
* to look for a match. If there is such a match, bytes 12 and 13 are returned as p_uuid->uuid and the index
* relative to @ref BLE_UUID_TYPE_VENDOR_BEGIN as p_uuid->type.
*
* @note If the UUID length supplied is 2, then the type set by this call will always be @ref BLE_UUID_TYPE_BLE.
*
* @param[in] uuid_le_len Length in bytes of the buffer pointed to by p_uuid_le (must be 2 or 16 bytes).
* @param[in] p_uuid_le Pointer pointing to little endian raw UUID bytes.
* @param[out] p_uuid Pointer to a @ref ble_uuid_t structure to be filled in.
*
* @retval ::NRF_SUCCESS Successfully decoded into the @ref ble_uuid_t structure.
* @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
* @retval ::NRF_ERROR_INVALID_LENGTH Invalid UUID length.
* @retval ::NRF_ERROR_NOT_FOUND For a 128-bit UUID, no match in the populated table of UUIDs.
*/
SVCALL(SD_BLE_UUID_DECODE, uint32_t, sd_ble_uuid_decode(uint8_t uuid_le_len, uint8_t const *p_uuid_le, ble_uuid_t *p_uuid));
/** @brief Encode a @ref ble_uuid_t structure into little endian raw UUID bytes (16-bit or 128-bit).
*
* @note The pointer to the destination buffer p_uuid_le may be NULL, in which case only the validity and size of p_uuid is computed.
*
* @param[in] p_uuid Pointer to a @ref ble_uuid_t structure that will be encoded into bytes.
* @param[out] p_uuid_le_len Pointer to a uint8_t that will be filled with the encoded length (2 or 16 bytes).
* @param[out] p_uuid_le Pointer to a buffer where the little endian raw UUID bytes (2 or 16) will be stored.
*
* @retval ::NRF_SUCCESS Successfully encoded into the buffer.
* @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
* @retval ::NRF_ERROR_INVALID_PARAM Invalid UUID type.
*/
SVCALL(SD_BLE_UUID_ENCODE, uint32_t, sd_ble_uuid_encode(ble_uuid_t const *p_uuid, uint8_t *p_uuid_le_len, uint8_t *p_uuid_le));
/**@brief Get Version Information.
*
* @details This call allows the application to get the BLE stack version information.
*
* @param[out] p_version Pointer to a ble_version_t structure to be filled in.
*
* @retval ::NRF_SUCCESS Version information stored successfully.
* @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
* @retval ::NRF_ERROR_BUSY The BLE stack is busy (typically doing a locally-initiated disconnection procedure).
*/
SVCALL(SD_BLE_VERSION_GET, uint32_t, sd_ble_version_get(ble_version_t *p_version));
/**@brief Provide a user memory block.
*
* @note This call can only be used as a response to a @ref BLE_EVT_USER_MEM_REQUEST event issued to the application.
*
* @param[in] conn_handle Connection handle.
* @param[in,out] p_block Pointer to a user memory block structure.
*
* @mscs
* @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_PEER_CANCEL_MSC}
* @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_AUTH_MSC}
* @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_NOAUTH_MSC}
* @mmsc{@ref BLE_GATTS_QUEUED_WRITE_BUF_AUTH_MSC}
* @mmsc{@ref BLE_GATTS_QUEUED_WRITE_BUF_NOAUTH_MSC}
* @mmsc{@ref BLE_GATTS_QUEUED_WRITE_QUEUE_FULL_MSC}
* @endmscs
*
* @retval ::NRF_SUCCESS Successfully queued a response to the peer.
* @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
* @retval ::NRF_ERROR_INVALID_STATE Invalid Connection state or no execute write request pending.
* @retval ::NRF_ERROR_BUSY The BLE stack is busy. Retry at later time.
*/
SVCALL(SD_BLE_USER_MEM_REPLY, uint32_t, sd_ble_user_mem_reply(uint16_t conn_handle, ble_user_mem_block_t const *p_block));
/**@brief Set a BLE option.
*
* @details This call allows the application to set the value of an option.
*
* @mscs
* @mmsc{@ref BLE_GAP_PERIPH_BONDING_STATIC_PK_MSC}
* @mmsc{@ref BLE_COMMON_CONF_BW}
* @endmscs
*
* @param[in] opt_id Option ID, see @ref BLE_COMMON_OPTS and @ref BLE_GAP_OPTS.
* @param[in] p_opt Pointer to a ble_opt_t structure containing the option value.
*
* @retval ::NRF_SUCCESS Option set successfully.
* @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
* @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
* @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, check parameter limits and constraints.
* @retval ::NRF_ERROR_INVALID_STATE Unable to set the parameter at this time.
* @retval ::NRF_ERROR_BUSY The BLE stack is busy or the previous procedure has not completed.
*/
SVCALL(SD_BLE_OPT_SET, uint32_t, sd_ble_opt_set(uint32_t opt_id, ble_opt_t const *p_opt));
/**@brief Get a BLE option.
*
* @details This call allows the application to retrieve the value of an option.
*
* @param[in] opt_id Option ID, see @ref BLE_COMMON_OPTS and @ref BLE_GAP_OPTS.
* @param[out] p_opt Pointer to a ble_opt_t structure to be filled in.
*
* @retval ::NRF_SUCCESS Option retrieved successfully.
* @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
* @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
* @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, check parameter limits and constraints.
* @retval ::NRF_ERROR_INVALID_STATE Unable to retrieve the parameter at this time.
* @retval ::NRF_ERROR_BUSY The BLE stack is busy or the previous procedure has not completed.
* @retval ::NRF_ERROR_NOT_SUPPORTED This option is not supported.
*
*/
SVCALL(SD_BLE_OPT_GET, uint32_t, sd_ble_opt_get(uint32_t opt_id, ble_opt_t *p_opt));
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* NRF_BLE_H__ */
/**
@}
@}
*/

View File

@ -0,0 +1,93 @@
/*
* Copyright (c) 2000 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/**
@addtogroup BLE_COMMON
@{
@addtogroup nrf_error
@{
@ingroup BLE_COMMON
@}
@defgroup ble_err General error codes
@{
@brief General error code definitions for the BLE API.
@ingroup BLE_COMMON
*/
#ifndef NRF_BLE_ERR_H__
#define NRF_BLE_ERR_H__
#include "nrf_error.h"
#ifdef __cplusplus
extern "C" {
#endif
/* @defgroup BLE_ERRORS Error Codes
* @{ */
#define BLE_ERROR_NOT_ENABLED (NRF_ERROR_STK_BASE_NUM+0x001) /**< @ref sd_ble_enable has not been called. */
#define BLE_ERROR_INVALID_CONN_HANDLE (NRF_ERROR_STK_BASE_NUM+0x002) /**< Invalid connection handle. */
#define BLE_ERROR_INVALID_ATTR_HANDLE (NRF_ERROR_STK_BASE_NUM+0x003) /**< Invalid attribute handle. */
#define BLE_ERROR_NO_TX_PACKETS (NRF_ERROR_STK_BASE_NUM+0x004) /**< Not enough application packets available on this connection. */
#define BLE_ERROR_INVALID_ROLE (NRF_ERROR_STK_BASE_NUM+0x005) /**< Invalid role. */
/** @} */
/** @defgroup BLE_ERROR_SUBRANGES Module specific error code subranges
* @brief Assignment of subranges for module specific error codes.
* @note For specific error codes, see ble_<module>.h or ble_error_<module>.h.
* @{ */
#define NRF_L2CAP_ERR_BASE (NRF_ERROR_STK_BASE_NUM+0x100) /**< L2CAP specific errors. */
#define NRF_GAP_ERR_BASE (NRF_ERROR_STK_BASE_NUM+0x200) /**< GAP specific errors. */
#define NRF_GATTC_ERR_BASE (NRF_ERROR_STK_BASE_NUM+0x300) /**< GATT client specific errors. */
#define NRF_GATTS_ERR_BASE (NRF_ERROR_STK_BASE_NUM+0x400) /**< GATT server specific errors. */
/** @} */
#ifdef __cplusplus
}
#endif
#endif
/**
@}
@}
*/

View File

@ -0,0 +1,215 @@
/*
* Copyright (c) 2000 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/**
@addtogroup BLE_GATT Generic Attribute Profile (GATT) Common
@{
@brief Common definitions and prototypes for the GATT interfaces.
*/
#ifndef NRF_BLE_GATT_H__
#define NRF_BLE_GATT_H__
#include "nrf_ble_types.h"
#include "nrf_ble_ranges.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @addtogroup BLE_GATT_DEFINES Defines
* @{ */
/** @brief Default MTU size. */
#define GATT_MTU_SIZE_DEFAULT 23
/** @brief Only the default MTU size of 23 is currently supported. */
#define GATT_RX_MTU 23
/**@brief Invalid Attribute Handle. */
#define BLE_GATT_HANDLE_INVALID 0x0000
/**@brief First Attribute Handle. */
#define BLE_GATT_HANDLE_START 0x0001
/**@brief Last Attribute Handle. */
#define BLE_GATT_HANDLE_END 0xFFFF
/** @defgroup BLE_GATT_TIMEOUT_SOURCES GATT Timeout sources
* @{ */
#define BLE_GATT_TIMEOUT_SRC_PROTOCOL 0x00 /**< ATT Protocol timeout. */
/** @} */
/** @defgroup BLE_GATT_WRITE_OPS GATT Write operations
* @{ */
#define BLE_GATT_OP_INVALID 0x00 /**< Invalid Operation. */
#define BLE_GATT_OP_WRITE_REQ 0x01 /**< Write Request. */
#define BLE_GATT_OP_WRITE_CMD 0x02 /**< Write Command. */
#define BLE_GATT_OP_SIGN_WRITE_CMD 0x03 /**< Signed Write Command. */
#define BLE_GATT_OP_PREP_WRITE_REQ 0x04 /**< Prepare Write Request. */
#define BLE_GATT_OP_EXEC_WRITE_REQ 0x05 /**< Execute Write Request. */
/** @} */
/** @defgroup BLE_GATT_EXEC_WRITE_FLAGS GATT Execute Write flags
* @{ */
#define BLE_GATT_EXEC_WRITE_FLAG_PREPARED_CANCEL 0x00
#define BLE_GATT_EXEC_WRITE_FLAG_PREPARED_WRITE 0x01
/** @} */
/** @defgroup BLE_GATT_HVX_TYPES GATT Handle Value operations
* @{ */
#define BLE_GATT_HVX_INVALID 0x00 /**< Invalid Operation. */
#define BLE_GATT_HVX_NOTIFICATION 0x01 /**< Handle Value Notification. */
#define BLE_GATT_HVX_INDICATION 0x02 /**< Handle Value Indication. */
/** @} */
/** @defgroup BLE_GATT_STATUS_CODES GATT Status Codes
* @{ */
#define BLE_GATT_STATUS_SUCCESS 0x0000 /**< Success. */
#define BLE_GATT_STATUS_UNKNOWN 0x0001 /**< Unknown or not applicable status. */
#define BLE_GATT_STATUS_ATTERR_INVALID 0x0100 /**< ATT Error: Invalid Error Code. */
#define BLE_GATT_STATUS_ATTERR_INVALID_HANDLE 0x0101 /**< ATT Error: Invalid Attribute Handle. */
#define BLE_GATT_STATUS_ATTERR_READ_NOT_PERMITTED 0x0102 /**< ATT Error: Read not permitted. */
#define BLE_GATT_STATUS_ATTERR_WRITE_NOT_PERMITTED 0x0103 /**< ATT Error: Write not permitted. */
#define BLE_GATT_STATUS_ATTERR_INVALID_PDU 0x0104 /**< ATT Error: Used in ATT as Invalid PDU. */
#define BLE_GATT_STATUS_ATTERR_INSUF_AUTHENTICATION 0x0105 /**< ATT Error: Authenticated link required. */
#define BLE_GATT_STATUS_ATTERR_REQUEST_NOT_SUPPORTED 0x0106 /**< ATT Error: Used in ATT as Request Not Supported. */
#define BLE_GATT_STATUS_ATTERR_INVALID_OFFSET 0x0107 /**< ATT Error: Offset specified was past the end of the attribute. */
#define BLE_GATT_STATUS_ATTERR_INSUF_AUTHORIZATION 0x0108 /**< ATT Error: Used in ATT as Insufficient Authorisation. */
#define BLE_GATT_STATUS_ATTERR_PREPARE_QUEUE_FULL 0x0109 /**< ATT Error: Used in ATT as Prepare Queue Full. */
#define BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_FOUND 0x010A /**< ATT Error: Used in ATT as Attribute not found. */
#define BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_LONG 0x010B /**< ATT Error: Attribute cannot be read or written using read/write blob requests. */
#define BLE_GATT_STATUS_ATTERR_INSUF_ENC_KEY_SIZE 0x010C /**< ATT Error: Encryption key size used is insufficient. */
#define BLE_GATT_STATUS_ATTERR_INVALID_ATT_VAL_LENGTH 0x010D /**< ATT Error: Invalid value size. */
#define BLE_GATT_STATUS_ATTERR_UNLIKELY_ERROR 0x010E /**< ATT Error: Very unlikely error. */
#define BLE_GATT_STATUS_ATTERR_INSUF_ENCRYPTION 0x010F /**< ATT Error: Encrypted link required. */
#define BLE_GATT_STATUS_ATTERR_UNSUPPORTED_GROUP_TYPE 0x0110 /**< ATT Error: Attribute type is not a supported grouping attribute. */
#define BLE_GATT_STATUS_ATTERR_INSUF_RESOURCES 0x0111 /**< ATT Error: Encrypted link required. */
#define BLE_GATT_STATUS_ATTERR_RFU_RANGE1_BEGIN 0x0112 /**< ATT Error: Reserved for Future Use range #1 begin. */
#define BLE_GATT_STATUS_ATTERR_RFU_RANGE1_END 0x017F /**< ATT Error: Reserved for Future Use range #1 end. */
#define BLE_GATT_STATUS_ATTERR_APP_BEGIN 0x0180 /**< ATT Error: Application range begin. */
#define BLE_GATT_STATUS_ATTERR_APP_END 0x019F /**< ATT Error: Application range end. */
#define BLE_GATT_STATUS_ATTERR_RFU_RANGE2_BEGIN 0x01A0 /**< ATT Error: Reserved for Future Use range #2 begin. */
#define BLE_GATT_STATUS_ATTERR_RFU_RANGE2_END 0x01DF /**< ATT Error: Reserved for Future Use range #2 end. */
#define BLE_GATT_STATUS_ATTERR_RFU_RANGE3_BEGIN 0x01E0 /**< ATT Error: Reserved for Future Use range #3 begin. */
#define BLE_GATT_STATUS_ATTERR_RFU_RANGE3_END 0x01FC /**< ATT Error: Reserved for Future Use range #3 end. */
#define BLE_GATT_STATUS_ATTERR_CPS_CCCD_CONFIG_ERROR 0x01FD /**< ATT Common Profile and Service Error: Client Characteristic Configuration Descriptor improperly configured. */
#define BLE_GATT_STATUS_ATTERR_CPS_PROC_ALR_IN_PROG 0x01FE /**< ATT Common Profile and Service Error: Procedure Already in Progress. */
#define BLE_GATT_STATUS_ATTERR_CPS_OUT_OF_RANGE 0x01FF /**< ATT Common Profile and Service Error: Out Of Range. */
/** @} */
/** @defgroup BLE_GATT_CPF_FORMATS Characteristic Presentation Formats
* @note Found at http://developer.bluetooth.org/gatt/descriptors/Pages/DescriptorViewer.aspx?u=org.bluetooth.descriptor.gatt.characteristic_presentation_format.xml
* @{ */
#define BLE_GATT_CPF_FORMAT_RFU 0x00 /**< Reserved For Future Use. */
#define BLE_GATT_CPF_FORMAT_BOOLEAN 0x01 /**< Boolean. */
#define BLE_GATT_CPF_FORMAT_2BIT 0x02 /**< Unsigned 2-bit integer. */
#define BLE_GATT_CPF_FORMAT_NIBBLE 0x03 /**< Unsigned 4-bit integer. */
#define BLE_GATT_CPF_FORMAT_UINT8 0x04 /**< Unsigned 8-bit integer. */
#define BLE_GATT_CPF_FORMAT_UINT12 0x05 /**< Unsigned 12-bit integer. */
#define BLE_GATT_CPF_FORMAT_UINT16 0x06 /**< Unsigned 16-bit integer. */
#define BLE_GATT_CPF_FORMAT_UINT24 0x07 /**< Unsigned 24-bit integer. */
#define BLE_GATT_CPF_FORMAT_UINT32 0x08 /**< Unsigned 32-bit integer. */
#define BLE_GATT_CPF_FORMAT_UINT48 0x09 /**< Unsigned 48-bit integer. */
#define BLE_GATT_CPF_FORMAT_UINT64 0x0A /**< Unsigned 64-bit integer. */
#define BLE_GATT_CPF_FORMAT_UINT128 0x0B /**< Unsigned 128-bit integer. */
#define BLE_GATT_CPF_FORMAT_SINT8 0x0C /**< Signed 2-bit integer. */
#define BLE_GATT_CPF_FORMAT_SINT12 0x0D /**< Signed 12-bit integer. */
#define BLE_GATT_CPF_FORMAT_SINT16 0x0E /**< Signed 16-bit integer. */
#define BLE_GATT_CPF_FORMAT_SINT24 0x0F /**< Signed 24-bit integer. */
#define BLE_GATT_CPF_FORMAT_SINT32 0x10 /**< Signed 32-bit integer. */
#define BLE_GATT_CPF_FORMAT_SINT48 0x11 /**< Signed 48-bit integer. */
#define BLE_GATT_CPF_FORMAT_SINT64 0x12 /**< Signed 64-bit integer. */
#define BLE_GATT_CPF_FORMAT_SINT128 0x13 /**< Signed 128-bit integer. */
#define BLE_GATT_CPF_FORMAT_FLOAT32 0x14 /**< IEEE-754 32-bit floating point. */
#define BLE_GATT_CPF_FORMAT_FLOAT64 0x15 /**< IEEE-754 64-bit floating point. */
#define BLE_GATT_CPF_FORMAT_SFLOAT 0x16 /**< IEEE-11073 16-bit SFLOAT. */
#define BLE_GATT_CPF_FORMAT_FLOAT 0x17 /**< IEEE-11073 32-bit FLOAT. */
#define BLE_GATT_CPF_FORMAT_DUINT16 0x18 /**< IEEE-20601 format. */
#define BLE_GATT_CPF_FORMAT_UTF8S 0x19 /**< UTF-8 string. */
#define BLE_GATT_CPF_FORMAT_UTF16S 0x1A /**< UTF-16 string. */
#define BLE_GATT_CPF_FORMAT_STRUCT 0x1B /**< Opaque Structure. */
/** @} */
/** @defgroup BLE_GATT_CPF_NAMESPACES GATT Bluetooth Namespaces
* @{
*/
#define BLE_GATT_CPF_NAMESPACE_BTSIG 0x01 /**< Bluetooth SIG defined Namespace. */
#define BLE_GATT_CPF_NAMESPACE_DESCRIPTION_UNKNOWN 0x0000 /**< Namespace Description Unknown. */
/** @} */
/** @} */
/** @addtogroup BLE_GATT_STRUCTURES Structures
* @{ */
/**@brief GATT Characteristic Properties. */
typedef struct
{
/* Standard properties */
uint8_t broadcast :1; /**< Broadcasting of the value permitted. */
uint8_t read :1; /**< Reading the value permitted. */
uint8_t write_wo_resp :1; /**< Writing the value with Write Command permitted. */
uint8_t write :1; /**< Writing the value with Write Request permitted. */
uint8_t notify :1; /**< Notications of the value permitted. */
uint8_t indicate :1; /**< Indications of the value permitted. */
uint8_t auth_signed_wr :1; /**< Writing the value with Signed Write Command permitted. */
} ble_gatt_char_props_t;
/**@brief GATT Characteristic Extended Properties. */
typedef struct
{
/* Extended properties */
uint8_t reliable_wr :1; /**< Writing the value with Queued Write operations permitted. */
uint8_t wr_aux :1; /**< Writing the Characteristic User Description descriptor permitted. */
} ble_gatt_char_ext_props_t;
#ifdef __cplusplus
}
#endif
#endif // NRF_BLE_GATT_H__
/** @} */
/**
@}
@}
*/

View File

@ -0,0 +1,572 @@
/*
* Copyright (c) 2000 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/**
@addtogroup BLE_GATTC Generic Attribute Profile (GATT) Client
@{
@brief Definitions and prototypes for the GATT Client interface.
*/
#ifndef NRF_BLE_GATTC_H__
#define NRF_BLE_GATTC_H__
#include "nrf_ble_gatt.h"
#include "nrf_ble_types.h"
#include "nrf_ble_ranges.h"
#include "nrf_svc.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @addtogroup BLE_GATTC_ENUMERATIONS Enumerations
* @{ */
/**@brief GATTC API SVC numbers. */
enum BLE_GATTC_SVCS
{
SD_BLE_GATTC_PRIMARY_SERVICES_DISCOVER = BLE_GATTC_SVC_BASE, /**< Primary Service Discovery. */
SD_BLE_GATTC_RELATIONSHIPS_DISCOVER, /**< Relationship Discovery. */
SD_BLE_GATTC_CHARACTERISTICS_DISCOVER, /**< Characteristic Discovery. */
SD_BLE_GATTC_DESCRIPTORS_DISCOVER, /**< Characteristic Descriptor Discovery. */
SD_BLE_GATTC_ATTR_INFO_DISCOVER, /**< Attribute Information Discovery. */
SD_BLE_GATTC_CHAR_VALUE_BY_UUID_READ, /**< Read Characteristic Value by UUID. */
SD_BLE_GATTC_READ, /**< Generic read. */
SD_BLE_GATTC_CHAR_VALUES_READ, /**< Read multiple Characteristic Values. */
SD_BLE_GATTC_WRITE, /**< Generic write. */
SD_BLE_GATTC_HV_CONFIRM, /**< Handle Value Confirmation. */
};
/**
* @brief GATT Client Event IDs.
*/
enum BLE_GATTC_EVTS
{
BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP = BLE_GATTC_EVT_BASE, /**< Primary Service Discovery Response event. \n See @ref ble_gattc_evt_prim_srvc_disc_rsp_t. */
BLE_GATTC_EVT_REL_DISC_RSP, /**< Relationship Discovery Response event. \n See @ref ble_gattc_evt_rel_disc_rsp_t. */
BLE_GATTC_EVT_CHAR_DISC_RSP, /**< Characteristic Discovery Response event. \n See @ref ble_gattc_evt_char_disc_rsp_t. */
BLE_GATTC_EVT_DESC_DISC_RSP, /**< Descriptor Discovery Response event. \n See @ref ble_gattc_evt_desc_disc_rsp_t. */
BLE_GATTC_EVT_ATTR_INFO_DISC_RSP, /**< Attribute Information Response event. \n See @ref ble_gattc_evt_attr_info_disc_rsp_t. */
BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP, /**< Read By UUID Response event. \n See @ref ble_gattc_evt_char_val_by_uuid_read_rsp_t. */
BLE_GATTC_EVT_READ_RSP, /**< Read Response event. \n See @ref ble_gattc_evt_read_rsp_t. */
BLE_GATTC_EVT_CHAR_VALS_READ_RSP, /**< Read multiple Response event. \n See @ref ble_gattc_evt_char_vals_read_rsp_t. */
BLE_GATTC_EVT_WRITE_RSP, /**< Write Response event. \n See @ref ble_gattc_evt_write_rsp_t. */
BLE_GATTC_EVT_HVX, /**< Handle Value Notification or Indication event. \n Confirm indication with @ref sd_ble_gattc_hv_confirm. \n See @ref ble_gattc_evt_hvx_t. */
BLE_GATTC_EVT_TIMEOUT /**< Timeout event. \n See @ref ble_gattc_evt_timeout_t. */
};
/** @} */
/** @addtogroup BLE_GATTC_DEFINES Defines
* @{ */
/** @defgroup BLE_ERRORS_GATTC SVC return values specific to GATTC
* @{ */
#define BLE_ERROR_GATTC_PROC_NOT_PERMITTED (NRF_GATTC_ERR_BASE + 0x000) /**< Procedure not Permitted. */
/** @} */
/** @defgroup BLE_GATTC_ATTR_INFO_FORMAT Attribute Information Formats
* @{ */
#define BLE_GATTC_ATTR_INFO_FORMAT_16BIT 1 /**< 16-bit Attribute Information Format. */
#define BLE_GATTC_ATTR_INFO_FORMAT_128BIT 2 /**< 128-bit Attribute Information Format. */
/** @} */
/** @} */
/** @addtogroup BLE_GATTC_STRUCTURES Structures
* @{ */
/**@brief Operation Handle Range. */
typedef struct
{
uint16_t start_handle; /**< Start Handle. */
uint16_t end_handle; /**< End Handle. */
} ble_gattc_handle_range_t;
/**@brief GATT service. */
typedef struct
{
ble_uuid_t uuid; /**< Service UUID. */
ble_gattc_handle_range_t handle_range; /**< Service Handle Range. */
} ble_gattc_service_t;
/**@brief GATT include. */
typedef struct
{
uint16_t handle; /**< Include Handle. */
ble_gattc_service_t included_srvc; /**< Handle of the included service. */
} ble_gattc_include_t;
/**@brief GATT characteristic. */
typedef struct
{
ble_uuid_t uuid; /**< Characteristic UUID. */
ble_gatt_char_props_t char_props; /**< Characteristic Properties. */
uint8_t char_ext_props : 1; /**< Extended properties present. */
uint16_t handle_decl; /**< Handle of the Characteristic Declaration. */
uint16_t handle_value; /**< Handle of the Characteristic Value. */
} ble_gattc_char_t;
/**@brief GATT descriptor. */
typedef struct
{
uint16_t handle; /**< Descriptor Handle. */
ble_uuid_t uuid; /**< Descriptor UUID. */
} ble_gattc_desc_t;
/**@brief Write Parameters. */
typedef struct
{
uint8_t write_op; /**< Write Operation to be performed, see @ref BLE_GATT_WRITE_OPS. */
uint8_t flags; /**< Flags, see @ref BLE_GATT_EXEC_WRITE_FLAGS. */
uint16_t handle; /**< Handle to the attribute to be written. */
uint16_t offset; /**< Offset in bytes. @note For WRITE_CMD and WRITE_REQ, offset must be 0. */
uint16_t len; /**< Length of data in bytes. */
uint8_t *p_value; /**< Pointer to the value data. */
} ble_gattc_write_params_t;
/**@brief Attribute Information. */
typedef struct
{
uint16_t handle; /**< Attribute handle. */
union {
ble_uuid_t uuid16; /**< 16-bit Attribute UUID. */
ble_uuid128_t uuid128; /**< 128-bit Attribute UUID. */
} info;
} ble_gattc_attr_info_t;
/**@brief Event structure for @ref BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP. */
typedef struct
{
uint16_t count; /**< Service count. */
ble_gattc_service_t services[1]; /**< Service data. @note This is a variable length array. The size of 1 indicated is only a placeholder for compilation.
See @ref sd_ble_evt_get for more information on how to use event structures with variable length array members. */
} ble_gattc_evt_prim_srvc_disc_rsp_t;
/**@brief Event structure for @ref BLE_GATTC_EVT_REL_DISC_RSP. */
typedef struct
{
uint16_t count; /**< Include count. */
ble_gattc_include_t includes[1]; /**< Include data. @note This is a variable length array. The size of 1 indicated is only a placeholder for compilation.
See @ref sd_ble_evt_get for more information on how to use event structures with variable length array members. */
} ble_gattc_evt_rel_disc_rsp_t;
/**@brief Event structure for @ref BLE_GATTC_EVT_CHAR_DISC_RSP. */
typedef struct
{
uint16_t count; /**< Characteristic count. */
ble_gattc_char_t chars[1]; /**< Characteristic data. @note This is a variable length array. The size of 1 indicated is only a placeholder for compilation.
See @ref sd_ble_evt_get for more information on how to use event structures with variable length array members. */
} ble_gattc_evt_char_disc_rsp_t;
/**@brief Event structure for @ref BLE_GATTC_EVT_DESC_DISC_RSP. */
typedef struct
{
uint16_t count; /**< Descriptor count. */
ble_gattc_desc_t descs[1]; /**< Descriptor data. @note This is a variable length array. The size of 1 indicated is only a placeholder for compilation.
See @ref sd_ble_evt_get for more information on how to use event structures with variable length array members. */
} ble_gattc_evt_desc_disc_rsp_t;
/**@brief Event structure for @ref BLE_GATTC_EVT_ATTR_INFO_DISC_RSP. */
typedef struct
{
uint16_t count; /**< Attribute count. */
uint8_t format; /**< Attribute information format, see @ref BLE_GATTC_ATTR_INFO_FORMAT. */
ble_gattc_attr_info_t attr_info[1]; /**< Attribute information. @note This is a variable length array. The size of 1 indicated is only a placeholder for compilation.
See @ref sd_ble_evt_get for more information on how to use event structures with variable length array members. */
} ble_gattc_evt_attr_info_disc_rsp_t;
/**@brief GATT read by UUID handle value pair. */
typedef struct
{
uint16_t handle; /**< Attribute Handle. */
uint8_t *p_value; /**< Pointer to value, variable length (length available as value_len in @ref ble_gattc_evt_char_val_by_uuid_read_rsp_t).
Please note that this pointer is absolute to the memory provided by the user when retrieving the event,
so it will effectively point to a location inside the handle_value array. */
} ble_gattc_handle_value_t;
/**@brief Event structure for @ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP. */
typedef struct
{
uint16_t count; /**< Handle-Value Pair Count. */
uint16_t value_len; /**< Length of the value in Handle-Value(s) list. */
ble_gattc_handle_value_t handle_value[1]; /**< Handle-Value(s) list. @note This is a variable length array. The size of 1 indicated is only a placeholder for compilation.
See @ref sd_ble_evt_get for more information on how to use event structures with variable length array members. */
} ble_gattc_evt_char_val_by_uuid_read_rsp_t;
/**@brief Event structure for @ref BLE_GATTC_EVT_READ_RSP. */
typedef struct
{
uint16_t handle; /**< Attribute Handle. */
uint16_t offset; /**< Offset of the attribute data. */
uint16_t len; /**< Attribute data length. */
uint8_t data[1]; /**< Attribute data. @note This is a variable length array. The size of 1 indicated is only a placeholder for compilation.
See @ref sd_ble_evt_get for more information on how to use event structures with variable length array members. */
} ble_gattc_evt_read_rsp_t;
/**@brief Event structure for @ref BLE_GATTC_EVT_CHAR_VALS_READ_RSP. */
typedef struct
{
uint16_t len; /**< Concatenated Attribute values length. */
uint8_t values[1]; /**< Attribute values. @note This is a variable length array. The size of 1 indicated is only a placeholder for compilation.
See @ref sd_ble_evt_get for more information on how to use event structures with variable length array members. */
} ble_gattc_evt_char_vals_read_rsp_t;
/**@brief Event structure for @ref BLE_GATTC_EVT_WRITE_RSP. */
typedef struct
{
uint16_t handle; /**< Attribute Handle. */
uint8_t write_op; /**< Type of write operation, see @ref BLE_GATT_WRITE_OPS. */
uint16_t offset; /**< Data offset. */
uint16_t len; /**< Data length. */
uint8_t data[1]; /**< Data. @note This is a variable length array. The size of 1 indicated is only a placeholder for compilation.
See @ref sd_ble_evt_get for more information on how to use event structures with variable length array members. */
} ble_gattc_evt_write_rsp_t;
/**@brief Event structure for @ref BLE_GATTC_EVT_HVX. */
typedef struct
{
uint16_t handle; /**< Handle to which the HVx operation applies. */
uint8_t type; /**< Indication or Notification, see @ref BLE_GATT_HVX_TYPES. */
uint16_t len; /**< Attribute data length. */
uint8_t data[1]; /**< Attribute data. @note This is a variable length array. The size of 1 indicated is only a placeholder for compilation.
See @ref sd_ble_evt_get for more information on how to use event structures with variable length array members. */
} ble_gattc_evt_hvx_t;
/**@brief Event structure for @ref BLE_GATTC_EVT_TIMEOUT. */
typedef struct
{
uint8_t src; /**< Timeout source, see @ref BLE_GATT_TIMEOUT_SOURCES. */
} ble_gattc_evt_timeout_t;
/**@brief GATTC event structure. */
typedef struct
{
uint16_t conn_handle; /**< Connection Handle on which event occured. */
uint16_t gatt_status; /**< GATT status code for the operation, see @ref BLE_GATT_STATUS_CODES. */
uint16_t error_handle; /**< In case of error: The handle causing the error. In all other cases @ref BLE_GATT_HANDLE_INVALID. */
union
{
ble_gattc_evt_prim_srvc_disc_rsp_t prim_srvc_disc_rsp; /**< Primary Service Discovery Response Event Parameters. */
ble_gattc_evt_rel_disc_rsp_t rel_disc_rsp; /**< Relationship Discovery Response Event Parameters. */
ble_gattc_evt_char_disc_rsp_t char_disc_rsp; /**< Characteristic Discovery Response Event Parameters. */
ble_gattc_evt_desc_disc_rsp_t desc_disc_rsp; /**< Descriptor Discovery Response Event Parameters. */
ble_gattc_evt_char_val_by_uuid_read_rsp_t char_val_by_uuid_read_rsp; /**< Characteristic Value Read by UUID Response Event Parameters. */
ble_gattc_evt_read_rsp_t read_rsp; /**< Read Response Event Parameters. */
ble_gattc_evt_char_vals_read_rsp_t char_vals_read_rsp; /**< Characteristic Values Read Response Event Parameters. */
ble_gattc_evt_write_rsp_t write_rsp; /**< Write Response Event Parameters. */
ble_gattc_evt_hvx_t hvx; /**< Handle Value Notification/Indication Event Parameters. */
ble_gattc_evt_timeout_t timeout; /**< Timeout Event Parameters. */
ble_gattc_evt_attr_info_disc_rsp_t attr_info_disc_rsp; /**< Attribute Information Discovery Event Parameters. */
} params; /**< Event Parameters. @note Only valid if @ref gatt_status == @ref BLE_GATT_STATUS_SUCCESS. */
} ble_gattc_evt_t;
/** @} */
/** @addtogroup BLE_GATTC_FUNCTIONS Functions
* @{ */
/**@brief Initiate or continue a GATT Primary Service Discovery procedure.
*
* @details This function initiates or resumes a Primary Service discovery procedure, starting from the supplied handle.
* If the last service has not been reached, this function must be called again with an updated start handle value to continue the search.
*
* @note If any of the discovered services have 128-bit UUIDs which are not present in the table provided to ble_vs_uuids_assign, a UUID structure with
* type @ref BLE_UUID_TYPE_UNKNOWN will be received in the corresponding event.
*
* @events
* @event{@ref BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP}
* @endevents
*
* @mscs
* @mmsc{@ref BLE_GATTC_PRIM_SRVC_DISC_MSC}
* @endmscs
*
* @param[in] conn_handle The connection handle identifying the connection to perform this procedure on.
* @param[in] start_handle Handle to start searching from.
* @param[in] p_srvc_uuid Pointer to the service UUID to be found. If it is NULL, all primary services will be returned.
*
* @retval ::NRF_SUCCESS Successfully started or resumed the Primary Service Discovery procedure.
* @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
* @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State.
* @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
* @retval ::NRF_ERROR_BUSY Client procedure already in progress.
*/
SVCALL(SD_BLE_GATTC_PRIMARY_SERVICES_DISCOVER, uint32_t, sd_ble_gattc_primary_services_discover(uint16_t conn_handle, uint16_t start_handle, ble_uuid_t const *p_srvc_uuid));
/**@brief Initiate or continue a GATT Relationship Discovery procedure.
*
* @details This function initiates or resumes the Find Included Services sub-procedure. If the last included service has not been reached,
* this must be called again with an updated handle range to continue the search.
*
* @events
* @event{@ref BLE_GATTC_EVT_REL_DISC_RSP}
* @endevents
*
* @mscs
* @mmsc{@ref BLE_GATTC_REL_DISC_MSC}
* @endmscs
*
* @param[in] conn_handle The connection handle identifying the connection to perform this procedure on.
* @param[in] p_handle_range A pointer to the range of handles of the Service to perform this procedure on.
*
* @retval ::NRF_SUCCESS Successfully started or resumed the Relationship Discovery procedure.
* @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
* @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State.
* @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
* @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
* @retval ::NRF_ERROR_BUSY Client procedure already in progress.
*/
SVCALL(SD_BLE_GATTC_RELATIONSHIPS_DISCOVER, uint32_t, sd_ble_gattc_relationships_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range));
/**@brief Initiate or continue a GATT Characteristic Discovery procedure.
*
* @details This function initiates or resumes a Characteristic discovery procedure. If the last Characteristic has not been reached,
* this must be called again with an updated handle range to continue the discovery.
*
* @note If any of the discovered characteristics have 128-bit UUIDs which are not present in the table provided to ble_vs_uuids_assign, a UUID structure with
* type @ref BLE_UUID_TYPE_UNKNOWN will be received in the corresponding event.
*
* @events
* @event{@ref BLE_GATTC_EVT_CHAR_DISC_RSP}
* @endevents
*
* @mscs
* @mmsc{@ref BLE_GATTC_CHAR_DISC_MSC}
* @endmscs
*
* @param[in] conn_handle The connection handle identifying the connection to perform this procedure on.
* @param[in] p_handle_range A pointer to the range of handles of the Service to perform this procedure on.
*
* @retval ::NRF_SUCCESS Successfully started or resumed the Characteristic Discovery procedure.
* @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
* @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State.
* @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
* @retval ::NRF_ERROR_BUSY Client procedure already in progress.
*/
SVCALL(SD_BLE_GATTC_CHARACTERISTICS_DISCOVER, uint32_t, sd_ble_gattc_characteristics_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range));
/**@brief Initiate or continue a GATT Characteristic Descriptor Discovery procedure.
*
* @details This function initiates or resumes a Characteristic Descriptor discovery procedure. If the last Descriptor has not been reached,
* this must be called again with an updated handle range to continue the discovery.
*
* @events
* @event{BLE_GATTC_EVT_DESC_DISC_RSP}
* @endevents
*
* @mscs
* @mmsc{@ref BLE_GATTC_DESC_DISC_MSC}
* @endmscs
*
* @param[in] conn_handle The connection handle identifying the connection to perform this procedure on.
* @param[in] p_handle_range A pointer to the range of handles of the Characteristic to perform this procedure on.
*
* @retval ::NRF_SUCCESS Successfully started or resumed the Descriptor Discovery procedure.
* @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
* @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State.
* @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
* @retval ::NRF_ERROR_BUSY Client procedure already in progress.
*/
SVCALL(SD_BLE_GATTC_DESCRIPTORS_DISCOVER, uint32_t, sd_ble_gattc_descriptors_discover(uint16_t conn_handle, ble_gattc_handle_range_t const *p_handle_range));
/**@brief Initiate or continue a GATT Read using Characteristic UUID procedure.
*
* @details This function initiates or resumes a Read using Characteristic UUID procedure. If the last Characteristic has not been reached,
* this must be called again with an updated handle range to continue the discovery.
*
* @events
* @event{BLE_GATTC_EVT_DESC_DISC_RSP}
* @endevents
*
* @mscs
* @mmsc{@ref BLE_GATTC_READ_UUID_MSC}
* @endmscs
*
* @param[in] conn_handle The connection handle identifying the connection to perform this procedure on.
* @param[in] p_uuid Pointer to a Characteristic value UUID to read.
* @param[in] p_handle_range A pointer to the range of handles to perform this procedure on.
*
* @retval ::NRF_SUCCESS Successfully started or resumed the Read using Characteristic UUID procedure.
* @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
* @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State.
* @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
* @retval ::NRF_ERROR_BUSY Client procedure already in progress.
*/
SVCALL(SD_BLE_GATTC_CHAR_VALUE_BY_UUID_READ, uint32_t, sd_ble_gattc_char_value_by_uuid_read(uint16_t conn_handle, ble_uuid_t const *p_uuid, ble_gattc_handle_range_t const *p_handle_range));
/**@brief Initiate or continue a GATT Read (Long) Characteristic or Descriptor procedure.
*
* @details This function initiates or resumes a GATT Read (Long) Characteristic or Descriptor procedure. If the Characteristic or Descriptor
* to be read is longer than ATT_MTU - 1, this function must be called multiple times with appropriate offset to read the
* complete value.
*
* @events
* @event{@ref BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP}
* @endevents
*
* @mscs
* @mmsc{@ref BLE_GATTC_VALUE_READ_MSC}
* @endmscs
*
* @param[in] conn_handle The connection handle identifying the connection to perform this procedure on.
* @param[in] handle The handle of the attribute to be read.
* @param[in] offset Offset into the attribute value to be read.
*
* @retval ::NRF_SUCCESS Successfully started or resumed the Read (Long) procedure.
* @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
* @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State.
* @retval ::NRF_ERROR_BUSY Client procedure already in progress.
*/
SVCALL(SD_BLE_GATTC_READ, uint32_t, sd_ble_gattc_read(uint16_t conn_handle, uint16_t handle, uint16_t offset));
/**@brief Initiate a GATT Read Multiple Characteristic Values procedure.
*
* @details This function initiates a GATT Read Multiple Characteristic Values procedure.
*
* @events
* @event{@ref BLE_GATTC_EVT_CHAR_VALS_READ_RSP}
* @endevents
*
* @mscs
* @mmsc{@ref BLE_GATTC_READ_MULT_MSC}
* @endmscs
*
* @param[in] conn_handle The connection handle identifying the connection to perform this procedure on.
* @param[in] p_handles A pointer to the handle(s) of the attribute(s) to be read.
* @param[in] handle_count The number of handles in p_handles.
*
* @retval ::NRF_SUCCESS Successfully started the Read Multiple Characteristic Values procedure.
* @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
* @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State.
* @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
* @retval ::NRF_ERROR_BUSY Client procedure already in progress.
*/
SVCALL(SD_BLE_GATTC_CHAR_VALUES_READ, uint32_t, sd_ble_gattc_char_values_read(uint16_t conn_handle, uint16_t const *p_handles, uint16_t handle_count));
/**@brief Perform a Write (Characteristic Value or Descriptor, with or without response, signed or not, long or reliable) procedure.
*
* @details This function can perform all write procedures described in GATT.
*
* @note It is important to note that a write without response will <b>consume an application buffer</b>, and will therefore
* generate a @ref BLE_EVT_TX_COMPLETE event when the packet has been transmitted. A write (with response) on the other hand will use the
* standard client internal buffer and thus will only generate a @ref BLE_GATTC_EVT_WRITE_RSP event as soon as the write response
* has been received from the peer. Please see the documentation of @ref sd_ble_tx_packet_count_get for more details.
*
* @events
* @event{@ref BLE_GATTC_EVT_WRITE_RSP, Generated when using write request or queued writes.}
* @endevents
*
* @mscs
* @mmsc{@ref BLE_GATTC_VALUE_WRITE_MSC}
* @mmsc{@ref BLE_GATTC_VALUE_LONG_WRITE_MSC}
* @mmsc{@ref BLE_GATTC_VALUE_RELIABLE_WRITE_MSC}
* @mmsc{@ref BLE_COMMON_APP_BUFF_MSC}
* @endmscs
*
* @param[in] conn_handle The connection handle identifying the connection to perform this procedure on.
* @param[in] p_write_params A pointer to a write parameters structure.
*
* @retval ::NRF_SUCCESS Successfully started the Write procedure.
* @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
* @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State.
* @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
* @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
* @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied.
* @retval ::NRF_ERROR_BUSY Procedure already in progress.
* @retval ::BLE_ERROR_NO_TX_PACKETS No available application packets for this connection.
*/
SVCALL(SD_BLE_GATTC_WRITE, uint32_t, sd_ble_gattc_write(uint16_t conn_handle, ble_gattc_write_params_t const *p_write_params));
/**@brief Send a Handle Value Confirmation to the GATT Server.
*
* @mscs
* @mmsc{@ref BLE_GATTC_HVI_MSC}
* @endmscs
*
* @param[in] conn_handle The connection handle identifying the connection to perform this procedure on.
* @param[in] handle The handle of the attribute in the indication.
*
* @retval ::NRF_SUCCESS Successfully queued the Handle Value Confirmation for transmission.
* @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
* @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State or no Indication pending to be confirmed.
* @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle.
*/
SVCALL(SD_BLE_GATTC_HV_CONFIRM, uint32_t, sd_ble_gattc_hv_confirm(uint16_t conn_handle, uint16_t handle));
/**@brief Discovers information about a range of attributes on a GATT server.
*
* @events
* @event{@ref BLE_GATTC_EVT_ATTR_INFO_DISC_RSP, Generated when information about a range of attributes has been received.}
* @endevents
*
* @param[in] conn_handle The connection handle identifying the connection to perform this procedure on.
* @param[in] p_handle_range The range of handles to request information about.
*
* @retval ::NRF_SUCCESS Successfully started an attribute information discovery procedure.
* @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle.
* @retval ::NRF_ERROR_INVALID_STATE Invalid connection state
* @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
* @retval ::NRF_ERROR_BUSY Client procedure already in progress.
*/
SVCALL(SD_BLE_GATTC_ATTR_INFO_DISCOVER, uint32_t, sd_ble_gattc_attr_info_discover(uint16_t conn_handle, ble_gattc_handle_range_t const * p_handle_range));
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* NRF_BLE_GATTC_H__ */
/**
@}
@}
*/

View File

@ -0,0 +1,725 @@
/*
* Copyright (c) 2000 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/**
@addtogroup BLE_GATTS Generic Attribute Profile (GATT) Server
@{
@brief Definitions and prototypes for the GATTS interface.
*/
#ifndef NRF_BLE_GATTS_H__
#define NRF_BLE_GATTS_H__
#include "nrf_ble_types.h"
#include "nrf_ble_ranges.h"
#include "nrf_ble_l2cap.h"
#include "nrf_ble_gap.h"
#include "nrf_ble_gatt.h"
#include "nrf_svc.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @addtogroup BLE_GATTS_ENUMERATIONS Enumerations
* @{ */
/**
* @brief GATTS API SVC numbers.
*/
enum BLE_GATTS_SVCS
{
SD_BLE_GATTS_SERVICE_ADD = BLE_GATTS_SVC_BASE, /**< Add a service. */
SD_BLE_GATTS_INCLUDE_ADD, /**< Add an included service. */
SD_BLE_GATTS_CHARACTERISTIC_ADD, /**< Add a characteristic. */
SD_BLE_GATTS_DESCRIPTOR_ADD, /**< Add a generic attribute. */
SD_BLE_GATTS_VALUE_SET, /**< Set an attribute value. */
SD_BLE_GATTS_VALUE_GET, /**< Get an attribute value. */
SD_BLE_GATTS_HVX, /**< Handle Value Notification or Indication. */
SD_BLE_GATTS_SERVICE_CHANGED, /**< Perform a Service Changed Indication to one or more peers. */
SD_BLE_GATTS_RW_AUTHORIZE_REPLY, /**< Reply to an authorization request for a read or write operation on one or more attributes. */
SD_BLE_GATTS_SYS_ATTR_SET, /**< Set the persistent system attributes for a connection. */
SD_BLE_GATTS_SYS_ATTR_GET, /**< Retrieve the persistent system attributes. */
SD_BLE_GATTS_INITIAL_USER_HANDLE_GET, /**< Retrieve the first valid user handle. */
SD_BLE_GATTS_ATTR_GET /**< Retrieve the UUID and/or metadata of an attribute. */
};
/**
* @brief GATT Server Event IDs.
*/
enum BLE_GATTS_EVTS
{
BLE_GATTS_EVT_WRITE = BLE_GATTS_EVT_BASE, /**< Write operation performed. \n See @ref ble_gatts_evt_write_t. */
BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST, /**< Read/Write Authorization request. \n Reply with @ref sd_ble_gatts_rw_authorize_reply. \n See @ref ble_gatts_evt_rw_authorize_request_t. */
BLE_GATTS_EVT_SYS_ATTR_MISSING, /**< A persistent system attribute access is pending. \n Respond with @ref sd_ble_gatts_sys_attr_set. \n See @ref ble_gatts_evt_sys_attr_missing_t. */
BLE_GATTS_EVT_HVC, /**< Handle Value Confirmation. \n See @ref ble_gatts_evt_hvc_t. */
BLE_GATTS_EVT_SC_CONFIRM, /**< Service Changed Confirmation. No additional event structure applies. */
BLE_GATTS_EVT_TIMEOUT /**< Peer failed to resonpond to an ATT request in time. \n See @ref ble_gatts_evt_timeout_t. */
};
/** @} */
/** @addtogroup BLE_GATTS_DEFINES Defines
* @{ */
/** @defgroup BLE_ERRORS_GATTS SVC return values specific to GATTS
* @{ */
#define BLE_ERROR_GATTS_INVALID_ATTR_TYPE (NRF_GATTS_ERR_BASE + 0x000) /**< Invalid attribute type. */
#define BLE_ERROR_GATTS_SYS_ATTR_MISSING (NRF_GATTS_ERR_BASE + 0x001) /**< System Attributes missing. */
/** @} */
/** @defgroup BLE_GATTS_ATTR_LENS_MAX Maximum attribute lengths
* @{ */
#define BLE_GATTS_FIX_ATTR_LEN_MAX (510) /**< Maximum length for fixed length Attribute Values. */
#define BLE_GATTS_VAR_ATTR_LEN_MAX (512) /**< Maximum length for variable length Attribute Values. */
/** @} */
/** @defgroup BLE_GATTS_SRVC_TYPES GATT Server Service Types
* @{ */
#define BLE_GATTS_SRVC_TYPE_INVALID 0x00 /**< Invalid Service Type. */
#define BLE_GATTS_SRVC_TYPE_PRIMARY 0x01 /**< Primary Service. */
#define BLE_GATTS_SRVC_TYPE_SECONDARY 0x02 /**< Secondary Type. */
/** @} */
/** @defgroup BLE_GATTS_ATTR_TYPES GATT Server Attribute Types
* @{ */
#define BLE_GATTS_ATTR_TYPE_INVALID 0x00 /**< Invalid Attribute Type. */
#define BLE_GATTS_ATTR_TYPE_PRIM_SRVC_DECL 0x01 /**< Primary Service Declaration. */
#define BLE_GATTS_ATTR_TYPE_SEC_SRVC_DECL 0x02 /**< Secondary Service Declaration. */
#define BLE_GATTS_ATTR_TYPE_INC_DECL 0x03 /**< Include Declaration. */
#define BLE_GATTS_ATTR_TYPE_CHAR_DECL 0x04 /**< Characteristic Declaration. */
#define BLE_GATTS_ATTR_TYPE_CHAR_VAL 0x05 /**< Characteristic Value. */
#define BLE_GATTS_ATTR_TYPE_DESC 0x06 /**< Descriptor. */
#define BLE_GATTS_ATTR_TYPE_OTHER 0x07 /**< Other, non-GATT specific type. */
/** @} */
/** @defgroup BLE_GATTS_OPS GATT Server Operations
* @{ */
#define BLE_GATTS_OP_INVALID 0x00 /**< Invalid Operation. */
#define BLE_GATTS_OP_WRITE_REQ 0x01 /**< Write Request. */
#define BLE_GATTS_OP_WRITE_CMD 0x02 /**< Write Command. */
#define BLE_GATTS_OP_SIGN_WRITE_CMD 0x03 /**< Signed Write Command. */
#define BLE_GATTS_OP_PREP_WRITE_REQ 0x04 /**< Prepare Write Request. */
#define BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL 0x05 /**< Execute Write Request: Cancel all prepared writes. */
#define BLE_GATTS_OP_EXEC_WRITE_REQ_NOW 0x06 /**< Execute Write Request: Immediately execute all prepared writes. */
/** @} */
/** @defgroup BLE_GATTS_VLOCS GATT Value Locations
* @{ */
#define BLE_GATTS_VLOC_INVALID 0x00 /**< Invalid Location. */
#define BLE_GATTS_VLOC_STACK 0x01 /**< Attribute Value is located in stack memory, no user memory is required. */
#define BLE_GATTS_VLOC_USER 0x02 /**< Attribute Value is located in user memory. This requires the user to maintain a valid buffer through the lifetime of the attribute, since the stack
will read and write directly to the memory using the pointer provided in the APIs. There are no alignment requirements for the buffer. */
/** @} */
/** @defgroup BLE_GATTS_AUTHORIZE_TYPES GATT Server Authorization Types
* @{ */
#define BLE_GATTS_AUTHORIZE_TYPE_INVALID 0x00 /**< Invalid Type. */
#define BLE_GATTS_AUTHORIZE_TYPE_READ 0x01 /**< Authorize a Read Operation. */
#define BLE_GATTS_AUTHORIZE_TYPE_WRITE 0x02 /**< Authorize a Write Request Operation. */
/** @} */
/** @defgroup BLE_GATTS_SYS_ATTR_FLAGS System Attribute Flags
* @{ */
#define BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS (1 << 0) /**< Restrict system attributes to system services only. */
#define BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS (1 << 1) /**< Restrict system attributes to user services only. */
/** @} */
/** @defgroup BLE_GATTS_ATTR_TAB_SIZE Attribute Table size
* @{
*/
#define BLE_GATTS_ATTR_TAB_SIZE_MIN 216 /**< Minimum Attribute Table size */
#define BLE_GATTS_ATTR_TAB_SIZE_DEFAULT 0x0000 /**< Default Attribute Table size (0x580 bytes for this version of the SoftDevice). */
/** @} */
/** @} */
/** @addtogroup BLE_GATTS_STRUCTURES Structures
* @{ */
/**
* @brief BLE GATTS initialization parameters.
*/
typedef struct
{
uint8_t service_changed:1; /**< Include the Service Changed characteristic in the Attribute Table. */
uint32_t attr_tab_size; /**< Attribute Table size in bytes. The size must be a multiple of 4. @ref BLE_GATTS_ATTR_TAB_SIZE_DEFAULT is used to set the default size. */
} ble_gatts_enable_params_t;
/**@brief Attribute metadata. */
typedef struct
{
ble_gap_conn_sec_mode_t read_perm; /**< Read permissions. */
ble_gap_conn_sec_mode_t write_perm; /**< Write permissions. */
uint8_t vlen :1; /**< Variable length attribute. */
uint8_t vloc :2; /**< Value location, see @ref BLE_GATTS_VLOCS.*/
uint8_t rd_auth :1; /**< Read authorization and value will be requested from the application on every read operation. */
uint8_t wr_auth :1; /**< Write authorization will be requested from the application on every Write Request operation (but not Write Command). */
} ble_gatts_attr_md_t;
/**@brief GATT Attribute. */
typedef struct
{
ble_uuid_t *p_uuid; /**< Pointer to the attribute UUID. */
ble_gatts_attr_md_t *p_attr_md; /**< Pointer to the attribute metadata structure. */
uint16_t init_len; /**< Initial attribute value length in bytes. */
uint16_t init_offs; /**< Initial attribute value offset in bytes. If different from zero, the first init_offs bytes of the attribute value will be left uninitialized. */
uint16_t max_len; /**< Maximum attribute value length in bytes, see @ref BLE_GATTS_ATTR_LENS_MAX for maximum values. */
uint8_t* p_value; /**< Pointer to the attribute data. Please note that if the @ref BLE_GATTS_VLOC_USER value location is selected in the attribute metadata, this will have to point to a buffer
that remains valid through the lifetime of the attribute. This excludes usage of automatic variables that may go out of scope or any other temporary location.
The stack may access that memory directly without the application's knowledge. For writable characteristics, this value must not be a location in flash memory.*/
} ble_gatts_attr_t;
/**@brief GATT Attribute Value. */
typedef struct
{
uint16_t len; /**< Length in bytes to be written or read. Length in bytes written or read after successful return.*/
uint16_t offset; /**< Attribute value offset. */
uint8_t *p_value; /**< Pointer to where value is stored or will be stored.
If value is stored in user memory, only the attribute length is updated when p_value == NULL.
Set to NULL when reading to obtain the complete length of the attribute value */
} ble_gatts_value_t;
/**@brief GATT Characteristic Presentation Format. */
typedef struct
{
uint8_t format; /**< Format of the value, see @ref BLE_GATT_CPF_FORMATS. */
int8_t exponent; /**< Exponent for integer data types. */
uint16_t unit; /**< Unit from Bluetooth Assigned Numbers. */
uint8_t name_space; /**< Namespace from Bluetooth Assigned Numbers, see @ref BLE_GATT_CPF_NAMESPACES. */
uint16_t desc; /**< Namespace description from Bluetooth Assigned Numbers, see @ref BLE_GATT_CPF_NAMESPACES. */
} ble_gatts_char_pf_t;
/**@brief GATT Characteristic metadata. */
typedef struct
{
ble_gatt_char_props_t char_props; /**< Characteristic Properties. */
ble_gatt_char_ext_props_t char_ext_props; /**< Characteristic Extended Properties. */
uint8_t *p_char_user_desc; /**< Pointer to a UTF-8 encoded string (non-NULL terminated), NULL if the descriptor is not required. */
uint16_t char_user_desc_max_size; /**< The maximum size in bytes of the user description descriptor. */
uint16_t char_user_desc_size; /**< The size of the user description, must be smaller or equal to char_user_desc_max_size. */
ble_gatts_char_pf_t* p_char_pf; /**< Pointer to a presentation format structure or NULL if the CPF descriptor is not required. */
ble_gatts_attr_md_t* p_user_desc_md; /**< Attribute metadata for the User Description descriptor, or NULL for default values. */
ble_gatts_attr_md_t* p_cccd_md; /**< Attribute metadata for the Client Characteristic Configuration Descriptor, or NULL for default values. */
ble_gatts_attr_md_t* p_sccd_md; /**< Attribute metadata for the Server Characteristic Configuration Descriptor, or NULL for default values. */
} ble_gatts_char_md_t;
/**@brief GATT Characteristic Definition Handles. */
typedef struct
{
uint16_t value_handle; /**< Handle to the characteristic value. */
uint16_t user_desc_handle; /**< Handle to the User Description descriptor, or @ref BLE_GATT_HANDLE_INVALID if not present. */
uint16_t cccd_handle; /**< Handle to the Client Characteristic Configuration Descriptor, or @ref BLE_GATT_HANDLE_INVALID if not present. */
uint16_t sccd_handle; /**< Handle to the Server Characteristic Configuration Descriptor, or @ref BLE_GATT_HANDLE_INVALID if not present. */
} ble_gatts_char_handles_t;
/**@brief GATT HVx parameters. */
typedef struct
{
uint16_t handle; /**< Characteristic Value Handle. */
uint8_t type; /**< Indication or Notification, see @ref BLE_GATT_HVX_TYPES. */
uint16_t offset; /**< Offset within the attribute value. */
uint16_t *p_len; /**< Length in bytes to be written, length in bytes written after successful return. */
uint8_t *p_data; /**< Actual data content, use NULL to use the current attribute value. */
} ble_gatts_hvx_params_t;
/**@brief GATT Authorization parameters. */
typedef struct
{
uint16_t gatt_status; /**< GATT status code for the operation, see @ref BLE_GATT_STATUS_CODES. */
uint8_t update : 1; /**< If set, data supplied in p_data will be used to update the attribute value.
Please note that for @ref BLE_GATTS_OP_WRITE_REQ operations this bit must always be set,
as the data to be written needs to be stored and later provided by the application. */
uint16_t offset; /**< Offset of the attribute value being updated. */
uint16_t len; /**< Length in bytes of the value in p_data pointer, see @ref BLE_GATTS_ATTR_LENS_MAX. */
const uint8_t *p_data; /**< Pointer to new value used to update the attribute value. */
} ble_gatts_authorize_params_t;
/**@brief GATT Read or Write Authorize Reply parameters. */
typedef struct
{
uint8_t type; /**< Type of authorize operation, see @ref BLE_GATTS_AUTHORIZE_TYPES. */
union {
ble_gatts_authorize_params_t read; /**< Read authorization parameters. */
ble_gatts_authorize_params_t write; /**< Write authorization parameters. */
} params; /**< Reply Parameters. */
} ble_gatts_rw_authorize_reply_params_t;
/**@brief Event structure for @ref BLE_GATTS_EVT_WRITE. */
typedef struct
{
uint16_t handle; /**< Attribute Handle. */
ble_uuid_t uuid; /**< Attribute UUID. */
uint8_t op; /**< Type of write operation, see @ref BLE_GATTS_OPS. */
uint8_t auth_required; /**< Writing operation deferred due to authorization requirement. Application may use @ref sd_ble_gatts_value_set to finalise the writing operation. */
uint16_t offset; /**< Offset for the write operation. */
uint16_t len; /**< Length of the received data. */
uint8_t data[1]; /**< Received data. @note This is a variable length array. The size of 1 indicated is only a placeholder for compilation.
See @ref sd_ble_evt_get for more information on how to use event structures with variable length array members. */
} ble_gatts_evt_write_t;
/**@brief Event substructure for authorized read requests, see @ref ble_gatts_evt_rw_authorize_request_t. */
typedef struct
{
uint16_t handle; /**< Attribute Handle. */
ble_uuid_t uuid; /**< Attribute UUID. */
uint16_t offset; /**< Offset for the read operation. */
} ble_gatts_evt_read_t;
/**@brief Event structure for @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST. */
typedef struct
{
uint8_t type; /**< Type of authorize operation, see @ref BLE_GATTS_AUTHORIZE_TYPES. */
union {
ble_gatts_evt_read_t read; /**< Attribute Read Parameters. */
ble_gatts_evt_write_t write; /**< Attribute Write Parameters. */
} request; /**< Request Parameters. */
} ble_gatts_evt_rw_authorize_request_t;
/**@brief Event structure for @ref BLE_GATTS_EVT_SYS_ATTR_MISSING. */
typedef struct
{
uint8_t hint; /**< Hint (currently unused). */
} ble_gatts_evt_sys_attr_missing_t;
/**@brief Event structure for @ref BLE_GATTS_EVT_HVC. */
typedef struct
{
uint16_t handle; /**< Attribute Handle. */
} ble_gatts_evt_hvc_t;
/**@brief Event structure for @ref BLE_GATTS_EVT_TIMEOUT. */
typedef struct
{
uint8_t src; /**< Timeout source, see @ref BLE_GATT_TIMEOUT_SOURCES. */
} ble_gatts_evt_timeout_t;
/**@brief GATT Server event callback event structure. */
typedef struct
{
uint16_t conn_handle; /**< Connection Handle on which the event occurred. */
union
{
ble_gatts_evt_write_t write; /**< Write Event Parameters. */
ble_gatts_evt_rw_authorize_request_t authorize_request; /**< Read or Write Authorize Request Parameters. */
ble_gatts_evt_sys_attr_missing_t sys_attr_missing; /**< System attributes missing. */
ble_gatts_evt_hvc_t hvc; /**< Handle Value Confirmation Event Parameters. */
ble_gatts_evt_timeout_t timeout; /**< Timeout Event. */
} params; /**< Event Parameters. */
} ble_gatts_evt_t;
/** @} */
/** @addtogroup BLE_GATTS_FUNCTIONS Functions
* @{ */
/**@brief Add a service declaration to the Attribute Table.
*
* @note Secondary Services are only relevant in the context of the entity that references them, it is therefore forbidden to
* add a secondary service declaration that is not referenced by another service later in the Attribute Table.
*
* @mscs
* @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC}
* @endmscs
*
* @param[in] type Toggles between primary and secondary services, see @ref BLE_GATTS_SRVC_TYPES.
* @param[in] p_uuid Pointer to service UUID.
* @param[out] p_handle Pointer to a 16-bit word where the assigned handle will be stored.
*
* @retval ::NRF_SUCCESS Successfully added a service declaration.
* @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
* @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, Vendor Specific UUIDs need to be present in the table.
* @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, certain UUIDs are reserved for the stack.
* @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation.
*/
SVCALL(SD_BLE_GATTS_SERVICE_ADD, uint32_t, sd_ble_gatts_service_add(uint8_t type, ble_uuid_t const *p_uuid, uint16_t *p_handle));
/**@brief Add an include declaration to the Attribute Table.
*
* @note It is currently only possible to add an include declaration to the last added service (i.e. only sequential population is supported at this time).
*
* @note The included service must already be present in the Attribute Table prior to this call.
*
* @mscs
* @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC}
* @endmscs
*
* @param[in] service_handle Handle of the service where the included service is to be placed, if @ref BLE_GATT_HANDLE_INVALID is used, it will be placed sequentially.
* @param[in] inc_srvc_handle Handle of the included service.
* @param[out] p_include_handle Pointer to a 16-bit word where the assigned handle will be stored.
*
* @retval ::NRF_SUCCESS Successfully added an include declaration.
* @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
* @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, handle values need to match previously added services.
* @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation.
* @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, self inclusions are not allowed.
* @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation.
* @retval ::NRF_ERROR_NOT_FOUND Attribute not found.
*/
SVCALL(SD_BLE_GATTS_INCLUDE_ADD, uint32_t, sd_ble_gatts_include_add(uint16_t service_handle, uint16_t inc_srvc_handle, uint16_t *p_include_handle));
/**@brief Add a characteristic declaration, a characteristic value declaration and optional characteristic descriptor declarations to the Attribute Table.
*
* @note It is currently only possible to add a characteristic to the last added service (i.e. only sequential population is supported at this time).
*
* @note Several restrictions apply to the parameters, such as matching permissions between the user description descriptor and the writeable auxiliaries bits,
* readable (no security) and writeable (selectable) CCCDs and SCCDs and valid presentation format values.
*
* @note If no metadata is provided for the optional descriptors, their permissions will be derived from the characteristic permissions.
*
* @mscs
* @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC}
* @endmscs
*
* @param[in] service_handle Handle of the service where the characteristic is to be placed, if @ref BLE_GATT_HANDLE_INVALID is used, it will be placed sequentially.
* @param[in] p_char_md Characteristic metadata.
* @param[in] p_attr_char_value Pointer to the attribute structure corresponding to the characteristic value.
* @param[out] p_handles Pointer to the structure where the assigned handles will be stored.
*
* @retval ::NRF_SUCCESS Successfully added a characteristic.
* @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
* @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, service handle, Vendor Specific UUIDs, lengths, and permissions need to adhere to the constraints.
* @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation, a service context is required.
* @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, certain UUIDs are reserved for the stack.
* @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation.
* @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, attribute lengths are restricted by @ref BLE_GATTS_ATTR_LENS_MAX.
*/
SVCALL(SD_BLE_GATTS_CHARACTERISTIC_ADD, uint32_t, sd_ble_gatts_characteristic_add(uint16_t service_handle, ble_gatts_char_md_t const *p_char_md, ble_gatts_attr_t const *p_attr_char_value, ble_gatts_char_handles_t *p_handles));
/**@brief Add a descriptor to the Attribute Table.
*
* @note It is currently only possible to add a descriptor to the last added characteristic (i.e. only sequential population is supported at this time).
*
* @mscs
* @mmsc{@ref BLE_GATTS_ATT_TABLE_POP_MSC}
* @endmscs
*
* @param[in] char_handle Handle of the characteristic where the descriptor is to be placed, if @ref BLE_GATT_HANDLE_INVALID is used, it will be placed sequentially.
* @param[in] p_attr Pointer to the attribute structure.
* @param[out] p_handle Pointer to a 16-bit word where the assigned handle will be stored.
*
* @retval ::NRF_SUCCESS Successfully added a descriptor.
* @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
* @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, characteristic handle, Vendor Specific UUIDs, lengths, and permissions need to adhere to the constraints.
* @retval ::NRF_ERROR_INVALID_STATE Invalid state to perform operation, a characteristic context is required.
* @retval ::NRF_ERROR_FORBIDDEN Forbidden value supplied, certain UUIDs are reserved for the stack.
* @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation.
* @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, attribute lengths are restricted by @ref BLE_GATTS_ATTR_LENS_MAX.
*/
SVCALL(SD_BLE_GATTS_DESCRIPTOR_ADD, uint32_t, sd_ble_gatts_descriptor_add(uint16_t char_handle, ble_gatts_attr_t const *p_attr, uint16_t *p_handle));
/**@brief Set the value of a given attribute.
*
* @note Values other than system attributes can be set at any time, regardless of wheter any active connections exist.
*
* @mscs
* @mmsc{@ref BLE_GATTS_QUEUED_WRITE_QUEUE_FULL_MSC}
* @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_NOAUTH_MSC}
* @endmscs
*
* @param[in] conn_handle Connection handle. If the value does not belong to a system attribute then @ref BLE_CONN_HANDLE_INVALID can be used.
* @param[in] handle Attribute handle.
* @param[in,out] p_value Attribute value information.
*
* @retval ::NRF_SUCCESS Successfully set the value of the attribute.
* @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
* @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
* @retval ::NRF_ERROR_NOT_FOUND Attribute not found.
* @retval ::NRF_ERROR_FORBIDDEN Forbidden handle supplied, certain attributes are not modifiable by the application.
* @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, attribute lengths are restricted by @ref BLE_GATTS_ATTR_LENS_MAX.
* @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied.
* @retval ::BLE_ERROR_GATTS_INVALID_ATTR_TYPE @ref BLE_CONN_HANDLE_INVALID supplied on a system attribute.
*/
SVCALL(SD_BLE_GATTS_VALUE_SET, uint32_t, sd_ble_gatts_value_set(uint16_t conn_handle, uint16_t handle, ble_gatts_value_t *p_value));
/**@brief Get the value of a given attribute.
*
* @note If the attribute value is longer than the size of the supplied buffer,
* p_len will return the total attribute value length (excluding offset),
* and not the number of bytes actually returned in p_data.
* The application may use this information to allocate a suitable buffer size.
*
* @note When retrieving system attribute values with this function, the connection handle
* may refer to an already disconnected connection. Refer to the documentation of
* @ref sd_ble_gatts_sys_attr_get for further information.
*
* @param[in] conn_handle Connection handle. If the value does not belong to a system attribute then @ref BLE_CONN_HANDLE_INVALID can be used.
* @param[in] handle Attribute handle.
* @param[in,out] p_value Attribute value information.
*
* @retval ::NRF_SUCCESS Successfully retrieved the value of the attribute.
* @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
* @retval ::NRF_ERROR_NOT_FOUND Attribute not found.
* @retval ::NRF_ERROR_INVALID_PARAM Invalid attribute offset supplied.
* @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid connection handle supplied.
* @retval ::BLE_ERROR_GATTS_INVALID_ATTR_TYPE @ref BLE_CONN_HANDLE_INVALID supplied on a system attribute.
*/
SVCALL(SD_BLE_GATTS_VALUE_GET, uint32_t, sd_ble_gatts_value_get(uint16_t conn_handle, uint16_t handle, ble_gatts_value_t *p_value));
/**@brief Notify or Indicate an attribute value.
*
* @details This function checks for the relevant Client Characteristic Configuration descriptor value to verify that the relevant operation
* (notification or indication) has been enabled by the client. It is also able to update the attribute value before issuing the PDU, so that
* the application can atomically perform a value update and a server initiated transaction with a single API call.
* If the application chooses to indicate an attribute value, a @ref BLE_GATTS_EVT_HVC event will be issued as soon as the confirmation arrives from
* the peer.
*
* @note The local attribute value may be updated even if an outgoing packet is not sent to the peer due to an error during execution.
* When receiveing the error codes @ref NRF_ERROR_INVALID_STATE, @ref NRF_ERROR_BUSY, @ref BLE_ERROR_GATTS_SYS_ATTR_MISSING and
* @ref BLE_ERROR_NO_TX_PACKETS the Attribute Table has been updated.
* The caller can check whether the value has been updated by looking at the contents of *(p_hvx_params->p_len).
*
* @note It is important to note that a notification will <b>consume an application buffer</b>, and will therefore
* generate a @ref BLE_EVT_TX_COMPLETE event when the packet has been transmitted. An indication on the other hand will use the
* standard server internal buffer and thus will only generate a @ref BLE_GATTS_EVT_HVC event as soon as the confirmation
* has been received from the peer. Please see the documentation of @ref sd_ble_tx_packet_count_get for more details.
*
* @events
* @event{@ref BLE_EVT_TX_COMPLETE, Transmission complete.}
* @event{@ref BLE_GATTS_EVT_HVC, Confirmation received from peer.}
* @endevents
*
* @mscs
* @mmsc{@ref BLE_GATTS_HVX_SYS_ATTRS_MISSING_MSC}
* @mmsc{@ref BLE_GATTS_HVN_MSC}
* @mmsc{@ref BLE_GATTS_HVI_MSC}
* @mmsc{@ref BLE_GATTS_HVX_DISABLED_MSC}
* @mmsc{@ref BLE_COMMON_APP_BUFF_MSC}
* @endmscs
*
* @param[in] conn_handle Connection handle.
* @param[in] p_hvx_params Pointer to an HVx parameters structure. If the p_data member contains a non-NULL pointer the attribute value will be updated with
* the contents pointed by it before sending the notification or indication.
*
* @retval ::NRF_SUCCESS Successfully queued a notification or indication for transmission, and optionally updated the attribute value.
* @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
* @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State or notifications and/or indications not enabled in the CCCD.
* @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
* @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
* @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle(s) supplied. Only attributes added directly by the application are available to notify and indicate.
* @retval ::BLE_ERROR_GATTS_INVALID_ATTR_TYPE Invalid attribute type(s) supplied, only characteristic values may be notified and indicated.
* @retval ::NRF_ERROR_NOT_FOUND Attribute not found.
* @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied.
* @retval ::NRF_ERROR_BUSY Procedure already in progress.
* @retval ::BLE_ERROR_GATTS_SYS_ATTR_MISSING System attributes missing, use @ref sd_ble_gatts_sys_attr_set to set them to a known value.
* @retval ::BLE_ERROR_NO_TX_PACKETS No available application packets for this connection, applies only to notifications.
*/
SVCALL(SD_BLE_GATTS_HVX, uint32_t, sd_ble_gatts_hvx(uint16_t conn_handle, ble_gatts_hvx_params_t const *p_hvx_params));
/**@brief Indicate the Service Changed attribute value.
*
* @details This call will send a Handle Value Indication to one or more peers connected to inform them that the Attribute
* Table layout has changed. As soon as the peer has confirmed the indication, a @ref BLE_GATTS_EVT_SC_CONFIRM event will
* be issued.
*
* @note Some of the restrictions and limitations that apply to @ref sd_ble_gatts_hvx also apply here.
*
* @events
* @event{@ref BLE_GATTS_EVT_SC_CONFIRM, Confirmation of attribute table change received from peer.}
* @endevents
*
* @mscs
* @mmsc{@ref BLE_GATTS_SC_MSC}
* @endmscs
*
* @param[in] conn_handle Connection handle.
* @param[in] start_handle Start of affected attribute handle range.
* @param[in] end_handle End of affected attribute handle range.
*
* @retval ::NRF_SUCCESS Successfully queued the Service Changed indication for transmission.
* @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
* @retval ::NRF_ERROR_NOT_SUPPORTED Service Changed not enabled at initialization. See @ref sd_ble_enable and @ref ble_gatts_enable_params_t.
* @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State or notifications and/or indications not enabled in the CCCD.
* @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
* @retval ::BLE_ERROR_INVALID_ATTR_HANDLE Invalid attribute handle(s) supplied, handles must be in the range populated by the application.
* @retval ::NRF_ERROR_BUSY Procedure already in progress.
* @retval ::BLE_ERROR_GATTS_SYS_ATTR_MISSING System attributes missing, use @ref sd_ble_gatts_sys_attr_set to set them to a known value.
*/
SVCALL(SD_BLE_GATTS_SERVICE_CHANGED, uint32_t, sd_ble_gatts_service_changed(uint16_t conn_handle, uint16_t start_handle, uint16_t end_handle));
/**@brief Respond to a Read/Write authorization request.
*
* @note This call should only be used as a response to a @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST event issued to the application.
*
* @mscs
* @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_AUTH_MSC}
* @mmsc{@ref BLE_GATTS_QUEUED_WRITE_BUF_AUTH_MSC}
* @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_NOAUTH_MSC}
* @mmsc{@ref BLE_GATTS_READ_REQ_AUTH_MSC}
* @mmsc{@ref BLE_GATTS_WRITE_REQ_AUTH_MSC}
* @mmsc{@ref BLE_GATTS_QUEUED_WRITE_QUEUE_FULL_MSC}
* @mmsc{@ref BLE_GATTS_QUEUED_WRITE_NOBUF_PEER_CANCEL_MSC}
* @endmscs
*
* @param[in] conn_handle Connection handle.
* @param[in] p_rw_authorize_reply_params Pointer to a structure with the attribute provided by the application.
*
* @retval ::NRF_SUCCESS Successfully queued a response to the peer, and in the case of a write operation, Attribute Table updated.
* @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
* @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
* @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State or no authorization request pending.
* @retval ::NRF_ERROR_INVALID_PARAM Authorization op invalid,
* handle supplied does not match requested handle,
* or invalid data to be written provided by the application.
* @retval ::NRF_ERROR_BUSY The stack is busy. Retry at later time.
*/
SVCALL(SD_BLE_GATTS_RW_AUTHORIZE_REPLY, uint32_t, sd_ble_gatts_rw_authorize_reply(uint16_t conn_handle, ble_gatts_rw_authorize_reply_params_t const *p_rw_authorize_reply_params));
/**@brief Update persistent system attribute information.
*
* @details Supply information about persistent system attributes to the stack,
* previously obtained using @ref sd_ble_gatts_sys_attr_get.
* This call is only allowed for active connections, and is usually
* made immediately after a connection is established with an known bonded device,
* often as a response to a @ref BLE_GATTS_EVT_SYS_ATTR_MISSING.
*
* p_sysattrs may point directly to the application's stored copy of the system attributes
* obtained using @ref sd_ble_gatts_sys_attr_get.
* If the pointer is NULL, the system attribute info is initialized, assuming that
* the application does not have any previously saved system attribute data for this device.
*
* @note The state of persistent system attributes is reset upon connection establishment and then remembered for its duration.
*
* @note If this call returns with an error code different from @ref NRF_SUCCESS, the storage of persistent system attributes may have been completed only partially.
* This means that the state of the attribute table is undefined, and the application should either provide a new set of attributes using this same call or
* reset the SoftDevice to return to a known state.
*
* @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS is used with this function, only the system attributes included in system services will be modified.
* @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS is used with this function, only the system attributes included in user services will be modified.
*
* @mscs
* @mmsc{@ref BLE_GATTS_HVX_SYS_ATTRS_MISSING_MSC}
* @mmsc{@ref BLE_GATTS_SYS_ATTRS_UNK_PEER_MSC}
* @mmsc{@ref BLE_GATTS_SYS_ATTRS_BONDED_PEER_MSC}
* @endmscs
*
* @param[in] conn_handle Connection handle.
* @param[in] p_sys_attr_data Pointer to a saved copy of system attributes supplied to the stack, or NULL.
* @param[in] len Size of data pointed by p_sys_attr_data, in octets.
* @param[in] flags Optional additional flags, see @ref BLE_GATTS_SYS_ATTR_FLAGS
*
* @retval ::NRF_SUCCESS Successfully set the system attribute information.
* @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
* @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
* @retval ::NRF_ERROR_INVALID_STATE Invalid Connection State.
* @retval ::NRF_ERROR_INVALID_DATA Invalid data supplied, the data should be exactly the same as retrieved with @ref sd_ble_gatts_sys_attr_get.
* @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation.
* @retval ::NRF_ERROR_BUSY The stack is busy. Retry at later time.
*/
SVCALL(SD_BLE_GATTS_SYS_ATTR_SET, uint32_t, sd_ble_gatts_sys_attr_set(uint16_t conn_handle, uint8_t const *p_sys_attr_data, uint16_t len, uint32_t flags));
/**@brief Retrieve persistent system attribute information from the stack.
*
* @details This call is used to retrieve information about values to be stored perisistently by the application
* during the lifetime of a connection or after it has been terminated. When a new connection is established with the same bonded device,
* the system attribute information retrieved with this function should be restored using using @ref sd_ble_gatts_sys_attr_set.
* If retrieved after disconnection, the data should be read before a new connection established. The connection handle for
* the previous, now disconnected, connection will remain valid until a new one is created to allow this API call to refer to it.
* Connection handles belonging to active connections can be used as well, but care should be taken since the system attributes
* may be written to at any time by the peer during a connection's lifetime.
*
* @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS is used with this function, only the system attributes included in system services will be returned.
* @note When the @ref BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS is used with this function, only the system attributes included in user services will be returned.
*
* @mscs
* @mmsc{@ref BLE_GATTS_SYS_ATTRS_BONDED_PEER_MSC}
* @endmscs
*
* @param[in] conn_handle Connection handle of the recently terminated connection.
* @param[out] p_sys_attr_data Pointer to a buffer where updated information about system attributes will be filled in. The format of the data is described
* in @ref BLE_GATTS_SYS_ATTRS_FORMAT. NULL can be provided to obtain the length of the data.
* @param[in,out] p_len Size of application buffer if p_sys_attr_data is not NULL. Unconditially updated to actual length of system attribute data.
* @param[in] flags Optional additional flags, see @ref BLE_GATTS_SYS_ATTR_FLAGS
*
* @retval ::NRF_SUCCESS Successfully retrieved the system attribute information.
* @retval ::BLE_ERROR_INVALID_CONN_HANDLE Invalid Connection Handle.
* @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
* @retval ::NRF_ERROR_DATA_SIZE The system attribute information did not fit into the provided buffer.
* @retval ::NRF_ERROR_NOT_FOUND No system attributes found.
*/
SVCALL(SD_BLE_GATTS_SYS_ATTR_GET, uint32_t, sd_ble_gatts_sys_attr_get(uint16_t conn_handle, uint8_t *p_sys_attr_data, uint16_t *p_len, uint32_t flags));
/**@brief Retrieve the first valid user attribute handle.
*
* @param[out] p_handle Pointer to an integer where the handle will be stored.
*
* @retval ::NRF_SUCCESS Successfully retrieved the handle.
* @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
*/
SVCALL(SD_BLE_GATTS_INITIAL_USER_HANDLE_GET, uint32_t, sd_ble_gatts_initial_user_handle_get(uint16_t *p_handle));
/**@brief Retrieve the attribute UUID and/or metadata.
*
* @param[in] handle Attribute handle
* @param[out] p_uuid UUID of the attribute. Use NULL to omit this field.
* @param[out] p_md Metadata of the attribute. Use NULL to omit this field.
*
* @retval ::NRF_SUCCESS Successfully retrieved the attribute metadata,
* @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
* @retval ::NRF_ERROR_INVALID_PARAM Invalid parameters supplied. Returned when both @c p_uuid and @c p_md are NULL.
* @retval ::NRF_ERROR_NOT_FOUND Attribute was not found.
*/
SVCALL(SD_BLE_GATTS_ATTR_GET, uint32_t, sd_ble_gatts_attr_get(uint16_t handle, ble_uuid_t * p_uuid, ble_gatts_attr_md_t * p_md));
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF_BLE_GATTS_H__
/**
@}
*/

View File

@ -0,0 +1,134 @@
/*
* Copyright (c) 2000 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/**
@addtogroup BLE_COMMON
@{
*/
#ifndef NRF_BLE_HCI_H__
#define NRF_BLE_HCI_H__
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup BLE_HCI_STATUS_CODES Bluetooth status codes
* @{ */
#define BLE_HCI_STATUS_CODE_SUCCESS 0x00 /**< Success. */
#define BLE_HCI_STATUS_CODE_UNKNOWN_BTLE_COMMAND 0x01 /**< Unknown BLE Command. */
#define BLE_HCI_STATUS_CODE_UNKNOWN_CONNECTION_IDENTIFIER 0x02 /**< Unknown Connection Identifier. */
/*0x03 Hardware Failure
0x04 Page Timeout
*/
#define BLE_HCI_AUTHENTICATION_FAILURE 0x05 /**< Authentication Failure. */
#define BLE_HCI_STATUS_CODE_PIN_OR_KEY_MISSING 0x06 /**< Pin or Key missing. */
#define BLE_HCI_MEMORY_CAPACITY_EXCEEDED 0x07 /**< Memory Capacity Exceeded. */
#define BLE_HCI_CONNECTION_TIMEOUT 0x08 /**< Connection Timeout. */
/*0x09 Connection Limit Exceeded
0x0A Synchronous Connection Limit To A Device Exceeded
0x0B ACL Connection Already Exists*/
#define BLE_HCI_STATUS_CODE_COMMAND_DISALLOWED 0x0C /**< Command Disallowed. */
/*0x0D Connection Rejected due to Limited Resources
0x0E Connection Rejected Due To Security Reasons
0x0F Connection Rejected due to Unacceptable BD_ADDR
0x10 Connection Accept Timeout Exceeded
0x11 Unsupported Feature or Parameter Value*/
#define BLE_HCI_STATUS_CODE_INVALID_BTLE_COMMAND_PARAMETERS 0x12 /**< Invalid BLE Command Parameters. */
#define BLE_HCI_REMOTE_USER_TERMINATED_CONNECTION 0x13 /**< Remote User Terminated Connection. */
#define BLE_HCI_REMOTE_DEV_TERMINATION_DUE_TO_LOW_RESOURCES 0x14 /**< Remote Device Terminated Connection due to low resources.*/
#define BLE_HCI_REMOTE_DEV_TERMINATION_DUE_TO_POWER_OFF 0x15 /**< Remote Device Terminated Connection due to power off. */
#define BLE_HCI_LOCAL_HOST_TERMINATED_CONNECTION 0x16 /**< Local Host Terminated Connection. */
/*
0x17 Repeated Attempts
0x18 Pairing Not Allowed
0x19 Unknown LMP PDU
*/
#define BLE_HCI_UNSUPPORTED_REMOTE_FEATURE 0x1A /**< Unsupported Remote Feature. */
/*
0x1B SCO Offset Rejected
0x1C SCO Interval Rejected
0x1D SCO Air Mode Rejected*/
#define BLE_HCI_STATUS_CODE_INVALID_LMP_PARAMETERS 0x1E /**< Invalid LMP Parameters. */
#define BLE_HCI_STATUS_CODE_UNSPECIFIED_ERROR 0x1F /**< Unspecified Error. */
/*0x20 Unsupported LMP Parameter Value
0x21 Role Change Not Allowed
*/
#define BLE_HCI_STATUS_CODE_LMP_RESPONSE_TIMEOUT 0x22 /**< LMP Response Timeout. */
/*0x23 LMP Error Transaction Collision*/
#define BLE_HCI_STATUS_CODE_LMP_PDU_NOT_ALLOWED 0x24 /**< LMP PDU Not Allowed. */
/*0x25 Encryption Mode Not Acceptable
0x26 Link Key Can Not be Changed
0x27 Requested QoS Not Supported
*/
#define BLE_HCI_INSTANT_PASSED 0x28 /**< Instant Passed. */
#define BLE_HCI_PAIRING_WITH_UNIT_KEY_UNSUPPORTED 0x29 /**< Pairing with Unit Key Unsupported. */
#define BLE_HCI_DIFFERENT_TRANSACTION_COLLISION 0x2A /**< Different Transaction Collision. */
/*
0x2B Reserved
0x2C QoS Unacceptable Parameter
0x2D QoS Rejected
0x2E Channel Classification Not Supported
0x2F Insufficient Security
0x30 Parameter Out Of Mandatory Range
0x31 Reserved
0x32 Role Switch Pending
0x33 Reserved
0x34 Reserved Slot Violation
0x35 Role Switch Failed
0x36 Extended Inquiry Response Too Large
0x37 Secure Simple Pairing Not Supported By Host.
0x38 Host Busy - Pairing
0x39 Connection Rejected due to No Suitable Channel Found*/
#define BLE_HCI_CONTROLLER_BUSY 0x3A /**< Controller Busy. */
#define BLE_HCI_CONN_INTERVAL_UNACCEPTABLE 0x3B /**< Connection Interval Unacceptable. */
#define BLE_HCI_DIRECTED_ADVERTISER_TIMEOUT 0x3C /**< Directed Adverisement Timeout. */
#define BLE_HCI_CONN_TERMINATED_DUE_TO_MIC_FAILURE 0x3D /**< Connection Terminated due to MIC Failure. */
#define BLE_HCI_CONN_FAILED_TO_BE_ESTABLISHED 0x3E /**< Connection Failed to be Established. */
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF_BLE_HCI_H__
/** @} */

View File

@ -0,0 +1,205 @@
/*
* Copyright (c) 2000 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/**
@addtogroup BLE_L2CAP Logical Link Control and Adaptation Protocol (L2CAP)
@{
@brief Definitions and prototypes for the L2CAP interface.
*/
#ifndef NRF_BLE_L2CAP_H__
#define NRF_BLE_L2CAP_H__
#include "nrf_ble_types.h"
#include "nrf_ble_ranges.h"
#include "nrf_ble_err.h"
#include "nrf_svc.h"
#ifdef __cplusplus
extern "C" {
#endif
/**@addtogroup BLE_L2CAP_ENUMERATIONS Enumerations
* @{ */
/**@brief L2CAP API SVC numbers. */
enum BLE_L2CAP_SVCS
{
SD_BLE_L2CAP_CID_REGISTER = BLE_L2CAP_SVC_BASE, /**< Register a CID. */
SD_BLE_L2CAP_CID_UNREGISTER, /**< Unregister a CID. */
SD_BLE_L2CAP_TX /**< Transmit a packet. */
};
/**@brief L2CAP Event IDs. */
enum BLE_L2CAP_EVTS
{
BLE_L2CAP_EVT_RX = BLE_L2CAP_EVT_BASE /**< L2CAP packet received. */
};
/** @} */
/**@addtogroup BLE_L2CAP_DEFINES Defines
* @{ */
/**@defgroup BLE_ERRORS_L2CAP SVC return values specific to L2CAP
* @{ */
#define BLE_ERROR_L2CAP_CID_IN_USE (NRF_L2CAP_ERR_BASE + 0x000) /**< CID already in use. */
/** @} */
/**@brief Default L2CAP MTU. */
#define BLE_L2CAP_MTU_DEF (23)
/**@brief Invalid Channel Identifier. */
#define BLE_L2CAP_CID_INVALID (0x0000)
/**@brief Dynamic Channel Identifier base. */
#define BLE_L2CAP_CID_DYN_BASE (0x0040)
/**@brief Maximum amount of dynamic CIDs. */
#define BLE_L2CAP_CID_DYN_MAX (8)
/** @} */
/**@addtogroup BLE_L2CAP_STRUCTURES Structures
* @{ */
/**@brief Packet header format for L2CAP transmission. */
typedef struct
{
uint16_t len; /**< Length of valid info in data member. */
uint16_t cid; /**< Channel ID on which packet is transmitted. */
} ble_l2cap_header_t;
/**@brief L2CAP Received packet event report. */
typedef struct
{
ble_l2cap_header_t header; /**< L2CAP packet header. */
uint8_t data[1]; /**< Packet data. @note This is a variable length array. The size of 1 indicated is only a placeholder for compilation.
See @ref sd_ble_evt_get for more information on how to use event structures with variable length array members. */
} ble_l2cap_evt_rx_t;
/**@brief L2CAP event callback event structure. */
typedef struct
{
uint16_t conn_handle; /**< Connection Handle on which event occured. */
union
{
ble_l2cap_evt_rx_t rx; /**< RX Event parameters. */
} params; /**< Event Parameters. */
} ble_l2cap_evt_t;
/** @} */
/**@addtogroup BLE_L2CAP_FUNCTIONS Functions
* @{ */
/**@brief Register a CID with L2CAP.
*
* @details This registers a higher protocol layer with the L2CAP multiplexer, and is requried prior to all operations on the CID.
*
* @mscs
* @mmsc{@ref BLE_L2CAP_API_MSC}
* @endmscs
*
* @param[in] cid L2CAP CID.
*
* @retval ::NRF_SUCCESS Successfully registered a CID with the L2CAP layer.
* @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, CID must be above @ref BLE_L2CAP_CID_DYN_BASE.
* @retval ::BLE_ERROR_L2CAP_CID_IN_USE L2CAP CID already in use.
* @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation.
*/
SVCALL(SD_BLE_L2CAP_CID_REGISTER, uint32_t, sd_ble_l2cap_cid_register(uint16_t cid));
/**@brief Unregister a CID with L2CAP.
*
* @details This unregisters a previously registerd higher protocol layer with the L2CAP multiplexer.
*
* @mscs
* @mmsc{@ref BLE_L2CAP_API_MSC}
* @endmscs
*
* @param[in] cid L2CAP CID.
*
* @retval ::NRF_SUCCESS Successfully unregistered the CID.
* @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied.
* @retval ::NRF_ERROR_NOT_FOUND CID not previously registered.
*/
SVCALL(SD_BLE_L2CAP_CID_UNREGISTER, uint32_t, sd_ble_l2cap_cid_unregister(uint16_t cid));
/**@brief Transmit an L2CAP packet.
*
* @note It is important to note that a call to this function will <b>consume an application packet</b>, and will therefore
* generate a @ref BLE_EVT_TX_COMPLETE event when the packet has been transmitted.
* Please see the documentation of @ref sd_ble_tx_packet_count_get for more details.
*
* @events
* @event{@ref BLE_EVT_TX_COMPLETE}
* @event{@ref BLE_L2CAP_EVT_RX}
* @endevents
*
* @mscs
* @mmsc{@ref BLE_L2CAP_API_MSC}
* @endmscs
*
* @param[in] conn_handle Connection Handle.
* @param[in] p_header Pointer to a packet header containing length and CID.
* @param[in] p_data Pointer to the data to be transmitted.
*
* @retval ::NRF_SUCCESS Successfully queued an L2CAP packet for transmission.
* @retval ::NRF_ERROR_INVALID_ADDR Invalid pointer supplied.
* @retval ::NRF_ERROR_INVALID_PARAM Invalid parameter(s) supplied, CIDs must be registered beforehand with @ref sd_ble_l2cap_cid_register.
* @retval ::NRF_ERROR_NOT_FOUND CID not found.
* @retval ::NRF_ERROR_NO_MEM Not enough memory to complete operation.
* @retval ::BLE_ERROR_NO_TX_PACKETS Not enough application packets available.
* @retval ::NRF_ERROR_DATA_SIZE Invalid data size(s) supplied, see @ref BLE_L2CAP_MTU_DEF.
*/
SVCALL(SD_BLE_L2CAP_TX, uint32_t, sd_ble_l2cap_tx(uint16_t conn_handle, ble_l2cap_header_t const *p_header, uint8_t const *p_data));
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF_BLE_L2CAP_H__
/**
@}
*/

View File

@ -0,0 +1,129 @@
/*
* Copyright (c) 2000 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/**
@addtogroup BLE_COMMON
@{
@defgroup ble_ranges Module specific SVC, event and option number subranges
@{
@brief Definition of SVC, event and option number subranges for each API module.
@note
SVCs, event and option numbers are split into subranges for each API module.
Each module receives its entire allocated range of SVC calls, whether implemented or not,
but return BLE_ERROR_NOT_SUPPORTED for unimplemented or undefined calls in its range.
Note that the symbols BLE_<module>_SVC_LAST is the end of the allocated SVC range,
rather than the last SVC function call actually defined and implemented.
Specific SVC, event and option values are defined in each module's ble_<module>.h file,
which defines names of each individual SVC code based on the range start value.
*/
#ifndef NRF_BLE_RANGES_H__
#define NRF_BLE_RANGES_H__
#ifdef __cplusplus
extern "C" {
#endif
#define BLE_SVC_BASE 0x60 /**< Common BLE SVC base. */
#define BLE_SVC_LAST 0x6B /**< Total: 12. */
#define BLE_RESERVED_SVC_BASE 0x6C /**< Reserved BLE SVC base. */
#define BLE_RESERVED_SVC_LAST 0x6F /**< Total: 4. */
#define BLE_GAP_SVC_BASE 0x70 /**< GAP BLE SVC base. */
#define BLE_GAP_SVC_LAST 0x8F /**< Total: 32. */
#define BLE_GATTC_SVC_BASE 0x90 /**< GATTC BLE SVC base. */
#define BLE_GATTC_SVC_LAST 0x9F /**< Total: 32. */
#define BLE_GATTS_SVC_BASE 0xA0 /**< GATTS BLE SVC base. */
#define BLE_GATTS_SVC_LAST 0xAF /**< Total: 16. */
#define BLE_L2CAP_SVC_BASE 0xB0 /**< L2CAP BLE SVC base. */
#define BLE_L2CAP_SVC_LAST 0xBF /**< Total: 16. */
#define BLE_EVT_INVALID 0x00 /**< Invalid BLE Event. */
#define BLE_EVT_BASE 0x01 /**< Common BLE Event base. */
#define BLE_EVT_LAST 0x0F /**< Total: 15. */
#define BLE_GAP_EVT_BASE 0x10 /**< GAP BLE Event base. */
#define BLE_GAP_EVT_LAST 0x2F /**< Total: 32. */
#define BLE_GATTC_EVT_BASE 0x30 /**< GATTC BLE Event base. */
#define BLE_GATTC_EVT_LAST 0x4F /**< Total: 32. */
#define BLE_GATTS_EVT_BASE 0x50 /**< GATTS BLE Event base. */
#define BLE_GATTS_EVT_LAST 0x6F /**< Total: 32. */
#define BLE_L2CAP_EVT_BASE 0x70 /**< L2CAP BLE Event base. */
#define BLE_L2CAP_EVT_LAST 0x8F /**< Total: 32. */
#define BLE_OPT_INVALID 0x00 /**< Invalid BLE Option. */
#define BLE_OPT_BASE 0x01 /**< Common BLE Option base. */
#define BLE_OPT_LAST 0x1F /**< Total: 31. */
#define BLE_GAP_OPT_BASE 0x20 /**< GAP BLE Option base. */
#define BLE_GAP_OPT_LAST 0x3F /**< Total: 32. */
#define BLE_GATTC_OPT_BASE 0x40 /**< GATTC BLE Option base. */
#define BLE_GATTC_OPT_LAST 0x5F /**< Total: 32. */
#define BLE_GATTS_OPT_BASE 0x60 /**< GATTS BLE Option base. */
#define BLE_GATTS_OPT_LAST 0x7F /**< Total: 32. */
#define BLE_L2CAP_OPT_BASE 0x80 /**< L2CAP BLE Option base. */
#define BLE_L2CAP_OPT_LAST 0x9F /**< Total: 32. */
#ifdef __cplusplus
}
#endif
#endif /* NRF_BLE_RANGES_H__ */
/**
@}
@}
*/

View File

@ -0,0 +1,208 @@
/*
* Copyright (c) 2000 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/**
@addtogroup BLE_COMMON
@{
@defgroup ble_types Common types and macro definitions
@{
@brief Common types and macro definitions for the BLE SoftDevice.
*/
#ifndef NRF_BLE_TYPES_H__
#define NRF_BLE_TYPES_H__
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/** @addtogroup BLE_TYPES_DEFINES Defines
* @{ */
/** @defgroup BLE_CONN_HANDLES BLE Connection Handles
* @{ */
#define BLE_CONN_HANDLE_INVALID 0xFFFF /**< Invalid Connection Handle. */
#define BLE_CONN_HANDLE_ALL 0xFFFE /**< Applies to all Connection Handles. */
/** @} */
/** @defgroup BLE_UUID_VALUES Assigned Values for BLE UUIDs
* @{ */
/* Generic UUIDs, applicable to all services */
#define BLE_UUID_UNKNOWN 0x0000 /**< Reserved UUID. */
#define BLE_UUID_SERVICE_PRIMARY 0x2800 /**< Primary Service. */
#define BLE_UUID_SERVICE_SECONDARY 0x2801 /**< Secondary Service. */
#define BLE_UUID_SERVICE_INCLUDE 0x2802 /**< Include. */
#define BLE_UUID_CHARACTERISTIC 0x2803 /**< Characteristic. */
#define BLE_UUID_DESCRIPTOR_CHAR_EXT_PROP 0x2900 /**< Characteristic Extended Properties Descriptor. */
#define BLE_UUID_DESCRIPTOR_CHAR_USER_DESC 0x2901 /**< Characteristic User Description Descriptor. */
#define BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG 0x2902 /**< Client Characteristic Configuration Descriptor. */
#define BLE_UUID_DESCRIPTOR_SERVER_CHAR_CONFIG 0x2903 /**< Server Characteristic Configuration Descriptor. */
#define BLE_UUID_DESCRIPTOR_CHAR_PRESENTATION_FORMAT 0x2904 /**< Characteristic Presentation Format Descriptor. */
#define BLE_UUID_DESCRIPTOR_CHAR_AGGREGATE_FORMAT 0x2905 /**< Characteristic Aggregate Format Descriptor. */
/* GATT specific UUIDs */
#define BLE_UUID_GATT 0x1801 /**< Generic Attribute Profile. */
#define BLE_UUID_GATT_CHARACTERISTIC_SERVICE_CHANGED 0x2A05 /**< Service Changed Characteristic. */
/* GAP specific UUIDs */
#define BLE_UUID_GAP 0x1800 /**< Generic Access Profile. */
#define BLE_UUID_GAP_CHARACTERISTIC_DEVICE_NAME 0x2A00 /**< Device Name Characteristic. */
#define BLE_UUID_GAP_CHARACTERISTIC_APPEARANCE 0x2A01 /**< Appearance Characteristic. */
#define BLE_UUID_GAP_CHARACTERISTIC_PPF 0x2A02 /**< Peripheral Privacy Flag Characteristic. */
#define BLE_UUID_GAP_CHARACTERISTIC_RECONN_ADDR 0x2A03 /**< Reconnection Address Characteristic. */
#define BLE_UUID_GAP_CHARACTERISTIC_PPCP 0x2A04 /**< Peripheral Preferred Connection Parameters Characteristic. */
/** @} */
/** @defgroup BLE_UUID_TYPES Types of UUID
* @{ */
#define BLE_UUID_TYPE_UNKNOWN 0x00 /**< Invalid UUID type. */
#define BLE_UUID_TYPE_BLE 0x01 /**< Bluetooth SIG UUID (16-bit). */
#define BLE_UUID_TYPE_VENDOR_BEGIN 0x02 /**< Vendor UUID types start at this index (128-bit). */
/** @} */
/** @defgroup BLE_APPEARANCES Bluetooth Appearance values
* @note Retrieved from http://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.gap.appearance.xml
* @{ */
#define BLE_APPEARANCE_UNKNOWN 0 /**< Unknown. */
#define BLE_APPEARANCE_GENERIC_PHONE 64 /**< Generic Phone. */
#define BLE_APPEARANCE_GENERIC_COMPUTER 128 /**< Generic Computer. */
#define BLE_APPEARANCE_GENERIC_WATCH 192 /**< Generic Watch. */
#define BLE_APPEARANCE_WATCH_SPORTS_WATCH 193 /**< Watch: Sports Watch. */
#define BLE_APPEARANCE_GENERIC_CLOCK 256 /**< Generic Clock. */
#define BLE_APPEARANCE_GENERIC_DISPLAY 320 /**< Generic Display. */
#define BLE_APPEARANCE_GENERIC_REMOTE_CONTROL 384 /**< Generic Remote Control. */
#define BLE_APPEARANCE_GENERIC_EYE_GLASSES 448 /**< Generic Eye-glasses. */
#define BLE_APPEARANCE_GENERIC_TAG 512 /**< Generic Tag. */
#define BLE_APPEARANCE_GENERIC_KEYRING 576 /**< Generic Keyring. */
#define BLE_APPEARANCE_GENERIC_MEDIA_PLAYER 640 /**< Generic Media Player. */
#define BLE_APPEARANCE_GENERIC_BARCODE_SCANNER 704 /**< Generic Barcode Scanner. */
#define BLE_APPEARANCE_GENERIC_THERMOMETER 768 /**< Generic Thermometer. */
#define BLE_APPEARANCE_THERMOMETER_EAR 769 /**< Thermometer: Ear. */
#define BLE_APPEARANCE_GENERIC_HEART_RATE_SENSOR 832 /**< Generic Heart rate Sensor. */
#define BLE_APPEARANCE_HEART_RATE_SENSOR_HEART_RATE_BELT 833 /**< Heart Rate Sensor: Heart Rate Belt. */
#define BLE_APPEARANCE_GENERIC_BLOOD_PRESSURE 896 /**< Generic Blood Pressure. */
#define BLE_APPEARANCE_BLOOD_PRESSURE_ARM 897 /**< Blood Pressure: Arm. */
#define BLE_APPEARANCE_BLOOD_PRESSURE_WRIST 898 /**< Blood Pressure: Wrist. */
#define BLE_APPEARANCE_GENERIC_HID 960 /**< Human Interface Device (HID). */
#define BLE_APPEARANCE_HID_KEYBOARD 961 /**< Keyboard (HID Subtype). */
#define BLE_APPEARANCE_HID_MOUSE 962 /**< Mouse (HID Subtype). */
#define BLE_APPEARANCE_HID_JOYSTICK 963 /**< Joystiq (HID Subtype). */
#define BLE_APPEARANCE_HID_GAMEPAD 964 /**< Gamepad (HID Subtype). */
#define BLE_APPEARANCE_HID_DIGITIZERSUBTYPE 965 /**< Digitizer Tablet (HID Subtype). */
#define BLE_APPEARANCE_HID_CARD_READER 966 /**< Card Reader (HID Subtype). */
#define BLE_APPEARANCE_HID_DIGITAL_PEN 967 /**< Digital Pen (HID Subtype). */
#define BLE_APPEARANCE_HID_BARCODE 968 /**< Barcode Scanner (HID Subtype). */
#define BLE_APPEARANCE_GENERIC_GLUCOSE_METER 1024 /**< Generic Glucose Meter. */
#define BLE_APPEARANCE_GENERIC_RUNNING_WALKING_SENSOR 1088 /**< Generic Running Walking Sensor. */
#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_IN_SHOE 1089 /**< Running Walking Sensor: In-Shoe. */
#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_ON_SHOE 1090 /**< Running Walking Sensor: On-Shoe. */
#define BLE_APPEARANCE_RUNNING_WALKING_SENSOR_ON_HIP 1091 /**< Running Walking Sensor: On-Hip. */
#define BLE_APPEARANCE_GENERIC_CYCLING 1152 /**< Generic Cycling. */
#define BLE_APPEARANCE_CYCLING_CYCLING_COMPUTER 1153 /**< Cycling: Cycling Computer. */
#define BLE_APPEARANCE_CYCLING_SPEED_SENSOR 1154 /**< Cycling: Speed Sensor. */
#define BLE_APPEARANCE_CYCLING_CADENCE_SENSOR 1155 /**< Cycling: Cadence Sensor. */
#define BLE_APPEARANCE_CYCLING_POWER_SENSOR 1156 /**< Cycling: Power Sensor. */
#define BLE_APPEARANCE_CYCLING_SPEED_CADENCE_SENSOR 1157 /**< Cycling: Speed and Cadence Sensor. */
#define BLE_APPEARANCE_GENERIC_PULSE_OXIMETER 3136 /**< Generic Pulse Oximeter. */
#define BLE_APPEARANCE_PULSE_OXIMETER_FINGERTIP 3137 /**< Fingertip (Pulse Oximeter subtype). */
#define BLE_APPEARANCE_PULSE_OXIMETER_WRIST_WORN 3138 /**< Wrist Worn(Pulse Oximeter subtype). */
#define BLE_APPEARANCE_GENERIC_WEIGHT_SCALE 3200 /**< Generic Weight Scale. */
#define BLE_APPEARANCE_GENERIC_OUTDOOR_SPORTS_ACT 5184 /**< Generic Outdoor Sports Activity. */
#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_DISP 5185 /**< Location Display Device (Outdoor Sports Activity subtype). */
#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_AND_NAV_DISP 5186 /**< Location and Navigation Display Device (Outdoor Sports Activity subtype). */
#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_POD 5187 /**< Location Pod (Outdoor Sports Activity subtype). */
#define BLE_APPEARANCE_OUTDOOR_SPORTS_ACT_LOC_AND_NAV_POD 5188 /**< Location and Navigation Pod (Outdoor Sports Activity subtype). */
/** @} */
/** @brief Set .type and .uuid fields of ble_uuid_struct to specified uuid value. */
#define BLE_UUID_BLE_ASSIGN(instance, value) do {\
instance.type = BLE_UUID_TYPE_BLE; \
instance.uuid = value;} while(0)
/** @brief Copy type and uuid members from src to dst ble_uuid_t pointer. Both pointers must be valid/non-null. */
#define BLE_UUID_COPY_PTR(dst, src) do {\
(dst)->type = (src)->type; \
(dst)->uuid = (src)->uuid;} while(0)
/** @brief Copy type and uuid members from src to dst ble_uuid_t struct. */
#define BLE_UUID_COPY_INST(dst, src) do {\
(dst).type = (src).type; \
(dst).uuid = (src).uuid;} while(0)
/** @brief Compare for equality both type and uuid members of two (valid, non-null) ble_uuid_t pointers. */
#define BLE_UUID_EQ(p_uuid1, p_uuid2) \
(((p_uuid1)->type == (p_uuid2)->type) && ((p_uuid1)->uuid == (p_uuid2)->uuid))
/** @brief Compare for difference both type and uuid members of two (valid, non-null) ble_uuid_t pointers. */
#define BLE_UUID_NEQ(p_uuid1, p_uuid2) \
(((p_uuid1)->type != (p_uuid2)->type) || ((p_uuid1)->uuid != (p_uuid2)->uuid))
/** @} */
/** @addtogroup BLE_TYPES_STRUCTURES Structures
* @{ */
/** @brief 128 bit UUID values. */
typedef struct
{
uint8_t uuid128[16]; /**< Little-Endian UUID bytes. */
} ble_uuid128_t;
/** @brief Bluetooth Low Energy UUID type, encapsulates both 16-bit and 128-bit UUIDs. */
typedef struct
{
uint16_t uuid; /**< 16-bit UUID value or octets 12-13 of 128-bit UUID. */
uint8_t type; /**< UUID type, see @ref BLE_UUID_TYPES. If type is @ref BLE_UUID_TYPE_UNKNOWN, the value of uuid is undefined. */
} ble_uuid_t;
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* NRF_BLE_TYPES_H__ */
/**
@}
@}
*/

View File

@ -0,0 +1,90 @@
/*
* Copyright (c) 2000 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/**
@defgroup nrf_error SoftDevice Global Error Codes
@{
@brief Global Error definitions
*/
/* Header guard */
#ifndef NRF_ERROR_H__
#define NRF_ERROR_H__
#ifdef __cplusplus
extern "C" {
#endif
/** @defgroup NRF_ERRORS_BASE Error Codes Base number definitions
* @{ */
#define NRF_ERROR_BASE_NUM (0x0) ///< Global error base
#define NRF_ERROR_SDM_BASE_NUM (0x1000) ///< SDM error base
#define NRF_ERROR_SOC_BASE_NUM (0x2000) ///< SoC error base
#define NRF_ERROR_STK_BASE_NUM (0x3000) ///< STK error base
/** @} */
#define NRF_SUCCESS (NRF_ERROR_BASE_NUM + 0) ///< Successful command
#define NRF_ERROR_SVC_HANDLER_MISSING (NRF_ERROR_BASE_NUM + 1) ///< SVC handler is missing
#define NRF_ERROR_SOFTDEVICE_NOT_ENABLED (NRF_ERROR_BASE_NUM + 2) ///< SoftDevice has not been enabled
#define NRF_ERROR_INTERNAL (NRF_ERROR_BASE_NUM + 3) ///< Internal Error
#define NRF_ERROR_NO_MEM (NRF_ERROR_BASE_NUM + 4) ///< No Memory for operation
#define NRF_ERROR_NOT_FOUND (NRF_ERROR_BASE_NUM + 5) ///< Not found
#define NRF_ERROR_NOT_SUPPORTED (NRF_ERROR_BASE_NUM + 6) ///< Not supported
#define NRF_ERROR_INVALID_PARAM (NRF_ERROR_BASE_NUM + 7) ///< Invalid Parameter
#define NRF_ERROR_INVALID_STATE (NRF_ERROR_BASE_NUM + 8) ///< Invalid state, operation disallowed in this state
#define NRF_ERROR_INVALID_LENGTH (NRF_ERROR_BASE_NUM + 9) ///< Invalid Length
#define NRF_ERROR_INVALID_FLAGS (NRF_ERROR_BASE_NUM + 10) ///< Invalid Flags
#define NRF_ERROR_INVALID_DATA (NRF_ERROR_BASE_NUM + 11) ///< Invalid Data
#define NRF_ERROR_DATA_SIZE (NRF_ERROR_BASE_NUM + 12) ///< Invalid Data size
#define NRF_ERROR_TIMEOUT (NRF_ERROR_BASE_NUM + 13) ///< Operation timed out
#define NRF_ERROR_NULL (NRF_ERROR_BASE_NUM + 14) ///< Null Pointer
#define NRF_ERROR_FORBIDDEN (NRF_ERROR_BASE_NUM + 15) ///< Forbidden Operation
#define NRF_ERROR_INVALID_ADDR (NRF_ERROR_BASE_NUM + 16) ///< Bad Memory Address
#define NRF_ERROR_BUSY (NRF_ERROR_BASE_NUM + 17) ///< Busy
#define NRF_ERROR_CONN_COUNT (NRF_ERROR_BASE_NUM + 18) ///< Maximum connection count exceeded.
#define NRF_ERROR_RESOURCES (NRF_ERROR_BASE_NUM + 19) ///< Not enough resources for operation
#ifdef __cplusplus
}
#endif
#endif // NRF_ERROR_H__
/**
@}
*/

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 2000 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/**
@addtogroup nrf_sdm_api
@{
@defgroup nrf_sdm_error SoftDevice Manager Error Codes
@{
@brief Error definitions for the SDM API
*/
/* Header guard */
#ifndef NRF_ERROR_SDM_H__
#define NRF_ERROR_SDM_H__
#include "nrf_error.h"
#ifdef __cplusplus
extern "C" {
#endif
#define NRF_ERROR_SDM_LFCLK_SOURCE_UNKNOWN (NRF_ERROR_SDM_BASE_NUM + 0) ///< Unknown lfclk source.
#define NRF_ERROR_SDM_INCORRECT_INTERRUPT_CONFIGURATION (NRF_ERROR_SDM_BASE_NUM + 1) ///< Incorrect interrupt configuration (can be caused by using illegal priority levels, or having enabled SoftDevice interrupts).
#define NRF_ERROR_SDM_INCORRECT_CLENR0 (NRF_ERROR_SDM_BASE_NUM + 2) ///< Incorrect CLENR0 (can be caused by erronous SoftDevice flashing).
#ifdef __cplusplus
}
#endif
#endif // NRF_ERROR_SDM_H__
/**
@}
@}
*/

View File

@ -0,0 +1,85 @@
/*
* Copyright (c) 2000 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/**
@addtogroup nrf_soc_api
@{
@defgroup nrf_soc_error SoC Library Error Codes
@{
@brief Error definitions for the SoC library
*/
/* Header guard */
#ifndef NRF_ERROR_SOC_H__
#define NRF_ERROR_SOC_H__
#include "nrf_error.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Mutex Errors */
#define NRF_ERROR_SOC_MUTEX_ALREADY_TAKEN (NRF_ERROR_SOC_BASE_NUM + 0) ///< Mutex already taken
/* NVIC errors */
#define NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE (NRF_ERROR_SOC_BASE_NUM + 1) ///< NVIC interrupt not available
#define NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED (NRF_ERROR_SOC_BASE_NUM + 2) ///< NVIC interrupt priority not allowed
#define NRF_ERROR_SOC_NVIC_SHOULD_NOT_RETURN (NRF_ERROR_SOC_BASE_NUM + 3) ///< NVIC should not return
/* Power errors */
#define NRF_ERROR_SOC_POWER_MODE_UNKNOWN (NRF_ERROR_SOC_BASE_NUM + 4) ///< Power mode unknown
#define NRF_ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN (NRF_ERROR_SOC_BASE_NUM + 5) ///< Power POF threshold unknown
#define NRF_ERROR_SOC_POWER_OFF_SHOULD_NOT_RETURN (NRF_ERROR_SOC_BASE_NUM + 6) ///< Power off should not return
/* Rand errors */
#define NRF_ERROR_SOC_RAND_NOT_ENOUGH_VALUES (NRF_ERROR_SOC_BASE_NUM + 7) ///< RAND not enough values
/* PPI errors */
#define NRF_ERROR_SOC_PPI_INVALID_CHANNEL (NRF_ERROR_SOC_BASE_NUM + 8) ///< Invalid PPI Channel
#define NRF_ERROR_SOC_PPI_INVALID_GROUP (NRF_ERROR_SOC_BASE_NUM + 9) ///< Invalid PPI Group
#ifdef __cplusplus
}
#endif
#endif // NRF_ERROR_SOC_H__
/**
@}
@}
*/

View File

@ -0,0 +1,486 @@
/*
* Copyright (c) 2000 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/**
* @defgroup nrf_nvic_api SoftDevice NVIC API
* @{
*
* @note In order to use this module, the following code has to be added to a .c file:
* \code
* nrf_nvic_state_t nrf_nvic_state;
* \endcode
*
* @note Definitions and declarations starting with __ (double underscore) in this header file are
* not intended for direct use by the application.
*
* @brief APIs for the accessing NVIC when using a SoftDevice.
*
*/
#ifndef NRF_NVIC_H__
#define NRF_NVIC_H__
#include <stdint.h>
#include "nrf.h"
#include "nrf_error_soc.h"
#ifdef __cplusplus
extern "C" {
#endif
/**@addtogroup NRF_NVIC_DEFINES Defines
* @{ */
/**@defgroup NRF_NVIC_ISER_DEFINES SoftDevice NVIC internal definitions
* @{ */
#define __NRF_NVIC_NVMC_IRQn (30) /**< The peripheral ID of the NVMC. IRQ numbers are used to identify peripherals, but the NVMC doesn't have an IRQ number in the MDK. */
#ifdef NRF51
#define __NRF_NVIC_ISER_COUNT (1) /**< The number of ISER/ICER registers in the NVIC that are used. */
/**@brief Interrupts used by the SoftDevice. */
#define __NRF_NVIC_SD_IRQS_0 ((uint32_t)( \
(1U << POWER_CLOCK_IRQn) \
| (1U << RADIO_IRQn) \
| (1U << RTC0_IRQn) \
| (1U << TIMER0_IRQn) \
| (1U << RNG_IRQn) \
| (1U << ECB_IRQn) \
| (1U << CCM_AAR_IRQn) \
| (1U << TEMP_IRQn) \
| (1U << __NRF_NVIC_NVMC_IRQn) \
| (1U << (uint32_t)SWI4_IRQn) \
| (1U << (uint32_t)SWI5_IRQn) \
))
/**@brief Interrupts available for to application. */
#define __NRF_NVIC_APP_IRQS_0 (~__NRF_NVIC_SD_IRQS_0)
#endif
#ifdef NRF52
#define __NRF_NVIC_ISER_COUNT (2) /**< The number of ISER/ICER registers in the NVIC that are used. */
/**@brief Interrupts used by the SoftDevice. */
#define __NRF_NVIC_SD_IRQS_0 ((uint32_t)( \
(1U << POWER_CLOCK_IRQn) \
| (1U << RADIO_IRQn) \
| (1U << RTC0_IRQn) \
| (1U << TIMER0_IRQn) \
| (1U << RNG_IRQn) \
| (1U << ECB_IRQn) \
| (1U << CCM_AAR_IRQn) \
| (1U << TEMP_IRQn) \
| (1U << __NRF_NVIC_NVMC_IRQn) \
| (1U << (uint32_t)SWI4_EGU4_IRQn) \
| (1U << (uint32_t)SWI5_EGU5_IRQn) \
))
#define __NRF_NVIC_SD_IRQS_1 ((uint32_t)0)
/**@brief Interrupts available for to application. */
#define __NRF_NVIC_APP_IRQS_0 (~__NRF_NVIC_SD_IRQS_0)
#define __NRF_NVIC_APP_IRQS_1 (~__NRF_NVIC_SD_IRQS_1)
#endif
/**@} */
/**@} */
/**@addtogroup NRF_NVIC_VARIABLES Variables
* @{ */
/**@brief Type representing the state struct for the SoftDevice NVIC module. */
typedef struct
{
uint32_t volatile __irq_masks[__NRF_NVIC_ISER_COUNT]; /**< IRQs enabled by the application in the NVIC. */
uint32_t volatile __cr_flag; /**< Non-zero if already in a critical region */
} nrf_nvic_state_t;
/**@brief Variable keeping the state for the SoftDevice NVIC module. This must be declared in an
* application source file. */
extern nrf_nvic_state_t nrf_nvic_state;
/**@} */
/**@addtogroup NRF_NVIC_INTERNAL_FUNCTIONS SoftDevice NVIC internal functions
* @{ */
/**@brief Disables IRQ interrupts globally, including the SoftDevice's interrupts.
*
* @retval The value of PRIMASK prior to disabling the interrupts.
*/
static inline int __sd_nvic_irq_disable(void)
{
int pm = __get_PRIMASK();
__disable_irq();
return pm;
}
/**@brief Enables IRQ interrupts globally, including the SoftDevice's interrupts.
*/
static inline void __sd_nvic_irq_enable(void)
{
__enable_irq();
}
/**@brief Checks if IRQn is available to application
* @param[in] IRQn irq to check
*
* @retval 1 (true) if the irq to check is available to the application
*/
static inline uint32_t __sd_nvic_app_accessible_irq(IRQn_Type IRQn)
{
if (IRQn < 32)
{
return ((1UL<<IRQn) & __NRF_NVIC_APP_IRQS_0) != 0;
}
#ifdef NRF52
else if (IRQn < 64)
{
return ((1UL<<(IRQn-32)) & __NRF_NVIC_APP_IRQS_1) != 0;
}
#endif
else
{
return 1;
}
}
/**@brief Checks if IRQn is available to application
* @param[in] priority priority to check
*
* @retval 1 (true) if the priority to check is available to the application
*/
static inline uint32_t __sd_nvic_is_app_accessible_priority(uint32_t priority)
{
if(priority >= (1 << __NVIC_PRIO_BITS))
{
return 0;
}
#ifdef NRF51
if( priority == 0
|| priority == 2
)
{
return 0;
}
#endif
#ifdef NRF52
if( priority == 0
|| priority == 1
|| priority == 4
|| priority == 5
)
{
return 0;
}
#endif
return 1;
}
/**@} */
/**@addtogroup NRF_NVIC_FUNCTIONS SoftDevice NVIC public functions
* @{ */
/**@brief Enable External Interrupt.
* @note Corresponds to NVIC_EnableIRQ in CMSIS.
*
* @pre IRQn is valid and not reserved by the stack.
*
* @param[in] IRQn See the NVIC_EnableIRQ documentation in CMSIS.
*
* @retval ::NRF_SUCCESS The interrupt was enabled.
* @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE The interrupt is not available for the application.
* @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED The interrupt has a priority not available for the application.
*/
static inline uint32_t sd_nvic_EnableIRQ(IRQn_Type IRQn)
{
if (!__sd_nvic_app_accessible_irq(IRQn))
{
return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE;
}
if (!__sd_nvic_is_app_accessible_priority(NVIC_GetPriority(IRQn)))
{
return NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED;
}
if (nrf_nvic_state.__cr_flag)
{
nrf_nvic_state.__irq_masks[(uint32_t)((int32_t)IRQn) >> 5] |= (uint32_t)(1 << ((uint32_t)((int32_t)IRQn) & (uint32_t)0x1F));
}
else
{
NVIC_EnableIRQ(IRQn);
}
return NRF_SUCCESS;
}
/**@brief Disable External Interrupt.
* @note Corresponds to NVIC_DisableIRQ in CMSIS.
*
* @pre IRQn is valid and not reserved by the stack.
*
* @param[in] IRQn See the NVIC_DisableIRQ documentation in CMSIS.
*
* @retval ::NRF_SUCCESS The interrupt was disabled.
* @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE The interrupt is not available for the application.
*/
static inline uint32_t sd_nvic_DisableIRQ(IRQn_Type IRQn)
{
if (!__sd_nvic_app_accessible_irq(IRQn))
{
return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE;
}
if (nrf_nvic_state.__cr_flag)
{
nrf_nvic_state.__irq_masks[(uint32_t)((int32_t)IRQn) >> 5] &= ~(1UL << ((uint32_t)(IRQn) & 0x1F));
}
else
{
NVIC_DisableIRQ(IRQn);
}
return NRF_SUCCESS;
}
/**@brief Get Pending Interrupt.
* @note Corresponds to NVIC_GetPendingIRQ in CMSIS.
*
* @pre IRQn is valid and not reserved by the stack.
*
* @param[in] IRQn See the NVIC_GetPendingIRQ documentation in CMSIS.
* @param[out] p_pending_irq Return value from NVIC_GetPendingIRQ.
*
* @retval ::NRF_SUCCESS The interrupt is available for the application.
* @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application.
*/
static inline uint32_t sd_nvic_GetPendingIRQ(IRQn_Type IRQn, uint32_t * p_pending_irq)
{
if (__sd_nvic_app_accessible_irq(IRQn))
{
*p_pending_irq = NVIC_GetPendingIRQ(IRQn);
return NRF_SUCCESS;
}
else
{
return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE;
}
}
/**@brief Set Pending Interrupt.
* @note Corresponds to NVIC_SetPendingIRQ in CMSIS.
*
* @pre IRQn is valid and not reserved by the stack.
*
* @param[in] IRQn See the NVIC_SetPendingIRQ documentation in CMSIS.
*
* @retval ::NRF_SUCCESS The interrupt is set pending.
* @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application.
*/
static inline uint32_t sd_nvic_SetPendingIRQ(IRQn_Type IRQn)
{
if (__sd_nvic_app_accessible_irq(IRQn))
{
NVIC_SetPendingIRQ(IRQn);
return NRF_SUCCESS;
}
else
{
return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE;
}
}
/**@brief Clear Pending Interrupt.
* @note Corresponds to NVIC_ClearPendingIRQ in CMSIS.
*
* @pre IRQn is valid and not reserved by the stack.
*
* @param[in] IRQn See the NVIC_ClearPendingIRQ documentation in CMSIS.
*
* @retval ::NRF_SUCCESS The interrupt pending flag is cleared.
* @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application.
*/
static inline uint32_t sd_nvic_ClearPendingIRQ(IRQn_Type IRQn)
{
if (__sd_nvic_app_accessible_irq(IRQn))
{
NVIC_ClearPendingIRQ(IRQn);
return NRF_SUCCESS;
}
else
{
return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE;
}
}
/**@brief Set Interrupt Priority.
* @note Corresponds to NVIC_SetPriority in CMSIS.
*
* @pre IRQn is valid and not reserved by the stack.
* @pre Priority is valid and not reserved by the stack.
*
* @param[in] IRQn See the NVIC_SetPriority documentation in CMSIS.
* @param[in] priority A valid IRQ priority for use by the application.
*
* @retval ::NRF_SUCCESS The interrupt and priority level is available for the application.
* @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE IRQn is not available for the application.
* @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED The interrupt priority is not available for the application.
*/
static inline uint32_t sd_nvic_SetPriority(IRQn_Type IRQn, uint32_t priority)
{
if (!__sd_nvic_app_accessible_irq(IRQn))
{
return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE;
}
if (!__sd_nvic_is_app_accessible_priority(priority))
{
return NRF_ERROR_SOC_NVIC_INTERRUPT_PRIORITY_NOT_ALLOWED;
}
NVIC_SetPriority(IRQn, (uint32_t)priority);
return NRF_SUCCESS;
}
/**@brief Get Interrupt Priority.
* @note Corresponds to NVIC_GetPriority in CMSIS.
*
* @pre IRQn is valid and not reserved by the stack.
*
* @param[in] IRQn See the NVIC_GetPriority documentation in CMSIS.
* @param[out] p_priority Return value from NVIC_GetPriority.
*
* @retval ::NRF_SUCCESS The interrupt priority is returned in p_priority.
* @retval ::NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE - IRQn is not available for the application.
*/
static inline uint32_t sd_nvic_GetPriority(IRQn_Type IRQn, uint32_t * p_priority)
{
if (__sd_nvic_app_accessible_irq(IRQn))
{
*p_priority = (NVIC_GetPriority(IRQn) & 0xFF);
return NRF_SUCCESS;
}
else
{
return NRF_ERROR_SOC_NVIC_INTERRUPT_NOT_AVAILABLE;
}
}
/**@brief System Reset.
* @note Corresponds to NVIC_SystemReset in CMSIS.
*
* @retval ::NRF_ERROR_SOC_NVIC_SHOULD_NOT_RETURN
*/
static inline uint32_t sd_nvic_SystemReset(void)
{
NVIC_SystemReset();
return NRF_ERROR_SOC_NVIC_SHOULD_NOT_RETURN;
}
/**@brief Enters critical region.
*
* @post Application interrupts will be disabled.
* @note sd_nvic_critical_region_enter() and ::sd_nvic_critical_region_exit() must be called in matching pairs inside each
* execution context
* @sa sd_nvic_critical_region_exit
*
* @retval ::NRF_SUCCESS
*/
static inline uint32_t sd_nvic_critical_region_enter(uint8_t * p_is_nested_critical_region)
{
int was_masked = __sd_nvic_irq_disable();
if (!nrf_nvic_state.__cr_flag)
{
nrf_nvic_state.__cr_flag = 1;
nrf_nvic_state.__irq_masks[0] = ( NVIC->ICER[0] & __NRF_NVIC_APP_IRQS_0 );
NVIC->ICER[0] = __NRF_NVIC_APP_IRQS_0;
#ifdef NRF52
nrf_nvic_state.__irq_masks[1] = ( NVIC->ICER[1] & __NRF_NVIC_APP_IRQS_1 );
NVIC->ICER[1] = __NRF_NVIC_APP_IRQS_1;
#endif
*p_is_nested_critical_region = 0;
}
else
{
*p_is_nested_critical_region = 1;
}
if (!was_masked)
{
__sd_nvic_irq_enable();
}
return NRF_SUCCESS;
}
/**@brief Exit critical region.
*
* @pre Application has entered a critical region using ::sd_nvic_critical_region_enter.
* @post If not in a nested critical region, the application interrupts will restored to the state before ::sd_nvic_critical_region_enter was called.
*
* @param[in] is_nested_critical_region If this is set to 1, the critical region won't be exited. @sa sd_nvic_critical_region_enter.
*
* @retval ::NRF_SUCCESS
*/
static inline uint32_t sd_nvic_critical_region_exit(uint8_t is_nested_critical_region)
{
if (nrf_nvic_state.__cr_flag && (is_nested_critical_region == 0))
{
int was_masked = __sd_nvic_irq_disable();
NVIC->ISER[0] = nrf_nvic_state.__irq_masks[0];
#ifdef NRF52
NVIC->ISER[1] = nrf_nvic_state.__irq_masks[1];
#endif
nrf_nvic_state.__cr_flag = 0;
if (!was_masked)
{
__sd_nvic_irq_enable();
}
}
return NRF_SUCCESS;
}
/**@} */
#ifdef __cplusplus
}
#endif
#endif // NRF_NVIC_H__
/**@} */

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 2015 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#ifndef NRF_SD_DEF_H__
#define NRF_SD_DEF_H__
#include <stdint.h>
#define SD_PPI_CHANNELS_USED 0xFFF0C000uL /**< PPI channels utilized by SotfDevice (not available to the application). */
#define SD_PPI_GROUPS_USED 0x0000000CuL /**< PPI groups utilized by SoftDevice (not available to the application). */
#define SD_TIMERS_USED 0x00000001uL /**< Timers used by SoftDevice. */
#define SD_SWI_USED 0x0000003CuL /**< Software interrupts used by SoftDevice */
#endif /* NRF_SD_DEF_H__ */

View File

@ -0,0 +1,274 @@
/*
* Copyright (c) 2000 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/**
@defgroup nrf_sdm_api SoftDevice Manager API
@{
@brief APIs for SoftDevice management.
*/
/* Header guard */
#ifndef NRF_SDM_H__
#define NRF_SDM_H__
#include "nrf_svc.h"
#include "nrf.h"
#include "nrf_soc.h"
#include "nrf_error_sdm.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @addtogroup NRF_SDM_DEFINES Defines
* @{ */
#ifdef NRFSOC_DOXYGEN
//Stuff defined elsewere, to satisfy doxygen
#define MBR_SIZE 0
#warning test
#endif
/** @brief SoftDevice Manager SVC Base number. */
#define SDM_SVC_BASE 0x10
/** @brief Defines the SoftDevice Information Structure location (address) as an offset from
the start of the softdevice (without MBR)*/
#define SOFTDEVICE_INFO_STRUCT_OFFSET (0x2000)
/** @brief Defines the absolute Softdevice information structure location (address)*/
#define SOFTDEVICE_INFO_STRUCT_ADDRESS (SOFTDEVICE_INFO_STRUCT_OFFSET + MBR_SIZE)
/** @brief Defines the offset for Softdevice size value relative to Softdevice base address*/
#define SD_SIZE_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x08)
/** @brief Defines the offset for FWID value relative to Softdevice base address*/
#define SD_FWID_OFFSET (SOFTDEVICE_INFO_STRUCT_OFFSET + 0x0C)
/** @brief Defines a macro for retreiving the actual Softdevice size value from a given base address
use @ref MBR_SIZE when Softdevice is installed just above the MBR (the usual case)*/
#define SD_SIZE_GET(baseaddr) (*((uint32_t *) ((baseaddr) + SD_SIZE_OFFSET)))
/** @brief Defines a macro for retreiving the actual FWID value from a given base address
use @ref MBR_SIZE when Softdevice is installed just above the MBR (the usual case)*/
#define SD_FWID_GET(baseaddr) ((*((uint32_t *) ((baseaddr) + SD_FWID_OFFSET))) & 0xFFFF)
/**@defgroup NRF_FAULT_ID_RANGES Fault ID ranges
* @{ */
#define NRF_FAULT_ID_SD_RANGE_START 0x00000000 /**< SoftDevice ID range start. */
#define NRF_FAULT_ID_APP_RANGE_START 0x00001000 /**< Application ID range start. */
/**@} */
/**@defgroup NRF_FAULT_IDS Fault ID types
* @{ */
#define NRF_FAULT_ID_SD_ASSERT (NRF_FAULT_ID_SD_RANGE_START + 1) /**< SoftDevice assertion. The info parameter will be set to 0x00000000. */
#define NRF_FAULT_ID_APP_MEMACC (NRF_FAULT_ID_APP_RANGE_START + 1) /**< Application invalid memory access. The info parameter will contain the address in memory that was accessed. */
/**@} */
/** @} */
/** @addtogroup NRF_SDM_ENUMS Enumerations
* @{ */
/**@brief nRF SoftDevice Manager API SVC numbers. */
enum NRF_SD_SVCS
{
SD_SOFTDEVICE_ENABLE = SDM_SVC_BASE, /**< ::sd_softdevice_enable */
SD_SOFTDEVICE_DISABLE, /**< ::sd_softdevice_disable */
SD_SOFTDEVICE_IS_ENABLED, /**< ::sd_softdevice_is_enabled */
SD_SOFTDEVICE_VECTOR_TABLE_BASE_SET, /**< ::sd_softdevice_vector_table_base_set */
SVC_SDM_LAST /**< Placeholder for last SDM SVC */
};
/** @} */
/** @addtogroup NRF_SDM_DEFINES Defines
* @{ */
/**@defgroup NRF_CLOCK_LF_XTAL_ACCURACY Clock accuracy * @{ */
#define NRF_CLOCK_LF_XTAL_ACCURACY_250_PPM (0) /* Default */
#define NRF_CLOCK_LF_XTAL_ACCURACY_500_PPM (1)
#define NRF_CLOCK_LF_XTAL_ACCURACY_150_PPM (2)
#define NRF_CLOCK_LF_XTAL_ACCURACY_100_PPM (3)
#define NRF_CLOCK_LF_XTAL_ACCURACY_75_PPM (4)
#define NRF_CLOCK_LF_XTAL_ACCURACY_50_PPM (5)
#define NRF_CLOCK_LF_XTAL_ACCURACY_30_PPM (6)
#define NRF_CLOCK_LF_XTAL_ACCURACY_20_PPM (7)
/** @} */
/**@defgroup NRF_CLOCK_LF_SRC Possible lfclk oscillator sources * @{ */
#define NRF_CLOCK_LF_SRC_RC (0) /**< LFCLK RC oscillator. */
#define NRF_CLOCK_LF_SRC_XTAL (1) /**< LFCLK crystal oscillator. */
#define NRF_CLOCK_LF_SRC_SYNTH (2) /**< LFCLK Synthesized from HFCLK. */
/** @} */
/** @} */
/** @addtogroup NRF_SDM_TYPES Types
* @{ */
/**@brief Type representing lfclk oscillator source. */
typedef struct
{
uint8_t source; /**< LF oscillator clock source, see @ref NRF_CLOCK_LF_SRC. */
uint8_t rc_ctiv; /**< Only for NRF_CLOCK_LF_SRC_RC: Calibration timer interval in 1/4 second
units (nRF51: 1-64, nRF52: 1-32).
@note To avoid excessive clock drift, 0.5 degrees Celsius is the
maximum temperature change allowed in one calibration timer
interval. The interval should be selected to ensure this.
@note Must be 0 if source is not NRF_CLOCK_LF_SRC_RC. */
uint8_t rc_temp_ctiv; /**< Only for NRF_CLOCK_LF_SRC_RC: How often (in number of calibration
intervals) the RC oscillator shall be calibrated if the temperature
hasn't changed.
0: Always calibrate even if the temperature hasn't changed.
1: Only calibrate if the temperature has changed (nRF51 only).
2-33: Check the temperature and only calibrate if it has changed,
however calibration will take place every rc_temp_ctiv
intervals in any case.
@note Must be 0 if source is not NRF_CLOCK_LF_SRC_RC.
@note For nRF52, the application must ensure calibration at least once
every 8 seconds to ensure +/-250ppm clock stability. The
recommended configuration for NRF_CLOCK_LF_SRC_RC on nRF52 is
rc_ctiv=16 and rc_temp_ctiv=2. This will ensure calibration at
least once every 8 seconds and for temperature changes of 0.5
degrees Celsius every 4 seconds. See the Product Specification
for the nRF52 device being used for more information.*/
uint8_t xtal_accuracy; /**< External crystal clock accuracy used in the LL to compute timing windows.
@note For the NRF_CLOCK_LF_SRC_RC clock source this parameter is ignored. */
} nrf_clock_lf_cfg_t;
/**@brief Fault Handler type.
*
* When certain unrecoverable errors occur within the application or SoftDevice the fault handler will be called back.
* The protocol stack will be in an undefined state when this happens and the only way to recover will be to
* perform a reset, using e.g. CMSIS NVIC_SystemReset().
*
* @note This callback is executed in HardFault context, thus SVC functions cannot be called from the fault callback.
*
* @param[in] id Fault identifier. See @ref NRF_FAULT_IDS.
* @param[in] pc The program counter of the instruction that triggered the fault.
* @param[in] info Optional additional information regarding the fault. Refer to each Fault identifier for details.
*/
typedef void (*nrf_fault_handler_t)(uint32_t id, uint32_t pc, uint32_t info);
/** @} */
/** @addtogroup NRF_SDM_FUNCTIONS Functions
* @{ */
/**@brief Enables the SoftDevice and by extension the protocol stack.
*
* @note Some care must be taken if a low frequency clock source is already running when calling this function:
* If the LF clock has a different source then the one currently running, it will be stopped. Then, the new
* clock source will be started.
*
* @note This function has no effect when returning with an error.
*
* @post If return code is ::NRF_SUCCESS
* - SoC library and protocol stack APIs are made available.
* - A portion of RAM will be unavailable (see relevant SDS documentation).
* - Some peripherals will be unavailable or available only through the SoC API (see relevant SDS documentation).
* - Interrupts will not arrive from protected peripherals or interrupts.
* - nrf_nvic_ functions must be used instead of CMSIS NVIC_ functions for reliable usage of the SoftDevice.
* - Interrupt latency may be affected by the SoftDevice (see relevant SDS documentation).
* - Chosen low frequency clock source will be running.
*
* @param p_clock_lf_cfg Low frequency clock source and accuracy.
If NULL the clock will be configured as an rc source with rc_ctiv = 16 and .rc_temp_ctiv = 2
In the case of XTAL source, the PPM accuracy of the chosen clock source must be greater than or equal to the actual characteristics of your XTAL clock.
* @param fault_handler Callback to be invoked in case of fault.
*
* @retval ::NRF_SUCCESS
* @retval ::NRF_ERROR_INVALID_STATE SoftDevice is already enabled, and the clock source and fault handler cannot be updated.
* @retval ::NRF_ERROR_SDM_INCORRECT_INTERRUPT_CONFIGURATION SoftDevice interrupt is already enabled, or an enabled interrupt has an illegal priority level.
* @retval ::NRF_ERROR_SDM_LFCLK_SOURCE_UNKNOWN Unknown low frequency clock source selected.
*/
SVCALL(SD_SOFTDEVICE_ENABLE, uint32_t, sd_softdevice_enable(nrf_clock_lf_cfg_t const * p_clock_lf_cfg, nrf_fault_handler_t fault_handler));
/**@brief Disables the SoftDevice and by extension the protocol stack.
*
* Idempotent function to disable the SoftDevice.
*
* @post SoC library and protocol stack APIs are made unavailable.
* @post All interrupts that was protected by the SoftDevice will be disabled and initialized to priority 0 (highest).
* @post All peripherals used by the SoftDevice will be reset to default values.
* @post All of RAM become available.
* @post All interrupts are forwarded to the application.
* @post LFCLK source chosen in ::sd_softdevice_enable will be left running.
*
* @retval ::NRF_SUCCESS
*/
SVCALL(SD_SOFTDEVICE_DISABLE, uint32_t, sd_softdevice_disable(void));
/**@brief Check if the SoftDevice is enabled.
*
* @param[out] p_softdevice_enabled If the SoftDevice is enabled: 1 else 0.
*
* @retval ::NRF_SUCCESS
*/
SVCALL(SD_SOFTDEVICE_IS_ENABLED, uint32_t, sd_softdevice_is_enabled(uint8_t * p_softdevice_enabled));
/**@brief Sets the base address of the interrupt vector table for interrupts forwarded from the SoftDevice
*
* This function is only intended to be called when a bootloader is enabled.
*
* @param[in] address The base address of the interrupt vector table for forwarded interrupts.
* @retval ::NRF_SUCCESS
*/
SVCALL(SD_SOFTDEVICE_VECTOR_TABLE_BASE_SET, uint32_t, sd_softdevice_vector_table_base_set(uint32_t address));
/** @} */
#ifdef __cplusplus
}
#endif
#endif // NRF_SDM_H__
/**
@}
*/

View File

@ -0,0 +1,911 @@
/*
* Copyright (c) 2000 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/**
* @defgroup nrf_soc_api SoC Library API
* @{
*
* @brief APIs for the SoC library.
*
*/
#ifndef NRF_SOC_H__
#define NRF_SOC_H__
#include <stdint.h>
#include <stdbool.h>
#include "nrf_svc.h"
#include "nrf.h"
#include "nrf_error_soc.h"
#ifdef __cplusplus
extern "C" {
#endif
/**@addtogroup NRF_SOC_DEFINES Defines
* @{ */
/**@brief The number of the lowest SVC number reserved for the SoC library. */
#define SOC_SVC_BASE (0x20)
#define SOC_SVC_BASE_NOT_AVAILABLE (0x2B)
/**@brief Guranteed time for application to process radio inactive notification. */
#define NRF_RADIO_NOTIFICATION_INACTIVE_GUARANTEED_TIME_US (62)
/**@brief The minimum allowed timeslot extension time. */
#define NRF_RADIO_MINIMUM_TIMESLOT_LENGTH_EXTENSION_TIME_US (200)
#define SOC_ECB_KEY_LENGTH (16) /**< ECB key length. */
#define SOC_ECB_CLEARTEXT_LENGTH (16) /**< ECB cleartext length. */
#define SOC_ECB_CIPHERTEXT_LENGTH (SOC_ECB_CLEARTEXT_LENGTH) /**< ECB ciphertext length. */
#ifdef NRF51
#define SD_EVT_IRQn (SWI2_IRQn) /**< SoftDevice Event IRQ number. Used for both protocol events and SoC events. */
#define SD_EVT_IRQHandler (SWI2_IRQHandler) /**< SoftDevice Event IRQ handler. Used for both protocol events and SoC events. */
#define RADIO_NOTIFICATION_IRQn (SWI1_IRQn) /**< The radio notification IRQ number. */
#define RADIO_NOTIFICATION_IRQHandler (SWI1_IRQHandler) /**< The radio notification IRQ handler. */
#endif
#ifdef NRF52
#define SD_EVT_IRQn (SWI2_EGU2_IRQn) /**< SoftDevice Event IRQ number. Used for both protocol events and SoC events. */
#define SD_EVT_IRQHandler (SWI2_EGU2_IRQHandler) /**< SoftDevice Event IRQ handler. Used for both protocol events and SoC events. */
#define RADIO_NOTIFICATION_IRQn (SWI1_EGU1_IRQn) /**< The radio notification IRQ number. */
#define RADIO_NOTIFICATION_IRQHandler (SWI1_EGU1_IRQHandler) /**< The radio notification IRQ handler. */
#endif
#define NRF_RADIO_LENGTH_MIN_US (100) /**< The shortest allowed radio timeslot, in microseconds. */
#define NRF_RADIO_LENGTH_MAX_US (100000) /**< The longest allowed radio timeslot, in microseconds. */
#define NRF_RADIO_DISTANCE_MAX_US (128000000UL - 1UL) /**< The longest timeslot distance, in microseconds, allowed for the distance parameter (see @ref nrf_radio_request_normal_t) in the request. */
#define NRF_RADIO_EARLIEST_TIMEOUT_MAX_US (128000000UL - 1UL) /**< The longest timeout, in microseconds, allowed when requesting the earliest possible timeslot. */
#define NRF_RADIO_START_JITTER_US (2) /**< The maximum jitter in @ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START relative to the requested start time. */
/**@} */
/**@addtogroup NRF_SOC_ENUMS Enumerations
* @{ */
/**@brief The SVC numbers used by the SVC functions in the SoC library. */
enum NRF_SOC_SVCS
{
SD_PPI_CHANNEL_ENABLE_GET = SOC_SVC_BASE,
SD_PPI_CHANNEL_ENABLE_SET,
SD_PPI_CHANNEL_ENABLE_CLR,
SD_PPI_CHANNEL_ASSIGN,
SD_PPI_GROUP_TASK_ENABLE,
SD_PPI_GROUP_TASK_DISABLE,
SD_PPI_GROUP_ASSIGN,
SD_PPI_GROUP_GET,
SD_FLASH_PAGE_ERASE,
SD_FLASH_WRITE,
SD_FLASH_PROTECT,
SD_MUTEX_NEW = SOC_SVC_BASE_NOT_AVAILABLE,
SD_MUTEX_ACQUIRE,
SD_MUTEX_RELEASE,
SD_RFU_1,
SD_RFU_2,
SD_RFU_3,
SD_RFU_4,
SD_RFU_5,
SD_RFU_6,
SD_RFU_7,
SD_RFU_8,
SD_RFU_9,
SD_RFU_10,
SD_RAND_APPLICATION_POOL_CAPACITY_GET,
SD_RAND_APPLICATION_BYTES_AVAILABLE_GET,
SD_RAND_APPLICATION_VECTOR_GET,
SD_POWER_MODE_SET,
SD_POWER_SYSTEM_OFF,
SD_POWER_RESET_REASON_GET,
SD_POWER_RESET_REASON_CLR,
SD_POWER_POF_ENABLE,
SD_POWER_POF_THRESHOLD_SET,
SD_POWER_RAMON_SET,
SD_POWER_RAMON_CLR,
SD_POWER_RAMON_GET,
SD_POWER_GPREGRET_SET,
SD_POWER_GPREGRET_CLR,
SD_POWER_GPREGRET_GET,
SD_POWER_DCDC_MODE_SET,
SD_APP_EVT_WAIT,
SD_CLOCK_HFCLK_REQUEST,
SD_CLOCK_HFCLK_RELEASE,
SD_CLOCK_HFCLK_IS_RUNNING,
SD_RADIO_NOTIFICATION_CFG_SET,
SD_ECB_BLOCK_ENCRYPT,
SD_ECB_BLOCKS_ENCRYPT,
SD_RADIO_SESSION_OPEN,
SD_RADIO_SESSION_CLOSE,
SD_RADIO_REQUEST,
SD_EVT_GET,
SD_TEMP_GET,
SVC_SOC_LAST
};
/**@brief Possible values of a ::nrf_mutex_t. */
enum NRF_MUTEX_VALUES
{
NRF_MUTEX_FREE,
NRF_MUTEX_TAKEN
};
/**@brief Power modes. */
enum NRF_POWER_MODES
{
NRF_POWER_MODE_CONSTLAT, /**< Constant latency mode. See power management in the reference manual. */
NRF_POWER_MODE_LOWPWR /**< Low power mode. See power management in the reference manual. */
};
/**@brief Power failure thresholds */
enum NRF_POWER_THRESHOLDS
{
NRF_POWER_THRESHOLD_V21, /**< 2.1 Volts power failure threshold. */
NRF_POWER_THRESHOLD_V23, /**< 2.3 Volts power failure threshold. */
NRF_POWER_THRESHOLD_V25, /**< 2.5 Volts power failure threshold. */
NRF_POWER_THRESHOLD_V27 /**< 2.7 Volts power failure threshold. */
};
/**@brief DC/DC converter modes. */
enum NRF_POWER_DCDC_MODES
{
NRF_POWER_DCDC_DISABLE, /**< The DCDC is disabled. */
NRF_POWER_DCDC_ENABLE /**< The DCDC is enabled. */
};
/**@brief Radio notification distances. */
enum NRF_RADIO_NOTIFICATION_DISTANCES
{
NRF_RADIO_NOTIFICATION_DISTANCE_NONE = 0, /**< The event does not have a notification. */
NRF_RADIO_NOTIFICATION_DISTANCE_800US, /**< The distance from the active notification to start of radio activity. */
NRF_RADIO_NOTIFICATION_DISTANCE_1740US, /**< The distance from the active notification to start of radio activity. */
NRF_RADIO_NOTIFICATION_DISTANCE_2680US, /**< The distance from the active notification to start of radio activity. */
NRF_RADIO_NOTIFICATION_DISTANCE_3620US, /**< The distance from the active notification to start of radio activity. */
NRF_RADIO_NOTIFICATION_DISTANCE_4560US, /**< The distance from the active notification to start of radio activity. */
NRF_RADIO_NOTIFICATION_DISTANCE_5500US /**< The distance from the active notification to start of radio activity. */
};
/**@brief Radio notification types. */
enum NRF_RADIO_NOTIFICATION_TYPES
{
NRF_RADIO_NOTIFICATION_TYPE_NONE = 0, /**< The event does not have a radio notification signal. */
NRF_RADIO_NOTIFICATION_TYPE_INT_ON_ACTIVE, /**< Using interrupt for notification when the radio will be enabled. */
NRF_RADIO_NOTIFICATION_TYPE_INT_ON_INACTIVE, /**< Using interrupt for notification when the radio has been disabled. */
NRF_RADIO_NOTIFICATION_TYPE_INT_ON_BOTH, /**< Using interrupt for notification both when the radio will be enabled and disabled. */
};
/**@brief The Radio signal callback types. */
enum NRF_RADIO_CALLBACK_SIGNAL_TYPE
{
NRF_RADIO_CALLBACK_SIGNAL_TYPE_START, /**< This signal indicates the start of the radio timeslot. */
NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0, /**< This signal indicates the NRF_TIMER0 interrupt. */
NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO, /**< This signal indicates the NRF_RADIO interrupt. */
NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_FAILED, /**< This signal indicates extend action failed. */
NRF_RADIO_CALLBACK_SIGNAL_TYPE_EXTEND_SUCCEEDED /**< This signal indicates extend action succeeded. */
};
/**@brief The actions requested by the signal callback.
*
* This code gives the SOC instructions about what action to take when the signal callback has
* returned.
*/
enum NRF_RADIO_SIGNAL_CALLBACK_ACTION
{
NRF_RADIO_SIGNAL_CALLBACK_ACTION_NONE, /**< Return without action. */
NRF_RADIO_SIGNAL_CALLBACK_ACTION_EXTEND, /**< Request an extension of the current timeslot (maximum execution time for this action is when the extension succeeded). */
NRF_RADIO_SIGNAL_CALLBACK_ACTION_END, /**< End the current radio timeslot. */
NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END /**< Request a new radio timeslot and end the current timeslot. */
};
/**@brief Radio timeslot high frequency clock source configuration. */
enum NRF_RADIO_HFCLK_CFG
{
NRF_RADIO_HFCLK_CFG_XTAL_GUARANTEED, /**< The SoftDevice will guarantee that the high frequency clock source is the
external crystal for the whole duration of the timeslot. This should be the
preferred option for events that use the radio or require high timing accuracy. */
NRF_RADIO_HFCLK_CFG_NO_GUARANTEE /**< This configuration allows for earlier and tighter scheduling of timeslots.
The RC oscillator may be the clock source in part or for the whole duration of the timeslot.
The RC oscillator's accuracy must therefore be taken into consideration.
@note If the application will use the radio peripheral in timeslots with this configuration,
it must make sure that the crystal is running and stable before starting the radio. */
};
/**@brief Radio timeslot priorities. */
enum NRF_RADIO_PRIORITY
{
NRF_RADIO_PRIORITY_HIGH, /**< High (equal priority as the normal connection priority of the SoftDevice stack(s)). */
NRF_RADIO_PRIORITY_NORMAL, /**< Normal (equal priority as the priority of secondary activites of the SoftDevice stack(s)). */
};
/**@brief Radio timeslot request type. */
enum NRF_RADIO_REQUEST_TYPE
{
NRF_RADIO_REQ_TYPE_EARLIEST, /**< Request radio timeslot as early as possible. This should always be used for the first request in a session. */
NRF_RADIO_REQ_TYPE_NORMAL /**< Normal radio timeslot request. */
};
/**@brief SoC Events. */
enum NRF_SOC_EVTS
{
NRF_EVT_HFCLKSTARTED, /**< Event indicating that the HFCLK has started. */
NRF_EVT_POWER_FAILURE_WARNING, /**< Event indicating that a power failure warning has occurred. */
NRF_EVT_FLASH_OPERATION_SUCCESS, /**< Event indicating that the ongoing flash operation has completed successfully. */
NRF_EVT_FLASH_OPERATION_ERROR, /**< Event indicating that the ongoing flash operation has timed out with an error. */
NRF_EVT_RADIO_BLOCKED, /**< Event indicating that a radio timeslot was blocked. */
NRF_EVT_RADIO_CANCELED, /**< Event indicating that a radio timeslot was canceled by SoftDevice. */
NRF_EVT_RADIO_SIGNAL_CALLBACK_INVALID_RETURN, /**< Event indicating that a radio timeslot signal callback handler return was invalid. */
NRF_EVT_RADIO_SESSION_IDLE, /**< Event indicating that a radio timeslot session is idle. */
NRF_EVT_RADIO_SESSION_CLOSED, /**< Event indicating that a radio timeslot session is closed. */
NRF_EVT_NUMBER_OF_EVTS
};
/**@} */
/**@addtogroup NRF_SOC_STRUCTURES Structures
* @{ */
/**@brief Represents a mutex for use with the nrf_mutex functions.
* @note Accessing the value directly is not safe, use the mutex functions!
*/
typedef volatile uint8_t nrf_mutex_t;
/**@brief Parameters for a request for a timeslot as early as possible. */
typedef struct
{
uint8_t hfclk; /**< High frequency clock source, see @ref NRF_RADIO_HFCLK_CFG. */
uint8_t priority; /**< The radio timeslot priority, see @ref NRF_RADIO_PRIORITY. */
uint32_t length_us; /**< The radio timeslot length (in the range 100 to 100,000] microseconds). */
uint32_t timeout_us; /**< Longest acceptable delay until the start of the requested timeslot (up to @ref NRF_RADIO_EARLIEST_TIMEOUT_MAX_US microseconds). */
} nrf_radio_request_earliest_t;
/**@brief Parameters for a normal radio timeslot request. */
typedef struct
{
uint8_t hfclk; /**< High frequency clock source, see @ref NRF_RADIO_HFCLK_CFG. */
uint8_t priority; /**< The radio timeslot priority, see @ref NRF_RADIO_PRIORITY. */
uint32_t distance_us; /**< Distance from the start of the previous radio timeslot (up to @ref NRF_RADIO_DISTANCE_MAX_US microseconds). */
uint32_t length_us; /**< The radio timeslot length (in the range [100..100,000] microseconds). */
} nrf_radio_request_normal_t;
/**@brief Radio timeslot request parameters. */
typedef struct
{
uint8_t request_type; /**< Type of request, see @ref NRF_RADIO_REQUEST_TYPE. */
union
{
nrf_radio_request_earliest_t earliest; /**< Parameters for requesting a radio timeslot as early as possible. */
nrf_radio_request_normal_t normal; /**< Parameters for requesting a normal radio timeslot. */
} params;
} nrf_radio_request_t;
/**@brief Return parameters of the radio timeslot signal callback. */
typedef struct
{
uint8_t callback_action; /**< The action requested by the application when returning from the signal callback, see @ref NRF_RADIO_SIGNAL_CALLBACK_ACTION. */
union
{
struct
{
nrf_radio_request_t * p_next; /**< The request parameters for the next radio timeslot. */
} request; /**< Additional parameters for return_code @ref NRF_RADIO_SIGNAL_CALLBACK_ACTION_REQUEST_AND_END. */
struct
{
uint32_t length_us; /**< Requested extension of the radio timeslot duration (microseconds) (for minimum time see @ref NRF_RADIO_MINIMUM_TIMESLOT_LENGTH_EXTENSION_TIME_US). */
} extend; /**< Additional parameters for return_code @ref NRF_RADIO_SIGNAL_CALLBACK_ACTION_EXTEND. */
} params;
} nrf_radio_signal_callback_return_param_t;
/**@brief The radio timeslot signal callback type.
*
* @note In case of invalid return parameters, the radio timeslot will automatically end
* immediately after returning from the signal callback and the
* @ref NRF_EVT_RADIO_SIGNAL_CALLBACK_INVALID_RETURN event will be sent.
* @note The returned struct pointer must remain valid after the signal callback
* function returns. For instance, this means that it must not point to a stack variable.
*
* @param[in] signal_type Type of signal, see @ref NRF_RADIO_CALLBACK_SIGNAL_TYPE.
*
* @return Pointer to structure containing action requested by the application.
*/
typedef nrf_radio_signal_callback_return_param_t * (*nrf_radio_signal_callback_t) (uint8_t signal_type);
/**@brief AES ECB parameter typedefs */
typedef uint8_t soc_ecb_key_t[SOC_ECB_KEY_LENGTH];
typedef uint8_t soc_ecb_cleartext_t[SOC_ECB_CLEARTEXT_LENGTH];
typedef uint8_t soc_ecb_ciphertext_t[SOC_ECB_CIPHERTEXT_LENGTH];
/**@brief AES ECB data structure */
typedef struct
{
soc_ecb_key_t key; /**< Encryption key. */
soc_ecb_cleartext_t cleartext; /**< Cleartext data. */
soc_ecb_ciphertext_t ciphertext; /**< Ciphertext data. */
} nrf_ecb_hal_data_t;
/**@brief AES ECB block. Used to provide multiple blocks in a single call
to @ref sd_ecb_blocks_encrypt.*/
typedef struct
{
soc_ecb_key_t* p_key; /**< Pointer to the Encryption key. */
soc_ecb_cleartext_t* p_cleartext; /**< Pointer to the Cleartext data. */
soc_ecb_ciphertext_t* p_ciphertext; /**< Pointer to the Ciphertext data. */
} nrf_ecb_hal_data_block_t;
/**@} */
/**@addtogroup NRF_SOC_FUNCTIONS Functions
* @{ */
/**@brief Initialize a mutex.
*
* @param[in] p_mutex Pointer to the mutex to initialize.
*
* @retval ::NRF_SUCCESS
*/
SVCALL(SD_MUTEX_NEW, uint32_t, sd_mutex_new(nrf_mutex_t * p_mutex));
/**@brief Attempt to acquire a mutex.
*
* @param[in] p_mutex Pointer to the mutex to acquire.
*
* @retval ::NRF_SUCCESS The mutex was successfully acquired.
* @retval ::NRF_ERROR_SOC_MUTEX_ALREADY_TAKEN The mutex could not be acquired.
*/
SVCALL(SD_MUTEX_ACQUIRE, uint32_t, sd_mutex_acquire(nrf_mutex_t * p_mutex));
/**@brief Release a mutex.
*
* @param[in] p_mutex Pointer to the mutex to release.
*
* @retval ::NRF_SUCCESS
*/
SVCALL(SD_MUTEX_RELEASE, uint32_t, sd_mutex_release(nrf_mutex_t * p_mutex));
/**@brief Query the capacity of the application random pool.
*
* @param[out] p_pool_capacity The capacity of the pool.
*
* @retval ::NRF_SUCCESS
*/
SVCALL(SD_RAND_APPLICATION_POOL_CAPACITY_GET, uint32_t, sd_rand_application_pool_capacity_get(uint8_t * p_pool_capacity));
/**@brief Get number of random bytes available to the application.
*
* @param[out] p_bytes_available The number of bytes currently available in the pool.
*
* @retval ::NRF_SUCCESS
*/
SVCALL(SD_RAND_APPLICATION_BYTES_AVAILABLE_GET, uint32_t, sd_rand_application_bytes_available_get(uint8_t * p_bytes_available));
/**@brief Get random bytes from the application pool.
*
* @param[out] p_buff Pointer to unit8_t buffer for storing the bytes.
* @param[in] length Number of bytes to take from pool and place in p_buff.
*
* @retval ::NRF_SUCCESS The requested bytes were written to p_buff.
* @retval ::NRF_ERROR_SOC_RAND_NOT_ENOUGH_VALUES No bytes were written to the buffer, because there were not enough bytes available.
*/
SVCALL(SD_RAND_APPLICATION_VECTOR_GET, uint32_t, sd_rand_application_vector_get(uint8_t * p_buff, uint8_t length));
/**@brief Gets the reset reason register.
*
* @param[out] p_reset_reason Contents of the NRF_POWER->RESETREAS register.
*
* @retval ::NRF_SUCCESS
*/
SVCALL(SD_POWER_RESET_REASON_GET, uint32_t, sd_power_reset_reason_get(uint32_t * p_reset_reason));
/**@brief Clears the bits of the reset reason register.
*
* @param[in] reset_reason_clr_msk Contains the bits to clear from the reset reason register.
*
* @retval ::NRF_SUCCESS
*/
SVCALL(SD_POWER_RESET_REASON_CLR, uint32_t, sd_power_reset_reason_clr(uint32_t reset_reason_clr_msk));
/**@brief Sets the power mode when in CPU sleep.
*
* @param[in] power_mode The power mode to use when in CPU sleep, see @ref NRF_POWER_MODES. @sa sd_app_evt_wait
*
* @retval ::NRF_SUCCESS The power mode was set.
* @retval ::NRF_ERROR_SOC_POWER_MODE_UNKNOWN The power mode was unknown.
*/
SVCALL(SD_POWER_MODE_SET, uint32_t, sd_power_mode_set(uint8_t power_mode));
/**@brief Puts the chip in System OFF mode.
*
* @retval ::NRF_ERROR_SOC_POWER_OFF_SHOULD_NOT_RETURN
*/
SVCALL(SD_POWER_SYSTEM_OFF, uint32_t, sd_power_system_off(void));
/**@brief Enables or disables the power-fail comparator.
*
* Enabling this will give a softdevice event (NRF_EVT_POWER_FAILURE_WARNING) when the power failure warning occurs.
* The event can be retrieved with sd_evt_get();
*
* @param[in] pof_enable True if the power-fail comparator should be enabled, false if it should be disabled.
*
* @retval ::NRF_SUCCESS
*/
SVCALL(SD_POWER_POF_ENABLE, uint32_t, sd_power_pof_enable(uint8_t pof_enable));
/**@brief Sets the power-fail threshold value.
*
* @param[in] threshold The power-fail threshold value to use, see @ref NRF_POWER_THRESHOLDS.
*
* @retval ::NRF_SUCCESS The power failure threshold was set.
* @retval ::NRF_ERROR_SOC_POWER_POF_THRESHOLD_UNKNOWN The power failure threshold is unknown.
*/
SVCALL(SD_POWER_POF_THRESHOLD_SET, uint32_t, sd_power_pof_threshold_set(uint8_t threshold));
/**@brief Sets bits in the NRF_POWER->RAMON register.
*
* @param[in] ramon Contains the bits needed to be set in the NRF_POWER->RAMON register.
*
* @retval ::NRF_SUCCESS
*/
SVCALL(SD_POWER_RAMON_SET, uint32_t, sd_power_ramon_set(uint32_t ramon));
/**@brief Clears bits in the NRF_POWER->RAMON register.
*
* @param ramon Contains the bits needed to be cleared in the NRF_POWER->RAMON register.
*
* @retval ::NRF_SUCCESS
*/
SVCALL(SD_POWER_RAMON_CLR, uint32_t, sd_power_ramon_clr(uint32_t ramon));
/**@brief Get contents of NRF_POWER->RAMON register, indicates power status of ram blocks.
*
* @param[out] p_ramon Content of NRF_POWER->RAMON register.
*
* @retval ::NRF_SUCCESS
*/
SVCALL(SD_POWER_RAMON_GET, uint32_t, sd_power_ramon_get(uint32_t * p_ramon));
/**@brief Set bits in the NRF_POWER->GPREGRET register.
*
* @param[in] gpregret_msk Bits to be set in the GPREGRET register.
*
* @retval ::NRF_SUCCESS
*/
SVCALL(SD_POWER_GPREGRET_SET, uint32_t, sd_power_gpregret_set(uint32_t gpregret_msk));
/**@brief Clear bits in the NRF_POWER->GPREGRET register.
*
* @param[in] gpregret_msk Bits to be clear in the GPREGRET register.
*
* @retval ::NRF_SUCCESS
*/
SVCALL(SD_POWER_GPREGRET_CLR, uint32_t, sd_power_gpregret_clr(uint32_t gpregret_msk));
/**@brief Get contents of the NRF_POWER->GPREGRET register.
*
* @param[out] p_gpregret Contents of the GPREGRET register.
*
* @retval ::NRF_SUCCESS
*/
SVCALL(SD_POWER_GPREGRET_GET, uint32_t, sd_power_gpregret_get(uint32_t *p_gpregret));
/**@brief Sets the DCDC mode.
*
* Enable or disable the DCDC peripheral.
*
* @param[in] dcdc_mode The mode of the DCDC, see @ref NRF_POWER_DCDC_MODES.
*
* @retval ::NRF_SUCCESS
* @retval ::NRF_ERROR_INVALID_PARAM The DCDC mode is invalid.
*/
SVCALL(SD_POWER_DCDC_MODE_SET, uint32_t, sd_power_dcdc_mode_set(uint8_t dcdc_mode));
/**@brief Request the high frequency crystal oscillator.
*
* Will start the high frequency crystal oscillator, the startup time of the crystal varies
* and the ::sd_clock_hfclk_is_running function can be polled to check if it has started.
*
* @see sd_clock_hfclk_is_running
* @see sd_clock_hfclk_release
*
* @retval ::NRF_SUCCESS
*/
SVCALL(SD_CLOCK_HFCLK_REQUEST, uint32_t, sd_clock_hfclk_request(void));
/**@brief Releases the high frequency crystal oscillator.
*
* Will stop the high frequency crystal oscillator, this happens immediately.
*
* @see sd_clock_hfclk_is_running
* @see sd_clock_hfclk_request
*
* @retval ::NRF_SUCCESS
*/
SVCALL(SD_CLOCK_HFCLK_RELEASE, uint32_t, sd_clock_hfclk_release(void));
/**@brief Checks if the high frequency crystal oscillator is running.
*
* @see sd_clock_hfclk_request
* @see sd_clock_hfclk_release
*
* @param[out] p_is_running 1 if the external crystal oscillator is running, 0 if not.
*
* @retval ::NRF_SUCCESS
*/
SVCALL(SD_CLOCK_HFCLK_IS_RUNNING, uint32_t, sd_clock_hfclk_is_running(uint32_t * p_is_running));
/**@brief Waits for an application event.
*
* An application event is either an application interrupt or a pended interrupt when the
* interrupt is disabled. When the interrupt is enabled it will be taken immediately since
* this function will wait in thread mode, then the execution will return in the application's
* main thread. When an interrupt is disabled and gets pended it will return to the application's
* thread main. The application must ensure that the pended flag is cleared using
* ::sd_nvic_ClearPendingIRQ in order to sleep using this function. This is only necessary for
* disabled interrupts, as the interrupt handler will clear the pending flag automatically for
* enabled interrupts.
*
* In order to wake up from disabled interrupts, the SEVONPEND flag has to be set in the Cortex-M0
* System Control Register (SCR). @sa CMSIS_SCB
*
* @note If an application interrupt has happened since the last time sd_app_evt_wait was
* called this function will return immediately and not go to sleep. This is to avoid race
* conditions that can occur when a flag is updated in the interrupt handler and processed
* in the main loop.
*
* @post An application interrupt has happened or a interrupt pending flag is set.
*
* @retval ::NRF_SUCCESS
*/
SVCALL(SD_APP_EVT_WAIT, uint32_t, sd_app_evt_wait(void));
/**@brief Get PPI channel enable register contents.
*
* @param[out] p_channel_enable The contents of the PPI CHEN register.
*
* @retval ::NRF_SUCCESS
*/
SVCALL(SD_PPI_CHANNEL_ENABLE_GET, uint32_t, sd_ppi_channel_enable_get(uint32_t * p_channel_enable));
/**@brief Set PPI channel enable register.
*
* @param[in] channel_enable_set_msk Mask containing the bits to set in the PPI CHEN register.
*
* @retval ::NRF_SUCCESS
*/
SVCALL(SD_PPI_CHANNEL_ENABLE_SET, uint32_t, sd_ppi_channel_enable_set(uint32_t channel_enable_set_msk));
/**@brief Clear PPI channel enable register.
*
* @param[in] channel_enable_clr_msk Mask containing the bits to clear in the PPI CHEN register.
*
* @retval ::NRF_SUCCESS
*/
SVCALL(SD_PPI_CHANNEL_ENABLE_CLR, uint32_t, sd_ppi_channel_enable_clr(uint32_t channel_enable_clr_msk));
/**@brief Assign endpoints to a PPI channel.
*
* @param[in] channel_num Number of the PPI channel to assign.
* @param[in] evt_endpoint Event endpoint of the PPI channel.
* @param[in] task_endpoint Task endpoint of the PPI channel.
*
* @retval ::NRF_ERROR_SOC_PPI_INVALID_CHANNEL The channel number is invalid.
* @retval ::NRF_SUCCESS
*/
SVCALL(SD_PPI_CHANNEL_ASSIGN, uint32_t, sd_ppi_channel_assign(uint8_t channel_num, const volatile void * evt_endpoint, const volatile void * task_endpoint));
/**@brief Task to enable a channel group.
*
* @param[in] group_num Number of the channel group.
*
* @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid
* @retval ::NRF_SUCCESS
*/
SVCALL(SD_PPI_GROUP_TASK_ENABLE, uint32_t, sd_ppi_group_task_enable(uint8_t group_num));
/**@brief Task to disable a channel group.
*
* @param[in] group_num Number of the PPI group.
*
* @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid.
* @retval ::NRF_SUCCESS
*/
SVCALL(SD_PPI_GROUP_TASK_DISABLE, uint32_t, sd_ppi_group_task_disable(uint8_t group_num));
/**@brief Assign PPI channels to a channel group.
*
* @param[in] group_num Number of the channel group.
* @param[in] channel_msk Mask of the channels to assign to the group.
*
* @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid.
* @retval ::NRF_SUCCESS
*/
SVCALL(SD_PPI_GROUP_ASSIGN, uint32_t, sd_ppi_group_assign(uint8_t group_num, uint32_t channel_msk));
/**@brief Gets the PPI channels of a channel group.
*
* @param[in] group_num Number of the channel group.
* @param[out] p_channel_msk Mask of the channels assigned to the group.
*
* @retval ::NRF_ERROR_SOC_PPI_INVALID_GROUP The group number is invalid.
* @retval ::NRF_SUCCESS
*/
SVCALL(SD_PPI_GROUP_GET, uint32_t, sd_ppi_group_get(uint8_t group_num, uint32_t * p_channel_msk));
/**@brief Configures the Radio Notification signal.
*
* @note
* - The notification signal latency depends on the interrupt priority settings of SWI used
* for notification signal.
* - To ensure that the radio notification signal behaves in a consistent way, always
* configure radio notifications when there is no protocol stack or other SoftDevice
* activity in progress. It is recommended that the radio notification signal is
* configured directly after the SoftDevice has been enabled.
* - In the period between the ACTIVE signal and the start of the Radio Event, the SoftDevice
* will interrupt the application to do Radio Event preparation.
* - Using the Radio Notification feature may limit the bandwidth, as the SoftDevice may have
* to shorten the connection events to have time for the Radio Notification signals.
*
* @param[in] type Type of notification signal, see @ref NRF_RADIO_NOTIFICATION_TYPES.
* @ref NRF_RADIO_NOTIFICATION_TYPE_NONE shall be used to turn off radio
* notification. Using @ref NRF_RADIO_NOTIFICATION_DISTANCE_NONE is
* recommended (but not required) to be used with
* @ref NRF_RADIO_NOTIFICATION_TYPE_NONE.
*
* @param[in] distance Distance between the notification signal and start of radio activity, see @ref NRF_RADIO_NOTIFICATION_DISTANCES.
* This parameter is ignored when @ref NRF_RADIO_NOTIFICATION_TYPE_NONE or
* @ref NRF_RADIO_NOTIFICATION_TYPE_INT_ON_INACTIVE is used.
*
* @retval ::NRF_ERROR_INVALID_PARAM The group number is invalid.
* @retval ::NRF_SUCCESS
*/
SVCALL(SD_RADIO_NOTIFICATION_CFG_SET, uint32_t, sd_radio_notification_cfg_set(uint8_t type, uint8_t distance));
/**@brief Encrypts a block according to the specified parameters.
*
* 128-bit AES encryption.
*
* @note:
* - The application may set the SEVONPEND bit in the SCR to 1 to make the SoftDevice sleep while
* the ECB is running. The SEVONPEND bit should only be cleared (set to 0) from application
* main or low interrupt level.
*
* @param[in, out] p_ecb_data Pointer to the ECB parameters' struct (two input
* parameters and one output parameter).
*
* @retval ::NRF_SUCCESS
*/
SVCALL(SD_ECB_BLOCK_ENCRYPT, uint32_t, sd_ecb_block_encrypt(nrf_ecb_hal_data_t * p_ecb_data));
/**@brief Encrypts multiple data blocks provided as an array of data block structures.
*
* @details: Performs 128-bit AES encryption on multiple data blocks
*
* @note:
* - The application may set the SEVONPEND bit in the SCR to 1 to make the SoftDevice sleep while
* the ECB is running. The SEVONPEND bit should only be cleared (set to 0) from application
* main or low interrupt level.
*
* @param[in] block_count Count of blocks in the p_data_blocks array.
* @param[in,out] p_data_blocks Pointer to the first entry in a contiguous array of
* @ref nrf_ecb_hal_data_block_t structures.
*
* @retval ::NRF_SUCCESS
*/
SVCALL(SD_ECB_BLOCKS_ENCRYPT, uint32_t, sd_ecb_blocks_encrypt(uint8_t block_count, nrf_ecb_hal_data_block_t * p_data_blocks));
/**@brief Gets any pending events generated by the SoC API.
*
* The application should keep calling this function to get events, until ::NRF_ERROR_NOT_FOUND is returned.
*
* @param[out] p_evt_id Set to one of the values in @ref NRF_SOC_EVTS, if any events are pending.
*
* @retval ::NRF_SUCCESS An event was pending. The event id is written in the p_evt_id parameter.
* @retval ::NRF_ERROR_NOT_FOUND No pending events.
*/
SVCALL(SD_EVT_GET, uint32_t, sd_evt_get(uint32_t * p_evt_id));
/**@brief Get the temperature measured on the chip
*
* This function will block until the temperature measurement is done.
* It takes around 50us from call to return.
*
* @param[out] p_temp Result of temperature measurement. Die temperature in 0.25 degrees celsius.
*
* @retval ::NRF_SUCCESS A temperature measurement was done, and the temperature was written to temp
*/
SVCALL(SD_TEMP_GET, uint32_t, sd_temp_get(int32_t * p_temp));
/**@brief Flash Write
*
* Commands to write a buffer to flash
*
* If the SoftDevice is enabled:
* This call initiates the flash access command, and its completion will be communicated to the
* application with exactly one of the following events:
* - @ref NRF_EVT_FLASH_OPERATION_SUCCESS - The command was successfully completed.
* - @ref NRF_EVT_FLASH_OPERATION_ERROR - The command could not be started.
*
* If the SoftDevice is not enabled no event will be generated, and this call will return @ref NRF_SUCCESS when the
* write has been completed
*
* @note
* - This call takes control over the radio and the CPU during flash erase and write to make sure that
* they will not interfere with the flash access. This means that all interrupts will be blocked
* for a predictable time (depending on the NVMC specification in nRF51 Series Reference Manual
* and the command parameters).
*
*
* @param[in] p_dst Pointer to start of flash location to be written.
* @param[in] p_src Pointer to buffer with data to be written.
* @param[in] size Number of 32-bit words to write. Maximum size is 256 32-bit words for nRF51 and 1024 for nRF52.
*
* @retval ::NRF_ERROR_INVALID_ADDR Tried to write to a non existing flash address, or p_dst or p_src was unaligned.
* @retval ::NRF_ERROR_BUSY The previous command has not yet completed.
* @retval ::NRF_ERROR_INVALID_LENGTH Size was 0, or higher than the maximum allowed size.
* @retval ::NRF_ERROR_FORBIDDEN Tried to write to or read from protected location.
* @retval ::NRF_SUCCESS The command was accepted.
*/
SVCALL(SD_FLASH_WRITE, uint32_t, sd_flash_write(uint32_t * const p_dst, uint32_t const * const p_src, uint32_t size));
/**@brief Flash Erase page
*
* Commands to erase a flash page
* If the SoftDevice is enabled:
* This call initiates the flash access command, and its completion will be communicated to the
* application with exactly one of the following events:
* - @ref NRF_EVT_FLASH_OPERATION_SUCCESS - The command was successfully completed.
* - @ref NRF_EVT_FLASH_OPERATION_ERROR - The command could not be started.
*
* If the SoftDevice is not enabled no event will be generated, and this call will return @ref NRF_SUCCESS when the
* erase has been completed
*
* @note
* - This call takes control over the radio and the CPU during flash erase and write to make sure that
* they will not interfere with the flash access. This means that all interrupts will be blocked
* for a predictable time (depending on the NVMC specification in nRF51 Series Reference Manual
* and the command parameters).
*
*
* @param[in] page_number Pagenumber of the page to erase
* @retval ::NRF_ERROR_INTERNAL If a new session could not be opened due to an internal error.
* @retval ::NRF_ERROR_INVALID_ADDR Tried to erase to a non existing flash page.
* @retval ::NRF_ERROR_BUSY The previous command has not yet completed.
* @retval ::NRF_ERROR_FORBIDDEN Tried to erase a protected page.
* @retval ::NRF_SUCCESS The command was accepted.
*/
SVCALL(SD_FLASH_PAGE_ERASE, uint32_t, sd_flash_page_erase(uint32_t page_number));
/**@brief Flash Protection set
*
* Commands to set the flash protection configuration registers.
On nRF51 this sets the PROTENSETx registers of the MPU peripheral.
On nRF52 this sets the CONFIGx registers of the BPROT peripheral.
*
* @note To read the values read them directly. They are only write-protected.
*
* @param[in] block_cfg0 Value to be written to the configuration register.
* @param[in] block_cfg1 Value to be written to the configuration register.
* @param[in] block_cfg2 Value to be written to the configuration register (ignored on nRF51).
* @param[in] block_cfg3 Value to be written to the configuration register (ignored on nRF51).
*
* @retval ::NRF_ERROR_FORBIDDEN Tried to protect the SoftDevice.
* @retval ::NRF_SUCCESS Values successfully written to configuration registers.
*/
SVCALL(SD_FLASH_PROTECT, uint32_t, sd_flash_protect(uint32_t block_cfg0, uint32_t block_cfg1, uint32_t block_cfg2, uint32_t block_cfg3));
/**@brief Opens a session for radio timeslot requests.
*
* @note Only one session can be open at a time.
* @note p_radio_signal_callback(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START) will be called when the radio timeslot
* starts. From this point the NRF_RADIO and NRF_TIMER0 peripherals can be freely accessed
* by the application.
* @note p_radio_signal_callback(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_TIMER0) is called whenever the NRF_TIMER0
* interrupt occurs.
* @note p_radio_signal_callback(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_RADIO) is called whenever the NRF_RADIO
* interrupt occurs.
* @note p_radio_signal_callback() will be called at ARM interrupt priority level 0. This
* implies that none of the sd_* API calls can be used from p_radio_signal_callback().
*
* @param[in] p_radio_signal_callback The signal callback.
*
* @retval ::NRF_ERROR_INVALID_ADDR p_radio_signal_callback is an invalid function pointer.
* @retval ::NRF_ERROR_BUSY If session cannot be opened.
* @retval ::NRF_ERROR_INTERNAL If a new session could not be opened due to an internal error.
* @retval ::NRF_SUCCESS Otherwise.
*/
SVCALL(SD_RADIO_SESSION_OPEN, uint32_t, sd_radio_session_open(nrf_radio_signal_callback_t p_radio_signal_callback));
/**@brief Closes a session for radio timeslot requests.
*
* @note Any current radio timeslot will be finished before the session is closed.
* @note If a radio timeslot is scheduled when the session is closed, it will be canceled.
* @note The application cannot consider the session closed until the @ref NRF_EVT_RADIO_SESSION_CLOSED
* event is received.
*
* @retval ::NRF_ERROR_FORBIDDEN If session not opened.
* @retval ::NRF_ERROR_BUSY If session is currently being closed.
* @retval ::NRF_SUCCESS Otherwise.
*/
SVCALL(SD_RADIO_SESSION_CLOSE, uint32_t, sd_radio_session_close(void));
/**@brief Requests a radio timeslot.
*
* @note The request type is determined by p_request->request_type, and can be one of @ref NRF_RADIO_REQ_TYPE_EARLIEST
* and @ref NRF_RADIO_REQ_TYPE_NORMAL. The first request in a session must always be of type @ref NRF_RADIO_REQ_TYPE_EARLIEST.
* @note For a normal request (@ref NRF_RADIO_REQ_TYPE_NORMAL), the start time of a radio timeslot is specified by
* p_request->distance_us and is given relative to the start of the previous timeslot.
* @note A too small p_request->distance_us will lead to a @ref NRF_EVT_RADIO_BLOCKED event.
* @note Timeslots scheduled too close will lead to a @ref NRF_EVT_RADIO_BLOCKED event.
* @note See the SoftDevice Specification for more on radio timeslot scheduling, distances and lengths.
* @note If an opportunity for the first radio timeslot is not found before 100ms after the call to this
* function, it is not scheduled, and instead a @ref NRF_EVT_RADIO_BLOCKED event is sent.
* The application may then try to schedule the first radio timeslot again.
* @note Successful requests will result in nrf_radio_signal_callback_t(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START).
* Unsuccessful requests will result in a @ref NRF_EVT_RADIO_BLOCKED event, see @ref NRF_SOC_EVTS.
* @note The jitter in the start time of the radio timeslots is +/- @ref NRF_RADIO_START_JITTER_US us.
* @note The nrf_radio_signal_callback_t(@ref NRF_RADIO_CALLBACK_SIGNAL_TYPE_START) call has a latency relative to the
* specified radio timeslot start, but this does not affect the actual start time of the timeslot.
* @note NRF_TIMER0 is reset at the start of the radio timeslot, and is clocked at 1MHz from the high frequency
* (16 MHz) clock source. If p_request->hfclk_force_xtal is true, the high frequency clock is
* guaranteed to be clocked from the external crystal.
* @note The SoftDevice will neither access the NRF_RADIO peripheral nor the NRF_TIMER0 peripheral
* during the radio timeslot.
*
* @param[in] p_request Pointer to the request parameters.
*
* @retval ::NRF_ERROR_FORBIDDEN If session not opened or the session is not IDLE.
* @retval ::NRF_ERROR_INVALID_ADDR If the p_request pointer is invalid.
* @retval ::NRF_ERROR_INVALID_PARAM If the parameters of p_request are not valid.
* @retval ::NRF_SUCCESS Otherwise.
*/
SVCALL(SD_RADIO_REQUEST, uint32_t, sd_radio_request(nrf_radio_request_t * p_request ));
/**@} */
#ifdef __cplusplus
}
#endif
#endif // NRF_SOC_H__
/**@} */

View File

@ -0,0 +1,91 @@
/*
* Copyright (c) 2000 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#ifndef NRF_SVC__
#define NRF_SVC__
#include "stdint.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef SVCALL_AS_NORMAL_FUNCTION
#define SVCALL(number, return_type, signature) return_type signature
#else
#ifndef SVCALL
#if defined (__CC_ARM)
#define SVCALL(number, return_type, signature) return_type __svc(number) signature
#elif defined (__GNUC__)
#ifdef __cplusplus
#define GCC_CAST_CPP (uint16_t)
#else
#define GCC_CAST_CPP
#endif
#define SVCALL(number, return_type, signature) \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wreturn-type\"") \
__attribute__((naked)) \
__attribute__((unused)) \
static return_type signature \
{ \
__asm( \
"svc %0\n" \
"bx r14" : : "I" (GCC_CAST_CPP number) : "r0" \
); \
} \
_Pragma("GCC diagnostic pop")
#elif defined (__ICCARM__)
#define PRAGMA(x) _Pragma(#x)
#define SVCALL(number, return_type, signature) \
PRAGMA(swi_number = (number)) \
__swi return_type signature;
#else
#define SVCALL(number, return_type, signature) return_type signature
#endif
#endif // SVCALL
#endif // SVCALL_AS_NORMAL_FUNCTION
#ifdef __cplusplus
}
#endif
#endif // NRF_SVC__

View File

@ -0,0 +1,57 @@
/* mbed Microcontroller Library
* Copyright (c) 2015 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.
*/
#ifndef COMMON_RTC_H
#define COMMON_RTC_H
#include "nrf_rtc.h"
#define RTC_COUNTER_BITS 24u
// Instance 0 is reserved for SoftDevice.
// Instance 1 is used as a common one for us_ticker, lp_ticker and (in case
// of NRF51) as an alternative tick source for RTOS.
// ["us_ticker.c" uses hard coded addresses of the 'NRF_RTC1->EVENT_COMPARE[1]'
// register in inline assembly implementations of COMMON_RTC_IRQ_HANDLER,
// please remember to update those in case of doing changes here]
#define COMMON_RTC_INSTANCE NRF_RTC1
#define COMMON_RTC_IRQ_HANDLER RTC1_IRQHandler
#define US_TICKER_CC_CHANNEL 0
#define OS_TICK_CC_CHANNEL 1
#define LP_TICKER_CC_CHANNEL 2
#define COMMON_RTC_EVENT_COMPARE(channel) \
CONCAT_2(NRF_RTC_EVENT_COMPARE_, channel)
#define COMMON_RTC_INT_COMPARE_MASK(channel) \
CONCAT_3(NRF_RTC_INT_COMPARE, channel, _MASK)
#define US_TICKER_EVENT COMMON_RTC_EVENT_COMPARE(US_TICKER_CC_CHANNEL)
#define US_TICKER_INT_MASK COMMON_RTC_INT_COMPARE_MASK(US_TICKER_CC_CHANNEL)
#define OS_TICK_EVENT COMMON_RTC_EVENT_COMPARE(OS_TICK_CC_CHANNEL)
#define OS_TICK_INT_MASK COMMON_RTC_INT_COMPARE_MASK(OS_TICK_CC_CHANNEL)
#define LP_TICKER_EVENT COMMON_RTC_EVENT_COMPARE(LP_TICKER_CC_CHANNEL)
#define LP_TICKER_INT_MASK COMMON_RTC_INT_COMPARE_MASK(LP_TICKER_CC_CHANNEL)
extern bool m_common_rtc_enabled;
extern uint32_t volatile m_common_rtc_overflows;
void common_rtc_init(void);
uint32_t common_rtc_32bit_ticks_get(void);
uint64_t common_rtc_64bit_us_get(void);
void common_rtc_set_interrupt(uint32_t us_timestamp, uint32_t cc_channel,
uint32_t int_mask);
#endif // COMMON_RTC_H

View File

@ -0,0 +1,249 @@
/* 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.
*/
#include "mbed_assert.h"
#include "gpio_api.h"
#include "gpio_irq_api.h"
#include "pinmap.h"
#include "nrf_drv_gpiote.h"
#if defined(TARGET_MCU_NRF51822)
#define GPIO_PIN_COUNT 31
#else
#define GPIO_PIN_COUNT 32
#endif
typedef struct {
bool used_as_gpio : 1;
PinDirection direction : 1;
bool init_high : 1;
PinMode pull : 2;
bool used_as_irq : 1;
bool irq_fall : 1;
bool irq_rise : 1;
} gpio_cfg_t;
uint32_t m_gpio_initialized;
gpio_cfg_t m_gpio_cfg[GPIO_PIN_COUNT];
/***********
GPIO IRQ
***********/
static gpio_irq_handler m_irq_handler;
static uint32_t m_channel_ids[GPIO_PIN_COUNT] = {0};
uint32_t m_gpio_irq_enabled;
static void gpiote_irq_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
nrf_gpio_pin_sense_t sense = nrf_gpio_pin_sense_get(pin);
gpio_irq_event event = (sense == NRF_GPIO_PIN_SENSE_LOW) ? IRQ_RISE : IRQ_FALL;
if (m_gpio_irq_enabled & (1UL << pin)) {
if (((event == IRQ_RISE) && m_gpio_cfg[pin].irq_rise)
|| ((event == IRQ_FALL) && m_gpio_cfg[pin].irq_fall)) {
m_irq_handler(m_channel_ids[pin], event);
}
}
}
void GPIOTE_IRQHandler(void);// exported from nrf_drv_gpiote.c
void gpio_init(gpio_t *obj, PinName pin)
{
obj->pin = pin;
if (pin == (PinName)NC) {
return;
}
MBED_ASSERT((uint32_t)pin < GPIO_PIN_COUNT);
NVIC_SetVector(GPIOTE_IRQn, (uint32_t) GPIOTE_IRQHandler);
(void) nrf_drv_gpiote_init();
m_gpio_cfg[obj->pin].used_as_gpio = true;
}
int gpio_read(gpio_t *obj)
{
MBED_ASSERT(obj->pin != (PinName)NC);
if (m_gpio_cfg[obj->pin].direction == PIN_OUTPUT) {
return ((NRF_GPIO->OUTSET & (1UL << obj->pin)) ? 1 : 0);
} else {
return nrf_gpio_pin_read(obj->pin);
}
}
static void gpiote_pin_uninit(uint8_t pin)
{
if (m_gpio_initialized & (1UL << pin)) {
if ((m_gpio_cfg[pin].direction == PIN_OUTPUT) && (!m_gpio_cfg[pin].used_as_irq)) {
nrf_drv_gpiote_out_uninit(pin);
}
else {
nrf_drv_gpiote_in_uninit(pin);
}
}
}
static void gpio_apply_config(uint8_t pin)
{
if (m_gpio_cfg[pin].used_as_gpio || m_gpio_cfg[pin].used_as_irq) {
if ((m_gpio_cfg[pin].direction == PIN_INPUT)
|| (m_gpio_cfg[pin].used_as_irq)) {
//Configure as input.
nrf_drv_gpiote_in_config_t cfg;
cfg.hi_accuracy = false;
cfg.is_watcher = false;
cfg.sense = NRF_GPIOTE_POLARITY_TOGGLE;
if (m_gpio_cfg[pin].used_as_irq) {
cfg.pull = NRF_GPIO_PIN_PULLUP;
nrf_drv_gpiote_in_init(pin, &cfg, gpiote_irq_handler);
if ((m_gpio_irq_enabled & (1 << pin))
&& (m_gpio_cfg[pin].irq_rise || m_gpio_cfg[pin].irq_fall))
{
nrf_drv_gpiote_in_event_enable(pin, true);
}
}
else {
switch(m_gpio_cfg[pin].pull) {
case PullUp:
cfg.pull = NRF_GPIO_PIN_PULLUP;
break;
case PullDown:
cfg.pull = NRF_GPIO_PIN_PULLDOWN;
break;
default:
cfg.pull = NRF_GPIO_PIN_NOPULL;
break;
}
nrf_drv_gpiote_in_init(pin, &cfg, NULL);
}
}
else {
// Configure as output.
nrf_drv_gpiote_out_config_t cfg = GPIOTE_CONFIG_OUT_SIMPLE(m_gpio_cfg[pin].init_high);
nrf_drv_gpiote_out_init(pin, &cfg);
}
m_gpio_initialized |= (1UL << pin);
}
else {
m_gpio_initialized &= ~(1UL << pin);
}
}
void gpio_mode(gpio_t *obj, PinMode mode)
{
MBED_ASSERT(obj->pin <= GPIO_PIN_COUNT);
gpiote_pin_uninit(obj->pin); // try to uninitialize gpio before a change.
m_gpio_cfg[obj->pin].pull = mode;
gpio_apply_config(obj->pin);
}
void gpio_dir(gpio_t *obj, PinDirection direction)
{
MBED_ASSERT(obj->pin <= GPIO_PIN_COUNT);
gpiote_pin_uninit(obj->pin); // try to uninitialize gpio before a change.
m_gpio_cfg[obj->pin].direction = direction;
gpio_apply_config(obj->pin);
}
/***********
GPIO IRQ
***********/
int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, uint32_t id)
{
if (pin == NC) {
return -1;
}
MBED_ASSERT((uint32_t)pin < GPIO_PIN_COUNT);
(void) nrf_drv_gpiote_init();
gpiote_pin_uninit(pin); // try to uninitialize gpio before a change.
m_gpio_cfg[pin].used_as_irq = true;
m_channel_ids[pin] = id;
obj->ch = pin;
m_irq_handler = handler;
m_channel_ids[pin] = id;
gpio_apply_config(pin);
return 1;
}
void gpio_irq_free(gpio_irq_t *obj)
{
nrf_drv_gpiote_in_uninit(obj->ch);
m_gpio_cfg[obj->ch].used_as_irq = false;
m_channel_ids[obj->ch] = 0;
gpio_apply_config(obj->ch);
}
void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable)
{
gpio_cfg_t* cfg = &m_gpio_cfg[obj->ch];
bool irq_enabled_before =
(m_gpio_irq_enabled & (1 << obj->ch)) &&
(cfg->irq_rise || cfg->irq_fall);
if (event == IRQ_RISE) {
cfg->irq_rise = enable ? true : false;
}
else if (event == IRQ_FALL) {
cfg->irq_fall = enable ? true : false;
}
bool irq_enabled_after = cfg->irq_rise || cfg->irq_fall;
if (irq_enabled_before != irq_enabled_after) {
if (irq_enabled_after) {
gpio_irq_enable(obj);
} else {
gpio_irq_disable(obj);
}
}
}
void gpio_irq_enable(gpio_irq_t *obj)
{
m_gpio_irq_enabled |= (1 << obj->ch);
if (m_gpio_cfg[obj->ch].irq_rise || m_gpio_cfg[obj->ch].irq_fall) {
nrf_drv_gpiote_in_event_enable(obj->ch, true);
}
}
void gpio_irq_disable(gpio_irq_t *obj)
{
m_gpio_irq_enabled &= ~(1 << obj->ch);
nrf_drv_gpiote_in_event_disable(obj->ch);
}

View File

@ -0,0 +1,48 @@
/* 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.
*/
#ifndef MBED_GPIO_OBJECT_H
#define MBED_GPIO_OBJECT_H
#include "mbed_assert.h"
#include "nrf_gpio.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
PinName pin;
} gpio_t;
static inline void gpio_write(gpio_t *obj, int value) {
MBED_ASSERT(obj->pin != (PinName)NC);
if (value) {
nrf_gpio_pin_set(obj->pin);
} else {
nrf_gpio_pin_clear(obj->pin);
}
}
static inline int gpio_is_connected(const gpio_t *obj) {
return obj->pin != (PinName)NC;
}
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,329 @@
/*
* Copyright (c) 2013 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#include "i2c_api.h"
#if DEVICE_I2C
#include "mbed_assert.h"
#include "mbed_error.h"
#include "nrf_drv_twi.h"
#include "app_util_platform.h"
#if DEVICE_I2C_ASYNCH
#define TWI_IDX(obj) ((obj)->i2c.twi_idx)
#else
#define TWI_IDX(obj) ((obj)->twi_idx)
#endif
#define TWI_INFO(obj) (&m_twi_info[TWI_IDX(obj)])
typedef struct {
bool initialized;
nrf_drv_twi_config_t config;
volatile bool transfer_finished;
#if DEVICE_I2C_ASYNCH
volatile uint32_t events;
void (*handler)(void);
uint32_t event_mask;
#endif
} twi_info_t;
static twi_info_t m_twi_info[TWI_COUNT];
static nrf_drv_twi_t const m_twi_instances[TWI_COUNT] = {
#if TWI0_ENABLED
NRF_DRV_TWI_INSTANCE(0),
#endif
#if TWI1_ENABLED
NRF_DRV_TWI_INSTANCE(1),
#endif
};
static void twi_event_handler(nrf_drv_twi_evt_t const *event, void *context)
{
twi_info_t * twi_info = TWI_INFO((i2c_t *)context);
twi_info->transfer_finished = true;
#if DEVICE_I2C_ASYNCH
switch (event->type) {
case NRF_DRV_TWI_EVT_DONE:
twi_info->events |= I2C_EVENT_TRANSFER_COMPLETE;
break;
case NRF_DRV_TWI_EVT_ADDRESS_NACK:
twi_info->events |= I2C_EVENT_ERROR_NO_SLAVE;
break;
case NRF_DRV_TWI_EVT_DATA_NACK:
twi_info->events |= I2C_EVENT_ERROR;
break;
}
if (twi_info->handler) {
twi_info->handler();
}
#endif // DEVICE_I2C_ASYNCH
}
static uint8_t twi_address(int i2c_address)
{
// The TWI driver requires 7-bit slave address (without R/W bit).
return (i2c_address >> 1);
}
void SPI0_TWI0_IRQHandler(void);
void SPI1_TWI1_IRQHandler(void);
static const peripheral_handler_desc_t twi_handlers[TWI_COUNT] =
{
#if TWI0_ENABLED
{
SPI0_TWI0_IRQn,
(uint32_t) SPI0_TWI0_IRQHandler
},
#endif
#if TWI1_ENABLED
{
SPI1_TWI1_IRQn,
(uint32_t) SPI1_TWI1_IRQHandler
}
#endif
};
void i2c_init(i2c_t *obj, PinName sda, PinName scl)
{
int i;
for (i = 0; i < TWI_COUNT; ++i) {
if (m_twi_info[i].initialized &&
m_twi_info[i].config.sda == (uint32_t)sda &&
m_twi_info[i].config.scl == (uint32_t)scl) {
TWI_IDX(obj) = i;
TWI_INFO(obj)->config.frequency = NRF_TWI_FREQ_100K;
i2c_reset(obj);
return;
}
}
nrf_drv_twi_config_t const config = {
.scl = scl,
.sda = sda,
.frequency = NRF_TWI_FREQ_100K,
#ifdef NRF51
.interrupt_priority = APP_IRQ_PRIORITY_LOW
#elif defined(NRF52)
.interrupt_priority = APP_IRQ_PRIORITY_LOWEST
#endif
};
for (i = 0; i < TWI_COUNT; ++i) {
if (!m_twi_info[i].initialized) {
NVIC_SetVector(twi_handlers[i].IRQn, twi_handlers[i].vector);
nrf_drv_twi_t const *twi = &m_twi_instances[i];
ret_code_t ret_code =
nrf_drv_twi_init(twi, &config, twi_event_handler, obj);
if (ret_code == NRF_SUCCESS) {
TWI_IDX(obj) = i;
TWI_INFO(obj)->initialized = true;
TWI_INFO(obj)->config = config;
nrf_drv_twi_enable(twi);
return;
}
}
}
// No available peripheral
error("No available I2C peripheral\r\n");
}
void i2c_reset(i2c_t *obj)
{
twi_info_t *twi_info = TWI_INFO(obj);
nrf_drv_twi_t const *twi = &m_twi_instances[TWI_IDX(obj)];
nrf_drv_twi_uninit(twi);
nrf_drv_twi_init(twi, &twi_info->config, twi_event_handler, obj);
nrf_drv_twi_enable(twi);
}
int i2c_start(i2c_t *obj)
{
(void)obj;
return -1; // Not implemented.
}
int i2c_stop(i2c_t *obj)
{
(void)obj;
return -1; // Not implemented.
}
void i2c_frequency(i2c_t *obj, int hz)
{
twi_info_t *twi_info = TWI_INFO(obj);
nrf_drv_twi_t const *twi = &m_twi_instances[TWI_IDX(obj)];
if (hz < 250000) {
twi_info->config.frequency = NRF_TWI_FREQ_100K;
} else if (hz < 400000) {
twi_info->config.frequency = NRF_TWI_FREQ_250K;
} else {
twi_info->config.frequency = NRF_TWI_FREQ_400K;
}
nrf_twi_frequency_set(twi->reg.p_twi, twi_info->config.frequency);
}
int i2c_read(i2c_t *obj, int address, char *data, int length, int stop)
{
(void)stop;
twi_info_t *twi_info = TWI_INFO(obj);
nrf_drv_twi_t const *twi = &m_twi_instances[TWI_IDX(obj)];
twi_info->transfer_finished = false;
ret_code_t ret_code = nrf_drv_twi_rx(twi, twi_address(address),
(uint8_t *)data, length);
if (ret_code != NRF_SUCCESS) {
return 0;
}
while (!twi_info->transfer_finished) {}
return nrf_drv_twi_data_count_get(twi);
}
int i2c_write(i2c_t *obj, int address, const char *data, int length, int stop)
{
twi_info_t *twi_info = TWI_INFO(obj);
nrf_drv_twi_t const *twi = &m_twi_instances[TWI_IDX(obj)];
twi_info->transfer_finished = false;
ret_code_t ret_code = nrf_drv_twi_tx(twi, twi_address(address),
(uint8_t const *)data, length, (stop == 0));
if (ret_code != NRF_SUCCESS) {
return 0;
}
while (!twi_info->transfer_finished) {}
return nrf_drv_twi_data_count_get(twi);
}
int i2c_byte_read(i2c_t *obj, int last)
{
(void)obj;
(void)last;
return -1; // Not implemented.
}
int i2c_byte_write(i2c_t *obj, int data)
{
(void)obj;
(void)data;
return -1; // Not implemented.
}
#if DEVICE_I2C_ASYNCH
void i2c_transfer_asynch(i2c_t *obj, const void *tx, size_t tx_length,
void *rx, size_t rx_length, uint32_t address,
uint32_t stop, uint32_t handler,
uint32_t event, DMAUsage hint)
{
(void)stop;
(void)hint;
if (i2c_active(obj)) {
return;
}
if ((tx_length == 0) && (rx_length == 0)) {
return;
}
twi_info_t *twi_info = TWI_INFO(obj);
twi_info->events = 0;
twi_info->handler = (void (*)(void))handler;
twi_info->event_mask = event;
uint8_t twi_addr = twi_address(address);
nrf_drv_twi_t const *twi = &m_twi_instances[TWI_IDX(obj)];
if ((tx_length > 0) && (rx_length == 0)) {
nrf_drv_twi_xfer_desc_t const xfer =
NRF_DRV_TWI_XFER_DESC_TX(twi_addr, (uint8_t *)tx, tx_length);
nrf_drv_twi_xfer(twi, &xfer,
stop ? 0 : NRF_DRV_TWI_FLAG_TX_NO_STOP);
}
else if ((tx_length == 0) && (rx_length > 0)) {
nrf_drv_twi_xfer_desc_t const xfer =
NRF_DRV_TWI_XFER_DESC_RX(twi_addr, rx, rx_length);
nrf_drv_twi_xfer(twi, &xfer, 0);
}
else if ((tx_length > 0) && (rx_length > 0)) {
nrf_drv_twi_xfer_desc_t const xfer =
NRF_DRV_TWI_XFER_DESC_TXRX(twi_addr,
(uint8_t *)tx, tx_length, rx, rx_length);
nrf_drv_twi_xfer(twi, &xfer, 0);
}
}
uint32_t i2c_irq_handler_asynch(i2c_t *obj)
{
twi_info_t *twi_info = TWI_INFO(obj);
return (twi_info->events & twi_info->event_mask);
}
uint8_t i2c_active(i2c_t *obj)
{
nrf_drv_twi_t const *twi = &m_twi_instances[TWI_IDX(obj)];
return nrf_drv_twi_is_busy(twi);
}
void i2c_abort_asynch(i2c_t *obj)
{
i2c_reset(obj);
}
#endif // DEVICE_I2C_ASYNCH
#endif // DEVICE_I2C

View File

@ -0,0 +1,55 @@
/*
* Copyright (c) 2016 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/**
* @file irq_handlers_hw.h
* @brief Heleper file for wiring irq handlers to theirs vectors.
*/
#ifndef IRQ_HANDLERS_HW_H__
#define IRQ_HANDLERS_HW_H__
typedef struct
{
IRQn_Type IRQn;
uint32_t vector;
} peripheral_handler_desc_t;
#endif // IRQ_HANDLERS_HW_H__

View File

@ -0,0 +1,48 @@
/* mbed Microcontroller Library
* Copyright (c) 2015 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.
*/
#include "lp_ticker_api.h"
#if DEVICE_LOWPOWERTIMER
#include "common_rtc.h"
void lp_ticker_init(void)
{
common_rtc_init();
}
uint32_t lp_ticker_read()
{
return (uint32_t)common_rtc_64bit_us_get();
}
void lp_ticker_set_interrupt(timestamp_t timestamp)
{
common_rtc_set_interrupt(timestamp,
LP_TICKER_CC_CHANNEL, LP_TICKER_INT_MASK);
}
void lp_ticker_disable_interrupt(void)
{
nrf_rtc_event_disable(COMMON_RTC_INSTANCE, LP_TICKER_INT_MASK);
}
void lp_ticker_clear_interrupt(void)
{
nrf_rtc_event_clear(COMMON_RTC_INSTANCE, LP_TICKER_EVENT);
}
#endif // DEVICE_LOWPOWERTIMER

View File

@ -0,0 +1,57 @@
/*
* Copyright (c) 2015-2016, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*/
#include <stdint.h> // uint32_t, UINT32_MAX
#include <assert.h> // uint32_t, UINT32_MAX
#include "cmsis.h"
#include "nrf_soc.h"
#include "nrf_sdm.h"
#include "nrf_nvic.h"
static uint8_t _sd_state = 0;
static volatile uint32_t _entry_count = 0;
void core_util_critical_section_enter()
{
// if a critical section has already been entered, just update the counter
if (_entry_count) {
++_entry_count;
return;
}
// in this path, a critical section has never been entered
// routine of SD V11 work even if the softdevice is not active
sd_nvic_critical_region_enter(&_sd_state);
assert(_entry_count == 0); // entry count should always be equal to 0 at this point
++_entry_count;
}
void core_util_critical_section_exit()
{
assert(_entry_count > 0);
--_entry_count;
// If their is other segments which have entered the critical section, just leave
if (_entry_count) {
return;
}
// This is the last segment of the critical section, state should be restored as before entering
// the critical section
sd_nvic_critical_region_exit(_sd_state);
}

View File

@ -0,0 +1,66 @@
/*
* Copyright (c) 2016 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#ifndef __NRF5X_LF_CLK_HELPER_H_
#ifndef MBED_CONF_NORDIC_NRF_LF_CLOCK_SRC
#define MBED_CONF_NORDIC_NRF_LF_CLOCK_SRC (NRF_LF_SRC_XTAL)
#warning No configuration for LF clock source. Xtal source will be used as a default configuration.
#endif
#define NRF_LF_SRC_XTAL 2
#define NRF_LF_SRC_SYNTH 3
#define NRF_LF_SRC_RC 4
#if MBED_CONF_NORDIC_NRF_LF_CLOCK_SRC == NRF_LF_SRC_SYNTH
#define CLOCK_LFCLKSRC_SRC_TO_USE (CLOCK_LFCLKSRC_SRC_Synth)
#elif MBED_CONF_NORDIC_NRF_LF_CLOCK_SRC == NRF_LF_SRC_XTAL
#define CLOCK_LFCLKSRC_SRC_TO_USE (CLOCK_LFCLKSRC_SRC_Xtal)
#elif MBED_CONF_NORDIC_NRF_LF_CLOCK_SRC == NRF_LF_SRC_RC
#define CLOCK_LFCLKSRC_SRC_TO_USE (CLOCK_LFCLKSRC_SRC_RC)
#else
#error Bad LFCLK configuration. Declare proper source through mbed configuration.
#endif
#undef NRF_LF_SRC_XTAL
#undef NRF_LF_SRC_SYNTH
#undef NRF_LF_SRC_RC
#endif

View File

@ -0,0 +1,94 @@
/*
* Copyright (c) 2013 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#ifndef MBED_OBJECTS_H
#define MBED_OBJECTS_H
#include "cmsis.h"
#include "PortNames.h"
#include "PeripheralNames.h"
#include "PinNames.h"
#ifdef __cplusplus
extern "C" {
#endif
struct serial_s {
uint32_t placeholder; // struct is unused by nRF5x API implementation
}; // but it must be not empty (required by strict compiler - IAR)
struct spi_s {
uint8_t spi_idx;
};
struct port_s {
__IO uint32_t *reg_cnf;
__IO uint32_t *reg_out;
__I uint32_t *reg_in;
PortName port;
uint32_t mask;
};
struct pwmout_s {
PWMName pwm_name;
PinName pin;
uint8_t pwm_channel;
void * pwm_struct;
};
struct i2c_s {
uint8_t twi_idx;
};
struct analogin_s {
ADCName adc;
uint8_t adc_pin;
};
struct gpio_irq_s {
uint32_t ch;
};
#include "gpio_object.h"
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,35 @@
/* 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.
*/
#include "mbed_assert.h"
#include "mbed_error.h"
#include "pinmap.h"
void pin_function(PinName pin, int function)
{
/* Avoid compiler warnings */
(void) pin;
(void) function;
}
void pin_mode(PinName pin, PinMode mode)
{
MBED_ASSERT(pin != (PinName)NC);
uint32_t pin_number = (uint32_t)pin;
NRF_GPIO->PIN_CNF[pin_number] &= ~GPIO_PIN_CNF_PULL_Msk;
NRF_GPIO->PIN_CNF[pin_number] |= (mode << GPIO_PIN_CNF_PULL_Pos);
}

View File

@ -0,0 +1,108 @@
/*
* Copyright (c) 2013 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#include "port_api.h"
#include "pinmap.h"
#include "gpio_api.h"
PinName port_pin(PortName port, int pin_n)
{
(void) port;
return (PinName)(pin_n);
}
void port_init(port_t *obj, PortName port, int mask, PinDirection dir)
{
obj->port = port;
obj->mask = mask;
obj->reg_out = &NRF_GPIO->OUT;
obj->reg_in = &NRF_GPIO->IN;
obj->reg_cnf = NRF_GPIO->PIN_CNF;
port_dir(obj, dir);
}
void port_mode(port_t *obj, PinMode mode)
{
uint32_t i;
// The mode is set per pin: reuse pinmap logic
for (i = 0; i<31; i++) {
if (obj->mask & (1 << i)) {
pin_mode(port_pin(obj->port, i), mode);
}
}
}
void port_dir(port_t *obj, PinDirection dir)
{
int i;
switch (dir) {
case PIN_INPUT:
for (i = 0; i<31; i++) {
if (obj->mask & (1 << i)) {
obj->reg_cnf[i] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
| (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
| (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
| (GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos);
}
}
break;
case PIN_OUTPUT:
for (i = 0; i<31; i++) {
if (obj->mask & (1 << i)) {
obj->reg_cnf[i] = (GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos)
| (GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
| (GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos)
| (GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
| (GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos);
}
}
break;
}
}
void port_write(port_t *obj, int value)
{
*obj->reg_out = value;
}
int port_read(port_t *obj)
{
return (*obj->reg_in);
}

View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2016 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#include "nrf.h"
#include "cmsis_nvic.h"
#include "stdint.h"
#include "nrf_sdm.h"
#include "section_vars.h"
#if defined(__CC_ARM)
__attribute__ ((section("noinit"),zero_init))
uint32_t nrf_dispatch_vector[NVIC_NUM_VECTORS];
#elif defined(__GNUC__)
__attribute__ ((section(".noinit")))
uint32_t nrf_dispatch_vector[NVIC_NUM_VECTORS];
#elif defined(__ICCARM__)
uint32_t nrf_dispatch_vector[NVIC_NUM_VECTORS] @ ".noinit";
#endif
typedef void (*generic_irq_handler_t)(void);
extern uint32_t __Vectors[];
#define VECTORS_FLASH_START __Vectors
/**
* @brief Function for relocation of the vector to RAM on nRF5x devices.
* This function is intended to be called during startup.
*/
void nrf_reloc_vector_table(void)
{
// Copy and switch to dynamic vectors
uint32_t *old_vectors = (uint32_t*)VECTORS_FLASH_START;
uint32_t i;
for (i = 0; i< NVIC_NUM_VECTORS; i++) {
nrf_dispatch_vector[i] = old_vectors[i];
}
sd_softdevice_vector_table_base_set((uint32_t) nrf_dispatch_vector);
}

View File

@ -0,0 +1,92 @@
/*
* Copyright (c) 2013 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#include "rtc_api.h"
#if DEVICE_RTC
#include "common_rtc.h"
#include "nrf_drv_clock.h"
#include "app_util_platform.h"
static time_t m_time_base;
void rtc_init(void)
{
common_rtc_init();
}
void rtc_free(void)
{
// A common counter is used for RTC, lp_ticker and us_ticker, so it can't be
// disabled here, but this does not cause any extra cost. Besides, currently
// this function is not used by RTC API in mbed-drivers.
}
int rtc_isenabled(void)
{
return m_common_rtc_enabled;
}
static uint32_t rtc_seconds_get(void)
{
// Convert current counter value to seconds.
uint32_t seconds = nrf_rtc_counter_get(COMMON_RTC_INSTANCE) / RTC_INPUT_FREQ;
// Add proper amount of seconds for each registered overflow of the counter.
uint32_t seconds_per_overflow = (1uL << RTC_COUNTER_BITS) / RTC_INPUT_FREQ;
return (seconds + (m_common_rtc_overflows * seconds_per_overflow));
}
time_t rtc_read(void)
{
return m_time_base + rtc_seconds_get();
}
void rtc_write(time_t t)
{
uint32_t seconds;
do {
seconds = rtc_seconds_get();
m_time_base = t - seconds;
// If the number of seconds indicated by the counter changed during the
// update of the time base, just repeat the update, now using the new
// number of seconds.
} while (seconds != rtc_seconds_get());
}
#endif // DEVICE_RTC

View File

@ -0,0 +1,594 @@
/*
* Copyright (c) 2015 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#include "ble_advdata.h"
#include "ble_advertising.h"
#include "nrf_soc.h"
#include "nrf_log.h"
#include "pstorage.h"
#include "fstorage.h"
#include "sdk_common.h"
#define ADV_LOG(...)
static bool m_advertising_start_pending = false; /**< Flag to keep track of ongoing operations on persistent memory. */
static ble_gap_addr_t m_peer_address; /**< Address of the most recently connected peer, used for direct advertising. */
static ble_advdata_t m_advdata; /**< Used by the initialization function to set name, appearance, and UUIDs and advertising flags visible to peer devices. */
static ble_adv_evt_t m_adv_evt; /**< Advertising event propogated to the main application. The event is either a transaction to a new advertising mode, or a request for whitelist or peer address.. */
static ble_advertising_evt_handler_t m_evt_handler; /**< Handler for the advertising events. Can be initialized as NULL if no handling is implemented on in the main application. */
static ble_advertising_error_handler_t m_error_handler; /**< Handler for the advertising error events. */
static ble_adv_mode_t m_adv_mode_current; /**< Variable to keep track of the current advertising mode. */
static ble_adv_modes_config_t m_adv_modes_config; /**< Struct to keep track of disabled and enabled advertising modes, as well as time-outs and intervals.*/
static ble_gap_whitelist_t m_whitelist; /**< Struct that points to whitelisted addresses. */
static ble_gap_addr_t * mp_whitelist_addr[BLE_GAP_WHITELIST_ADDR_MAX_COUNT]; /**< Pointer to a list of addresses. Pointed to by the whitelist */
static ble_gap_irk_t * mp_whitelist_irk[BLE_GAP_WHITELIST_IRK_MAX_COUNT]; /**< Pointer to a list of Identity Resolving Keys (IRK). Pointed to by the whitelist */
static bool m_whitelist_temporarily_disabled = false; /**< Flag to keep track of temporary disabling of the whitelist. */
static bool m_whitelist_reply_expected = false; /**< Flag to verify that whitelist is only set when it is requested. */
static bool m_peer_addr_reply_expected = false; /**< Flag to verify that peer address is only set when requested. */
static ble_advdata_manuf_data_t m_manuf_specific_data; /**< Manufacturer specific data structure*/
static uint8_t m_manuf_data_array[BLE_GAP_ADV_MAX_SIZE]; /**< Array to store the Manufacturer specific data*/
static ble_advdata_service_data_t m_service_data; /**< Service data structure. */
static uint8_t m_service_data_array[BLE_GAP_ADV_MAX_SIZE]; /**< Array to store the service data. */
static ble_advdata_conn_int_t m_slave_conn_int; /**< Connection interval range structure.*/
static int8_t m_tx_power_level; /**< TX power level*/
/**@brief Function for checking that the whitelist has entries.
*/
static bool whitelist_has_entries(ble_gap_whitelist_t const * whitelist)
{
if ((whitelist->addr_count != 0) || (whitelist->irk_count != 0))
{
return true;
}
return false;
}
/**@brief Function for setting the stored peer address back to zero.
*/
static void ble_advertising_peer_address_clear()
{
memset(&m_peer_address, 0, sizeof(m_peer_address));
}
/**@brief Function for checking if an address is non-zero. Used to determine if
*/
static bool peer_address_exists(uint8_t const * address)
{
uint32_t i;
for (i = 0; i < BLE_GAP_ADDR_LEN; i++)
{
if (address[i] != 0)
{
return true;
}
}
return false;
}
uint32_t ble_advertising_init(ble_advdata_t const * p_advdata,
ble_advdata_t const * p_srdata,
ble_adv_modes_config_t const * p_config,
ble_advertising_evt_handler_t const evt_handler,
ble_advertising_error_handler_t const error_handler)
{
uint32_t err_code;
VERIFY_PARAM_NOT_NULL(p_advdata);
VERIFY_PARAM_NOT_NULL(p_config);
m_adv_mode_current = BLE_ADV_MODE_IDLE;
m_evt_handler = evt_handler;
m_error_handler = error_handler;
m_adv_modes_config = *p_config;
ble_advertising_peer_address_clear();
// Prepare Whitelist. Address and IRK double pointers point to allocated arrays.
m_whitelist.pp_addrs = mp_whitelist_addr;
m_whitelist.pp_irks = mp_whitelist_irk;
// Copy and set advertising data.
memset(&m_advdata, 0, sizeof(m_advdata));
// Copy advertising data.
m_advdata.name_type = p_advdata->name_type;
m_advdata.include_appearance = p_advdata->include_appearance;
m_advdata.flags = p_advdata->flags;
m_advdata.short_name_len = p_advdata->short_name_len;
/*
if(p_advdata->uuids_complete != NULL)
{
m_advdata.uuids_complete = p_advdata->uuids_complete;
}
*/
m_advdata.uuids_complete = p_advdata->uuids_complete;
m_advdata.uuids_more_available = p_advdata->uuids_more_available;
m_advdata.uuids_solicited = p_advdata->uuids_solicited;
if(p_advdata->p_manuf_specific_data != NULL)
{
m_advdata.p_manuf_specific_data = &m_manuf_specific_data;
m_manuf_specific_data.data.p_data = m_manuf_data_array;
m_advdata.p_manuf_specific_data->company_identifier =
p_advdata->p_manuf_specific_data->company_identifier;
m_advdata.p_manuf_specific_data->data.size = p_advdata->p_manuf_specific_data->data.size;
for(uint32_t i = 0; i < m_advdata.p_manuf_specific_data->data.size; i++)
{
m_manuf_data_array[i] = p_advdata->p_manuf_specific_data->data.p_data[i];
}
}
if(p_advdata->p_service_data_array != NULL)
{
m_service_data.data.p_data = m_service_data_array;
m_advdata.p_service_data_array = &m_service_data;
m_advdata.p_service_data_array->data.p_data = m_service_data_array;
m_advdata.p_service_data_array->data.size = p_advdata->p_service_data_array->data.size;
m_advdata.p_service_data_array->service_uuid = p_advdata->p_service_data_array->service_uuid;
for(uint32_t i = 0; i < m_advdata.p_service_data_array->data.size; i++)
{
m_service_data_array[i] = p_advdata->p_service_data_array->data.p_data[i];
}
m_advdata.service_data_count = p_advdata->service_data_count;
}
if(p_advdata->p_slave_conn_int != NULL)
{
m_advdata.p_slave_conn_int = &m_slave_conn_int;
m_advdata.p_slave_conn_int->max_conn_interval = p_advdata->p_slave_conn_int->max_conn_interval;
m_advdata.p_slave_conn_int->min_conn_interval = p_advdata->p_slave_conn_int->min_conn_interval;
}
if(p_advdata->p_tx_power_level != NULL)
{
m_advdata.p_tx_power_level = &m_tx_power_level;
m_advdata.p_tx_power_level = p_advdata->p_tx_power_level;
}
err_code = ble_advdata_set(&m_advdata, p_srdata);
return err_code;
}
/** @brief Function to determine if a flash access in in progress. If it is the case, we can not
* start advertising until it is finished. attempted restart
* in @ref ble_advertising_on_sys_evt
*
* @return true if a flash access is in progress, false if not.
*/
static bool flash_access_in_progress()
{
uint32_t err_code;
uint32_t count = 0;
err_code = pstorage_access_status_get(&count);
if ((err_code != NRF_ERROR_INVALID_STATE) && (err_code != NRF_SUCCESS))
{
ADV_LOG("[ADV]: pstorage_access_status_get returned %d.\r\n", err_code);
return true;
}
if (err_code == NRF_ERROR_INVALID_STATE)
{
err_code = fs_queued_op_count_get(&count);
if (err_code != FS_SUCCESS)
{
return false;
}
ADV_LOG("[ADV]: fs_queued_op_count_get gives count %d.\r\n", count);
}
if(count != 0)
{
return true;
}
else
{
return false;
}
}
uint32_t ble_advertising_start(ble_adv_mode_t advertising_mode)
{
uint32_t err_code;
ble_gap_adv_params_t adv_params;
m_adv_mode_current = advertising_mode;
// Verify if there are any pending flash operations. If so, delay starting advertising until
// the flash operations are complete.
if(flash_access_in_progress())
{
m_advertising_start_pending = true;
return NRF_SUCCESS;
}
ADV_LOG("[ADV]: no flash operations in progress, prepare advertising.\r\n");
// Fetch the peer address.
ble_advertising_peer_address_clear();
if ( ((m_adv_modes_config.ble_adv_directed_enabled) && (m_adv_mode_current == BLE_ADV_MODE_DIRECTED))
||((m_adv_modes_config.ble_adv_directed_slow_enabled) && (m_adv_mode_current == BLE_ADV_MODE_DIRECTED))
||((m_adv_modes_config.ble_adv_directed_slow_enabled) && (m_adv_mode_current == BLE_ADV_MODE_DIRECTED_SLOW))
)
{
if (m_evt_handler != NULL)
{
m_peer_addr_reply_expected = true;
m_evt_handler(BLE_ADV_EVT_PEER_ADDR_REQUEST);
}
else
{
m_peer_addr_reply_expected = false;
}
}
// If a mode is disabled, continue to the next mode. I.e fast instead of direct, slow instead of fast, idle instead of slow.
if ( (m_adv_mode_current == BLE_ADV_MODE_DIRECTED)
&&(!m_adv_modes_config.ble_adv_directed_enabled || !peer_address_exists(m_peer_address.addr)))
{
m_adv_mode_current = BLE_ADV_MODE_DIRECTED_SLOW;
}
if ( (m_adv_mode_current == BLE_ADV_MODE_DIRECTED_SLOW)
&&(!m_adv_modes_config.ble_adv_directed_slow_enabled || !peer_address_exists(m_peer_address.addr)))
{
m_adv_mode_current = BLE_ADV_MODE_FAST;
}
if (!m_adv_modes_config.ble_adv_fast_enabled && m_adv_mode_current == BLE_ADV_MODE_FAST)
{
m_adv_mode_current = BLE_ADV_MODE_SLOW;
}
if (!m_adv_modes_config.ble_adv_slow_enabled && m_adv_mode_current == BLE_ADV_MODE_SLOW)
{
m_adv_mode_current = BLE_ADV_MODE_IDLE;
m_adv_evt = BLE_ADV_EVT_IDLE;
}
// Fetch the whitelist.
if ( (m_evt_handler != NULL)
&& (m_adv_mode_current == BLE_ADV_MODE_FAST || m_adv_mode_current == BLE_ADV_MODE_SLOW)
&& (m_adv_modes_config.ble_adv_whitelist_enabled)
&& (!m_whitelist_temporarily_disabled))
{
m_whitelist_reply_expected = true;
m_evt_handler(BLE_ADV_EVT_WHITELIST_REQUEST);
}
else
{
m_whitelist_reply_expected = false;
}
// Initialize advertising parameters with default values.
memset(&adv_params, 0, sizeof(adv_params));
adv_params.type = BLE_GAP_ADV_TYPE_ADV_IND;
adv_params.p_peer_addr = NULL;
adv_params.fp = BLE_GAP_ADV_FP_ANY;
adv_params.p_whitelist = NULL;
// Set advertising parameters and events according to selected advertising mode.
switch (m_adv_mode_current)
{
case BLE_ADV_MODE_DIRECTED:
ADV_LOG("[ADV]: Starting direct advertisement.\r\n");
adv_params.p_peer_addr = &m_peer_address; // Directed advertising.
adv_params.type = BLE_GAP_ADV_TYPE_ADV_DIRECT_IND;
adv_params.timeout = 0;
adv_params.interval = 0;
m_adv_evt = BLE_ADV_EVT_DIRECTED;
break;
case BLE_ADV_MODE_DIRECTED_SLOW:
ADV_LOG("[ADV]: Starting direct advertisement.\r\n");
adv_params.p_peer_addr = &m_peer_address; // Directed advertising.
adv_params.type = BLE_GAP_ADV_TYPE_ADV_DIRECT_IND;
adv_params.timeout = m_adv_modes_config.ble_adv_directed_slow_timeout;
adv_params.interval = m_adv_modes_config.ble_adv_directed_slow_interval;
m_adv_evt = BLE_ADV_EVT_DIRECTED_SLOW;
break;
case BLE_ADV_MODE_FAST:
adv_params.timeout = m_adv_modes_config.ble_adv_fast_timeout;
adv_params.interval = m_adv_modes_config.ble_adv_fast_interval;
if ( whitelist_has_entries(&m_whitelist)
&& m_adv_modes_config.ble_adv_whitelist_enabled
&& !m_whitelist_temporarily_disabled)
{
adv_params.fp = BLE_GAP_ADV_FP_FILTER_CONNREQ;
adv_params.p_whitelist = &m_whitelist;
m_advdata.flags = BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED;
err_code = ble_advdata_set(&m_advdata, NULL);
VERIFY_SUCCESS(err_code);
m_adv_evt = BLE_ADV_EVT_FAST_WHITELIST;
ADV_LOG("[ADV]: Starting fast advertisement with whitelist.\r\n");
}
else
{
m_adv_evt = BLE_ADV_EVT_FAST;
ADV_LOG("[ADV]: Starting fast advertisement.\r\n");
}
break;
case BLE_ADV_MODE_SLOW:
adv_params.interval = m_adv_modes_config.ble_adv_slow_interval;
adv_params.timeout = m_adv_modes_config.ble_adv_slow_timeout;
if ( whitelist_has_entries(&m_whitelist)
&& m_adv_modes_config.ble_adv_whitelist_enabled
&& !m_whitelist_temporarily_disabled)
{
adv_params.fp = BLE_GAP_ADV_FP_FILTER_CONNREQ;
adv_params.p_whitelist = &m_whitelist;
m_advdata.flags = BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED;
err_code = ble_advdata_set(&m_advdata, NULL);
VERIFY_SUCCESS(err_code);
m_adv_evt = BLE_ADV_EVT_SLOW_WHITELIST;
ADV_LOG("[ADV]: Starting slow advertisement with whitelist.\r\n");
}
else
{
m_adv_evt = BLE_ADV_EVT_SLOW;
ADV_LOG("[ADV]: Starting slow advertisement.\r\n");
}
break;
default:
break;
}
if (m_adv_mode_current != BLE_ADV_MODE_IDLE)
{
err_code = sd_ble_gap_adv_start(&adv_params);
VERIFY_SUCCESS(err_code);
}
if (m_evt_handler != NULL)
{
m_evt_handler(m_adv_evt);
}
return NRF_SUCCESS;
}
void ble_advertising_on_ble_evt(ble_evt_t const * p_ble_evt)
{
static uint16_t current_slave_link_conn_handle = BLE_CONN_HANDLE_INVALID;
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
if (p_ble_evt->evt.gap_evt.params.connected.role == BLE_GAP_ROLE_PERIPH)
{
current_slave_link_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
}
break;
// Upon disconnection, whitelist will be activated and direct advertising is started.
case BLE_GAP_EVT_DISCONNECTED:
{
uint32_t err_code;
m_whitelist_temporarily_disabled = false;
if (p_ble_evt->evt.gap_evt.conn_handle == current_slave_link_conn_handle)
{
err_code = ble_advertising_start(BLE_ADV_MODE_DIRECTED);
if ((err_code != NRF_SUCCESS) && (m_error_handler != NULL))
{
m_error_handler(err_code);
}
}
break;
}
// Upon time-out, the next advertising mode is started, i.e. go from fast to slow or from slow to idle.
case BLE_GAP_EVT_TIMEOUT:
if (p_ble_evt->evt.gap_evt.params.timeout.src == BLE_GAP_TIMEOUT_SRC_ADVERTISING)
{
switch (m_adv_mode_current)
{
case BLE_ADV_MODE_DIRECTED:
ADV_LOG("[ADV]: Timed out from directed advertising.\r\n");
{
uint32_t err_code;
err_code = ble_advertising_start(BLE_ADV_MODE_DIRECTED_SLOW);
if ((err_code != NRF_SUCCESS) && (m_error_handler != NULL))
{
m_error_handler(err_code);
}
}
break;
case BLE_ADV_MODE_DIRECTED_SLOW:
ADV_LOG("[ADV]: Timed out from directed slow advertising.\r\n");
{
uint32_t err_code;
err_code = ble_advertising_start(BLE_ADV_MODE_FAST);
if ((err_code != NRF_SUCCESS) && (m_error_handler != NULL))
{
m_error_handler(err_code);
}
}
break;
case BLE_ADV_MODE_FAST:
{
uint32_t err_code;
m_adv_evt = BLE_ADV_EVT_FAST;
ADV_LOG("[ADV]: Timed out from fast advertising, starting slow advertising.\r\n");
err_code = ble_advertising_start(BLE_ADV_MODE_SLOW);
if ((err_code != NRF_SUCCESS) && (m_error_handler != NULL))
{
m_error_handler(err_code);
}
break;
}
case BLE_ADV_MODE_SLOW:
m_adv_evt = BLE_ADV_EVT_IDLE;
ADV_LOG("[ADV]: Timed out from slow advertising, stopping advertising.\r\n");
if (m_evt_handler != NULL)
{
m_evt_handler(m_adv_evt);
}
break;
default:
// No implementation needed.
break;
}
}
break;
default:
// No implementation needed.
break;
}
}
void ble_advertising_on_sys_evt(uint32_t sys_evt)
{
uint32_t err_code = NRF_SUCCESS;
switch (sys_evt)
{
case NRF_EVT_FLASH_OPERATION_SUCCESS:
// Fall through.
//When a flash operation finishes, advertising no longer needs to be pending.
case NRF_EVT_FLASH_OPERATION_ERROR:
if (m_advertising_start_pending)
{
m_advertising_start_pending = false;
err_code = ble_advertising_start(m_adv_mode_current);
if ((err_code != NRF_SUCCESS) && (m_error_handler != NULL))
{
m_error_handler(err_code);
}
}
break;
default:
// No implementation needed.
break;
}
}
uint32_t ble_advertising_peer_addr_reply(ble_gap_addr_t * p_peer_address)
{
if(m_peer_addr_reply_expected == false)
{
return NRF_ERROR_INVALID_STATE;
}
m_peer_address.addr_type = p_peer_address->addr_type;
for (int i = 0; i < BLE_GAP_ADDR_LEN; i++)
{
m_peer_address.addr[i] = p_peer_address->addr[i];
}
m_peer_addr_reply_expected = false;
return NRF_SUCCESS;
}
uint32_t ble_advertising_whitelist_reply(ble_gap_whitelist_t * p_whitelist)
{
uint32_t i;
if(m_whitelist_reply_expected == false)
{
return NRF_ERROR_INVALID_STATE;
}
m_whitelist.addr_count = p_whitelist->addr_count;
m_whitelist.irk_count = p_whitelist->irk_count;
for (i = 0; i < m_whitelist.irk_count; i++)
{
mp_whitelist_irk[i] = p_whitelist->pp_irks[i];
}
for (i = 0; i < m_whitelist.addr_count; i++)
{
mp_whitelist_addr[i] = p_whitelist->pp_addrs[i];
}
m_whitelist_reply_expected = false;
return NRF_SUCCESS;
}
uint32_t ble_advertising_restart_without_whitelist(void)
{
uint32_t err_code;
if( m_adv_modes_config.ble_adv_whitelist_enabled == BLE_ADV_WHITELIST_ENABLED
&& !m_whitelist_temporarily_disabled)
{
if (m_adv_mode_current != BLE_ADV_MODE_IDLE)
{
err_code = sd_ble_gap_adv_stop();
VERIFY_SUCCESS(err_code);
}
m_whitelist_temporarily_disabled = true;
m_advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
err_code = ble_advdata_set(&m_advdata, NULL);
VERIFY_SUCCESS(err_code);
err_code = ble_advertising_start(m_adv_mode_current);
if ((err_code != NRF_SUCCESS) && (m_error_handler != NULL))
{
m_error_handler(err_code);
}
}
return NRF_SUCCESS;
}

View File

@ -0,0 +1,251 @@
/*
* Copyright (c) 2015 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/**@file
*
* @defgroup ble_sdk_lib_advertising Advertising Module
* @{
* @ingroup ble_sdk_lib
* @brief Module for handling connectable BLE advertising.
*
* @details The Advertising Module handles connectable advertising for your application. It can
* be configured with advertising modes to suit most typical use cases.
* Your main application can react to changes in advertising modes
* if an event handler is provided.
*
* @note The Advertising Module supports only applications with a single peripheral link.
*
* The application must propagate BLE stack events to this module by calling
* @ref ble_advertising_on_ble_evt() and system events by calling
* @ref ble_advertising_on_sys_evt().
*
*/
#ifndef BLE_ADVERTISING_H__
#define BLE_ADVERTISING_H__
#include <stdint.h>
#include "nrf_ble_gattc.h"
#include "nrf_ble.h"
#include "nrf_error.h"
#include "ble_advdata.h"
/**@brief Advertising modes.
*/
typedef enum
{
BLE_ADV_MODE_IDLE, /**< Idle; no connectable advertising is ongoing.*/
BLE_ADV_MODE_DIRECTED, /**< Directed advertising attempts to connect to the most recently disconnected peer. */
BLE_ADV_MODE_DIRECTED_SLOW, /**< Directed advertising (low duty cycle) attempts to connect to the most recently disconnected peer. */
BLE_ADV_MODE_FAST, /**< Fast advertising will connect to any peer device, or filter with a whitelist if one exists. */
BLE_ADV_MODE_SLOW, /**< Slow advertising is similar to fast advertising. By default, it uses a longer advertising interval and time-out than fast advertising. However, these options are defined by the user. */
} ble_adv_mode_t;
/**@brief Advertising events.
*
* @details These events are propagated to the main application if a handler was provided during
* initialization of the Advertising Module. Events for modes that are not used can be
* ignored. Similarly, BLE_ADV_EVT_WHITELIST_REQUEST and BLE_ADV_EVT_PEER_ADDR_REQUEST
* can be ignored if whitelist and direct advertising is not used.
*/
typedef enum
{
BLE_ADV_EVT_IDLE, /**< Idle; no connectable advertising is ongoing.*/
BLE_ADV_EVT_DIRECTED, /**< Direct advertising mode has started. */
BLE_ADV_EVT_DIRECTED_SLOW, /**< Directed advertising (low duty cycle) has started. */
BLE_ADV_EVT_FAST, /**< Fast advertising mode has started. */
BLE_ADV_EVT_SLOW, /**< Slow advertising mode has started.*/
BLE_ADV_EVT_FAST_WHITELIST, /**< Fast advertising mode using the whitelist has started. */
BLE_ADV_EVT_SLOW_WHITELIST, /**< Slow advertising mode using the whitelist has started.*/
BLE_ADV_EVT_WHITELIST_REQUEST, /**< Request a whitelist from the main application. For whitelist advertising to work, the whitelist must be set when this event occurs. */
BLE_ADV_EVT_PEER_ADDR_REQUEST /**< Request a peer address from the main application. For directed advertising to work, the peer address must be set when this event occurs. */
} ble_adv_evt_t;
/**@brief Options for the different advertisement modes.
*
* @details This structure is used to enable or disable advertising modes and to configure time-out
* periods and advertising intervals.
*/
typedef struct
{
bool ble_adv_whitelist_enabled; /**< Enable or disable use of the whitelist. */
bool ble_adv_directed_enabled; /**< Enable or disable direct advertising mode. */
bool ble_adv_directed_slow_enabled; /**< Enable or disable direct advertising mode. */
uint32_t ble_adv_directed_slow_interval; /**< Advertising interval for directed advertising. */
uint32_t ble_adv_directed_slow_timeout; /**< Time-out (number of tries) for direct advertising. */
bool ble_adv_fast_enabled; /**< Enable or disable fast advertising mode. */
uint32_t ble_adv_fast_interval; /**< Advertising interval for fast advertising. */
uint32_t ble_adv_fast_timeout; /**< Time-out (in seconds) for fast advertising. */
bool ble_adv_slow_enabled; /**< Enable or disable slow advertising mode. */
uint32_t ble_adv_slow_interval; /**< Advertising interval for slow advertising. */
uint32_t ble_adv_slow_timeout; /**< Time-out (in seconds) for slow advertising. */
}ble_adv_modes_config_t;
/**@brief BLE advertising event handler type. */
typedef void (*ble_advertising_evt_handler_t) (ble_adv_evt_t const adv_evt);
/**@brief BLE advertising error handler type. */
typedef void (*ble_advertising_error_handler_t) (uint32_t nrf_error);
/**@brief Initialization parameters for the Advertising Module.
* @details This structure is used to pass advertising options, advertising data, and an event handler to the Advertising Module during initialization. */
typedef struct
{
ble_adv_modes_config_t options; /**< Parameters for advertising modes.*/
ble_advdata_t advdata; /**< Advertising data. */
ble_advertising_evt_handler_t evt_handler; /**< Event handler. */
}ble_adv_init_t;
/* Defines to make the mode options easier to set during advertising init.*/
#define BLE_ADV_DIRECTED_ENABLED true
#define BLE_ADV_DIRECTED_DISABLED false
#define BLE_ADV_DIRECTED_SLOW_ENABLED true
#define BLE_ADV_DIRECTED_SLOW_DISABLED false
#define BLE_ADV_FAST_ENABLED true
#define BLE_ADV_FAST_DISABLED false
#define BLE_ADV_SLOW_ENABLED true
#define BLE_ADV_SLOW_DISABLED false
#define BLE_ADV_WHITELIST_ENABLED true
#define BLE_ADV_WHITELIST_DISABLED false
/**@brief Function for handling BLE events.
*
* @details This function must be called from the BLE stack event dispatcher for
* the module to handle BLE events that are relevant for the Advertising Module.
*
* @param[in] p_ble_evt BLE stack event.
*/
void ble_advertising_on_ble_evt(const ble_evt_t * const p_ble_evt);
/**@brief Function for handling system events.
*
* @details This function must be called to handle system events that are relevant
* for the Advertising Module. Specifically, the advertising module can not use the
* softdevice as long as there are pending writes to the flash memory. This
* event handler is designed to delay advertising until there is no flash operation.
*
* @param[in] sys_evt System event.
*/
void ble_advertising_on_sys_evt(uint32_t sys_evt);
/**@brief Function for initializing the Advertising Module.
*
* @details Encodes the required advertising data and passes it to the stack.
* Also builds a structure to be passed to the stack when starting advertising.
* The supplied advertising data is copied to a local structure and is manipulated
* depending on what advertising modes are started in @ref ble_advertising_start.
*
* @param[in] p_advdata Advertising data: name, appearance, discovery flags, and more.
* @param[in] p_srdata Scan response data: Supplement to advertising data.
* @param[in] p_config Select which advertising modes and intervals will be utilized.
* @param[in] evt_handler Event handler that will be called upon advertising events.
* @param[in] error_handler Error handler that will propogate internal errors to the main applications.
*
* @retval NRF_SUCCESS If initialization was successful. Otherwise, an error code is returned.
*/
uint32_t ble_advertising_init(ble_advdata_t const * p_advdata,
ble_advdata_t const * p_srdata,
ble_adv_modes_config_t const * p_config,
ble_advertising_evt_handler_t const evt_handler,
ble_advertising_error_handler_t const error_handler);
/**@brief Function for starting advertising.
*
* @details You can start advertising in any of the advertising modes that you enabled
* during initialization.
*
* @param[in] advertising_mode Advertising mode.
*
* @retval @ref NRF_SUCCESS On success, else an error code indicating reason for failure.
* @retval @ref NRF_ERROR_INVALID_STATE
*/
uint32_t ble_advertising_start(ble_adv_mode_t advertising_mode);
/**@brief Function for setting the peer address.
*
* @details The peer address must be set by the application upon receiving a
* @ref BLE_ADV_EVT_PEER_ADDR_REQUEST event. Without the peer address, the directed
* advertising mode will not be run.
*
* @param[in] p_peer_addr Pointer to a peer address.
*
* @retval @ref NRF_SUCCESS Successfully stored the peer address pointer in the advertising module.
* @retval @ref NRF_ERROR_INVALID_STATE If a reply was not expected.
*/
uint32_t ble_advertising_peer_addr_reply(ble_gap_addr_t * p_peer_addr);
/**@brief Function for setting a whitelist.
*
* @details The whitelist must be set by the application upon receiving a
* @ref BLE_ADV_EVT_WHITELIST_REQUEST event. Without the whitelist, the whitelist
* advertising for fast and slow modes will not be run.
*
* @param[in] p_whitelist Pointer to a whitelist.
*
* @retval @ref NRF_SUCCESS Successfully stored pointers to the whitelist into the advertising module.
* @retval @ref NRF_ERROR_INVALID_STATE If a reply was not expected.
*/
uint32_t ble_advertising_whitelist_reply(ble_gap_whitelist_t * p_whitelist);
/**@brief Function for disabling whitelist advertising.
*
* @details This function temporarily disables whitelist advertising.
* Calling this function resets the current time-out countdown.
*
* @retval @ref NRF_SUCCESS On success, else an error message propogated from the Softdevice.
*/
uint32_t ble_advertising_restart_without_whitelist(void);
/** @} */
#endif // BLE_ADVERTISING_H__
/** @} */

View File

@ -0,0 +1,967 @@
/*
* Copyright (c) 2013 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#include "ble_db_discovery.h"
#include <stdlib.h>
#include "nrf_ble.h"
#include "nrf_log.h"
#include "sdk_common.h"
#define SRV_DISC_START_HANDLE 0x0001 /**< The start handle value used during service discovery. */
#define DB_DISCOVERY_MAX_USERS BLE_DB_DISCOVERY_MAX_SRV /**< The maximum number of users/registrations allowed by this module. */
#define DB_LOG NRF_LOG_PRINTF_DEBUG /**< A debug logger macro that can be used in this file to do logging information over UART. */
/**@brief Array of structures containing information about the registered application modules. */
static ble_uuid_t m_registered_handlers[DB_DISCOVERY_MAX_USERS];
/**@brief Array of structures containing pending events to be sent to the application modules.
*
* @details Whenever a discovery related event is to be raised to a user module, it will be stored
* in this array first. When all services needed to be discovered have been
* discovered, all pending events will be sent to the corresponding user modules.
**/
static struct
{
ble_db_discovery_evt_t evt; /**< The pending event. */
ble_db_discovery_evt_handler_t evt_handler; /**< The event handler which should be called to raise this event. */
} m_pending_user_evts[DB_DISCOVERY_MAX_USERS];
static ble_db_discovery_evt_handler_t m_evt_handler;
static uint32_t m_pending_usr_evt_index; /**< The index to the pending user event array, pointing to the last added pending user event. */
static uint32_t m_num_of_handlers_reg; /**< The number of handlers registered with the DB Discovery module. */
static bool m_initialized = false; /**< This variable Indicates if the module is initialized or not. */
#define MODULE_INITIALIZED (m_initialized == true)
#include "sdk_macros.h"
/**@brief Function for fetching the event handler provided by a registered application module.
*
* @param[in] srv_uuid UUID of the service.
*
* @retval evt_handler Event handler of the module, registered for the given service UUID.
* @retval NULL If no event handler is found.
*/
static ble_db_discovery_evt_handler_t registered_handler_get(const ble_uuid_t * const p_srv_uuid)
{
uint32_t i;
for (i = 0; i < m_num_of_handlers_reg; i++)
{
if (BLE_UUID_EQ(&(m_registered_handlers[i]), p_srv_uuid))
{
return (m_evt_handler);
}
}
return NULL;
}
/**@brief Function for storing the event handler provided by a registered application module.
*
* @param[in] p_srv_uuid The UUID of the service.
* @param[in] p_evt_handler The event handler provided by the application.
*
* @retval NRF_SUCCESS If the handler was stored or already present in the list.
* @retval NRF_ERROR_NO_MEM If there is no space left to store the handler.
*/
static uint32_t registered_handler_set(const ble_uuid_t * const p_srv_uuid,
ble_db_discovery_evt_handler_t p_evt_handler)
{
if (registered_handler_get(p_srv_uuid) != NULL)
{
return NRF_SUCCESS;
}
if (m_num_of_handlers_reg < DB_DISCOVERY_MAX_USERS)
{
m_registered_handlers[m_num_of_handlers_reg] = *p_srv_uuid;
m_num_of_handlers_reg++;
return NRF_SUCCESS;
}
else
{
return NRF_ERROR_NO_MEM;
}
}
/**@brief Function for sending all pending discovery events to the corresponding user modules.
*/
static void pending_user_evts_send(void)
{
uint32_t i = 0;
for (i = 0; i < m_num_of_handlers_reg; i++)
{
// Pass the event to the corresponding event handler.
m_pending_user_evts[i].evt_handler(&(m_pending_user_evts[i].evt));
}
m_pending_usr_evt_index = 0;
}
/**@brief Function for indicating error to the application.
*
* @details This function will fetch the event handler based on the UUID of the service being
* discovered. (The event handler is registered by the application beforehand).
* The error code is added to the pending events together with the event handler.
* If no event handler was found, then this function will do nothing.
*
* @param[in] p_db_discovery Pointer to the DB discovery structure.
* @param[in] err_code Error code that should be provided to the application.
* @param[in] conn_handle Connection Handle.
*
*/
static void discovery_error_evt_trigger(ble_db_discovery_t * const p_db_discovery,
uint32_t err_code,
uint16_t const conn_handle)
{
ble_db_discovery_evt_handler_t p_evt_handler;
ble_gatt_db_srv_t * p_srv_being_discovered;
p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]);
p_evt_handler = registered_handler_get(&(p_srv_being_discovered->srv_uuid));
if (p_evt_handler != NULL)
{
ble_db_discovery_evt_t evt;
evt.conn_handle = conn_handle;
evt.evt_type = BLE_DB_DISCOVERY_ERROR;
evt.params.err_code = err_code;
p_evt_handler(&evt);
}
}
/**@brief Function for triggering a Discovery Complete or Service Not Found event to the
* application.
*
* @details This function will fetch the event handler based on the UUID of the service being
* discovered. (The event handler is registered by the application beforehand).
* It then triggers an event indicating the completion of the service discovery.
* If no event handler was found, then this function will do nothing.
*
* @param[in] p_db_discovery Pointer to the DB discovery structure.
* @param[in] is_srv_found Variable to indicate if the service was found at the peer.
* @param[in] conn_handle Connection Handle.
*/
static void discovery_complete_evt_trigger(ble_db_discovery_t * const p_db_discovery,
bool is_srv_found,
uint16_t const conn_handle)
{
ble_db_discovery_evt_handler_t p_evt_handler;
ble_gatt_db_srv_t * p_srv_being_discovered;
p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]);
p_evt_handler = registered_handler_get(&(p_srv_being_discovered->srv_uuid));
if (p_evt_handler != NULL)
{
if (m_pending_usr_evt_index < DB_DISCOVERY_MAX_USERS)
{
// Insert an event into the pending event list.
m_pending_user_evts[m_pending_usr_evt_index].evt.conn_handle = conn_handle;
m_pending_user_evts[m_pending_usr_evt_index].evt.params.discovered_db =
*p_srv_being_discovered;
if (is_srv_found)
{
m_pending_user_evts[m_pending_usr_evt_index].evt.evt_type =
BLE_DB_DISCOVERY_COMPLETE;
}
else
{
m_pending_user_evts[m_pending_usr_evt_index].evt.evt_type =
BLE_DB_DISCOVERY_SRV_NOT_FOUND;
}
m_pending_user_evts[m_pending_usr_evt_index].evt_handler = p_evt_handler;
m_pending_usr_evt_index++;
if (m_pending_usr_evt_index == m_num_of_handlers_reg)
{
// All registered modules have pending events. Send all pending events to the user
// modules.
pending_user_evts_send();
}
else
{
// Too many events pending. Do nothing. (Ideally this should not happen.)
}
}
}
}
/**@brief Function for handling service discovery completion.
*
* @details This function will be used to determine if there are more services to be discovered,
* and if so, initiate the discovery of the next service.
*
* @param[in] p_db_discovery Pointer to the DB Discovery Structure.
* @param[in] conn_handle Connection Handle.
*/
static void on_srv_disc_completion(ble_db_discovery_t * p_db_discovery,
uint16_t const conn_handle)
{
p_db_discovery->discoveries_count++;
// Check if more services need to be discovered.
if (p_db_discovery->discoveries_count < m_num_of_handlers_reg)
{
// Reset the current characteristic index since a new service discovery is about to start.
p_db_discovery->curr_char_ind = 0;
// Initiate discovery of the next service.
p_db_discovery->curr_srv_ind++;
ble_gatt_db_srv_t * p_srv_being_discovered;
p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]);
p_srv_being_discovered->srv_uuid = m_registered_handlers[p_db_discovery->curr_srv_ind];
// Reset the characteristic count in the current service to zero since a new service
// discovery is about to start.
p_srv_being_discovered->char_count = 0;
DB_LOG("[DB]: Starting discovery of service with UUID 0x%x for Connection handle %d\r\n",
p_srv_being_discovered->srv_uuid.uuid, conn_handle);
uint32_t err_code;
err_code = sd_ble_gattc_primary_services_discover
(
conn_handle,
SRV_DISC_START_HANDLE,
&(p_srv_being_discovered->srv_uuid)
);
if (err_code != NRF_SUCCESS)
{
p_db_discovery->discovery_in_progress = false;
// Error with discovering the service.
// Indicate the error to the registered user application.
discovery_error_evt_trigger(p_db_discovery, err_code, conn_handle);
m_pending_user_evts[0].evt.evt_type = BLE_DB_DISCOVERY_AVAILABLE;
m_pending_user_evts[0].evt.conn_handle = conn_handle;
// m_evt_handler(&m_pending_user_evts[0].evt);
return;
}
}
else
{
// No more service discovery is needed.
p_db_discovery->discovery_in_progress = false;
m_pending_user_evts[0].evt.evt_type = BLE_DB_DISCOVERY_AVAILABLE;
m_pending_user_evts[0].evt.conn_handle = conn_handle;
//m_evt_handler(&m_pending_user_evts[0].evt);
}
}
/**@brief Function for finding out if a characteristic discovery should be performed after the
* last discovered characteristic.
*
* @details This function is used during the time of database discovery to find out if there is
* a need to do more characteristic discoveries. The value handles of the
* last discovered characteristic is compared with the end handle of the service.
* If the service handle is greater than one of the former characteristic handles,
* it means that a characteristic discovery is required.
*
* @param[in] p_db_discovery The pointer to the DB Discovery structure.
* @param[in] p_after_char The pointer to the last discovered characteristic.
*
* @retval True if a characteristic discovery is required.
* @retval False if a characteristic discovery is NOT required.
*/
static bool is_char_discovery_reqd(ble_db_discovery_t * const p_db_discovery,
ble_gattc_char_t * p_after_char)
{
if (
p_after_char->handle_value <
p_db_discovery->services[p_db_discovery->curr_srv_ind].handle_range.end_handle
)
{
// Handle value of the characteristic being discovered is less than the end handle of
// the service being discovered. There is a possibility of more characteristics being
// present. Hence a characteristic discovery is required.
return true;
}
return false;
}
/**@brief Function to find out if a descriptor discovery is required.
*
* @details This function finds out if there is a possibility of existence of descriptors between
* current characteristic and the next characteristic. If so, this function will compute
* the handle range on which the descriptors may be present and will return it.
* If the current characteristic is the last known characteristic, then this function
* will use the service end handle to find out if the current characteristic can have
* descriptors.
*
* @param[in] p_db_discovery Pointer to the DB Discovery structure.
* @param[in] p_curr_char Pointer to the current characteristic.
* @param[in] p_next_char Pointer to the next characteristic. This should be NULL if the
* caller knows that there is no characteristic after the current
* characteristic at the peer.
* @param[out] p_handle_range Pointer to the handle range in which descriptors may exist at the
* the peer.
*
* @retval True If a descriptor discovery is required.
* @retval False If a descriptor discovery is NOT required.
*/
static bool is_desc_discovery_reqd(ble_db_discovery_t * p_db_discovery,
ble_gatt_db_char_t * p_curr_char,
ble_gatt_db_char_t * p_next_char,
ble_gattc_handle_range_t * p_handle_range)
{
if (p_next_char == NULL)
{
// Current characteristic is the last characteristic in the service. Check if the value
// handle of the current characteristic is equal to the service end handle.
if (
p_curr_char->characteristic.handle_value ==
p_db_discovery->services[p_db_discovery->curr_srv_ind].handle_range.end_handle
)
{
// No descriptors can be present for the current characteristic. p_curr_char is the last
// characteristic with no descriptors.
return false;
}
p_handle_range->start_handle = p_curr_char->characteristic.handle_value + 1;
// Since the current characteristic is the last characteristic in the service, the end
// handle should be the end handle of the service.
p_handle_range->end_handle =
p_db_discovery->services[p_db_discovery->curr_srv_ind].handle_range.end_handle;
return true;
}
// p_next_char != NULL. Check for existence of descriptors between the current and the next
// characteristic.
if ((p_curr_char->characteristic.handle_value + 1) == p_next_char->characteristic.handle_decl)
{
// No descriptors can exist between the two characteristic.
return false;
}
p_handle_range->start_handle = p_curr_char->characteristic.handle_value + 1;
p_handle_range->end_handle = p_next_char->characteristic.handle_decl - 1;
return true;
}
/**@brief Function for performing characteristic discovery.
*
* @param[in] p_db_discovery Pointer to the DB Discovery structure.
* @param[in] conn_handle Connection Handle.
*
* @return NRF_SUCCESS if the SoftDevice was successfully requested to perform the characteristic
* discovery. Otherwise an error code. This function returns the error code returned
* by the SoftDevice API @ref sd_ble_gattc_characteristics_discover.
*/
static uint32_t characteristics_discover(ble_db_discovery_t * const p_db_discovery,
uint16_t const conn_handle)
{
ble_gatt_db_srv_t * p_srv_being_discovered;
ble_gattc_handle_range_t handle_range;
p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]);
if (p_db_discovery->curr_char_ind != 0)
{
// This is not the first characteristic being discovered. Hence the 'start handle' to be
// used must be computed using the handle_value of the previous characteristic.
ble_gattc_char_t * p_prev_char;
uint8_t prev_char_ind = p_db_discovery->curr_char_ind - 1;
p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]);
p_prev_char = &(p_srv_being_discovered->charateristics[prev_char_ind].characteristic);
handle_range.start_handle = p_prev_char->handle_value + 1;
}
else
{
// This is the first characteristic of this service being discovered.
handle_range.start_handle = p_srv_being_discovered->handle_range.start_handle;
}
handle_range.end_handle = p_srv_being_discovered->handle_range.end_handle;
return sd_ble_gattc_characteristics_discover(conn_handle, &handle_range);
}
/**@brief Function for performing descriptor discovery, if required.
*
* @details This function will check if descriptor discovery is required and then perform it if
* needed. If no more descriptor discovery is required for the service, then the output
* parameter p_raise_discov_complete is set to true, indicating to the caller that a
* discovery complete event can be triggered to the application.
*
* @param[in] p_db_discovery Pointer to the DB Discovery structure.
* @param[out] p_raise_discov_complete The value pointed to by this pointer will be set to true if
* the Discovery Complete event can be triggered to the
* application.
* @param[in] conn_handle Connection Handle.
*
* @return NRF_SUCCESS if the SoftDevice was successfully requested to perform the descriptor
* discovery, or if no more descriptor discovery is required. Otherwise an error code.
* This function returns the error code returned by the SoftDevice API @ref
* sd_ble_gattc_descriptors_discover.
*/
static uint32_t descriptors_discover(ble_db_discovery_t * const p_db_discovery,
bool * p_raise_discov_complete,
uint16_t const conn_handle)
{
ble_gattc_handle_range_t handle_range;
ble_gatt_db_char_t * p_curr_char_being_discovered;
ble_gatt_db_srv_t * p_srv_being_discovered;
bool is_discovery_reqd = false;
p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]);
p_curr_char_being_discovered =
&(p_srv_being_discovered->charateristics[p_db_discovery->curr_char_ind]);
if ((p_db_discovery->curr_char_ind + 1) == p_srv_being_discovered->char_count)
{
// This is the last characteristic of this service.
is_discovery_reqd = is_desc_discovery_reqd(p_db_discovery,
p_curr_char_being_discovered,
NULL,
&handle_range);
}
else
{
uint8_t i;
ble_gatt_db_char_t * p_next_char;
for (i = p_db_discovery->curr_char_ind;
i < p_srv_being_discovered->char_count;
i++)
{
if (i == (p_srv_being_discovered->char_count - 1))
{
// The current characteristic is the last characteristic in the service.
p_next_char = NULL;
}
else
{
p_next_char = &(p_srv_being_discovered->charateristics[i + 1]);
}
// Check if it is possible for the current characteristic to have a descriptor.
if (is_desc_discovery_reqd(p_db_discovery,
p_curr_char_being_discovered,
p_next_char,
&handle_range))
{
is_discovery_reqd = true;
break;
}
else
{
// No descriptors can exist.
p_curr_char_being_discovered = p_next_char;
p_db_discovery->curr_char_ind++;
}
}
}
if (!is_discovery_reqd)
{
// No more descriptor discovery required. Discovery is complete.
// This informs the caller that a discovery complete event can be triggered.
*p_raise_discov_complete = true;
return NRF_SUCCESS;
}
*p_raise_discov_complete = false;
return sd_ble_gattc_descriptors_discover(conn_handle, &handle_range);
}
/**@brief Function for handling primary service discovery response.
*
* @details This function will handle the primary service discovery response and start the
* discovery of characteristics within that service.
*
* @param[in] p_db_discovery Pointer to the DB Discovery structure.
* @param[in] p_ble_gattc_evt Pointer to the GATT Client event.
*/
static void on_primary_srv_discovery_rsp(ble_db_discovery_t * const p_db_discovery,
const ble_gattc_evt_t * const p_ble_gattc_evt)
{
ble_gatt_db_srv_t * p_srv_being_discovered;
p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]);
if (p_ble_gattc_evt->conn_handle != p_db_discovery->conn_handle)
{
return;
}
if (p_ble_gattc_evt->gatt_status == BLE_GATT_STATUS_SUCCESS)
{
uint32_t err_code;
const ble_gattc_evt_prim_srvc_disc_rsp_t * p_prim_srvc_disc_rsp_evt;
DB_LOG("Found service UUID 0x%x\r\n", p_srv_being_discovered->srv_uuid.uuid);
p_prim_srvc_disc_rsp_evt = &(p_ble_gattc_evt->params.prim_srvc_disc_rsp);
p_srv_being_discovered->srv_uuid = p_prim_srvc_disc_rsp_evt->services[0].uuid;
p_srv_being_discovered->handle_range = p_prim_srvc_disc_rsp_evt->services[0].handle_range;
err_code = characteristics_discover(p_db_discovery,
p_ble_gattc_evt->conn_handle);
if (err_code != NRF_SUCCESS)
{
p_db_discovery->discovery_in_progress = false;
// Error with discovering the service.
// Indicate the error to the registered user application.
discovery_error_evt_trigger(p_db_discovery,
err_code,
p_ble_gattc_evt->conn_handle);
m_pending_user_evts[0].evt.evt_type = BLE_DB_DISCOVERY_AVAILABLE;
m_pending_user_evts[0].evt.conn_handle = p_ble_gattc_evt->conn_handle;
//m_evt_handler(&m_pending_user_evts[0].evt);
}
}
else
{
DB_LOG("Service UUID 0x%x Not found\r\n", p_srv_being_discovered->srv_uuid.uuid);
// Trigger Service Not Found event to the application.
discovery_complete_evt_trigger(p_db_discovery,
false,
p_ble_gattc_evt->conn_handle);
on_srv_disc_completion(p_db_discovery,
p_ble_gattc_evt->conn_handle);
}
}
/**@brief Function for handling characteristic discovery response.
*
* @param[in] p_db_discovery Pointer to the DB Discovery structure.
* @param[in] p_ble_gattc_evt Pointer to the GATT Client event.
*/
static void on_characteristic_discovery_rsp(ble_db_discovery_t * const p_db_discovery,
const ble_gattc_evt_t * const p_ble_gattc_evt)
{
uint32_t err_code;
ble_gatt_db_srv_t * p_srv_being_discovered;
bool perform_desc_discov = false;
if (p_ble_gattc_evt->conn_handle != p_db_discovery->conn_handle)
{
return;
}
p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]);
if (p_ble_gattc_evt->gatt_status == BLE_GATT_STATUS_SUCCESS)
{
const ble_gattc_evt_char_disc_rsp_t * p_char_disc_rsp_evt;
p_char_disc_rsp_evt = &(p_ble_gattc_evt->params.char_disc_rsp);
// Find out the number of characteristics that were previously discovered (in earlier
// characteristic discovery responses, if any).
uint8_t num_chars_prev_disc = p_srv_being_discovered->char_count;
// Find out the number of characteristics that are currently discovered (in the
// characteristic discovery response being handled).
uint8_t num_chars_curr_disc = p_char_disc_rsp_evt->count;
// Check if the total number of discovered characteristics are supported by this module.
if ((num_chars_prev_disc + num_chars_curr_disc) <= BLE_GATT_DB_MAX_CHARS)
{
// Update the characteristics count.
p_srv_being_discovered->char_count += num_chars_curr_disc;
}
else
{
// The number of characteristics discovered at the peer is more than the supported
// maximum. This module will store only the characteristics found up to this point.
p_srv_being_discovered->char_count = BLE_GATT_DB_MAX_CHARS;
}
uint32_t i;
uint32_t j;
for (i = num_chars_prev_disc, j = 0; i < p_srv_being_discovered->char_count; i++, j++)
{
p_srv_being_discovered->charateristics[i].characteristic =
p_char_disc_rsp_evt->chars[j];
p_srv_being_discovered->charateristics[i].cccd_handle = BLE_GATT_HANDLE_INVALID;
}
ble_gattc_char_t * p_last_known_char;
p_last_known_char = &(p_srv_being_discovered->charateristics[i - 1].characteristic);
// If no more characteristic discovery is required, or if the maximum number of supported
// characteristic per service has been reached, descriptor discovery will be performed.
if (
!is_char_discovery_reqd(p_db_discovery, p_last_known_char) ||
(p_srv_being_discovered->char_count == BLE_GATT_DB_MAX_CHARS)
)
{
perform_desc_discov = true;
}
else
{
// Update the current characteristic index.
p_db_discovery->curr_char_ind = p_srv_being_discovered->char_count;
// Perform another round of characteristic discovery.
err_code = characteristics_discover(p_db_discovery,
p_ble_gattc_evt->conn_handle);
if (err_code != NRF_SUCCESS)
{
p_db_discovery->discovery_in_progress = false;
discovery_error_evt_trigger(p_db_discovery,
err_code,
p_ble_gattc_evt->conn_handle);
m_pending_user_evts[0].evt.evt_type = BLE_DB_DISCOVERY_AVAILABLE;
m_pending_user_evts[0].evt.conn_handle = p_ble_gattc_evt->conn_handle;
//m_evt_handler(&m_pending_user_evts[0].evt);
return;
}
}
}
else
{
// The previous characteristic discovery resulted in no characteristics.
// descriptor discovery should be performed.
perform_desc_discov = true;
}
if (perform_desc_discov)
{
bool raise_discov_complete;
p_db_discovery->curr_char_ind = 0;
err_code = descriptors_discover(p_db_discovery,
&raise_discov_complete,
p_ble_gattc_evt->conn_handle);
if (err_code != NRF_SUCCESS)
{
p_db_discovery->discovery_in_progress = false;
discovery_error_evt_trigger(p_db_discovery,
err_code,
p_ble_gattc_evt->conn_handle);
m_pending_user_evts[0].evt.evt_type = BLE_DB_DISCOVERY_AVAILABLE;
m_pending_user_evts[0].evt.conn_handle = p_ble_gattc_evt->conn_handle;
//m_evt_handler(&m_pending_user_evts[0].evt);
return;
}
if (raise_discov_complete)
{
// No more characteristics and descriptors need to be discovered. Discovery is complete.
// Send a discovery complete event to the user application.
DB_LOG("[DB]: Discovery of service with UUID 0x%x completed with success for Connection"
" handle %d\r\n", p_srv_being_discovered->srv_uuid.uuid,
p_ble_gattc_evt->conn_handle);
discovery_complete_evt_trigger(p_db_discovery,
true,
p_ble_gattc_evt->conn_handle);
on_srv_disc_completion(p_db_discovery,
p_ble_gattc_evt->conn_handle);
}
}
}
/**@brief Function for handling descriptor discovery response.
*
* @param[in] p_db_discovery Pointer to the DB Discovery structure.
* @param[in] p_ble_gattc_evt Pointer to the GATT Client event.
*/
static void on_descriptor_discovery_rsp(ble_db_discovery_t * const p_db_discovery,
const ble_gattc_evt_t * const p_ble_gattc_evt)
{
const ble_gattc_evt_desc_disc_rsp_t * p_desc_disc_rsp_evt;
ble_gatt_db_srv_t * p_srv_being_discovered;
if (p_ble_gattc_evt->conn_handle != p_db_discovery->conn_handle)
{
return;
}
p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]);
p_desc_disc_rsp_evt = &(p_ble_gattc_evt->params.desc_disc_rsp);
ble_gatt_db_char_t * p_char_being_discovered =
&(p_srv_being_discovered->charateristics[p_db_discovery->curr_char_ind]);
if (p_ble_gattc_evt->gatt_status == BLE_GATT_STATUS_SUCCESS)
{
// The descriptor was found at the peer.
// If the descriptor was a CCCD, then the cccd_handle needs to be populated.
uint32_t i;
// Loop through all the descriptors to find the CCCD.
for (i = 0; i < p_desc_disc_rsp_evt->count; i++)
{
if (
p_desc_disc_rsp_evt->descs[i].uuid.uuid ==
BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG
)
{
p_char_being_discovered->cccd_handle = p_desc_disc_rsp_evt->descs[i].handle;
break;
}
}
}
bool raise_discov_complete = false;
if ((p_db_discovery->curr_char_ind + 1) == p_srv_being_discovered->char_count)
{
// No more characteristics and descriptors need to be discovered. Discovery is complete.
// Send a discovery complete event to the user application.
raise_discov_complete = true;
}
else
{
// Begin discovery of descriptors for the next characteristic.
uint32_t err_code;
p_db_discovery->curr_char_ind++;
err_code = descriptors_discover(p_db_discovery,
&raise_discov_complete,
p_ble_gattc_evt->conn_handle);
if (err_code != NRF_SUCCESS)
{
p_db_discovery->discovery_in_progress = false;
// Error with discovering the service.
// Indicate the error to the registered user application.
discovery_error_evt_trigger(p_db_discovery,
err_code,
p_ble_gattc_evt->conn_handle);
m_pending_user_evts[0].evt.evt_type = BLE_DB_DISCOVERY_AVAILABLE;
m_pending_user_evts[0].evt.conn_handle = p_ble_gattc_evt->conn_handle;
return;
}
}
if (raise_discov_complete)
{
DB_LOG("[DB]: Discovery of service with UUID 0x%x completed with success for Connection"
"handle %d\r\n", p_srv_being_discovered->srv_uuid.uuid,
p_ble_gattc_evt->conn_handle);
discovery_complete_evt_trigger(p_db_discovery,
true,
p_ble_gattc_evt->conn_handle);
on_srv_disc_completion(p_db_discovery,
p_ble_gattc_evt->conn_handle);
}
}
uint32_t ble_db_discovery_init(const ble_db_discovery_evt_handler_t evt_handler)
{
uint32_t err_code = NRF_SUCCESS;
VERIFY_PARAM_NOT_NULL(evt_handler);
m_num_of_handlers_reg = 0;
m_initialized = true;
m_pending_usr_evt_index = 0;
m_evt_handler = evt_handler;
return err_code;
}
uint32_t ble_db_discovery_close()
{
m_num_of_handlers_reg = 0;
m_initialized = false;
m_pending_usr_evt_index = 0;
return NRF_SUCCESS;
}
uint32_t ble_db_discovery_evt_register(const ble_uuid_t * const p_uuid)
{
VERIFY_PARAM_NOT_NULL(p_uuid);
VERIFY_MODULE_INITIALIZED();
return registered_handler_set(p_uuid, m_evt_handler);
}
uint32_t ble_db_discovery_start(ble_db_discovery_t * const p_db_discovery,
uint16_t conn_handle)
{
VERIFY_PARAM_NOT_NULL(p_db_discovery);
VERIFY_MODULE_INITIALIZED();
if (m_num_of_handlers_reg == 0)
{
// No user modules were registered. There are no services to discover.
return NRF_ERROR_INVALID_STATE;
}
if (p_db_discovery->discovery_in_progress)
{
return NRF_ERROR_BUSY;
}
p_db_discovery->conn_handle = conn_handle;
ble_gatt_db_srv_t * p_srv_being_discovered;
m_pending_usr_evt_index = 0;
p_db_discovery->discoveries_count = 0;
p_db_discovery->curr_srv_ind = 0;
p_srv_being_discovered = &(p_db_discovery->services[p_db_discovery->curr_srv_ind]);
p_srv_being_discovered->srv_uuid = m_registered_handlers[p_db_discovery->curr_srv_ind];
DB_LOG("[DB]: Starting discovery of service with UUID 0x%x for Connection handle %d\r\n",
p_srv_being_discovered->srv_uuid.uuid, conn_handle);
uint32_t err_code;
err_code = sd_ble_gattc_primary_services_discover(conn_handle,
SRV_DISC_START_HANDLE,
&(p_srv_being_discovered->srv_uuid));
VERIFY_SUCCESS(err_code);
p_db_discovery->discovery_in_progress = true;
return NRF_SUCCESS;
}
/**@brief Function for handling disconnected event.
*
* @param[in] p_db_discovery Pointer to the DB Discovery structure.
* @param[in] p_ble_gattc_evt Pointer to the GAP event.
*/
static void on_disconnected(ble_db_discovery_t * const p_db_discovery,
const ble_gap_evt_t * const p_evt)
{
if (p_evt->conn_handle == p_db_discovery->conn_handle)
{
p_db_discovery->discovery_in_progress = false;
}
}
void ble_db_discovery_on_ble_evt(ble_db_discovery_t * const p_db_discovery,
const ble_evt_t * const p_ble_evt)
{
VERIFY_PARAM_NOT_NULL_VOID(p_db_discovery);
VERIFY_PARAM_NOT_NULL_VOID(p_ble_evt);
VERIFY_MODULE_INITIALIZED_VOID();
switch (p_ble_evt->header.evt_id)
{
case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP:
on_primary_srv_discovery_rsp(p_db_discovery, &(p_ble_evt->evt.gattc_evt));
break;
case BLE_GATTC_EVT_CHAR_DISC_RSP:
on_characteristic_discovery_rsp(p_db_discovery, &(p_ble_evt->evt.gattc_evt));
break;
case BLE_GATTC_EVT_DESC_DISC_RSP:
on_descriptor_discovery_rsp(p_db_discovery, &(p_ble_evt->evt.gattc_evt));
break;
case BLE_GAP_EVT_DISCONNECTED:
on_disconnected(p_db_discovery, &(p_ble_evt->evt.gap_evt));
break;
default:
break;
}
}

View File

@ -0,0 +1,208 @@
/*
* Copyright (c) 2013 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/**@file
*
* @defgroup ble_sdk_lib_db_discovery Database Discovery
* @{
* @ingroup ble_sdk_lib
* @brief Database discovery module.
*
* @details This module contains the APIs and types exposed by the DB Discovery module. These APIs
* and types can be used by the application to perform discovery of a service and its
* characteristics at the peer server. This module can also be used to discover the
* desired services in multiple remote devices.
*
* @warning The maximum number of characteristics per service that can be discovered by this module
* is determined by the number of characteristics in the service structure defined in
* db_disc_config.h. If the peer has more than the supported number of characteristics, then
* the first found will be discovered and any further characteristics will be ignored. No
* descriptors other than Client Characteristic Configuration Descriptors will be searched
* for at the peer.
*
* @note Presently only one instance of a Primary Service can be discovered by this module. If
* there are multiple instances of the service at the peer, only the first instance
* of it at the peer is fetched and returned to the application.
*
* @note The application must propagate BLE stack events to this module by calling
* ble_db_discovery_on_ble_evt().
*
*/
#ifndef BLE_DB_DISCOVERY_H__
#define BLE_DB_DISCOVERY_H__
#include <stdint.h>
#include "nrf_ble_gattc.h"
#include "nrf_ble.h"
#include "nrf_error.h"
#include "ble_srv_common.h"
#include "ble_gatt_db.h"
#define BLE_DB_DISCOVERY_MAX_SRV 6 /**< Maximum number of services supported by this module. This also indicates the maximum number of users allowed to be registered to this module. (one user per service). */
/**@brief Type of the DB Discovery event.
*/
typedef enum
{
BLE_DB_DISCOVERY_COMPLETE, /**< Event indicating that the GATT Database discovery is complete. */
BLE_DB_DISCOVERY_ERROR, /**< Event indicating that an internal error has occurred in the DB Discovery module. This could typically be because of the SoftDevice API returning an error code during the DB discover.*/
BLE_DB_DISCOVERY_SRV_NOT_FOUND, /**< Event indicating that the service was not found at the peer.*/
BLE_DB_DISCOVERY_AVAILABLE /**< Event indicating that the DB discovery module is available.*/
} ble_db_discovery_evt_type_t;
/**@brief Structure for holding the information related to the GATT database at the server.
*
* @details This module identifies a remote database. Use one instance of this structure per
* connection.
*
* @warning This structure must be zero-initialized.
*/
typedef struct
{
ble_gatt_db_srv_t services[BLE_DB_DISCOVERY_MAX_SRV]; /**< Information related to the current service being discovered. This is intended for internal use during service discovery.*/
uint8_t srv_count; /**< Number of services at the peers GATT database.*/
uint8_t curr_char_ind; /**< Index of the current characteristic being discovered. This is intended for internal use during service discovery.*/
uint8_t curr_srv_ind; /**< Index of the current service being discovered. This is intended for internal use during service discovery.*/
bool discovery_in_progress; /**< Variable to indicate if there is a service discovery in progress. */
uint8_t discoveries_count; /**< Number of service discoveries made, both successful and unsuccessful. */
uint16_t conn_handle; /**< Connection handle on which the discovery is started*/
} ble_db_discovery_t;
/**@brief Structure containing the event from the DB discovery module to the application.
*/
typedef struct
{
ble_db_discovery_evt_type_t evt_type; /**< Type of event. */
uint16_t conn_handle; /**< Handle of the connection for which this event has occurred. */
union
{
ble_gatt_db_srv_t discovered_db; /**< Structure containing the information about the GATT Database at the server. This will be filled when the event type is @ref BLE_DB_DISCOVERY_COMPLETE.*/
uint32_t err_code; /**< nRF Error code indicating the type of error which occurred in the DB Discovery module. This will be filled when the event type is @ref BLE_DB_DISCOVERY_ERROR. */
} params;
} ble_db_discovery_evt_t;
/**@brief DB Discovery event handler type. */
typedef void (* ble_db_discovery_evt_handler_t)(ble_db_discovery_evt_t * p_evt);
/**@brief Function for initializing the DB Discovery module.
*
* @param[in] evt_handler Event handler to be called by the DB discovery module when any event
* related to discovery of the registered service occurs.
*
* @retval NRF_SUCCESS On successful initialization.
* @retval NRF_ERROR_NULL If the handler was NULL.
*/
uint32_t ble_db_discovery_init(ble_db_discovery_evt_handler_t evt_handler);
/**@brief Function for closing the DB Discovery module.
*
* @details This function will clear up any internal variables and states maintained by the
* module. To re-use the module after calling this function, the function @ref
* ble_db_discovery_init must be called again.
*
* @retval NRF_SUCCESS Operation success.
*/
uint32_t ble_db_discovery_close(void);
/**@brief Function for registering with the DB Discovery module.
*
* @details The application can use this function to inform which service it is interested in
* discovering at the server.
*
* @param[in] p_uuid Pointer to the UUID of the service to be discovered at the server.
*
* @note The total number of services that can be discovered by this module is @ref
* BLE_DB_DISCOVERY_MAX_SRV. This effectively means that the maximum number of
* registrations possible is equal to the @ref BLE_DB_DISCOVERY_MAX_SRV.
*
* @retval NRF_SUCCESS Operation success.
* @retval NRF_ERROR_NULL When a NULL pointer is passed as input.
* @retval NRF_ERROR_INVALID_STATE If this function is called without calling the
* @ref ble_db_discovery_init.
* @retval NRF_ERROR_NO_MEM The maximum number of registrations allowed by this module
* has been reached.
*/
uint32_t ble_db_discovery_evt_register(const ble_uuid_t * const p_uuid);
/**@brief Function for starting the discovery of the GATT database at the server.
*
* @warning p_db_discovery structure must be zero-initialized.
*
* @param[out] p_db_discovery Pointer to the DB Discovery structure.
* @param[in] conn_handle The handle of the connection for which the discovery should be
* started.
*
* @retval NRF_SUCCESS Operation success.
* @retval NRF_ERROR_NULL When a NULL pointer is passed as input.
* @retval NRF_ERROR_INVALID_STATE If this function is called without calling the
* @ref ble_db_discovery_init, or without calling
* @ref ble_db_discovery_evt_register.
* @retval NRF_ERROR_BUSY If a discovery is already in progress for the current
* connection.
*
* @return This API propagates the error code returned by the
* SoftDevice API @ref sd_ble_gattc_primary_services_discover.
*/
uint32_t ble_db_discovery_start(ble_db_discovery_t * const p_db_discovery,
uint16_t conn_handle);
/**@brief Function for handling the Application's BLE Stack events.
*
* @param[in,out] p_db_discovery Pointer to the DB Discovery structure.
* @param[in] p_ble_evt Pointer to the BLE event received.
*/
void ble_db_discovery_on_ble_evt(ble_db_discovery_t * const p_db_discovery,
const ble_evt_t * const p_ble_evt);
#endif // BLE_DB_DISCOVERY_H__
/** @} */

View File

@ -0,0 +1,82 @@
/*
* Copyright (c) 2013 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#include "ble_debug_assert_handler.h"
#include <string.h>
#include "nrf.h"
#include "ble_error_log.h"
#include "nordic_common.h"
#define MAX_LENGTH_FILENAME 128 /**< Max length of filename to copy for the debug error handlier. */
// WARNING - DO NOT USE THIS FUNCTION IN END PRODUCT. - WARNING
// WARNING - FOR DEBUG PURPOSES ONLY. - WARNING
void ble_debug_assert_handler(uint32_t error_code, uint32_t line_num, const uint8_t * p_file_name)
{
// Copying parameters to static variables because parameters may not be accessible in debugger.
static volatile uint8_t s_file_name[MAX_LENGTH_FILENAME];
static volatile uint16_t s_line_num;
static volatile uint32_t s_error_code;
strncpy((char *)s_file_name, (const char *)p_file_name, MAX_LENGTH_FILENAME - 1);
s_file_name[MAX_LENGTH_FILENAME - 1] = '\0';
s_line_num = line_num;
s_error_code = error_code;
UNUSED_VARIABLE(s_file_name);
UNUSED_VARIABLE(s_line_num);
UNUSED_VARIABLE(s_error_code);
// WARNING: The PRIMASK register is set to disable ALL interrups during writing the error log.
//
// Do not use __disable_irq() in normal operation.
__disable_irq();
// This function will write error code, filename, and line number to the flash.
// In addition, the Cortex-M0 stack memory will also be written to the flash.
//(void) ble_error_log_write(error_code, p_file_name, line_num);
// For debug purposes, this function never returns.
// Attach a debugger for tracing the error cause.
for (;;)
{
// Do nothing.
}
}

View File

@ -0,0 +1,78 @@
/*
* Copyright (c) 2013 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/** @file
*
* @defgroup ble_debug_assert_handler Assert handler for debug purposes
* @{
* @ingroup ble_sdk_lib
* @brief Module for handling of assert during application development when debugging.
*
* @details This module may be used during development of an application to facilitate debugging.
* It contains a function to write file name, line number and the Stack Memory to flash.
* This module is ONLY for debugging purposes and must never be used in final product.
*
*/
#ifndef BLE_DEBUG_ASSERT_HANDLER_H__
#define BLE_DEBUG_ASSERT_HANDLER_H__
#include <stdint.h>
/**@brief Function for handling the Debug assert, which can be called from an error handler.
* To be used only for debugging purposes.
*
*@details This code will copy the filename and line number into local variables for them to always
* be accessible in Keil debugger. The function will also write the ARM Cortex-M0 stack
* memory into flash where it can be retrieved and manually un-winded in order to
* back-trace the location where the error ocured.<br>
* @warning <b>ALL INTERRUPTS WILL BE DISABLED.</b>
*
* @note This function will never return but loop forever for debug purposes.
*
* @param[in] error_code Error code supplied to the handler.
* @param[in] line_num Line number where the original handler is called.
* @param[in] p_file_name Pointer to the file name.
*/
void ble_debug_assert_handler(uint32_t error_code, uint32_t line_num, const uint8_t * p_file_name);
#endif /* BLE_DEBUG_ASSERT_HANDLER_H__ */
/** @} */

View File

@ -0,0 +1,670 @@
/*
* Copyright (c) 2012 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#include "ble_dtm.h"
#include <stdbool.h>
#include <string.h>
#include "nrf.h"
#define DTM_HEADER_OFFSET 0 /**< Index where the header of the pdu is located. */
#define DTM_HEADER_SIZE 2 /**< Size of PDU header. */
#define DTM_PAYLOAD_MAX_SIZE 37 /**< Maximum payload size allowed during dtm execution. */
#define DTM_LENGTH_OFFSET (DTM_HEADER_OFFSET + 1) /**< Index where the length of the payload is encoded. */
#define DTM_PDU_MAX_MEMORY_SIZE (DTM_HEADER_SIZE + DTM_PAYLOAD_MAX_SIZE) /**< Maximum PDU size allowed during dtm execution. */
/**@details The UART poll cycle in micro seconds.
* Baud rate of 19200 bits / second, and 8 data bits, 1 start/stop bit, no flow control,
* give the time to transmit a byte: 10 bits * 1/19200 = approx: 520 us.
*
* To ensure no loss of bytes, the UART should be polled every 260 us.
*
* @note If UART bit rate is changed, this value should be recalculated as well.
*/
#define UART_POLL_CYCLE 260
#define RX_MODE true /**< Constant defining RX mode for radio during dtm test. */
#define TX_MODE false /**< Constant defining TX mode for radio during dtm test. */
#define PHYS_CH_MAX 39 /**< Maximum number of valid channels in BLE. */
// Values that for now are "constants" - they could be configured by a function setting them,
// but most of these are set by the BLE DTM standard, so changing them is not relevant.
#define RFPHY_TEST_0X0F_REF_PATTERN 0x0f /**< RF-PHY test packet patterns, for the repeated octet packets. */
#define RFPHY_TEST_0X55_REF_PATTERN 0x55 /**< RF-PHY test packet patterns, for the repeated octet packets. */
#define PRBS9_CONTENT {0xff, 0xc1, 0xfb, 0xe8, 0x4c, 0x90, 0x72, 0x8b, \
0xe7, 0xb3, 0x51, 0x89, 0x63, 0xab, 0x23, 0x23, \
0x2, 0x84, 0x18, 0x72, 0xaa, 0x61, 0x2f, 0x3b, \
0x51, 0xa8, 0xe5, 0x37, 0x49, 0xfb, 0xc9, 0xca, \
0xc, 0x18, 0x53, 0x2c, 0xfd} /**< The PRBS9 sequence used as packet payload. */
/**@brief Structure holding the PDU used for transmitting/receiving a PDU.
*/
typedef struct
{
uint8_t content[DTM_HEADER_SIZE + DTM_PAYLOAD_MAX_SIZE]; /**< PDU packet content. */
} pdu_type_t;
/**@brief States used for the DTM test implementation.
*/
typedef enum
{
STATE_UNINITIALIZED, /**< The DTM is uninitialized. */
STATE_IDLE, /**< State when system has just initialized, or current test has completed. */
STATE_TRANSMITTER_TEST, /**< State used when a DTM Transmission test is running. */
STATE_CARRIER_TEST, /**< State used when a DTM Carrier test is running (Vendor specific test). */
STATE_RECEIVER_TEST /**< State used when a DTM Receive test is running. */
} state_t;
// Internal variables set as side effects of commands or events.
static state_t m_state = STATE_UNINITIALIZED; /**< Current machine state. */
static uint16_t m_rx_pkt_count; /**< Number of valid packets received. */
static pdu_type_t m_pdu; /**< PDU to be sent. */
static uint16_t m_event; /**< current command status - initially "ok", may be set if error detected, or to packet count. */
static bool m_new_event; /**< Command has been processed - number of not yet reported event bytes. */
static uint8_t m_packet_length; /**< Payload length of transmitted PDU, bits 2:7 of 16-bit dtm command. */
static dtm_pkt_type_t m_packet_type; /**< Bits 0..1 of 16-bit transmit command, or 0xFFFFFFFF. */
static dtm_freq_t m_phys_ch; /**< 0..39 physical channel number (base 2402 MHz, Interval 2 MHz), bits 8:13 of 16-bit dtm command. */
static uint32_t m_current_time = 0; /**< Counter for interrupts from timer to ensure that the 2 bytes forming a DTM command are received within the time window. */
// Nordic specific configuration values (not defined by BLE standard).
// Definition of initial values found in ble_dtm.h
static int32_t m_tx_power = DEFAULT_TX_POWER; /**< TX power for transmission test, default to maximum value (+4 dBm). */
static NRF_TIMER_Type * mp_timer = DEFAULT_TIMER; /**< Timer to be used. */
static IRQn_Type m_timer_irq = DEFAULT_TIMER_IRQn; /**< which interrupt line to clear on every timeout */
static uint8_t const m_prbs_content[] = PRBS9_CONTENT; /**< Pseudo-random bit sequence defined by the BLE standard. */
static uint8_t m_packetHeaderLFlen = 8; /**< Length of length field in packet Header (in bits). */
static uint8_t m_packetHeaderS0len = 1; /**< Length of S0 field in packet Header (in bytes). */
static uint8_t m_packetHeaderS1len = 0; /**< Length of S1 field in packet Header (in bits). */
static uint8_t m_crcConfSkipAddr = 1; /**< Leave packet address field out of CRC calculation. */
static uint8_t m_static_length = 0; /**< Number of bytes sent in addition to the var.length payload. */
static uint32_t m_balen = 3; /**< Base address length in bytes. */
static uint32_t m_endian = RADIO_PCNF1_ENDIAN_Little; /**< On air endianess of packet, this applies to the S0, LENGTH, S1 and the PAYLOAD fields. */
static uint32_t m_whitening = RADIO_PCNF1_WHITEEN_Disabled; /**< Whitening disabled. */
static uint8_t m_crcLength = RADIO_CRCCNF_LEN_Three; /**< CRC Length (in bytes). */
static uint32_t m_address = 0x71764129; /**< Address. */
static uint32_t m_crc_poly = 0x0000065B; /**< CRC polynomial. */
static uint32_t m_crc_init = 0x00555555; /**< Initial value for CRC calculation. */
static uint8_t m_radio_mode = RADIO_MODE_MODE_Ble_1Mbit; /**< nRF51 specific radio mode vale. */
static uint32_t m_txIntervaluS = 625; /**< Time between start of Tx packets (in uS). */
/**@brief Function for verifying that a received PDU has the expected structure and content.
*/
static bool check_pdu(void)
{
uint8_t k; // Byte pointer for running through PDU payload
uint8_t pattern; // Repeating octet value in payload
dtm_pkt_type_t pdu_packet_type; // Note: PDU packet type is a 4-bit field in HCI, but 2 bits in BLE DTM
uint8_t length;
pdu_packet_type = (dtm_pkt_type_t)(m_pdu.content[DTM_HEADER_OFFSET] & 0x0F);
length = m_pdu.content[DTM_LENGTH_OFFSET];
if ((pdu_packet_type > (dtm_pkt_type_t)PACKET_TYPE_MAX) || (length > DTM_PAYLOAD_MAX_SIZE))
{
return false;
}
if (pdu_packet_type == DTM_PKT_PRBS9)
{
// Payload does not consist of one repeated octet; must compare ir with entire block into
return (memcmp(m_pdu.content+DTM_HEADER_SIZE, m_prbs_content, length) == 0);
}
if (pdu_packet_type == DTM_PKT_0X0F)
{
pattern = RFPHY_TEST_0X0F_REF_PATTERN;
}
else
{
pattern = RFPHY_TEST_0X55_REF_PATTERN;
}
for (k = 0; k < length; k++)
{
// Check repeated pattern filling the PDU payload
if (m_pdu.content[k + 2] != pattern)
{
return false;
}
}
return true;
}
/**@brief Function for turning off the radio after a test.
* Also called after test done, to be ready for next test.
*/
static void radio_reset(void)
{
NRF_PPI->CHENCLR = PPI_CHENCLR_CH0_Msk | PPI_CHENCLR_CH1_Msk;
NRF_RADIO->SHORTS = 0;
NRF_RADIO->EVENTS_DISABLED = 0;
NRF_RADIO->TASKS_DISABLE = 1;
while (NRF_RADIO->EVENTS_DISABLED == 0)
{
// Do nothing
}
NRF_RADIO->EVENTS_DISABLED = 0;
NRF_RADIO->TASKS_RXEN = 0;
NRF_RADIO->TASKS_TXEN = 0;
m_rx_pkt_count = 0;
}
/**@brief Function for initializing the radio for DTM.
*/
static uint32_t radio_init(void)
{
#ifdef NRF51
// Handle BLE Radio tuning parameters from production for DTM if required.
// Only needed for DTM without SoftDevice, as the SoftDevice normally handles this.
// PCN-083.
if ( ((NRF_FICR->OVERRIDEEN) & FICR_OVERRIDEEN_BLE_1MBIT_Msk) == FICR_OVERRIDEEN_BLE_1MBIT_Override)
{
NRF_RADIO->OVERRIDE0 = NRF_FICR->BLE_1MBIT[0];
NRF_RADIO->OVERRIDE1 = NRF_FICR->BLE_1MBIT[1];
NRF_RADIO->OVERRIDE2 = NRF_FICR->BLE_1MBIT[2];
NRF_RADIO->OVERRIDE3 = NRF_FICR->BLE_1MBIT[3];
NRF_RADIO->OVERRIDE4 = NRF_FICR->BLE_1MBIT[4];
}
#endif // NRF51
// Initializing code below is quite generic - for BLE, the values are fixed, and expressions
// are constant. Non-constant values are essentially set in radio_prepare().
if (((m_tx_power & 0x03) != 0) || // tx_power should be a multiple of 4
((m_tx_power & 0xffffff00) != 0) || // Upper 24 bits are required to be zeroed
((int8_t)m_tx_power > 4) || // Max tx_power is +4 dBm
((int8_t)(m_tx_power & 0xff) < -40) || // Min tx_power is -40 dBm
(m_radio_mode > RADIO_MODE_MODE_Ble_1Mbit) // Values 0-2: Proprietary mode, 3 (last valid): BLE
)
{
return DTM_ERROR_ILLEGAL_CONFIGURATION;
}
// Turn off radio before configuring it
radio_reset();
NRF_RADIO->TXPOWER = m_tx_power;
NRF_RADIO->MODE = m_radio_mode << RADIO_MODE_MODE_Pos;
// Set the access address, address0/prefix0 used for both Rx and Tx address
NRF_RADIO->PREFIX0 &= ~RADIO_PREFIX0_AP0_Msk;
NRF_RADIO->PREFIX0 |= (m_address >> 24) & RADIO_PREFIX0_AP0_Msk;
NRF_RADIO->BASE0 = m_address << 8;
NRF_RADIO->RXADDRESSES = RADIO_RXADDRESSES_ADDR0_Enabled << RADIO_RXADDRESSES_ADDR0_Pos;
NRF_RADIO->TXADDRESS = (0x00 << RADIO_TXADDRESS_TXADDRESS_Pos) & RADIO_TXADDRESS_TXADDRESS_Msk;
// Configure CRC calculation
NRF_RADIO->CRCCNF = (m_crcConfSkipAddr << RADIO_CRCCNF_SKIP_ADDR_Pos) |
(m_crcLength << RADIO_CRCCNF_LEN_Pos);
NRF_RADIO->PCNF0 = (m_packetHeaderS1len << RADIO_PCNF0_S1LEN_Pos) |
(m_packetHeaderS0len << RADIO_PCNF0_S0LEN_Pos) |
(m_packetHeaderLFlen << RADIO_PCNF0_LFLEN_Pos);
NRF_RADIO->PCNF1 = (m_whitening << RADIO_PCNF1_WHITEEN_Pos) |
(m_endian << RADIO_PCNF1_ENDIAN_Pos) |
(m_balen << RADIO_PCNF1_BALEN_Pos) |
(m_static_length << RADIO_PCNF1_STATLEN_Pos) |
(DTM_PAYLOAD_MAX_SIZE << RADIO_PCNF1_MAXLEN_Pos);
return DTM_SUCCESS;
}
/**@brief Function for preparing the radio. At start of each test: Turn off RF, clear interrupt flags of RF, initialize the radio
* at given RF channel.
*
*@param[in] rx boolean indicating if radio should be prepared in rx mode (true) or tx mode.
*/
static void radio_prepare(bool rx)
{
#ifdef NRF51
NRF_RADIO->TEST = 0;
#elif defined(NRF52)
NRF_RADIO->MODECNF0 = (RADIO_MODECNF0_RU_Default << RADIO_MODECNF0_RU_Pos) |
(RADIO_MODECNF0_DTX_B1 << RADIO_MODECNF0_DTX_Pos);
#endif // NRF51 / NRF52
NRF_RADIO->CRCPOLY = m_crc_poly;
NRF_RADIO->CRCINIT = m_crc_init;
NRF_RADIO->FREQUENCY = (m_phys_ch << 1) + 2; // Actual frequency (MHz): 2400 + register value
NRF_RADIO->PACKETPTR = (uint32_t)&m_pdu; // Setting packet pointer will start the radio
NRF_RADIO->EVENTS_READY = 0;
NRF_RADIO->SHORTS = (1 << RADIO_SHORTS_READY_START_Pos) | // Shortcut between READY event and START task
(1 << RADIO_SHORTS_END_DISABLE_Pos); // Shortcut between END event and DISABLE task
if (rx)
{
NRF_RADIO->EVENTS_END = 0;
NRF_RADIO->TASKS_RXEN = 1; // shorts will start radio in RX mode when it is ready
}
else // tx
{
NRF_RADIO->TXPOWER = m_tx_power;
}
}
/**@brief Function for terminating the ongoing test (if any) and closing down the radio.
*/
static void dtm_test_done(void)
{
#ifdef NRF51
NRF_RADIO->TEST = 0;
#elif defined(NRF52)
NRF_RADIO->MODECNF0 = (RADIO_MODECNF0_RU_Default << RADIO_MODECNF0_RU_Pos) |
(RADIO_MODECNF0_DTX_B1 << RADIO_MODECNF0_DTX_Pos);
#endif // NRF51 / NRF52
NRF_PPI->CHENCLR = 0x01;
NRF_PPI->CH[0].EEP = 0; // Break connection from timer to radio to stop transmit loop
NRF_PPI->CH[0].TEP = 0;
radio_reset();
m_state = STATE_IDLE;
}
/**@brief Function for configuring the timer for 625us cycle time.
*/
static uint32_t timer_init(void)
{
// Use 16MHz from external crystal
// This could be customized for RC/Xtal, or even to use a 32 kHz crystal
NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
NRF_CLOCK->TASKS_HFCLKSTART = 1;
while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0)
{
// Do nothing while waiting for the clock to start
}
mp_timer->TASKS_STOP = 1; // Stop timer, if it was running
mp_timer->TASKS_CLEAR = 1;
mp_timer->MODE = TIMER_MODE_MODE_Timer; // Timer mode (not counter)
mp_timer->EVENTS_COMPARE[0] = 0; // clean up possible old events
mp_timer->EVENTS_COMPARE[1] = 0;
mp_timer->EVENTS_COMPARE[2] = 0;
mp_timer->EVENTS_COMPARE[3] = 0;
// Timer is polled, but enable the compare0 interrupt in order to wakeup from CPU sleep
mp_timer->INTENSET = TIMER_INTENSET_COMPARE0_Msk;
mp_timer->SHORTS = 1 << TIMER_SHORTS_COMPARE0_CLEAR_Pos; // Clear the count every time timer reaches the CCREG0 count
mp_timer->PRESCALER = 4; // Input clock is 16MHz, timer clock = 2 ^ prescale -> interval 1us
mp_timer->CC[0] = m_txIntervaluS; // 625uS with 1MHz clock to the timer
mp_timer->CC[1] = UART_POLL_CYCLE; // 260uS with 1MHz clock to the timer
mp_timer->TASKS_START = 1; // Start the timer - it will be running continuously
m_current_time = 0;
return DTM_SUCCESS;
}
/**@brief Function for handling vendor specific commands.
* Used when packet type is set to Vendor specific.
* The length field is used for encoding vendor specific command.
* The frequency field is used for encoding vendor specific options to the command.
*
* @param[in] vendor_cmd Vendor specific command to be executed.
* @param[in] vendor_option Vendor specific option to the vendor command.
*
* @return DTM_SUCCESS or one of the DTM_ERROR_ values
*/
static uint32_t dtm_vendor_specific_pkt(uint32_t vendor_cmd, dtm_freq_t vendor_option)
{
switch (vendor_cmd)
{
// nRFgo Studio uses CARRIER_TEST_STUDIO to indicate a continuous carrier without
// a modulated signal.
case CARRIER_TEST:
case CARRIER_TEST_STUDIO:
// Not a packet type, but used to indicate that a continuous carrier signal
// should be transmitted by the radio.
radio_prepare(TX_MODE);
#ifdef NRF51
NRF_RADIO->TEST = (RADIO_TEST_PLL_LOCK_Enabled << RADIO_TEST_PLL_LOCK_Pos) |
(RADIO_TEST_CONST_CARRIER_Enabled << RADIO_TEST_CONST_CARRIER_Pos);
#elif defined(NRF52)
NRF_RADIO->MODECNF0 = (RADIO_MODECNF0_RU_Default << RADIO_MODECNF0_RU_Pos) |
(RADIO_MODECNF0_DTX_B1 << RADIO_MODECNF0_DTX_Pos);
#endif // NRF51 / NRF52
// Shortcut between READY event and START task
NRF_RADIO->SHORTS = 1 << RADIO_SHORTS_READY_START_Pos;
// Shortcut will start radio in Tx mode when it is ready
NRF_RADIO->TASKS_TXEN = 1;
m_state = STATE_CARRIER_TEST;
break;
case SET_TX_POWER:
if (!dtm_set_txpower(vendor_option))
{
return DTM_ERROR_ILLEGAL_CONFIGURATION;
}
break;
case SELECT_TIMER:
if (!dtm_set_timer(vendor_option))
{
return DTM_ERROR_ILLEGAL_CONFIGURATION;
}
break;
}
// Event code is unchanged, successful
return DTM_SUCCESS;
}
uint32_t dtm_init(void)
{
if ((timer_init() != DTM_SUCCESS) || (radio_init() != DTM_SUCCESS))
{
return DTM_ERROR_ILLEGAL_CONFIGURATION;
}
m_new_event = false;
m_state = STATE_IDLE;
// Enable wake-up on event
SCB->SCR |= SCB_SCR_SEVONPEND_Msk;
return DTM_SUCCESS;
}
uint32_t dtm_wait(void)
{
// Enable wake-up on event
SCB->SCR |= SCB_SCR_SEVONPEND_Msk;
for (;;)
{
// Event may be the reception of a packet -
// handle radio first, to give it highest priority:
if (NRF_RADIO->EVENTS_END != 0)
{
NRF_RADIO->EVENTS_END = 0;
NVIC_ClearPendingIRQ(RADIO_IRQn);
if (m_state == STATE_RECEIVER_TEST)
{
NRF_RADIO->TASKS_RXEN = 1;
if ((NRF_RADIO->CRCSTATUS == 1) && check_pdu())
{
// Count the number of successfully received packets
m_rx_pkt_count++;
}
// Note that failing packets are simply ignored (CRC or contents error).
// Zero fill all pdu fields to avoid stray data
memset(&m_pdu, 0, DTM_PDU_MAX_MEMORY_SIZE);
}
// If no RECEIVER_TEST is running, ignore incoming packets (but do clear IRQ!)
}
// Check for timeouts:
if (mp_timer->EVENTS_COMPARE[0] != 0)
{
mp_timer->EVENTS_COMPARE[0] = 0;
}
else if (mp_timer->EVENTS_COMPARE[1] != 0)
{
// Reset timeout event flag for next iteration.
mp_timer->EVENTS_COMPARE[1] = 0;
NVIC_ClearPendingIRQ(m_timer_irq);
return ++m_current_time;
}
// Other events: No processing
}
}
uint32_t dtm_cmd(dtm_cmd_t cmd, dtm_freq_t freq, uint32_t length, dtm_pkt_type_t payload)
{
// Save specified packet in static variable for tx/rx functions to use.
// Note that BLE conformance testers always use full length packets.
m_packet_length = ((uint8_t)length & 0xFF);
m_packet_type = payload;
m_phys_ch = freq;
// Clean out any non-retrieved event that might linger from an earlier test
m_new_event = true;
// Set default event; any error will set it to LE_TEST_STATUS_EVENT_ERROR
m_event = LE_TEST_STATUS_EVENT_SUCCESS;
if (m_state == STATE_UNINITIALIZED)
{
// Application has not explicitly initialized DTM,
return DTM_ERROR_UNINITIALIZED;
}
if (cmd == LE_RESET)
{
// Note that timer will continue running after a reset
dtm_test_done();
return DTM_SUCCESS;
}
if (cmd == LE_TEST_END)
{
if (m_state == STATE_IDLE)
{
// Sequencing error - only rx or tx test may be ended!
m_event = LE_TEST_STATUS_EVENT_ERROR;
return DTM_ERROR_INVALID_STATE;
}
m_event = LE_PACKET_REPORTING_EVENT | m_rx_pkt_count;
dtm_test_done();
return DTM_SUCCESS;
}
if (m_state != STATE_IDLE)
{
// Sequencing error - only TEST_END/RESET are legal while test is running
// Note: State is unchanged; ongoing test not affected
m_event = LE_TEST_STATUS_EVENT_ERROR;
return DTM_ERROR_INVALID_STATE;
}
if (m_phys_ch > PHYS_CH_MAX)
{
// Parameter error
// Note: State is unchanged; ongoing test not affected
m_event = LE_TEST_STATUS_EVENT_ERROR;
return DTM_ERROR_ILLEGAL_CHANNEL;
}
m_rx_pkt_count = 0;
if (cmd == LE_RECEIVER_TEST)
{
// Zero fill all pdu fields to avoid stray data from earlier test run
memset(&m_pdu, 0, DTM_PDU_MAX_MEMORY_SIZE);
radio_prepare(RX_MODE); // Reinitialize "everything"; RF interrupts OFF
m_state = STATE_RECEIVER_TEST;
return DTM_SUCCESS;
}
if (cmd == LE_TRANSMITTER_TEST)
{
if (m_packet_length > DTM_PAYLOAD_MAX_SIZE)
{
// Parameter error
m_event = LE_TEST_STATUS_EVENT_ERROR;
return DTM_ERROR_ILLEGAL_LENGTH;
}
// Note that PDU uses 4 bits even though BLE DTM uses only 2 (the HCI SDU uses all 4)
m_pdu.content[DTM_HEADER_OFFSET] = ((uint8_t)m_packet_type & 0x0F);
m_pdu.content[DTM_LENGTH_OFFSET] = m_packet_length;
switch (m_packet_type)
{
case DTM_PKT_PRBS9:
// Non-repeated, must copy entire pattern to PDU
memcpy(m_pdu.content + DTM_HEADER_SIZE, m_prbs_content, length);
break;
case DTM_PKT_0X0F:
// Bit pattern 00001111 repeated
memset(m_pdu.content + DTM_HEADER_SIZE, RFPHY_TEST_0X0F_REF_PATTERN, length);
break;
case DTM_PKT_0X55:
// Bit pattern 01010101 repeated
memset(m_pdu.content + DTM_HEADER_SIZE, RFPHY_TEST_0X55_REF_PATTERN, length);
break;
case DTM_PKT_VENDORSPECIFIC:
// The length field is for indicating the vendor specific command to execute.
// The frequency field is used for vendor specific options to the command.
return dtm_vendor_specific_pkt(length, freq);
default:
// Parameter error
m_event = LE_TEST_STATUS_EVENT_ERROR;
return DTM_ERROR_ILLEGAL_CONFIGURATION;
}
// Initialize CRC value, set channel:
radio_prepare(TX_MODE);
// Configure PPI so that timer will activate radio every 625 us
NRF_PPI->CH[0].EEP = (uint32_t)&mp_timer->EVENTS_COMPARE[0];
NRF_PPI->CH[0].TEP = (uint32_t)&NRF_RADIO->TASKS_TXEN;
NRF_PPI->CHENSET = 0x01;
m_state = STATE_TRANSMITTER_TEST;
}
return DTM_SUCCESS;
}
bool dtm_event_get(dtm_event_t *p_dtm_event)
{
bool was_new = m_new_event;
// mark the current event as retrieved
m_new_event = false;
*p_dtm_event = m_event;
// return value indicates whether this value was already retrieved.
return was_new;
}
// =================================================================================================
// Configuration functions (only for parameters not definitely determined by the BLE DTM standard).
// These functions return true if successful, false if value could not be set
/**@brief Function for configuring the output power for transmitter test.
This function may be called directly, or through dtm_cmd() specifying
DTM_PKT_VENDORSPECIFIC as payload, SET_TX_POWER as length, and the dBm value as frequency.
*/
bool dtm_set_txpower(uint32_t new_tx_power)
{
// radio->TXPOWER register is 32 bits, low octet a signed value, upper 24 bits zeroed
int8_t new_power8 = (int8_t)(new_tx_power & 0xFF);
if (m_state > STATE_IDLE)
{
// radio must be idle to change the tx power
return false;
}
if ((new_power8 > 4) || (new_power8 < -40))
{
// Parameter outside valid range: nRF radio is restricted to the range -40 dBm to +4 dBm
return false;
}
if (new_tx_power & 0x03)
{
// Parameter error: The nRF51 radio requires settings that are a multiple of 4.
return false;
}
m_tx_power = new_tx_power;
return true;
}
/**@brief Function for selecting a timer resource.
* This function may be called directly, or through dtm_cmd() specifying
* DTM_PKT_VENDORSPECIFIC as payload, SELECT_TIMER as length, and the timer as freq
*
* @param[in] new_timer Timer id for the timer to use: 0, 1, or 2.
*
* @return true if the timer was successfully changed, false otherwise.
*/
bool dtm_set_timer(uint32_t new_timer)
{
if (m_state > STATE_IDLE)
{
return false;
}
if (new_timer == 0)
{
mp_timer = NRF_TIMER0;
m_timer_irq = TIMER0_IRQn;
}
else if (new_timer == 1)
{
mp_timer = NRF_TIMER1;
m_timer_irq = TIMER1_IRQn;
}
else if (new_timer == 2)
{
mp_timer = NRF_TIMER2;
m_timer_irq = TIMER2_IRQn;
}
else
{
// Parameter error: Only TIMER 0, 1, 2 provided by nRF51
return false;
}
// New timer has been selected:
return true;
}
/// @}

View File

@ -0,0 +1,168 @@
/*
* Copyright (c) 2012 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/** @file
*
* @defgroup ble_sdk_dtmlib_dtm DTM - Direct Test Mode
* @{
* @ingroup ble_sdk_lib
* @brief Module for testing RF/PHY using DTM commands.
*/
#ifndef BLE_DTM_H__
#define BLE_DTM_H__
#include <stdint.h>
#include <stdbool.h>
/**@brief Configuration parameters. */
#define DEFAULT_TX_POWER RADIO_TXPOWER_TXPOWER_0dBm /**< Default Transmission power using in the DTM module. */
#define DEFAULT_TIMER NRF_TIMER0 /**< Default timer used for timing. */
#define DEFAULT_TIMER_IRQn TIMER0_IRQn /**< IRQ used for timer. NOTE: MUST correspond to DEFAULT_TIMER. */
/**@brief BLE DTM command codes. */
typedef uint32_t dtm_cmd_t; /**< DTM command type. */
#define LE_RESET 0 /**< DTM command: Reset device. */
#define LE_RECEIVER_TEST 1 /**< DTM command: Start receive test. */
#define LE_TRANSMITTER_TEST 2 /**< DTM command: Start transmission test. */
#define LE_TEST_END 3 /**< DTM command: End test and send packet report. */
// Configuration options used as parameter 2
// when cmd == LE_TRANSMITTER_TEST and payload == DTM_PKT_VENDORSPECIFIC
// Configuration value, if any, is supplied in parameter 3
#define CARRIER_TEST 0 /**< Length=0 indicates a constant, unmodulated carrier until LE_TEST_END or LE_RESET */
#define CARRIER_TEST_STUDIO 1 /**< nRFgo Studio uses value 1 in length field, to indicate a constant, unmodulated carrier until LE_TEST_END or LE_RESET */
#define SET_TX_POWER 2 /**< Set transmission power, value -40..+4 dBm in steps of 4 */
#define SELECT_TIMER 3 /**< Select on of the 16 MHz timers 0, 1 or 2 */
#define LE_PACKET_REPORTING_EVENT 0x8000 /**< DTM Packet reporting event, returned by the device to the tester. */
#define LE_TEST_STATUS_EVENT_SUCCESS 0x0000 /**< DTM Status event, indicating success. */
#define LE_TEST_STATUS_EVENT_ERROR 0x0001 /**< DTM Status event, indicating an error. */
#define DTM_PKT_PRBS9 0x00 /**< Bit pattern PRBS9. */
#define DTM_PKT_0X0F 0x01 /**< Bit pattern 11110000 (LSB is the leftmost bit). */
#define DTM_PKT_0X55 0x02 /**< Bit pattern 10101010 (LSB is the leftmost bit). */
#define DTM_PKT_VENDORSPECIFIC 0xFFFFFFFF /**< Vendor specific. Nordic: Continuous carrier test, or configuration. */
/**@brief Return codes from dtm_cmd(). */
#define DTM_SUCCESS 0x00 /**< Indicate that the DTM function completed with success. */
#define DTM_ERROR_ILLEGAL_CHANNEL 0x01 /**< Physical channel number must be in the range 0..39. */
#define DTM_ERROR_INVALID_STATE 0x02 /**< Sequencing error: Command is not valid now. */
#define DTM_ERROR_ILLEGAL_LENGTH 0x03 /**< Payload size must be in the range 0..37. */
#define DTM_ERROR_ILLEGAL_CONFIGURATION 0x04 /**< Parameter out of range (legal range is function dependent). */
#define DTM_ERROR_UNINITIALIZED 0x05 /**< DTM module has not been initialized by the application. */
// Note: DTM_PKT_VENDORSPECIFIC, is not a packet type
#define PACKET_TYPE_MAX DTM_PKT_0X55 /**< Highest value allowed as DTM Packet type. */
/** @brief BLE DTM event type. */
typedef uint32_t dtm_event_t; /**< Type for handling DTM event. */
/** @brief BLE DTM frequency type. */
typedef uint32_t dtm_freq_t; /**< Physical channel, valid range: 0..39. */
/**@brief BLE DTM packet types. */
typedef uint32_t dtm_pkt_type_t; /**< Type for holding the requested DTM payload type.*/
/**@brief Function for initializing or re-initializing DTM module
*
* @return DTM_SUCCESS on successful initialization of the DTM module.
*/
uint32_t dtm_init(void);
/**@brief Function for giving control to dtmlib for handling timer and radio events.
* Will return to caller at 625us intervals or whenever another event than radio occurs
* (such as UART input). Function will put MCU to sleep between events.
*
* @return Time counter, incremented every 625 us.
*/
uint32_t dtm_wait(void);
/**@brief Function for calling when a complete command has been prepared by the Tester.
*
* @param[in] cmd One of the DTM_CMD values (bits 14:15 in the 16-bit UART format).
* @param[in] freq Phys. channel no - actual frequency = (2402 + freq * 2) MHz (bits 8:13 in
* the 16-bit UART format).
* @param[in] length Payload length, 0..37 (bits 2:7 in the 16-bit UART format).
* @param[in] payload One of the DTM_PKT values (bits 0:1 in the 16-bit UART format).
*
* @return DTM_SUCCESS or one of the DTM_ERROR_ values
*/
uint32_t dtm_cmd(dtm_cmd_t cmd, dtm_freq_t freq, uint32_t length, dtm_pkt_type_t payload);
/**@brief Function for reading the result of a DTM command
*
* @param[out] p_dtm_event Pointer to buffer for 16 bit event code according to DTM standard.
*
* @return true: new event, false: no event since last call, this event has been read earlier
*/
bool dtm_event_get(dtm_event_t * p_dtm_event);
/**@brief Function for configuring the timer to use.
*
* @note Must be called when no DTM test is running.
*
* @param[in] new_timer Index (0..2) of timer to be used by the DTM library
*
* @return true: success, new timer was selected, false: parameter error
*/
bool dtm_set_timer(uint32_t new_timer);
/**@brief Function for configuring the transmit power.
*
* @note Must be called when no DTM test is running.
*
* @param[in] new_tx_power New output level, +4..-40, in steps of 4.
*
* @return true: tx power setting changed, false: parameter error
*/
bool dtm_set_txpower(uint32_t new_tx_power);
#endif // BLE_DTM_H__
/** @} */

View File

@ -0,0 +1,96 @@
/*
* Copyright (c) 2012 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/** @file
*
* @defgroup ble_error_log_module Error Log Module
* @{
* @ingroup ble_sdk_lib
* @brief Module for writing error and stack to flash memory.
*
* @details It contains functions for writing an error code, line number, filename/message and
* the stack to the flash during an error, e.g. in the assert handler.
*
*/
#ifndef BLE_ERROR_LOG_H__
#define BLE_ERROR_LOG_H__
#include <stdint.h>
#include <stdbool.h>
#include "ble_flash.h"
#define ERROR_MESSAGE_LENGTH 128 /**< Length of error message to stored. */
#define STACK_DUMP_LENGTH 256 /**< Length of stack to be stored at max: 64 entries of 4 bytes each. */
#define FLASH_PAGE_ERROR_LOG (BLE_FLASH_PAGE_END - 2) /**< Address in flash where stack trace can be stored. */
/**@brief Error Log Data structure.
*
* @details The structure contains the error, message/filename, line number as well as the current
* stack, at the time where an error occured.
*/
typedef struct
{
uint16_t failure; /**< Indication that a major failure has occurred during last execution of the application. */
uint16_t line_number; /**< Line number indicating at which line the failure occurred. */
uint32_t err_code; /**< Error code when failure occurred. */
uint8_t message[ERROR_MESSAGE_LENGTH]; /**< Will just use the first 128 bytes of filename to store for debugging purposes. */
uint32_t stack_info[STACK_DUMP_LENGTH / 4]; /**< Will contain stack information, can be manually unwinded for debug purposes. */
} ble_error_log_data_t;
/**@brief Function for writing the file name/message, line number, and current program stack
* to flash.
*
* @note This function will force the writing to flash, and disregard any radio communication.
* USE THIS FUNCTION WITH CARE.
*
* @param[in] err_code Error code to be logged.
* @param[in] p_message Message to be written to the flash together with stack dump, usually
* the file name where the error occured.
* @param[in] line_number Line number where the error occured.
*
* @return NRF_SUCCESS on successful writing of the error log.
*
*/
uint32_t ble_error_log_write(uint32_t err_code, const uint8_t * p_message, uint16_t line_number);
#endif /* BLE_ERROR_LOG_H__ */
/** @} */

View File

@ -0,0 +1,84 @@
/*
* Copyright (c) 2012 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#include "ble_racp.h"
#include <stdlib.h>
void ble_racp_decode(uint8_t data_len, uint8_t * p_data, ble_racp_value_t * p_racp_val)
{
p_racp_val->opcode = 0xFF;
p_racp_val->operator = 0xFF;
p_racp_val->operand_len = 0;
p_racp_val->p_operand = NULL;
if (data_len > 0)
{
p_racp_val->opcode = p_data[0];
}
if (data_len > 1)
{
p_racp_val->operator = p_data[1]; //lint !e415
}
if (data_len > 2)
{
p_racp_val->operand_len = data_len - 2;
p_racp_val->p_operand = &p_data[2]; //lint !e416
}
}
uint8_t ble_racp_encode(const ble_racp_value_t * p_racp_val, uint8_t * p_data)
{
uint8_t len = 0;
int i;
if (p_data != NULL)
{
p_data[len++] = p_racp_val->opcode;
p_data[len++] = p_racp_val->operator;
for (i = 0; i < p_racp_val->operand_len; i++)
{
p_data[len++] = p_racp_val->p_operand[i];
}
}
return len;
}

View File

@ -0,0 +1,123 @@
/*
* Copyright (c) 2012 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/** @file
*
* @defgroup ble_sdk_lib_racp Record Access Control Point
* @{
* @ingroup ble_sdk_lib
* @brief Record Access Control Point library.
*/
#ifndef BLE_RACP_H__
#define BLE_RACP_H__
#include <stdint.h>
#include <stdbool.h>
#include "nrf_ble.h"
#include "nrf_ble_types.h"
#include "nrf_ble.h"
/**@brief Record Access Control Point opcodes. */
#define RACP_OPCODE_RESERVED 0 /**< Record Access Control Point opcode - Reserved for future use. */
#define RACP_OPCODE_REPORT_RECS 1 /**< Record Access Control Point opcode - Report stored records. */
#define RACP_OPCODE_DELETE_RECS 2 /**< Record Access Control Point opcode - Delete stored records. */
#define RACP_OPCODE_ABORT_OPERATION 3 /**< Record Access Control Point opcode - Abort operation. */
#define RACP_OPCODE_REPORT_NUM_RECS 4 /**< Record Access Control Point opcode - Report number of stored records. */
#define RACP_OPCODE_NUM_RECS_RESPONSE 5 /**< Record Access Control Point opcode - Number of stored records response. */
#define RACP_OPCODE_RESPONSE_CODE 6 /**< Record Access Control Point opcode - Response code. */
/**@brief Record Access Control Point operators. */
#define RACP_OPERATOR_NULL 0 /**< Record Access Control Point operator - Null. */
#define RACP_OPERATOR_ALL 1 /**< Record Access Control Point operator - All records. */
#define RACP_OPERATOR_LESS_OR_EQUAL 2 /**< Record Access Control Point operator - Less than or equal to. */
#define RACP_OPERATOR_GREATER_OR_EQUAL 3 /**< Record Access Control Point operator - Greater than or equal to. */
#define RACP_OPERATOR_RANGE 4 /**< Record Access Control Point operator - Within range of (inclusive). */
#define RACP_OPERATOR_FIRST 5 /**< Record Access Control Point operator - First record (i.e. oldest record). */
#define RACP_OPERATOR_LAST 6 /**< Record Access Control Point operator - Last record (i.e. most recent record). */
#define RACP_OPERATOR_RFU_START 7 /**< Record Access Control Point operator - Start of Reserved for Future Use area. */
/**@brief Record Access Control Point response codes. */
#define RACP_RESPONSE_RESERVED 0 /**< Record Access Control Point response code - Reserved for future use. */
#define RACP_RESPONSE_SUCCESS 1 /**< Record Access Control Point response code - Successful operation. */
#define RACP_RESPONSE_OPCODE_UNSUPPORTED 2 /**< Record Access Control Point response code - Unsupported op code received. */
#define RACP_RESPONSE_INVALID_OPERATOR 3 /**< Record Access Control Point response code - Operator not valid for service. */
#define RACP_RESPONSE_OPERATOR_UNSUPPORTED 4 /**< Record Access Control Point response code - Unsupported operator. */
#define RACP_RESPONSE_INVALID_OPERAND 5 /**< Record Access Control Point response code - Operand not valid for service. */
#define RACP_RESPONSE_NO_RECORDS_FOUND 6 /**< Record Access Control Point response code - No matching records found. */
#define RACP_RESPONSE_ABORT_FAILED 7 /**< Record Access Control Point response code - Abort could not be completed. */
#define RACP_RESPONSE_PROCEDURE_NOT_DONE 8 /**< Record Access Control Point response code - Procedure could not be completed. */
#define RACP_RESPONSE_OPERAND_UNSUPPORTED 9 /**< Record Access Control Point response code - Unsupported operand. */
/**@brief Record Access Control Point value structure. */
typedef struct
{
uint8_t opcode; /**< Op Code. */
uint8_t operator; /**< Operator. */
uint8_t operand_len; /**< Length of the operand. */
uint8_t * p_operand; /**< Pointer to the operand. */
} ble_racp_value_t;
/**@brief Function for decoding a Record Access Control Point write.
*
* @details This call decodes a write to the Record Access Control Point.
*
* @param[in] data_len Length of data in received write.
* @param[in] p_data Pointer to received data.
* @param[out] p_racp_val Pointer to decoded Record Access Control Point write.
* @note This does not do a data copy. It assumes the data pointed to by
* p_data is persistant until no longer needed.
*/
void ble_racp_decode(uint8_t data_len, uint8_t * p_data, ble_racp_value_t * p_racp_val);
/**@brief Function for encoding a Record Access Control Point response.
*
* @details This call encodes a response from the Record Access Control Point response.
*
* @param[in] p_racp_val Pointer to Record Access Control Point to encode.
* @param[out] p_data Pointer to where encoded data is written.
* NOTE! It is calling routines respsonsibility to make sure.
*
* @return Length of encoded data.
*/
uint8_t ble_racp_encode(const ble_racp_value_t * p_racp_val, uint8_t * p_data);
#endif // BLE_RACP_H__
/** @} */

View File

@ -0,0 +1,88 @@
/*
* Copyright (c) 2012 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#include "ble_radio_notification.h"
#include <stdlib.h>
#include "nrf_nvic.h"
static bool m_radio_active = false; /**< Current radio state. */
static ble_radio_notification_evt_handler_t m_evt_handler = NULL; /**< Application event handler for handling Radio Notification events. */
void SWI1_IRQHandler(void)
{
m_radio_active = !m_radio_active;
if (m_evt_handler != NULL)
{
m_evt_handler(m_radio_active);
}
}
uint32_t ble_radio_notification_init(uint32_t irq_priority,
uint8_t distance,
ble_radio_notification_evt_handler_t evt_handler)
{
uint32_t err_code;
m_evt_handler = evt_handler;
// Initialize Radio Notification software interrupt
err_code = sd_nvic_ClearPendingIRQ(SWI1_IRQn);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
err_code = sd_nvic_SetPriority(SWI1_IRQn, irq_priority);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
err_code = sd_nvic_EnableIRQ(SWI1_IRQn);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
// Configure the event
return sd_radio_notification_cfg_set(NRF_RADIO_NOTIFICATION_TYPE_INT_ON_BOTH, distance);
}

View File

@ -0,0 +1,74 @@
/*
* Copyright (c) 2012 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/** @file
*
* @defgroup ble_radio_notification Radio Notification Event Handler
* @{
* @ingroup ble_sdk_lib
* @brief Module for propagating Radio Notification events to the application.
*/
#ifndef BLE_RADIO_NOTIFICATION_H__
#define BLE_RADIO_NOTIFICATION_H__
#include <stdint.h>
#include <stdbool.h>
#include "nrf_soc.h"
/**@brief Application radio notification event handler type. */
typedef void (*ble_radio_notification_evt_handler_t) (bool radio_active);
/**@brief Function for initializing the Radio Notification module.
*
* @param[in] irq_priority Interrupt priority for the Radio Notification interrupt handler.
* @param[in] distance The time from an Active event until the radio is activated.
* @param[in] evt_handler Handler to be executed when a radio notification event has been
* received.
*
* @return NRF_SUCCESS on successful initialization, otherwise an error code.
*/
uint32_t ble_radio_notification_init(uint32_t irq_priority,
uint8_t distance,
ble_radio_notification_evt_handler_t evt_handler);
#endif // BLE_RADIO_NOTIFICATION_H__
/** @} */

View File

@ -0,0 +1,676 @@
/*
* Copyright (c) 2013 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#include "ble_dfu.h"
#include "nrf_ble_types.h"
#include "nrf_ble_gatts.h"
#include "ble_srv_common.h"
#include <stddef.h>
#include "sdk_common.h"
#define MAX_DFU_PKT_LEN 20 /**< Maximum length (in bytes) of the DFU Packet characteristic. */
#define PKT_START_DFU_PARAM_LEN 2 /**< Length (in bytes) of the parameters for Packet Start DFU Request. */
#define PKT_INIT_DFU_PARAM_LEN 2 /**< Length (in bytes) of the parameters for Packet Init DFU Request. */
#define PKT_RCPT_NOTIF_REQ_LEN 3 /**< Length (in bytes) of the Packet Receipt Notification Request. */
#define MAX_PKTS_RCPT_NOTIF_LEN 6 /**< Maximum length (in bytes) of the Packets Receipt Notification. */
#define MAX_RESPONSE_LEN 7 /**< Maximum length (in bytes) of the response to a Control Point command. */
#define MAX_NOTIF_BUFFER_LEN MAX(MAX_PKTS_RCPT_NOTIF_LEN, MAX_RESPONSE_LEN) /**< Maximum length (in bytes) of the buffer needed by DFU Service while sending notifications to peer. */
enum
{
OP_CODE_START_DFU = 1, /**< Value of the Op code field for 'Start DFU' command.*/
OP_CODE_RECEIVE_INIT = 2, /**< Value of the Op code field for 'Initialize DFU parameters' command.*/
OP_CODE_RECEIVE_FW = 3, /**< Value of the Op code field for 'Receive firmware image' command.*/
OP_CODE_VALIDATE = 4, /**< Value of the Op code field for 'Validate firmware' command.*/
OP_CODE_ACTIVATE_N_RESET = 5, /**< Value of the Op code field for 'Activate & Reset' command.*/
OP_CODE_SYS_RESET = 6, /**< Value of the Op code field for 'Reset System' command.*/
OP_CODE_IMAGE_SIZE_REQ = 7, /**< Value of the Op code field for 'Report received image size' command.*/
OP_CODE_PKT_RCPT_NOTIF_REQ = 8, /**< Value of the Op code field for 'Request packet receipt notification.*/
OP_CODE_RESPONSE = 16, /**< Value of the Op code field for 'Response.*/
OP_CODE_PKT_RCPT_NOTIF = 17 /**< Value of the Op code field for 'Packets Receipt Notification'.*/
};
static bool m_is_dfu_service_initialized = false; /**< Variable to check if the DFU service was initialized by the application.*/
static uint8_t m_notif_buffer[MAX_NOTIF_BUFFER_LEN]; /**< Buffer used for sending notifications to peer. */
/**@brief Function for adding DFU Packet characteristic to the BLE Stack.
*
* @param[in] p_dfu DFU Service structure.
*
* @return NRF_SUCCESS on success. Otherwise an error code.
*/
static uint32_t dfu_pkt_char_add(ble_dfu_t * const p_dfu)
{
ble_gatts_char_md_t char_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t char_uuid;
ble_gatts_attr_md_t attr_md;
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.write_wo_resp = 1;
char_md.p_char_user_desc = NULL;
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = NULL;
char_md.p_sccd_md = NULL;
char_uuid.type = p_dfu->uuid_type;
char_uuid.uuid = BLE_DFU_PKT_CHAR_UUID;
memset(&attr_md, 0, sizeof(attr_md));
BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 1;
memset(&attr_char_value, 0, sizeof(attr_char_value));
attr_char_value.p_uuid = &char_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = 0;
attr_char_value.init_offs = 0;
attr_char_value.max_len = MAX_DFU_PKT_LEN;
attr_char_value.p_value = NULL;
return sd_ble_gatts_characteristic_add(p_dfu->service_handle,
&char_md,
&attr_char_value,
&p_dfu->dfu_pkt_handles);
}
/**@brief Function for adding DFU Revision characteristic to the BLE Stack.
*
* @param[in] p_dfu DFU Service structure.
*
* @return NRF_SUCCESS on success. Otherwise an error code.
*/
static uint32_t dfu_rev_char_add(ble_dfu_t * const p_dfu, ble_dfu_init_t const * const p_dfu_init)
{
ble_gatts_char_md_t char_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t char_uuid;
ble_gatts_attr_md_t attr_md;
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.read = 1;
char_md.p_char_user_desc = NULL;
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = NULL;
char_md.p_sccd_md = NULL;
char_uuid.type = p_dfu->uuid_type;
char_uuid.uuid = BLE_DFU_REV_CHAR_UUID;
memset(&attr_md, 0, sizeof(attr_md));
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.write_perm);
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.rd_auth = 0;
attr_md.wr_auth = 0;
attr_md.vlen = 1;
memset(&attr_char_value, 0, sizeof(attr_char_value));
attr_char_value.p_uuid = &char_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = sizeof(uint16_t);
attr_char_value.init_offs = 0;
attr_char_value.max_len = sizeof(uint16_t);
attr_char_value.p_value = (uint8_t *)&p_dfu_init->revision;
return sd_ble_gatts_characteristic_add(p_dfu->service_handle,
&char_md,
&attr_char_value,
&p_dfu->dfu_rev_handles);
}
/**@brief Function for adding DFU Control Point characteristic to the BLE Stack.
*
* @param[in] p_dfu DFU Service structure.
*
* @return NRF_SUCCESS on success. Otherwise an error code.
*/
static uint32_t dfu_ctrl_pt_add(ble_dfu_t * const p_dfu)
{
ble_gatts_char_md_t char_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t char_uuid;
ble_gatts_attr_md_t attr_md;
memset(&char_md, 0, sizeof(char_md));
char_md.char_props.write = 1;
char_md.char_props.notify = 1;
char_md.p_char_user_desc = NULL;
char_md.p_char_pf = NULL;
char_md.p_user_desc_md = NULL;
char_md.p_cccd_md = NULL;
char_md.p_sccd_md = NULL;
char_uuid.type = p_dfu->uuid_type;
char_uuid.uuid = BLE_DFU_CTRL_PT_UUID;
memset(&attr_md, 0, sizeof(attr_md));
BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(&attr_md.read_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&attr_md.write_perm);
attr_md.vloc = BLE_GATTS_VLOC_STACK;
attr_md.rd_auth = 0;
attr_md.wr_auth = 1;
attr_md.vlen = 1;
memset(&attr_char_value, 0, sizeof(attr_char_value));
attr_char_value.p_uuid = &char_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.init_len = 0;
attr_char_value.init_offs = 0;
attr_char_value.max_len = BLE_L2CAP_MTU_DEF;
attr_char_value.p_value = NULL;
return sd_ble_gatts_characteristic_add(p_dfu->service_handle,
&char_md,
&attr_char_value,
&p_dfu->dfu_ctrl_pt_handles);
}
/**@brief Function for handling the @ref BLE_GAP_EVT_CONNECTED event from the S110 SoftDevice.
*
* @param[in] p_dfu DFU Service Structure.
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
*/
static void on_connect(ble_dfu_t * p_dfu, ble_evt_t * p_ble_evt)
{
p_dfu->conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
}
/**@brief Function for checking if the CCCD of DFU Control point is configured for Notification.
*
* @details This function checks if the CCCD of DFU Control Point characteristic is configured
* for Notification by the DFU Controller.
*
* @param[in] p_dfu DFU Service structure.
*
* @return True if the CCCD of DFU Control Point characteristic is configured for Notification.
* False otherwise.
*/
static bool is_cccd_configured(ble_dfu_t * p_dfu)
{
// Check if the CCCDs are configured.
uint8_t cccd_val_buf[BLE_CCCD_VALUE_LEN];
ble_gatts_value_t gatts_value;
// Initialize value struct.
memset(&gatts_value, 0, sizeof(gatts_value));
gatts_value.len = BLE_CCCD_VALUE_LEN;
gatts_value.offset = 0;
gatts_value.p_value = cccd_val_buf;
// Check the CCCD Value of DFU Control Point.
uint32_t err_code = sd_ble_gatts_value_get(p_dfu->conn_handle,
p_dfu->dfu_ctrl_pt_handles.cccd_handle,
&gatts_value);
if (err_code != NRF_SUCCESS)
{
if (p_dfu->error_handler != NULL)
{
p_dfu->error_handler(err_code);
}
return false;
}
return ble_srv_is_notification_enabled(cccd_val_buf);
}
/**@brief Function for handling a Write event on the Control Point characteristic.
*
* @param[in] p_dfu DFU Service Structure.
* @param[in] p_ble_write_evt Pointer to the write event received from BLE stack.
*
* @return NRF_SUCCESS on successful processing of control point write. Otherwise an error code.
*/
static uint32_t on_ctrl_pt_write(ble_dfu_t * p_dfu, ble_gatts_evt_write_t * p_ble_write_evt)
{
ble_gatts_rw_authorize_reply_params_t auth_reply;
auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
auth_reply.params.write.update = 1;
auth_reply.params.write.offset = p_ble_write_evt->offset;
auth_reply.params.write.len = p_ble_write_evt->len;
auth_reply.params.write.p_data = p_ble_write_evt->data;
if (!is_cccd_configured(p_dfu))
{
// Send an error response to the peer indicating that the CCCD is improperly configured.
auth_reply.params.write.gatt_status =
BLE_GATT_STATUS_ATTERR_CPS_CCCD_CONFIG_ERROR;
return (sd_ble_gatts_rw_authorize_reply(p_dfu->conn_handle, &auth_reply));
}
else
{
uint32_t err_code;
auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
err_code = (sd_ble_gatts_rw_authorize_reply(p_dfu->conn_handle, &auth_reply));
VERIFY_SUCCESS(err_code);
}
ble_dfu_evt_t ble_dfu_evt;
switch (p_ble_write_evt->data[0])
{
case OP_CODE_START_DFU:
ble_dfu_evt.ble_dfu_evt_type = BLE_DFU_START;
if (p_ble_write_evt->len < PKT_START_DFU_PARAM_LEN)
{
return ble_dfu_response_send(p_dfu,
(ble_dfu_procedure_t) p_ble_write_evt->data[0],
BLE_DFU_RESP_VAL_OPER_FAILED);
}
ble_dfu_evt.evt.ble_dfu_pkt_write.len = 1;
ble_dfu_evt.evt.ble_dfu_pkt_write.p_data = &(p_ble_write_evt->data[1]);
p_dfu->evt_handler(p_dfu, &ble_dfu_evt);
break;
case OP_CODE_RECEIVE_INIT:
ble_dfu_evt.ble_dfu_evt_type = BLE_DFU_RECEIVE_INIT_DATA;
if (p_ble_write_evt->len < PKT_INIT_DFU_PARAM_LEN)
{
return ble_dfu_response_send(p_dfu,
(ble_dfu_procedure_t) p_ble_write_evt->data[0],
BLE_DFU_RESP_VAL_OPER_FAILED);
}
ble_dfu_evt.evt.ble_dfu_pkt_write.len = 1;
ble_dfu_evt.evt.ble_dfu_pkt_write.p_data = &(p_ble_write_evt->data[1]);
p_dfu->evt_handler(p_dfu, &ble_dfu_evt);
break;
case OP_CODE_RECEIVE_FW:
ble_dfu_evt.ble_dfu_evt_type = BLE_DFU_RECEIVE_APP_DATA;
p_dfu->evt_handler(p_dfu, &ble_dfu_evt);
break;
case OP_CODE_VALIDATE:
ble_dfu_evt.ble_dfu_evt_type = BLE_DFU_VALIDATE;
p_dfu->evt_handler(p_dfu, &ble_dfu_evt);
break;
case OP_CODE_ACTIVATE_N_RESET:
ble_dfu_evt.ble_dfu_evt_type = BLE_DFU_ACTIVATE_N_RESET;
p_dfu->evt_handler(p_dfu, &ble_dfu_evt);
break;
case OP_CODE_SYS_RESET:
ble_dfu_evt.ble_dfu_evt_type = BLE_DFU_SYS_RESET;
p_dfu->evt_handler(p_dfu, &ble_dfu_evt);
break;
case OP_CODE_PKT_RCPT_NOTIF_REQ:
if (p_ble_write_evt->len < PKT_RCPT_NOTIF_REQ_LEN)
{
return (ble_dfu_response_send(p_dfu,
BLE_DFU_PKT_RCPT_REQ_PROCEDURE,
BLE_DFU_RESP_VAL_NOT_SUPPORTED));
}
ble_dfu_evt.evt.pkt_rcpt_notif_req.num_of_pkts =
uint16_decode(&(p_ble_write_evt->data[1]));
if (ble_dfu_evt.evt.pkt_rcpt_notif_req.num_of_pkts == 0)
{
ble_dfu_evt.ble_dfu_evt_type = BLE_DFU_PKT_RCPT_NOTIF_DISABLED;
}
else
{
ble_dfu_evt.ble_dfu_evt_type = BLE_DFU_PKT_RCPT_NOTIF_ENABLED;
}
p_dfu->evt_handler(p_dfu, &ble_dfu_evt);
break;
case OP_CODE_IMAGE_SIZE_REQ:
ble_dfu_evt.ble_dfu_evt_type = BLE_DFU_BYTES_RECEIVED_SEND;
p_dfu->evt_handler(p_dfu, &ble_dfu_evt);
break;
default:
// Unsupported op code.
return ble_dfu_response_send(p_dfu,
(ble_dfu_procedure_t) p_ble_write_evt->data[0],
BLE_DFU_RESP_VAL_NOT_SUPPORTED);
}
return NRF_SUCCESS;
}
/**@brief Function for handling the @ref BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST event from the S110
* Stack.
*
* @param[in] p_dfu DFU Service Structure.
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
*/
static void on_rw_authorize_req(ble_dfu_t * p_dfu, ble_evt_t * p_ble_evt)
{
ble_gatts_evt_rw_authorize_request_t * p_authorize_request;
p_authorize_request = &(p_ble_evt->evt.gatts_evt.params.authorize_request);
if (
(p_authorize_request->type == BLE_GATTS_AUTHORIZE_TYPE_WRITE)
&&
(p_authorize_request->request.write.handle == p_dfu->dfu_ctrl_pt_handles.value_handle)
&&
(p_ble_evt->evt.gatts_evt.params.authorize_request.request.write.op != BLE_GATTS_OP_PREP_WRITE_REQ)
&&
(p_ble_evt->evt.gatts_evt.params.authorize_request.request.write.op != BLE_GATTS_OP_EXEC_WRITE_REQ_NOW)
&&
(p_ble_evt->evt.gatts_evt.params.authorize_request.request.write.op != BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL)
)
{
uint32_t err_code;
err_code = on_ctrl_pt_write(p_dfu, &(p_authorize_request->request.write));
if (err_code != NRF_SUCCESS && p_dfu->error_handler != NULL)
{
p_dfu->error_handler(err_code);
}
}
}
/**@brief Function for handling the @ref BLE_GATTS_EVT_WRITE event from the S110 SoftDevice.
*
* @param[in] p_dfu DFU Service Structure.
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
*/
static void on_write(ble_dfu_t * p_dfu, ble_evt_t * p_ble_evt)
{
if (p_ble_evt->evt.gatts_evt.params.write.handle == p_dfu->dfu_pkt_handles.value_handle)
{
// DFU Packet written
ble_dfu_evt_t ble_dfu_evt;
ble_dfu_evt.ble_dfu_evt_type = BLE_DFU_PACKET_WRITE;
ble_dfu_evt.evt.ble_dfu_pkt_write.len = p_ble_evt->evt.gatts_evt.params.write.len;
ble_dfu_evt.evt.ble_dfu_pkt_write.p_data = p_ble_evt->evt.gatts_evt.params.write.data;
p_dfu->evt_handler(p_dfu, &ble_dfu_evt);
}
}
/**@brief Function for handling the BLE_GAP_EVT_DISCONNECTED event from the S110 SoftDevice.
*
* @param[in] p_dfu DFU Service Structure.
* @param[in] p_ble_evt Pointer to the event received from BLE stack.
*/
static void on_disconnect(ble_dfu_t * p_dfu, ble_evt_t * p_ble_evt)
{
p_dfu->conn_handle = BLE_CONN_HANDLE_INVALID;
}
uint32_t ble_dfu_init(ble_dfu_t * p_dfu, ble_dfu_init_t * p_dfu_init)
{
if ((p_dfu == NULL) || (p_dfu_init == NULL) || (p_dfu_init->evt_handler == NULL))
{
return NRF_ERROR_NULL;
}
p_dfu->conn_handle = BLE_CONN_HANDLE_INVALID;
ble_uuid_t service_uuid;
uint32_t err_code;
const ble_uuid128_t base_uuid128 =
{
{
0x23, 0xD1, 0xBC, 0xEA, 0x5F, 0x78, 0x23, 0x15,
0xDE, 0xEF, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00
}
};
service_uuid.uuid = BLE_DFU_SERVICE_UUID;
err_code = sd_ble_uuid_vs_add(&base_uuid128, &(service_uuid.type));
VERIFY_SUCCESS(err_code);
err_code = sd_ble_gatts_service_add(BLE_GATTS_SRVC_TYPE_PRIMARY,
&service_uuid,
&(p_dfu->service_handle));
VERIFY_SUCCESS(err_code);
p_dfu->uuid_type = service_uuid.type;
err_code = dfu_pkt_char_add(p_dfu);
VERIFY_SUCCESS(err_code);
err_code = dfu_ctrl_pt_add(p_dfu);
VERIFY_SUCCESS(err_code);
err_code = dfu_rev_char_add(p_dfu, p_dfu_init);
VERIFY_SUCCESS(err_code);
p_dfu->evt_handler = p_dfu_init->evt_handler;
if (p_dfu_init->error_handler != NULL)
{
p_dfu->error_handler = p_dfu_init->error_handler;
}
m_is_dfu_service_initialized = true;
return NRF_SUCCESS;
}
void ble_dfu_on_ble_evt(ble_dfu_t * p_dfu, ble_evt_t * p_ble_evt)
{
if ((p_dfu == NULL) || (p_ble_evt == NULL))
{
return;
}
if (p_dfu->evt_handler != NULL)
{
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
on_connect(p_dfu, p_ble_evt);
break;
case BLE_GATTS_EVT_WRITE:
on_write(p_dfu, p_ble_evt);
break;
case BLE_GAP_EVT_DISCONNECTED:
on_disconnect(p_dfu, p_ble_evt);
break;
case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
on_rw_authorize_req(p_dfu, p_ble_evt);
break;
default:
// No implementation needed.
break;
}
}
}
uint32_t ble_dfu_bytes_rcvd_report(ble_dfu_t * p_dfu, uint32_t num_of_firmware_bytes_rcvd)
{
if (p_dfu == NULL)
{
return NRF_ERROR_NULL;
}
if ((p_dfu->conn_handle == BLE_CONN_HANDLE_INVALID) || !m_is_dfu_service_initialized)
{
return NRF_ERROR_INVALID_STATE;
}
ble_gatts_hvx_params_t hvx_params;
uint16_t index = 0;
// Encode the Op Code.
m_notif_buffer[index++] = OP_CODE_RESPONSE;
// Encode the Reqest Op Code.
m_notif_buffer[index++] = OP_CODE_IMAGE_SIZE_REQ;
// Encode the Response Value.
m_notif_buffer[index++] = (uint8_t)BLE_DFU_RESP_VAL_SUCCESS;
index += uint32_encode(num_of_firmware_bytes_rcvd, &m_notif_buffer[index]);
memset(&hvx_params, 0, sizeof(hvx_params));
hvx_params.handle = p_dfu->dfu_ctrl_pt_handles.value_handle;
hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
hvx_params.offset = 0;
hvx_params.p_len = &index;
hvx_params.p_data = m_notif_buffer;
return sd_ble_gatts_hvx(p_dfu->conn_handle, &hvx_params);
}
uint32_t ble_dfu_pkts_rcpt_notify(ble_dfu_t * p_dfu, uint32_t num_of_firmware_bytes_rcvd)
{
if (p_dfu == NULL)
{
return NRF_ERROR_NULL;
}
if ((p_dfu->conn_handle == BLE_CONN_HANDLE_INVALID) || !m_is_dfu_service_initialized)
{
return NRF_ERROR_INVALID_STATE;
}
ble_gatts_hvx_params_t hvx_params;
uint16_t index = 0;
m_notif_buffer[index++] = OP_CODE_PKT_RCPT_NOTIF;
index += uint32_encode(num_of_firmware_bytes_rcvd, &m_notif_buffer[index]);
memset(&hvx_params, 0, sizeof(hvx_params));
hvx_params.handle = p_dfu->dfu_ctrl_pt_handles.value_handle;
hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
hvx_params.offset = 0;
hvx_params.p_len = &index;
hvx_params.p_data = m_notif_buffer;
return sd_ble_gatts_hvx(p_dfu->conn_handle, &hvx_params);
}
uint32_t ble_dfu_response_send(ble_dfu_t * p_dfu,
ble_dfu_procedure_t dfu_proc,
ble_dfu_resp_val_t resp_val)
{
if (p_dfu == NULL)
{
return NRF_ERROR_NULL;
}
if ((p_dfu->conn_handle == BLE_CONN_HANDLE_INVALID) || !m_is_dfu_service_initialized)
{
return NRF_ERROR_INVALID_STATE;
}
ble_gatts_hvx_params_t hvx_params;
uint16_t index = 0;
m_notif_buffer[index++] = OP_CODE_RESPONSE;
// Encode the Request Op code
m_notif_buffer[index++] = (uint8_t)dfu_proc;
// Encode the Response Value.
m_notif_buffer[index++] = (uint8_t)resp_val;
memset(&hvx_params, 0, sizeof(hvx_params));
hvx_params.handle = p_dfu->dfu_ctrl_pt_handles.value_handle;
hvx_params.type = BLE_GATT_HVX_NOTIFICATION;
hvx_params.offset = 0;
hvx_params.p_len = &index;
hvx_params.p_data = m_notif_buffer;
return sd_ble_gatts_hvx(p_dfu->conn_handle, &hvx_params);
}

View File

@ -0,0 +1,266 @@
/*
* Copyright (c) 2013 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/**@file
*
* @defgroup ble_sdk_srv_dfu Device Firmware Update Service
* @{
* @ingroup ble_sdk_srv
* @brief Device Firmware Update Service
*
* @details The Device Firmware Update (DFU) service is a GATT based service that can be used for
* performing firmware updates over BLE. Note that this implementation uses vendor
* specific UUIDs for service and characteristics and is intended to demonstrate the
* firmware updates over BLE. Refer @ref bledfu_transport_bleservice and @ref
* bledfu_transport_bleprofile for more information on the service and profile respectively.
*/
#ifndef BLE_DFU_H__
#define BLE_DFU_H__
#include <stdint.h>
#include "nrf_ble_gatts.h"
#include "nrf_ble_gap.h"
#include "nrf_ble.h"
#include "ble_srv_common.h"
#define BLE_DFU_SERVICE_UUID 0x1530 /**< The UUID of the DFU Service. */
#define BLE_DFU_PKT_CHAR_UUID 0x1532 /**< The UUID of the DFU Packet Characteristic. */
#define BLE_DFU_CTRL_PT_UUID 0x1531 /**< The UUID of the DFU Control Point. */
#define BLE_DFU_STATUS_REP_UUID 0x1533 /**< The UUID of the DFU Status Report Characteristic. */
#define BLE_DFU_REV_CHAR_UUID 0x1534 /**< The UUID of the DFU Revision Characteristic. */
/**@brief DFU Event type.
*
* @details This enumeration contains the types of events that will be received from the DFU Service.
*/
typedef enum
{
BLE_DFU_START, /**< The event indicating that the peer wants the application to prepare for a new firmware update. */
BLE_DFU_RECEIVE_INIT_DATA, /**< The event indicating that the peer wants the application to prepare to receive init parameters. */
BLE_DFU_RECEIVE_APP_DATA, /**< The event indicating that the peer wants the application to prepare to receive the new firmware image. */
BLE_DFU_VALIDATE, /**< The event indicating that the peer wants the application to validate the newly received firmware image. */
BLE_DFU_ACTIVATE_N_RESET, /**< The event indicating that the peer wants the application to undergo activate new firmware and restart with new valid application */
BLE_DFU_SYS_RESET, /**< The event indicating that the peer wants the application to undergo a reset and start the currently valid application image.*/
BLE_DFU_PKT_RCPT_NOTIF_ENABLED, /**< The event indicating that the peer has enabled packet receipt notifications. It is the responsibility of the application to call @ref ble_dfu_pkts_rcpt_notify each time the number of packets indicated by num_of_pkts field in @ref ble_dfu_evt_t is received.*/
BLE_DFU_PKT_RCPT_NOTIF_DISABLED, /**< The event indicating that the peer has disabled the packet receipt notifications.*/
BLE_DFU_PACKET_WRITE, /**< The event indicating that the peer has written a value to the 'DFU Packet' characteristic. The data received from the peer will be present in the @ref BLE_DFU_PACKET_WRITE element contained within @ref ble_dfu_evt_t.*/
BLE_DFU_BYTES_RECEIVED_SEND /**< The event indicating that the peer is requesting for the number of bytes of firmware data last received by the application. It is the responsibility of the application to call @ref ble_dfu_pkts_rcpt_notify in response to this event. */
} ble_dfu_evt_type_t;
/**@brief DFU Procedure type.
*
* @details This enumeration contains the types of DFU procedures.
*/
typedef enum
{
BLE_DFU_START_PROCEDURE = 1, /**< DFU Start procedure.*/
BLE_DFU_INIT_PROCEDURE = 2, /**< DFU Initialization procedure.*/
BLE_DFU_RECEIVE_APP_PROCEDURE = 3, /**< Firmware receiving procedure.*/
BLE_DFU_VALIDATE_PROCEDURE = 4, /**< Firmware image validation procedure .*/
BLE_DFU_PKT_RCPT_REQ_PROCEDURE = 8 /**< Packet receipt notification request procedure. */
} ble_dfu_procedure_t;
/**@brief DFU Response value type.
*/
typedef enum
{
BLE_DFU_RESP_VAL_SUCCESS = 1, /**< Success.*/
BLE_DFU_RESP_VAL_INVALID_STATE, /**< Invalid state.*/
BLE_DFU_RESP_VAL_NOT_SUPPORTED, /**< Operation not supported.*/
BLE_DFU_RESP_VAL_DATA_SIZE, /**< Data size exceeds limit.*/
BLE_DFU_RESP_VAL_CRC_ERROR, /**< CRC Error.*/
BLE_DFU_RESP_VAL_OPER_FAILED /**< Operation failed.*/
} ble_dfu_resp_val_t;
/**@brief DFU Packet structure.
*
* @details This structure contains the value of the DFU Packet characteristic as written by the
* peer and the length of the value written. It will be filled by the DFU Service when the
* peer writes to the DFU Packet characteristic.
*/
typedef struct
{
uint8_t * p_data; /**< Pointer to the received packet. This will point to a word aligned memory location.*/
uint8_t len; /**< Length of the packet received. */
} ble_dfu_pkt_write_t;
/**@brief Packet receipt notification request structure.
*
* @details This structure contains the contents of the packet receipt notification request
* sent by the DFU Controller.
*/
typedef struct
{
uint16_t num_of_pkts; /**< The number of packets of firmware data to be received by application before sending the next Packet Receipt Notification to the peer. */
} ble_pkt_rcpt_notif_req_t;
/**@brief DFU Event structure.
*
* @details This structure contains the event generated by the DFU Service based on the data
* received from the peer.
*/
typedef struct
{
ble_dfu_evt_type_t ble_dfu_evt_type; /**< Type of the event.*/
union
{
ble_dfu_pkt_write_t ble_dfu_pkt_write; /**< The DFU packet received. This field is when the @ref ble_dfu_evt_type field is set to @ref BLE_DFU_PACKET_WRITE.*/
ble_pkt_rcpt_notif_req_t pkt_rcpt_notif_req; /**< Packet receipt notification request. This field is when the @ref ble_dfu_evt_type field is set to @ref BLE_DFU_PKT_RCPT_NOTIF_ENABLED.*/
} evt;
} ble_dfu_evt_t;
// Forward declaration of the ble_dfu_t type.
typedef struct ble_dfu_s ble_dfu_t;
/**@brief DFU Service event handler type. */
typedef void (*ble_dfu_evt_handler_t) (ble_dfu_t * p_dfu, ble_dfu_evt_t * p_evt);
/**@brief DFU service structure.
*
* @details This structure contains status information related to the service.
*/
struct ble_dfu_s
{
uint16_t conn_handle; /**< Handle of the current connection (as provided by the SoftDevice). This will be BLE_CONN_HANDLE_INVALID when not in a connection. */
uint16_t revision; /**< Handle of DFU Service (as provided by the SoftDevice). */
uint16_t service_handle; /**< Handle of DFU Service (as provided by the SoftDevice). */
uint8_t uuid_type; /**< UUID type assigned for DFU Service by the SoftDevice. */
ble_gatts_char_handles_t dfu_pkt_handles; /**< Handles related to the DFU Packet characteristic. */
ble_gatts_char_handles_t dfu_ctrl_pt_handles; /**< Handles related to the DFU Control Point characteristic. */
ble_gatts_char_handles_t dfu_status_rep_handles; /**< Handles related to the DFU Status Report characteristic. */
ble_gatts_char_handles_t dfu_rev_handles; /**< Handles related to the DFU Revision characteristic. */
ble_dfu_evt_handler_t evt_handler; /**< The event handler to be called when an event is to be sent to the application.*/
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
};
/**@brief DFU service initialization structure.
*
* @details This structure contains the initialization information for the DFU Service. The
* application needs to fill this structure and pass it to the DFU Service using the
* @ref ble_dfu_init function.
*/
typedef struct
{
uint16_t revision; /**< Revision number to be exposed by the DFU service. */
ble_dfu_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Device Firmware Update Service. */
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
} ble_dfu_init_t;
/**@brief Function for handling a BLE event.
*
* @details The DFU service expects the application to call this function each time an event
* is received from the SoftDevice. This function processes the event, if it is
* relevant for the DFU service and calls the DFU event handler of the application if
* necessary.
*
* @param[in] p_dfu Pointer to the DFU service structure.
* @param[in] p_ble_evt Pointer to the event received from SoftDevice.
*/
void ble_dfu_on_ble_evt(ble_dfu_t * p_dfu, ble_evt_t * p_ble_evt);
/**@brief Function for initializing the DFU service.
*
* @param[out] p_dfu Device Firmware Update service structure. This structure will have to be
* supplied by the application. It will be initialized by this function,
* and will later be used to identify the service instance.
* @param[in] p_dfu_init Information needed to initialize the service.
*
* @return NRF_SUCCESS if the DFU service and its characteristics were successfully added to the
* SoftDevice. Otherwise an error code.
* This function returns NRF_ERROR_NULL if the value of evt_handler in p_dfu_init
* structure provided is NULL or if the pointers supplied as input are NULL.
*/
uint32_t ble_dfu_init(ble_dfu_t * p_dfu, ble_dfu_init_t * p_dfu_init);
/**@brief Function for sending response to a control point command.
*
* @details This function will encode a DFU Control Point response using the given input
* parameters and will send a notification of the same to the peer.
*
* @param[in] p_dfu Pointer to the DFU service structure.
* @param[in] dfu_proc Procedure for which this response is to be sent.
* @param[in] resp_val Response value.
*
* @return NRF_SUCCESS if the DFU Service has successfully requested the SoftDevice to
* send the notification. Otherwise an error code.
* This function returns NRF_ERROR_INVALID_STATE if the device is not connected to a
* peer or if the DFU service is not initialized or if the notification of the DFU
* Status Report characteristic was not enabled by the peer. It returns NRF_ERROR_NULL
* if the pointer p_dfu is NULL.
*/
uint32_t ble_dfu_response_send(ble_dfu_t * p_dfu,
ble_dfu_procedure_t dfu_proc,
ble_dfu_resp_val_t resp_val);
/**@brief Function for notifying the peer about the number of bytes of firmware data received.
*
* @param[in] p_dfu Pointer to the DFU service structure.
* @param[in] num_of_firmware_bytes_rcvd Number of bytes.
*
* @return NRF_SUCCESS if the DFU Service has successfully requested the SoftDevice to send
* the notification. Otherwise an error code.
* This function returns NRF_ERROR_INVALID_STATE if the device is not connected to a
* peer or if the DFU service is not initialized or if the notification of the DFU
* Status Report characteristic was not enabled by the peer. It returns NRF_ERROR_NULL
* if the pointer p_dfu is NULL.
*/
uint32_t ble_dfu_bytes_rcvd_report(ble_dfu_t * p_dfu, uint32_t num_of_firmware_bytes_rcvd);
/**@brief Function for sending Packet Receipt Notification to the peer.
*
* This function will encode the number of bytes received as input parameter into a
* notification of the control point characteristic and send it to the peer.
*
* @param[in] p_dfu Pointer to the DFU service structure.
* @param[in] num_of_firmware_bytes_rcvd Number of bytes of firmware image received.
*
* @return NRF_SUCCESS if the DFU Service has successfully requested the SoftDevice to send
* the notification. Otherwise an error code.
* This function returns NRF_ERROR_INVALID_STATE if the device is not connected to a
* peer or if the DFU service is not initialized or if the notification of the DFU
* Status Report characteristic was not enabled by the peer. It returns NRF_ERROR_NULL
* if the pointer p_dfu is NULL.
*/
uint32_t ble_dfu_pkts_rcpt_notify(ble_dfu_t * p_dfu, uint32_t num_of_firmware_bytes_rcvd);
#endif // BLE_DFU_H__
/** @} */

View File

@ -0,0 +1,788 @@
/*
* Copyright (c) 2012 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#include "ble_advdata.h"
#include "nrf_ble_gap.h"
#include "ble_srv_common.h"
#include "sdk_common.h"
// NOTE: For now, Security Manager Out of Band Flags (OOB) are omitted from the advertising data.
// Types of LE Bluetooth Device Address AD type
#define AD_TYPE_BLE_DEVICE_ADDR_TYPE_PUBLIC 0UL
#define AD_TYPE_BLE_DEVICE_ADDR_TYPE_RANDOM 1UL
static uint32_t tk_value_encode(ble_advdata_tk_value_t * p_tk_value,
uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
int8_t i;
// Check for buffer overflow.
if (((*p_offset) + AD_TYPE_TK_VALUE_SIZE) > max_size)
{
return NRF_ERROR_DATA_SIZE;
}
// Encode LE Role.
p_encoded_data[*p_offset] = (uint8_t)(ADV_AD_TYPE_FIELD_SIZE + AD_TYPE_TK_VALUE_DATA_SIZE);
*p_offset += ADV_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_SECURITY_MANAGER_TK_VALUE;
*p_offset += ADV_AD_TYPE_FIELD_SIZE;
for (i = AD_TYPE_TK_VALUE_DATA_SIZE - 1; i >= 0; i--, (*p_offset)++)
{
p_encoded_data[*p_offset] = p_tk_value->tk[i];
}
return NRF_SUCCESS;
}
static uint32_t le_role_encode(ble_advdata_le_role_t le_role,
uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
// Check for buffer overflow.
if (((*p_offset) + AD_TYPE_LE_ROLE_SIZE) > max_size)
{
return NRF_ERROR_DATA_SIZE;
}
// Encode LE Role.
p_encoded_data[*p_offset] = (uint8_t)(ADV_AD_TYPE_FIELD_SIZE + AD_TYPE_LE_ROLE_DATA_SIZE);
*p_offset += ADV_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_LE_ROLE;
*p_offset += ADV_AD_TYPE_FIELD_SIZE;
switch(le_role)
{
case BLE_ADVDATA_ROLE_ONLY_PERIPH:
p_encoded_data[*p_offset] = 0;
break;
case BLE_ADVDATA_ROLE_ONLY_CENTRAL:
p_encoded_data[*p_offset] = 1;
break;
case BLE_ADVDATA_ROLE_BOTH_PERIPH_PREFERRED:
p_encoded_data[*p_offset] = 2;
break;
case BLE_ADVDATA_ROLE_BOTH_CENTRAL_PREFERRED:
p_encoded_data[*p_offset] = 3;
break;
default:
return NRF_ERROR_INVALID_PARAM;
}
*p_offset += AD_TYPE_LE_ROLE_DATA_SIZE;
return NRF_SUCCESS;
}
static uint32_t ble_device_addr_encode(uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
uint32_t err_code;
ble_gap_addr_t device_addr;
// Check for buffer overflow.
if (((*p_offset) + AD_TYPE_BLE_DEVICE_ADDR_SIZE) > max_size)
{
return NRF_ERROR_DATA_SIZE;
}
// Get BLE address
err_code = sd_ble_gap_address_get(&device_addr);
VERIFY_SUCCESS(err_code);
// Encode LE Bluetooth Device Address
p_encoded_data[*p_offset] = (uint8_t)(ADV_AD_TYPE_FIELD_SIZE +
AD_TYPE_BLE_DEVICE_ADDR_DATA_SIZE);
*p_offset += ADV_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_LE_BLUETOOTH_DEVICE_ADDRESS;
*p_offset += ADV_AD_TYPE_FIELD_SIZE;
memcpy(&p_encoded_data[*p_offset], &device_addr.addr[0], BLE_GAP_ADDR_LEN);
*p_offset += BLE_GAP_ADDR_LEN;
if(BLE_GAP_ADDR_TYPE_PUBLIC == device_addr.addr_type)
{
p_encoded_data[*p_offset] = AD_TYPE_BLE_DEVICE_ADDR_TYPE_PUBLIC;
}
else
{
p_encoded_data[*p_offset] = AD_TYPE_BLE_DEVICE_ADDR_TYPE_RANDOM;
}
*p_offset += AD_TYPE_BLE_DEVICE_ADDR_TYPE_SIZE;
return NRF_SUCCESS;
}
static uint32_t name_encode(const ble_advdata_t * p_advdata,
uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
uint32_t err_code;
uint16_t rem_adv_data_len;
uint16_t actual_length;
uint8_t adv_data_format;
// Validate parameters
if((BLE_ADVDATA_SHORT_NAME == p_advdata->name_type) && (0 == p_advdata->short_name_len))
{
return NRF_ERROR_INVALID_PARAM;
}
// Check for buffer overflow.
if ( (((*p_offset) + ADV_AD_DATA_OFFSET) > max_size) ||
( (BLE_ADVDATA_SHORT_NAME == p_advdata->name_type) &&
(((*p_offset) + ADV_AD_DATA_OFFSET + p_advdata->short_name_len) > max_size)))
{
return NRF_ERROR_DATA_SIZE;
}
rem_adv_data_len = max_size - (*p_offset) - ADV_AD_DATA_OFFSET;
actual_length = rem_adv_data_len;
// Get GAP device name and length
err_code = sd_ble_gap_device_name_get(&p_encoded_data[(*p_offset) + ADV_AD_DATA_OFFSET],
&actual_length);
VERIFY_SUCCESS(err_code);
// Check if device intend to use short name and it can fit available data size.
if ((p_advdata->name_type == BLE_ADVDATA_FULL_NAME) && (actual_length <= rem_adv_data_len))
{
// Complete device name can fit, setting Complete Name in Adv Data.
adv_data_format = BLE_GAP_AD_TYPE_COMPLETE_LOCAL_NAME;
}
else
{
// Else short name needs to be used. Or application has requested use of short name.
adv_data_format = BLE_GAP_AD_TYPE_SHORT_LOCAL_NAME;
// If application has set a preference on the short name size, it needs to be considered,
// else fit what can be fit.
if ((BLE_ADVDATA_SHORT_NAME == p_advdata->name_type) &&
(p_advdata->short_name_len <= rem_adv_data_len))
{
// Short name fits available size.
actual_length = p_advdata->short_name_len;
}
// Else whatever can fit the data buffer will be packed.
else
{
actual_length = rem_adv_data_len;
}
}
// There is only 1 byte intended to encode length which is (actual_length + ADV_AD_TYPE_FIELD_SIZE)
if(actual_length > (0x00FF - ADV_AD_TYPE_FIELD_SIZE))
{
return NRF_ERROR_DATA_SIZE;
}
// Complete name field in encoded data.
p_encoded_data[*p_offset] = (uint8_t)(ADV_AD_TYPE_FIELD_SIZE + actual_length);
*p_offset += ADV_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = adv_data_format;
*p_offset += ADV_AD_TYPE_FIELD_SIZE;
*p_offset += actual_length;
return NRF_SUCCESS;
}
static uint32_t appearance_encode(uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
uint32_t err_code;
uint16_t appearance;
// Check for buffer overflow.
if (((*p_offset) + AD_TYPE_APPEARANCE_SIZE) > max_size)
{
return NRF_ERROR_DATA_SIZE;
}
// Get GAP appearance field.
err_code = sd_ble_gap_appearance_get(&appearance);
VERIFY_SUCCESS(err_code);
// Encode Length, AD Type and Appearance.
p_encoded_data[*p_offset] = (uint8_t)(ADV_AD_TYPE_FIELD_SIZE + AD_TYPE_APPEARANCE_DATA_SIZE);
*p_offset += ADV_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_APPEARANCE;
*p_offset += ADV_AD_TYPE_FIELD_SIZE;
*p_offset += uint16_encode(appearance, &p_encoded_data[*p_offset]);
return NRF_SUCCESS;
}
static uint32_t flags_encode(int8_t flags,
uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
// Check for buffer overflow.
if (((*p_offset) + AD_TYPE_FLAGS_SIZE) > max_size)
{
return NRF_ERROR_DATA_SIZE;
}
// Encode flags.
p_encoded_data[*p_offset] = (uint8_t)(ADV_AD_TYPE_FIELD_SIZE + AD_TYPE_FLAGS_DATA_SIZE);
*p_offset += ADV_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_FLAGS;
*p_offset += ADV_AD_TYPE_FIELD_SIZE;
p_encoded_data[*p_offset] = flags;
*p_offset += AD_TYPE_FLAGS_DATA_SIZE;
return NRF_SUCCESS;
}
static uint32_t sec_mgr_oob_flags_encode(uint8_t oob_flags,
uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
// Check for buffer overflow.
if (((*p_offset) + AD_TYPE_OOB_FLAGS_SIZE) > max_size)
{
return NRF_ERROR_DATA_SIZE;
}
// Encode flags.
p_encoded_data[*p_offset] = (uint8_t)(ADV_AD_TYPE_FIELD_SIZE + AD_TYPE_OOB_FLAGS_DATA_SIZE);
*p_offset += ADV_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_SECURITY_MANAGER_OOB_FLAGS;
*p_offset += ADV_AD_TYPE_FIELD_SIZE;
p_encoded_data[*p_offset] = oob_flags;
*p_offset += AD_TYPE_OOB_FLAGS_DATA_SIZE;
return NRF_SUCCESS;
}
static uint32_t tx_power_level_encode(int8_t tx_power_level,
uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
// Check for buffer overflow.
if (((*p_offset) + AD_TYPE_TX_POWER_LEVEL_SIZE) > max_size)
{
return NRF_ERROR_DATA_SIZE;
}
// Encode TX Power Level.
p_encoded_data[*p_offset] = (uint8_t)(ADV_AD_TYPE_FIELD_SIZE +
AD_TYPE_TX_POWER_LEVEL_DATA_SIZE);
*p_offset += ADV_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_TX_POWER_LEVEL;
*p_offset += ADV_AD_TYPE_FIELD_SIZE;
p_encoded_data[*p_offset] = tx_power_level;
*p_offset += AD_TYPE_TX_POWER_LEVEL_DATA_SIZE;
return NRF_SUCCESS;
}
static uint32_t uuid_list_sized_encode(const ble_advdata_uuid_list_t * p_uuid_list,
uint8_t adv_type,
uint8_t uuid_size,
uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
int i;
bool is_heading_written = false;
uint16_t start_pos = *p_offset;
uint16_t length;
for (i = 0; i < p_uuid_list->uuid_cnt; i++)
{
uint32_t err_code;
uint8_t encoded_size;
ble_uuid_t uuid = p_uuid_list->p_uuids[i];
// Find encoded uuid size.
err_code = sd_ble_uuid_encode(&uuid, &encoded_size, NULL);
VERIFY_SUCCESS(err_code);
// Check size.
if (encoded_size == uuid_size)
{
uint8_t heading_bytes = (is_heading_written) ? 0 : ADV_AD_DATA_OFFSET;
// Check for buffer overflow
if (((*p_offset) + encoded_size + heading_bytes) > max_size)
{
return NRF_ERROR_DATA_SIZE;
}
if (!is_heading_written)
{
// Write AD structure heading.
*p_offset += ADV_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = adv_type;
*p_offset += ADV_AD_TYPE_FIELD_SIZE;
is_heading_written = true;
}
// Write UUID.
err_code = sd_ble_uuid_encode(&uuid, &encoded_size, &p_encoded_data[*p_offset]);
VERIFY_SUCCESS(err_code);
*p_offset += encoded_size;
}
}
if (is_heading_written)
{
// Write length.
length = (*p_offset) - (start_pos + ADV_LENGTH_FIELD_SIZE);
// There is only 1 byte intended to encode length
if(length > 0x00FF)
{
return NRF_ERROR_DATA_SIZE;
}
p_encoded_data[start_pos] = (uint8_t)length;
}
return NRF_SUCCESS;
}
static uint32_t uuid_list_encode(const ble_advdata_uuid_list_t * p_uuid_list,
uint8_t adv_type_16,
uint8_t adv_type_128,
uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
uint32_t err_code;
// Encode 16 bit UUIDs.
err_code = uuid_list_sized_encode(p_uuid_list,
adv_type_16,
sizeof(uint16_le_t),
p_encoded_data,
p_offset,
max_size);
VERIFY_SUCCESS(err_code);
// Encode 128 bit UUIDs.
err_code = uuid_list_sized_encode(p_uuid_list,
adv_type_128,
sizeof(ble_uuid128_t),
p_encoded_data,
p_offset,
max_size);
VERIFY_SUCCESS(err_code);
return NRF_SUCCESS;
}
static uint32_t conn_int_check(const ble_advdata_conn_int_t *p_conn_int)
{
// Check Minimum Connection Interval.
if ((p_conn_int->min_conn_interval < 0x0006) ||
(
(p_conn_int->min_conn_interval > 0x0c80) &&
(p_conn_int->min_conn_interval != 0xffff)
)
)
{
return NRF_ERROR_INVALID_PARAM;
}
// Check Maximum Connection Interval.
if ((p_conn_int->max_conn_interval < 0x0006) ||
(
(p_conn_int->max_conn_interval > 0x0c80) &&
(p_conn_int->max_conn_interval != 0xffff)
)
)
{
return NRF_ERROR_INVALID_PARAM;
}
// Make sure Minimum Connection Interval is not bigger than Maximum Connection Interval.
if ((p_conn_int->min_conn_interval != 0xffff) &&
(p_conn_int->max_conn_interval != 0xffff) &&
(p_conn_int->min_conn_interval > p_conn_int->max_conn_interval)
)
{
return NRF_ERROR_INVALID_PARAM;
}
return NRF_SUCCESS;
}
static uint32_t conn_int_encode(const ble_advdata_conn_int_t * p_conn_int,
uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
uint32_t err_code;
// Check for buffer overflow.
if (((*p_offset) + AD_TYPE_CONN_INT_SIZE) > max_size)
{
return NRF_ERROR_DATA_SIZE;
}
// Check parameters.
err_code = conn_int_check(p_conn_int);
VERIFY_SUCCESS(err_code);
// Encode Length and AD Type.
p_encoded_data[*p_offset] = (uint8_t)(ADV_AD_TYPE_FIELD_SIZE + AD_TYPE_CONN_INT_DATA_SIZE);
*p_offset += ADV_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE;
*p_offset += ADV_AD_TYPE_FIELD_SIZE;
// Encode Minimum and Maximum Connection Intervals.
*p_offset += uint16_encode(p_conn_int->min_conn_interval, &p_encoded_data[*p_offset]);
*p_offset += uint16_encode(p_conn_int->max_conn_interval, &p_encoded_data[*p_offset]);
return NRF_SUCCESS;
}
static uint32_t manuf_specific_data_encode(const ble_advdata_manuf_data_t * p_manuf_sp_data,
uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
uint32_t data_size = AD_TYPE_MANUF_SPEC_DATA_ID_SIZE + p_manuf_sp_data->data.size;
// Check for buffer overflow.
if (((*p_offset) + ADV_AD_DATA_OFFSET + data_size) > max_size)
{
return NRF_ERROR_DATA_SIZE;
}
// There is only 1 byte intended to encode length which is (data_size + ADV_AD_TYPE_FIELD_SIZE)
if(data_size > (0x00FF - ADV_AD_TYPE_FIELD_SIZE))
{
return NRF_ERROR_DATA_SIZE;
}
// Encode Length and AD Type.
p_encoded_data[*p_offset] = (uint8_t)(ADV_AD_TYPE_FIELD_SIZE + data_size);
*p_offset += ADV_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_MANUFACTURER_SPECIFIC_DATA;
*p_offset += ADV_AD_TYPE_FIELD_SIZE;
// Encode Company Identifier.
*p_offset += uint16_encode(p_manuf_sp_data->company_identifier, &p_encoded_data[*p_offset]);
// Encode additional manufacturer specific data.
if (p_manuf_sp_data->data.size > 0)
{
if (p_manuf_sp_data->data.p_data == NULL)
{
return NRF_ERROR_INVALID_PARAM;
}
memcpy(&p_encoded_data[*p_offset], p_manuf_sp_data->data.p_data, p_manuf_sp_data->data.size);
*p_offset += p_manuf_sp_data->data.size;
}
return NRF_SUCCESS;
}
// Implemented only for 16-bit UUIDs
static uint32_t service_data_encode(const ble_advdata_t * p_advdata,
uint8_t * p_encoded_data,
uint16_t * p_offset,
uint16_t max_size)
{
uint8_t i;
// Check parameter consistency.
if (p_advdata->p_service_data_array == NULL)
{
return NRF_ERROR_INVALID_PARAM;
}
for (i = 0; i < p_advdata->service_data_count; i++)
{
ble_advdata_service_data_t * p_service_data;
uint32_t data_size;
p_service_data = &p_advdata->p_service_data_array[i];
// For now implemented only for 16-bit UUIDs
data_size = AD_TYPE_SERV_DATA_16BIT_UUID_SIZE + p_service_data->data.size;
// There is only 1 byte intended to encode length which is (data_size + ADV_AD_TYPE_FIELD_SIZE)
if(data_size > (0x00FF - ADV_AD_TYPE_FIELD_SIZE))
{
return NRF_ERROR_DATA_SIZE;
}
// Encode Length and AD Type.
p_encoded_data[*p_offset] = (uint8_t)(ADV_AD_TYPE_FIELD_SIZE + data_size);
*p_offset += ADV_LENGTH_FIELD_SIZE;
p_encoded_data[*p_offset] = BLE_GAP_AD_TYPE_SERVICE_DATA;
*p_offset += ADV_AD_TYPE_FIELD_SIZE;
// Encode service 16-bit UUID.
*p_offset += uint16_encode(p_service_data->service_uuid, &p_encoded_data[*p_offset]);
// Encode additional service data.
if (p_service_data->data.size > 0)
{
if (p_service_data->data.p_data == NULL)
{
return NRF_ERROR_INVALID_PARAM;
}
memcpy(&p_encoded_data[*p_offset], p_service_data->data.p_data, p_service_data->data.size);
*p_offset += p_service_data->data.size;
}
}
return NRF_SUCCESS;
}
uint32_t adv_data_encode(ble_advdata_t const * const p_advdata,
uint8_t * const p_encoded_data,
uint16_t * const p_len)
{
uint32_t err_code = NRF_SUCCESS;
uint16_t max_size = *p_len;
*p_len = 0;
//Encode Security Manager OOB Flags
if (p_advdata->p_sec_mgr_oob_flags != NULL)
{
err_code = sec_mgr_oob_flags_encode(*p_advdata->p_sec_mgr_oob_flags,
p_encoded_data,
p_len,
max_size);
VERIFY_SUCCESS(err_code);
}
// Encode Security Manager TK value
if (NULL != p_advdata->p_tk_value)
{
err_code = tk_value_encode(p_advdata->p_tk_value, p_encoded_data, p_len, max_size);
VERIFY_SUCCESS(err_code);
}
// Encode LE Role
if (BLE_ADVDATA_ROLE_NOT_PRESENT != p_advdata->le_role)
{
err_code = le_role_encode(p_advdata->le_role, p_encoded_data, p_len, max_size);
VERIFY_SUCCESS(err_code);
}
// Encode LE Bluetooth Device Address
if (p_advdata->include_ble_device_addr)
{
err_code = ble_device_addr_encode(p_encoded_data, p_len, max_size);
VERIFY_SUCCESS(err_code);
}
// Encode appearance.
if (p_advdata->include_appearance)
{
err_code = appearance_encode(p_encoded_data, p_len, max_size);
VERIFY_SUCCESS(err_code);
}
//Encode Flags
if(p_advdata->flags != 0 )
{
err_code = flags_encode(p_advdata->flags, p_encoded_data, p_len, max_size);
VERIFY_SUCCESS(err_code);
}
// Encode TX power level.
if (p_advdata->p_tx_power_level != NULL)
{
err_code = tx_power_level_encode(*p_advdata->p_tx_power_level,
p_encoded_data,
p_len,
max_size);
VERIFY_SUCCESS(err_code);
}
// Encode 'more available' uuid list.
if (p_advdata->uuids_more_available.uuid_cnt > 0)
{
err_code = uuid_list_encode(&p_advdata->uuids_more_available,
BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE,
BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE,
p_encoded_data,
p_len,
max_size);
VERIFY_SUCCESS(err_code);
}
// Encode 'complete' uuid list.
if (p_advdata->uuids_complete.uuid_cnt > 0)
{
err_code = uuid_list_encode(&p_advdata->uuids_complete,
BLE_GAP_AD_TYPE_16BIT_SERVICE_UUID_COMPLETE,
BLE_GAP_AD_TYPE_128BIT_SERVICE_UUID_COMPLETE,
p_encoded_data,
p_len,
max_size);
VERIFY_SUCCESS(err_code);
}
// Encode 'solicited service' uuid list.
if (p_advdata->uuids_solicited.uuid_cnt > 0)
{
err_code = uuid_list_encode(&p_advdata->uuids_solicited,
BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_16BIT,
BLE_GAP_AD_TYPE_SOLICITED_SERVICE_UUIDS_128BIT,
p_encoded_data,
p_len,
max_size);
VERIFY_SUCCESS(err_code);
}
// Encode Slave Connection Interval Range.
if (p_advdata->p_slave_conn_int != NULL)
{
err_code = conn_int_encode(p_advdata->p_slave_conn_int, p_encoded_data, p_len, max_size);
VERIFY_SUCCESS(err_code);
}
// Encode Manufacturer Specific Data.
if (p_advdata->p_manuf_specific_data != NULL)
{
err_code = manuf_specific_data_encode(p_advdata->p_manuf_specific_data,
p_encoded_data,
p_len,
max_size);
VERIFY_SUCCESS(err_code);
}
// Encode Service Data.
if (p_advdata->service_data_count > 0)
{
err_code = service_data_encode(p_advdata, p_encoded_data, p_len, max_size);
VERIFY_SUCCESS(err_code);
}
// Encode name. WARNING: it is encoded last on purpose since too long device name is truncated.
if (p_advdata->name_type != BLE_ADVDATA_NO_NAME)
{
err_code = name_encode(p_advdata, p_encoded_data, p_len, max_size);
VERIFY_SUCCESS(err_code);
}
return err_code;
}
static uint32_t advdata_check(const ble_advdata_t * p_advdata)
{
// Flags must be included in advertising data, and the BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED flag must be set.
if (
((p_advdata->flags & BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED) == 0)
)
{
return NRF_ERROR_INVALID_PARAM;
}
return NRF_SUCCESS;
}
static uint32_t srdata_check(const ble_advdata_t * p_srdata)
{
// Flags shall not be included in the scan response data.
if (p_srdata->flags)
{
return NRF_ERROR_INVALID_PARAM;
}
return NRF_SUCCESS;
}
uint32_t ble_advdata_set(const ble_advdata_t * p_advdata, const ble_advdata_t * p_srdata)
{
uint32_t err_code;
uint16_t len_advdata = BLE_GAP_ADV_MAX_SIZE;
uint16_t len_srdata = BLE_GAP_ADV_MAX_SIZE;
uint8_t encoded_advdata[BLE_GAP_ADV_MAX_SIZE];
uint8_t encoded_srdata[BLE_GAP_ADV_MAX_SIZE];
uint8_t * p_encoded_advdata;
uint8_t * p_encoded_srdata;
// Encode advertising data (if supplied).
if (p_advdata != NULL)
{
err_code = advdata_check(p_advdata);
VERIFY_SUCCESS(err_code);
err_code = adv_data_encode(p_advdata, encoded_advdata, &len_advdata);
VERIFY_SUCCESS(err_code);
p_encoded_advdata = encoded_advdata;
}
else
{
p_encoded_advdata = NULL;
len_advdata = 0;
}
// Encode scan response data (if supplied).
if (p_srdata != NULL)
{
err_code = srdata_check(p_srdata);
VERIFY_SUCCESS(err_code);
err_code = adv_data_encode(p_srdata, encoded_srdata, &len_srdata);
VERIFY_SUCCESS(err_code);
p_encoded_srdata = encoded_srdata;
}
else
{
p_encoded_srdata = NULL;
len_srdata = 0;
}
// Pass encoded advertising data and/or scan response data to the stack.
return sd_ble_gap_adv_data_set(p_encoded_advdata, len_advdata, p_encoded_srdata, len_srdata);
}

View File

@ -0,0 +1,239 @@
/*
* Copyright (c) 2012 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/** @file
*
* @defgroup ble_sdk_lib_advdata Advertising and Scan Response Data Encoder
* @{
* @ingroup ble_sdk_lib
* @brief Functions for encoding data in the Advertising and Scan Response Data format,
* and for passing the data to the stack.
*/
#ifndef BLE_ADVDATA_H__
#define BLE_ADVDATA_H__
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include "nrf_ble.h"
#include "app_util.h"
#define ADV_LENGTH_FIELD_SIZE 1UL /**< Advertising Data and Scan Response format contains 1 octet for the length. */
#define ADV_AD_TYPE_FIELD_SIZE 1UL /**< Advertising Data and Scan Response format contains 1 octet for the AD type. */
#define ADV_AD_DATA_OFFSET (ADV_LENGTH_FIELD_SIZE + \
ADV_AD_TYPE_FIELD_SIZE) /**< Offset for the AD data field of the Advertising Data and Scan Response format. */
#define AD_TYPE_TK_VALUE_DATA_SIZE (sizeof(ble_advdata_tk_value_t)) /**< Data size (in octets) of the Security Manager TK value AD type. */
#define AD_TYPE_TK_VALUE_SIZE (ADV_AD_DATA_OFFSET + \
AD_TYPE_TK_VALUE_DATA_SIZE) /**< Size (in octets) of the Security Manager TK value AD type. */
#define AD_TYPE_LE_ROLE_DATA_SIZE 1UL /**< Data size (in octets) of the LE Bluetooth Device Address AD type. */
#define AD_TYPE_LE_ROLE_SIZE (ADV_AD_DATA_OFFSET + \
AD_TYPE_LE_ROLE_DATA_SIZE) /**< Size (in octets) of the LE Bluetooth Device Address AD type. */
#define AD_TYPE_BLE_DEVICE_ADDR_TYPE_SIZE 1UL /**< Data size (in octets) of the Address type of the LE Bluetooth Device Address AD type. */
#define AD_TYPE_BLE_DEVICE_ADDR_DATA_SIZE (BLE_GAP_ADDR_LEN + \
AD_TYPE_BLE_DEVICE_ADDR_TYPE_SIZE) /**< Data size (in octets) of the LE Bluetooth Device Address AD type. */
#define AD_TYPE_BLE_DEVICE_ADDR_SIZE (ADV_AD_DATA_OFFSET + \
AD_TYPE_BLE_DEVICE_ADDR_DATA_SIZE) /**< Size (in octets) of the LE Bluetooth Device Address AD type. */
#define AD_TYPE_APPEARANCE_DATA_SIZE 2UL /**< Data size (in octets) of the Appearance AD type. */
#define AD_TYPE_APPEARANCE_SIZE (ADV_AD_DATA_OFFSET + \
AD_TYPE_APPEARANCE_DATA_SIZE) /**< Size (in octets) of the Appearance AD type. */
#define AD_TYPE_FLAGS_DATA_SIZE 1UL /**< Data size (in octets) of the Flags AD type. */
#define AD_TYPE_FLAGS_SIZE (ADV_AD_DATA_OFFSET + \
AD_TYPE_FLAGS_DATA_SIZE) /**< Size (in octets) of the Flags AD type. */
#define AD_TYPE_TX_POWER_LEVEL_DATA_SIZE 1UL /**< Data size (in octets) of the TX Power Level AD type. */
#define AD_TYPE_TX_POWER_LEVEL_SIZE (ADV_AD_DATA_OFFSET + \
AD_TYPE_TX_POWER_LEVEL_DATA_SIZE) /**< Size (in octets) of the TX Power Level AD type. */
#define AD_TYPE_CONN_INT_DATA_SIZE 4UL /**< Data size (in octets) of the Slave Connection Interval Range AD type. */
#define AD_TYPE_CONN_INT_SIZE (ADV_AD_DATA_OFFSET + \
AD_TYPE_CONN_INT_DATA_SIZE) /**< Data size (in octets) of the Slave Connection Interval Range AD type. */
#define AD_TYPE_MANUF_SPEC_DATA_ID_SIZE 2UL /**< Size (in octets) of the Company Identifier Code, which is a part of the Manufacturer Specific Data AD type. */
#define AD_TYPE_SERV_DATA_16BIT_UUID_SIZE 2UL /**< Size (in octets) of the 16-bit UUID, which is a part of the Service Data AD type. */
#define AD_TYPE_OOB_FLAGS_DATA_SIZE 1UL /**< Data size (in octets) of the Security Manager OOB Flags AD type. */
#define AD_TYPE_OOB_FLAGS_SIZE (ADV_AD_DATA_OFFSET + \
AD_TYPE_OOB_FLAGS_DATA_SIZE) /**< Size (in octets) of the Security Manager OOB Flags AD type. */
#define AD_TYPE_SEC_MGR_OOB_FLAG_SET 1U /**< Security Manager OOB Flag set. Flag selection is done using _POS defines */
#define AD_TYPE_SEC_MGR_OOB_FLAG_CLEAR 0U /**< Security Manager OOB Flag clear. Flag selection is done using _POS defines */
#define AD_TYPE_SEC_MGR_OOB_FLAG_OOB_DATA_PRESENT_POS 0UL /**< Security Manager OOB Data Present Flag position. */
#define AD_TYPE_SEC_MGR_OOB_FLAG_OOB_LE_SUPPORTED_POS 1UL /**< Security Manager OOB Low Energy Supported Flag position. */
#define AD_TYPE_SEC_MGR_OOB_FLAG_SIM_LE_AND_EP_POS 2UL /**< Security Manager OOB Simultaneous LE and BR/EDR to Same Device Capable Flag position. */
#define AD_TYPE_SEC_MGR_OOB_ADDRESS_TYPE_PUBLIC 0UL /**< Security Manager OOB Public Address type. */
#define AD_TYPE_SEC_MGR_OOB_ADDRESS_TYPE_RANDOM 1UL /**< Security Manager OOB Random Address type. */
#define AD_TYPE_SEC_MGR_OOB_FLAG_ADDRESS_TYPE_POS 3UL /**< Security Manager OOB Address type Flag (0 = Public Address, 1 = Random Address) position. */
/**@brief Security Manager TK value. */
typedef struct
{
uint8_t tk[BLE_GAP_SEC_KEY_LEN]; /**< Array containing TK value. */
} ble_advdata_tk_value_t;
/**@brief Advertising data LE Role types. This enumeration contains the options available for the LE role inside
* the advertising data. */
typedef enum
{
BLE_ADVDATA_ROLE_NOT_PRESENT = 0, /**< LE Role AD structure not present. */
BLE_ADVDATA_ROLE_ONLY_PERIPH, /**< Only Peripheral Role supported. */
BLE_ADVDATA_ROLE_ONLY_CENTRAL, /**< Only Central Role supported. */
BLE_ADVDATA_ROLE_BOTH_PERIPH_PREFERRED, /**< Peripheral and Central Role supported. Peripheral Role preferred for connection establishment. */
BLE_ADVDATA_ROLE_BOTH_CENTRAL_PREFERRED /**< Peripheral and Central Role supported. Central Role preferred for connection establishment */
} ble_advdata_le_role_t;
/**@brief Advertising data name type. This enumeration contains the options available for the device name inside
* the advertising data. */
typedef enum
{
BLE_ADVDATA_NO_NAME, /**< Include no device name in advertising data. */
BLE_ADVDATA_SHORT_NAME, /**< Include short device name in advertising data. */
BLE_ADVDATA_FULL_NAME /**< Include full device name in advertising data. */
} ble_advdata_name_type_t;
/**@brief UUID list type. */
typedef struct
{
uint16_t uuid_cnt; /**< Number of UUID entries. */
ble_uuid_t * p_uuids; /**< Pointer to UUID array entries. */
} ble_advdata_uuid_list_t;
/**@brief Connection interval range structure. */
typedef struct
{
uint16_t min_conn_interval; /**< Minimum connection interval, in units of 1.25 ms, range 6 to 3200 (7.5 ms to 4 s). */
uint16_t max_conn_interval; /**< Maximum connection interval, in units of 1.25 ms, range 6 to 3200 (7.5 ms to 4 s). The value 0xFFFF indicates no specific maximum. */
} ble_advdata_conn_int_t;
/**@brief Manufacturer specific data structure. */
typedef struct
{
uint16_t company_identifier; /**< Company identifier code. */
uint8_array_t data; /**< Additional manufacturer specific data. */
} ble_advdata_manuf_data_t;
/**@brief Service data structure. */
typedef struct
{
uint16_t service_uuid; /**< Service UUID. */
uint8_array_t data; /**< Additional service data. */
} ble_advdata_service_data_t;
/**@brief Advertising data structure. This structure contains all options and data needed for encoding and
* setting the advertising data. */
typedef struct
{
ble_advdata_name_type_t name_type; /**< Type of device name. */
uint8_t short_name_len; /**< Length of short device name (if short type is specified). */
bool include_appearance; /**< Determines if Appearance shall be included. */
uint8_t flags; /**< Advertising data Flags field. */
int8_t * p_tx_power_level; /**< TX Power Level field. */
ble_advdata_uuid_list_t uuids_more_available; /**< List of UUIDs in the 'More Available' list. */
ble_advdata_uuid_list_t uuids_complete; /**< List of UUIDs in the 'Complete' list. */
ble_advdata_uuid_list_t uuids_solicited; /**< List of solicited UUIDs. */
ble_advdata_conn_int_t * p_slave_conn_int; /**< Slave Connection Interval Range. */
ble_advdata_manuf_data_t * p_manuf_specific_data; /**< Manufacturer specific data. */
ble_advdata_service_data_t * p_service_data_array; /**< Array of Service data structures. */
uint8_t service_data_count; /**< Number of Service data structures. */
bool include_ble_device_addr; /**< Determines if LE Bluetooth Device Address shall be included. */
ble_advdata_le_role_t le_role; /**< LE Role field. Included when different from @ref BLE_ADVDATA_ROLE_NOT_PRESENT. @warning This field can be used only for NFC. For BLE advertising, set it to NULL. */
ble_advdata_tk_value_t * p_tk_value; /**< Security Manager TK value field. Included when different from NULL. @warning This field can be used only for NFC. For BLE advertising, set it to NULL.*/
uint8_t * p_sec_mgr_oob_flags; /**< Security Manager Out Of Band Flags field. Included when different from NULL. @warning This field can be used only for NFC. For BLE advertising, set it to NULL.*/
} ble_advdata_t;
/**@brief Function for encoding data in the Advertising and Scan Response data format
* (AD structures).
*
* @details This function encodes data into the Advertising and Scan Response data format
* (AD structures) based on the selections in the supplied structures. This function can be used to
* create a payload of Advertising packet or Scan Response packet, or a payload of NFC
* message intended for initiating the Out-of-Band pairing.
*
* @param[in] p_advdata Pointer to the structure for specifying the content of encoded data.
* @param[out] p_encoded_data Pointer to the buffer where encoded data will be returned.
* @param[in,out] p_len \c in: Size of \p p_encoded_data buffer.
* \c out: Length of encoded data.
*
* @retval NRF_SUCCESS If the operation was successful.
* @retval NRF_ERROR_INVALID_PARAM If the operation failed because a wrong parameter was provided in \p p_advdata.
* @retval NRF_ERROR_DATA_SIZE If the operation failed because not all the requested data could fit into the
* provided buffer or some encoded AD structure is too long and its
* length cannot be encoded with one octet.
*
* @warning This API may override the application's request to use the long name and use a short name
* instead. This truncation will occur in case the long name does not fit the provided buffer size.
* The application can specify a preferred short name length if truncation is required.
* For example, if the complete device name is ABCD_HRMonitor, the application can specify the short name
* length to be 8, so that the short device name appears as ABCD_HRM instead of ABCD_HRMo or ABCD_HRMoni
* if the available size for the short name is 9 or 12 respectively, to have a more appropriate short name.
* However, it should be noted that this is just a preference that the application can specify, and
* if the preference is too large to fit in the provided buffer, the name can be truncated further.
*/
uint32_t adv_data_encode(ble_advdata_t const * const p_advdata,
uint8_t * const p_encoded_data,
uint16_t * const p_len);
/**@brief Function for encoding and setting the advertising data and/or scan response data.
*
* @details This function encodes advertising data and/or scan response data based on the selections
* in the supplied structures, and passes the encoded data to the stack.
*
* @param[in] p_advdata Structure for specifying the content of the advertising data.
* Set to NULL if advertising data is not to be set.
* @param[in] p_srdata Structure for specifying the content of the scan response data.
* Set to NULL if scan response data is not to be set.
*
* @retval NRF_SUCCESS If the operation was successful.
* @retval NRF_ERROR_INVALID_PARAM If the operation failed because a wrong parameter was provided in \p p_advdata.
* @retval NRF_ERROR_DATA_SIZE If the operation failed because not all the requested data could fit into the
* advertising packet. The maximum size of the advertisement packet
* is @ref BLE_GAP_ADV_MAX_SIZE.
*
* @warning This API may override the application's request to use the long name and use a short name
* instead. This truncation will occur in case the long name does not fit the provided buffer size.
* The application can specify a preferred short name length if truncation is required.
* For example, if the complete device name is ABCD_HRMonitor, the application can specify the short name
* length to be 8, so that the short device name appears as ABCD_HRM instead of ABCD_HRMo or ABCD_HRMoni
* if the available size for the short name is 9 or 12 respectively, to have a more appropriate short name.
* However, it should be noted that this is just a preference that the application can specify, and
* if the preference is too large to fit in the provided buffer, the name can be truncated further.
*/
uint32_t ble_advdata_set(const ble_advdata_t * p_advdata, const ble_advdata_t * p_srdata);
#endif // BLE_ADVDATA_H__
/** @} */

View File

@ -0,0 +1,138 @@
/*
* Copyright (c) 2012 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/** @file
*
* @defgroup ble_sdk_lib_conn_params Connection Parameters Negotiation
* @{
* @ingroup ble_sdk_lib
* @brief Module for initiating and executing a connection parameters negotiation procedure.
*/
#ifndef BLE_CONN_PARAMS_H__
#define BLE_CONN_PARAMS_H__
#include <stdint.h>
#include "nrf_ble.h"
#include "ble_srv_common.h"
/**@brief Connection Parameters Module event type. */
typedef enum
{
BLE_CONN_PARAMS_EVT_FAILED , /**< Negotiation procedure failed. */
BLE_CONN_PARAMS_EVT_SUCCEEDED /**< Negotiation procedure succeeded. */
} ble_conn_params_evt_type_t;
/**@brief Connection Parameters Module event. */
typedef struct
{
ble_conn_params_evt_type_t evt_type; /**< Type of event. */
} ble_conn_params_evt_t;
/**@brief Connection Parameters Module event handler type. */
typedef void (*ble_conn_params_evt_handler_t) (ble_conn_params_evt_t * p_evt);
/**@brief Connection Parameters Module init structure. This contains all options and data needed for
* initialization of the connection parameters negotiation module. */
typedef struct
{
ble_gap_conn_params_t * p_conn_params; /**< Pointer to the connection parameters desired by the application. When calling ble_conn_params_init, if this parameter is set to NULL, the connection parameters will be fetched from host. */
uint32_t first_conn_params_update_delay; /**< Time from initiating event (connect or start of notification) to first time sd_ble_gap_conn_param_update is called (in number of timer ticks). */
uint32_t next_conn_params_update_delay; /**< Time between each call to sd_ble_gap_conn_param_update after the first (in number of timer ticks). Recommended value 30 seconds as per BLUETOOTH SPECIFICATION Version 4.0. */
uint8_t max_conn_params_update_count; /**< Number of attempts before giving up the negotiation. */
uint16_t start_on_notify_cccd_handle; /**< If procedure is to be started when notification is started, set this to the handle of the corresponding CCCD. Set to BLE_GATT_HANDLE_INVALID if procedure is to be started on connect event. */
bool disconnect_on_fail; /**< Set to TRUE if a failed connection parameters update shall cause an automatic disconnection, set to FALSE otherwise. */
ble_conn_params_evt_handler_t evt_handler; /**< Event handler to be called for handling events in the Connection Parameters. */
ble_srv_error_handler_t error_handler; /**< Function to be called in case of an error. */
} ble_conn_params_init_t;
/**@brief Function for initializing the Connection Parameters module.
*
* @note If the negotiation procedure should be triggered when notification/indication of
* any characteristic is enabled by the peer, then this function must be called after
* having initialized the services.
*
* @param[in] p_init This contains information needed to initialize this module.
*
* @return NRF_SUCCESS on successful initialization, otherwise an error code.
*/
uint32_t ble_conn_params_init(const ble_conn_params_init_t * p_init);
/**@brief Function for stopping the Connection Parameters module.
*
* @details This function is intended to be used by the application to clean up the connection
* parameters update module. This will stop the connection parameters update timer if
* running, thereby preventing any impending connection parameters update procedure. This
* function must be called by the application when it needs to clean itself up (for
* example, before disabling the bluetooth SoftDevice) so that an unwanted timer expiry
* event can be avoided.
*
* @return NRF_SUCCESS on successful initialization, otherwise an error code.
*/
uint32_t ble_conn_params_stop(void);
/**@brief Function for changing the current connection parameters to a new set.
*
* @details Use this function to change the connection parameters to a new set of parameter
* (ie different from the ones given at init of the module).
* This function is usefull for scenario where most of the time the application
* needs a relatively big connection interval, and just sometimes, for a temporary
* period requires shorter connection interval, for example to transfer a higher
* amount of data.
* If the given parameters does not match the current connection's parameters
* this function initiates a new negotiation.
*
* @param[in] new_params This contains the new connections parameters to setup.
*
* @return NRF_SUCCESS on successful initialization, otherwise an error code.
*/
uint32_t ble_conn_params_change_conn_params(ble_gap_conn_params_t *new_params);
/**@brief Function for handling the Application's BLE Stack events.
*
* @details Handles all events from the BLE stack that are of interest to this module.
*
* @param[in] p_ble_evt The event received from the BLE stack.
*/
void ble_conn_params_on_ble_evt(ble_evt_t * p_ble_evt);
#endif // BLE_CONN_PARAMS_H__
/** @} */

View File

@ -0,0 +1,414 @@
/*
* Copyright (c) 2015 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#include "ble_conn_state.h"
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "nrf_ble.h"
#include "sdk_mapped_flags.h"
#include "app_error.h"
#if defined(__CC_ARM)
#pragma push
#pragma anon_unions
#elif defined(__ICCARM__)
#pragma language=extended
#elif defined(__GNUC__)
/* anonymous unions are enabled by default */
#endif
#define BLE_CONN_STATE_N_DEFAULT_FLAGS 5 /**< The number of flags kept for each connection, excluding user flags. */
#define BLE_CONN_STATE_N_FLAGS (BLE_CONN_STATE_N_DEFAULT_FLAGS + BLE_CONN_STATE_N_USER_FLAGS) /**< The number of flags kept for each connection, including user flags. */
/**@brief Structure containing all the flag collections maintained by the Connection State module.
*/
typedef struct
{
sdk_mapped_flags_t valid_flags; /**< Flags indicating which connection handles are valid. */
sdk_mapped_flags_t connected_flags; /**< Flags indicating which connections are connected, since disconnected connection handles will not immediately be invalidated. */
sdk_mapped_flags_t central_flags; /**< Flags indicating in which connections the local device is the central. */
sdk_mapped_flags_t encrypted_flags; /**< Flags indicating which connections are encrypted. */
sdk_mapped_flags_t mitm_protected_flags; /**< Flags indicating which connections have encryption with protection from man-in-the-middle attacks. */
sdk_mapped_flags_t user_flags[BLE_CONN_STATE_N_USER_FLAGS]; /**< Flags that can be reserved by the user. The flags will be cleared when a connection is invalidated, otherwise, the user is wholly responsible for the flag states. */
} ble_conn_state_flag_collections_t;
/**@brief Structure containing the internal state of the Connection State module.
*/
typedef struct
{
uint32_t acquired_flags; /**< Bitmap for keeping track of which user flags have been acquired. */
uint16_t valid_conn_handles[SDK_MAPPED_FLAGS_N_KEYS]; /**< List of connection handles used as keys for the sdk_mapped_flags module. */
union
{
ble_conn_state_flag_collections_t flags; /**< Flag collections kept by the Connection State module. */
sdk_mapped_flags_t flag_array[BLE_CONN_STATE_N_FLAGS]; /**< Flag collections as array to allow use of @ref sdk_mapped_flags_bulk_update_by_key() when setting all flags. */
};
} ble_conn_state_t;
#if defined(__CC_ARM)
#pragma pop
#elif defined(__ICCARM__)
/* leave anonymous unions enabled */
#elif defined(__GNUC__)
/* anonymous unions are enabled by default */
#endif
static ble_conn_state_t m_bcs = {0}; /**< Instantiation of the internal state. */
/**@brief Function for resetting all internal memory to the values it had at initialization.
*/
void bcs_internal_state_reset(void)
{
memset( &m_bcs, 0, sizeof(ble_conn_state_t) );
}
/**@brief Function for activating a connection record.
*
* @param p_record The record to activate.
* @param conn_handle The connection handle to copy into the record.
* @param role The role of the connection.
*
* @return whether the record was activated successfully.
*/
static bool record_activate(uint16_t conn_handle)
{
uint16_t available_index = sdk_mapped_flags_first_key_index_get(~m_bcs.flags.valid_flags);
if (available_index != SDK_MAPPED_FLAGS_INVALID_INDEX)
{
m_bcs.valid_conn_handles[available_index] = conn_handle;
sdk_mapped_flags_update_by_key(m_bcs.valid_conn_handles,
&m_bcs.flags.connected_flags,
conn_handle,
1);
sdk_mapped_flags_update_by_key(m_bcs.valid_conn_handles,
&m_bcs.flags.valid_flags,
conn_handle,
1);
return true;
}
return false;
}
/**@brief Function for marking a connection record as invalid and resetting the values.
*
* @param p_record The record to invalidate.
*/
static void record_invalidate(uint16_t conn_handle)
{
sdk_mapped_flags_bulk_update_by_key(m_bcs.valid_conn_handles,
m_bcs.flag_array,
BLE_CONN_STATE_N_FLAGS,
conn_handle,
0);
}
/**@brief Function for marking a connection as disconnected. See @ref BLE_CONN_STATUS_DISCONNECTED.
*
* @param p_record The record of the connection to set as disconnected.
*/
static void record_set_disconnected(uint16_t conn_handle)
{
sdk_mapped_flags_update_by_key(m_bcs.valid_conn_handles,
&m_bcs.flags.connected_flags,
conn_handle,
0);
}
/**@brief Function for invalidating records with a @ref BLE_CONN_STATUS_DISCONNECTED
* connection status
*/
static void record_purge_disconnected()
{
sdk_mapped_flags_key_list_t disconnected_list;
disconnected_list = sdk_mapped_flags_key_list_get(
m_bcs.valid_conn_handles,
(~m_bcs.flags.connected_flags) & (m_bcs.flags.valid_flags));
for (uint32_t i = 0; i < disconnected_list.len; i++)
{
record_invalidate(disconnected_list.flag_keys[i]);
}
}
/**@brief Function for checking if a user flag has been acquired.
*
* @param[in] flag_id Which flag to check.
*
* @return Whether the flag has been acquired.
*/
static bool user_flag_is_acquired(ble_conn_state_user_flag_id_t flag_id)
{
return ((m_bcs.acquired_flags & (1 << flag_id)) != 0);
}
/**@brief Function for marking a user flag as acquired.
*
* @param[in] flag_id Which flag to mark.
*/
static void user_flag_acquire(ble_conn_state_user_flag_id_t flag_id)
{
m_bcs.acquired_flags |= (1 << flag_id);
}
void ble_conn_state_init(void)
{
bcs_internal_state_reset();
}
void ble_conn_state_on_ble_evt(ble_evt_t * p_ble_evt)
{
switch (p_ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
record_purge_disconnected();
if ( !record_activate(p_ble_evt->evt.gap_evt.conn_handle) )
{
// No more records available. Should not happen.
APP_ERROR_HANDLER(NRF_ERROR_NO_MEM);
}
else
{
bool is_central =
(p_ble_evt->evt.gap_evt.params.connected.role == BLE_GAP_ROLE_CENTRAL);
sdk_mapped_flags_update_by_key(m_bcs.valid_conn_handles,
&m_bcs.flags.central_flags,
p_ble_evt->evt.gap_evt.conn_handle,
is_central);
}
break;
case BLE_GAP_EVT_DISCONNECTED:
record_set_disconnected(p_ble_evt->evt.gap_evt.conn_handle);
break;
case BLE_GAP_EVT_CONN_SEC_UPDATE:
sdk_mapped_flags_update_by_key(
m_bcs.valid_conn_handles,
&m_bcs.flags.encrypted_flags,
p_ble_evt->evt.gap_evt.conn_handle,
(p_ble_evt->evt.gap_evt.params.conn_sec_update.conn_sec.sec_mode.lv > 1));
sdk_mapped_flags_update_by_key(
m_bcs.valid_conn_handles,
&m_bcs.flags.mitm_protected_flags,
p_ble_evt->evt.gap_evt.conn_handle,
(p_ble_evt->evt.gap_evt.params.conn_sec_update.conn_sec.sec_mode.lv > 2));
break;
}
}
bool ble_conn_state_valid(uint16_t conn_handle)
{
return sdk_mapped_flags_get_by_key(m_bcs.valid_conn_handles,
m_bcs.flags.valid_flags,
conn_handle);
}
uint8_t ble_conn_state_role(uint16_t conn_handle)
{
uint8_t role = BLE_GAP_ROLE_INVALID;
if ( sdk_mapped_flags_get_by_key(m_bcs.valid_conn_handles, m_bcs.flags.valid_flags, conn_handle) )
{
bool central = sdk_mapped_flags_get_by_key(m_bcs.valid_conn_handles,
m_bcs.flags.central_flags,
conn_handle);
role = central ? BLE_GAP_ROLE_CENTRAL : BLE_GAP_ROLE_PERIPH;
}
return role;
}
ble_conn_state_status_t ble_conn_state_status(uint16_t conn_handle)
{
ble_conn_state_status_t conn_status = BLE_CONN_STATUS_INVALID;
bool valid = sdk_mapped_flags_get_by_key(m_bcs.valid_conn_handles,
m_bcs.flags.valid_flags,
conn_handle);
if (valid)
{
bool connected = sdk_mapped_flags_get_by_key(m_bcs.valid_conn_handles,
m_bcs.flags.connected_flags,
conn_handle);
conn_status = connected ? BLE_CONN_STATUS_CONNECTED : BLE_CONN_STATUS_DISCONNECTED;
}
return conn_status;
}
bool ble_conn_state_encrypted(uint16_t conn_handle)
{
return sdk_mapped_flags_get_by_key(m_bcs.valid_conn_handles,
m_bcs.flags.encrypted_flags,
conn_handle);
}
bool ble_conn_state_mitm_protected(uint16_t conn_handle)
{
return sdk_mapped_flags_get_by_key(m_bcs.valid_conn_handles,
m_bcs.flags.mitm_protected_flags,
conn_handle);
}
uint32_t ble_conn_state_n_connections(void)
{
return sdk_mapped_flags_n_flags_set(m_bcs.flags.connected_flags);
}
uint32_t ble_conn_state_n_centrals(void)
{
return sdk_mapped_flags_n_flags_set((m_bcs.flags.central_flags) & (m_bcs.flags.connected_flags));
}
uint32_t ble_conn_state_n_peripherals(void)
{
return sdk_mapped_flags_n_flags_set((~m_bcs.flags.central_flags) & (m_bcs.flags.connected_flags));
}
sdk_mapped_flags_key_list_t ble_conn_state_conn_handles(void)
{
return sdk_mapped_flags_key_list_get(m_bcs.valid_conn_handles, m_bcs.flags.valid_flags);
}
sdk_mapped_flags_key_list_t ble_conn_state_central_handles(void)
{
return sdk_mapped_flags_key_list_get(m_bcs.valid_conn_handles,
(m_bcs.flags.central_flags) & (m_bcs.flags.connected_flags));
}
sdk_mapped_flags_key_list_t ble_conn_state_periph_handles(void)
{
return sdk_mapped_flags_key_list_get(m_bcs.valid_conn_handles,
(~m_bcs.flags.central_flags) & (m_bcs.flags.connected_flags));
}
ble_conn_state_user_flag_id_t ble_conn_state_user_flag_acquire(void)
{
for (ble_conn_state_user_flag_id_t i = BLE_CONN_STATE_USER_FLAG0;
i < BLE_CONN_STATE_N_USER_FLAGS;
i++)
{
if ( !user_flag_is_acquired(i) )
{
user_flag_acquire(i);
return i;
}
}
return BLE_CONN_STATE_USER_FLAG_INVALID;
}
bool ble_conn_state_user_flag_get(uint16_t conn_handle, ble_conn_state_user_flag_id_t flag_id)
{
if (user_flag_is_acquired(flag_id))
{
return sdk_mapped_flags_get_by_key(m_bcs.valid_conn_handles,
m_bcs.flags.user_flags[flag_id],
conn_handle);
}
else
{
return false;
}
}
void ble_conn_state_user_flag_set(uint16_t conn_handle,
ble_conn_state_user_flag_id_t flag_id,
bool value)
{
if (user_flag_is_acquired(flag_id))
{
sdk_mapped_flags_update_by_key(m_bcs.valid_conn_handles,
&m_bcs.flags.user_flags[flag_id],
conn_handle,
value);
}
}
sdk_mapped_flags_t ble_conn_state_user_flag_collection(ble_conn_state_user_flag_id_t flag_id)
{
if ( user_flag_is_acquired(flag_id) )
{
return m_bcs.flags.user_flags[flag_id];
}
else
{
return 0;
}
}

View File

@ -0,0 +1,302 @@
/*
* Copyright (c) 2015 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/**
* @file
*
* @defgroup ble_conn_state Connection state
* @ingroup ble_sdk_lib
* @{
* @brief Module for storing data on BLE connections.
*
* @details This module stores certain states for each connection, which can be queried by
* connection handle. The module uses BLE events to keep the states updated.
*
* In addition to the preprogrammed states, this module can also keep track of a number of
* binary user states, or <i>user flags</i>. These are reset to 0 for new connections, but
* otherwise not touched by this module.
*
* This module uses the @ref sdk_mapped_flags module, with connection handles as keys and
* the connection states as flags.
*
* @note A connection handle is not immediately invalidated when it is disconnected. Certain states,
* such as the role, can still be queried until the next time a new connection is established
* to any device.
*
* To function properly, this module must be provided with BLE events from the SoftDevice
* through the @ref ble_conn_state_on_ble_evt() function. This module should be the first
* to receive BLE events if they are dispatched to multiple modules.
*/
#ifndef BLE_CONN_STATE_H__
#define BLE_CONN_STATE_H__
#include <stdbool.h>
#include <stdint.h>
#include "nrf_ble.h"
#include "sdk_mapped_flags.h"
/**@brief Connection handle statuses.
*/
typedef enum
{
BLE_CONN_STATUS_INVALID, /**< The connection handle is invalid. */
BLE_CONN_STATUS_DISCONNECTED, /**< The connection handle refers to a connection that has been disconnected, but not yet invalidated. */
BLE_CONN_STATUS_CONNECTED, /**< The connection handle refers to an active connection. */
} ble_conn_state_status_t;
#define BLE_CONN_STATE_N_USER_FLAGS 24 /**< The number of available user flags. */
/**@brief One ID for each user flag collection.
*
* @details These IDs are used to identify user flag collections in the API calls.
*/
typedef enum
{
BLE_CONN_STATE_USER_FLAG0 = 0,
BLE_CONN_STATE_USER_FLAG1,
BLE_CONN_STATE_USER_FLAG2,
BLE_CONN_STATE_USER_FLAG3,
BLE_CONN_STATE_USER_FLAG4,
BLE_CONN_STATE_USER_FLAG5,
BLE_CONN_STATE_USER_FLAG6,
BLE_CONN_STATE_USER_FLAG7,
BLE_CONN_STATE_USER_FLAG8,
BLE_CONN_STATE_USER_FLAG9,
BLE_CONN_STATE_USER_FLAG10,
BLE_CONN_STATE_USER_FLAG11,
BLE_CONN_STATE_USER_FLAG12,
BLE_CONN_STATE_USER_FLAG13,
BLE_CONN_STATE_USER_FLAG14,
BLE_CONN_STATE_USER_FLAG15,
BLE_CONN_STATE_USER_FLAG16,
BLE_CONN_STATE_USER_FLAG17,
BLE_CONN_STATE_USER_FLAG18,
BLE_CONN_STATE_USER_FLAG19,
BLE_CONN_STATE_USER_FLAG20,
BLE_CONN_STATE_USER_FLAG21,
BLE_CONN_STATE_USER_FLAG22,
BLE_CONN_STATE_USER_FLAG23,
BLE_CONN_STATE_USER_FLAG_INVALID,
} ble_conn_state_user_flag_id_t;
/**
* @defgroup ble_conn_state_functions BLE connection state functions
* @{
*/
/**@brief Function for initializing or resetting the module.
*
* @details This function sets all states to their default, removing all records of connection handles.
*/
void ble_conn_state_init(void);
/**@brief Function for providing BLE SoftDevice events to the connection state module.
*
* @param[in] p_ble_evt The SoftDevice event.
*/
void ble_conn_state_on_ble_evt(ble_evt_t * p_ble_evt);
/**@brief Function for querying whether a connection handle represents a valid connection.
*
* @details A connection might be valid and have a BLE_CONN_STATUS_DISCONNECTED status.
* Those connections are invalidated after a new connection occurs.
*
* @param[in] conn_handle Handle of the connection.
*
* @retval true If conn_handle represents a valid connection, thus a connection for which
we have a record.
* @retval false If conn_handle is @ref BLE_GAP_ROLE_INVALID, or if it has never been recorded.
*/
bool ble_conn_state_valid(uint16_t conn_handle);
/**@brief Function for querying the role of the local device in a connection.
*
* @param[in] conn_handle Handle of the connection to get the role for.
*
* @return The role of the local device in the connection (see @ref BLE_GAP_ROLES).
* If conn_handle is not valid, the function returns BLE_GAP_ROLE_INVALID.
*/
uint8_t ble_conn_state_role(uint16_t conn_handle);
/**@brief Function for querying the status of a connection.
*
* @param[in] conn_handle Handle of the connection.
*
* @return The status of the connection.
* If conn_handle is not valid, the function returns BLE_CONN_STATE_INVALID.
*/
ble_conn_state_status_t ble_conn_state_status(uint16_t conn_handle);
/**@brief Function for querying whether a connection is encrypted.
*
* @param[in] conn_handle Handle of connection to get the encryption state for.
*
* @retval true If the connection is encrypted.
* @retval false If the connection is not encrypted or conn_handle is invalid.
*/
bool ble_conn_state_encrypted(uint16_t conn_handle);
/**@brief Function for querying whether a connection encryption is protected from Man in the Middle
* attacks.
*
* @param[in] conn_handle Handle of connection to get the MITM state for.
*
* @retval true If the connection is encrypted with MITM protection.
* @retval false If the connection is not encrypted, or encryption is not MITM protected, or
* conn_handle is invalid.
*/
bool ble_conn_state_mitm_protected(uint16_t conn_handle);
/**@brief Function for querying the total number of connections.
*
* @return The total number of valid connections for which the module has a record.
*/
uint32_t ble_conn_state_n_connections(void);
/**@brief Function for querying the total number of connections in which the role of the local
* device is @ref BLE_GAP_ROLE_CENTRAL.
*
* @return The number of connections in which the role of the local device is
* @ref BLE_GAP_ROLE_CENTRAL.
*/
uint32_t ble_conn_state_n_centrals(void);
/**@brief Function for querying the total number of connections in which the role of the local
* device is @ref BLE_GAP_ROLE_PERIPH.
*
* @return The number of connections in which the role of the local device is
* @ref BLE_GAP_ROLE_PERIPH.
*/
uint32_t ble_conn_state_n_peripherals(void);
/**@brief Function for obtaining a list of all connection handles for which the module has a record.
*
* @details This function takes into account connections whose state is BLE_CONN_STATUS_DISCONNECTED.
*
* @return A list of all valid connection handles for which the module has a record.
*/
sdk_mapped_flags_key_list_t ble_conn_state_conn_handles(void);
/**@brief Function for obtaining a list of connection handles in which the role of the local
* device is @ref BLE_GAP_ROLE_CENTRAL.
*
* @details This function takes into account connections whose state is BLE_CONN_STATUS_DISCONNECTED.
*
* @return A list of all valid connection handles for which the module has a record and in which
* the role of local device is @ref BLE_GAP_ROLE_CENTRAL.
*/
sdk_mapped_flags_key_list_t ble_conn_state_central_handles(void);
/**@brief Function for obtaining the handle for the connection in which the role of the local device
* is @ref BLE_GAP_ROLE_PERIPH.
*
* @details This function takes into account connections whose state is BLE_CONN_STATUS_DISCONNECTED.
*
* @return A list of all valid connection handles for which the module has a record and in which
* the role of local device is @ref BLE_GAP_ROLE_PERIPH.
*/
sdk_mapped_flags_key_list_t ble_conn_state_periph_handles(void);
/**@brief Function for obtaining exclusive access to one of the user flag collections.
*
* @details The acquired collection contains one flag for each connection. These flags can be set
* and read individually for each connection.
*
* The state of user flags will not be modified by the connection state module, except to
* set it to 0 for a connection when that connection is invalidated.
*
* @return The ID of the acquired flag, or BLE_CONN_STATE_USER_FLAG_INVALID if none are available.
*/
ble_conn_state_user_flag_id_t ble_conn_state_user_flag_acquire(void);
/**@brief Function for reading the value of a user flag.
*
* @param[in] conn_handle Handle of connection to get the flag state for.
* @param[in] flag_id Which flag to get the state for.
*
* @return The state of the flag. If conn_handle is invalid, the function returns false.
*/
bool ble_conn_state_user_flag_get(uint16_t conn_handle, ble_conn_state_user_flag_id_t flag_id);
/**@brief Function for setting the value of a user flag.
*
* @param[in] conn_handle Handle of connection to set the flag state for.
* @param[in] flag_id Which flag to set the state for.
* @param[in] value Value to set the flag state to.
*/
void ble_conn_state_user_flag_set(uint16_t conn_handle,
ble_conn_state_user_flag_id_t flag_id,
bool value);
/**@brief Function for getting the state of a user flag for all connection handles.
*
* @details The returned collection can be used with the @ref sdk_mapped_flags API. The returned
* collection is a copy, so modifying it has no effect on the conn_state module.
*
* @param[in] flag_id Which flag to get states for.
*
* @return The collection of flag states. The collection is always all zeros when the flag_id is
* unregistered.
*/
sdk_mapped_flags_t ble_conn_state_user_flag_collection(ble_conn_state_user_flag_id_t flag_id);
/** @} */
/** @} */
#endif /* BLE_CONN_STATE_H__ */

View File

@ -0,0 +1,104 @@
/*
* Copyright (c) 2011 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/* Attention!
* To maintain compliance with Nordic Semiconductor ASAs Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
/** @file
* @brief Contains definition of ble_date_time structure.
*/
/** @file
*
* @defgroup ble_sdk_srv_date_time BLE Date Time characteristic type
* @{
* @ingroup ble_sdk_lib
* @brief Definition of ble_date_time_t type.
*/
#ifndef BLE_DATE_TIME_H__
#define BLE_DATE_TIME_H__
#include <stdint.h>
/**@brief Date and Time structure. */
typedef struct
{
uint16_t year;
uint8_t month;
uint8_t day;
uint8_t hours;
uint8_t minutes;
uint8_t seconds;
} ble_date_time_t;
static __INLINE uint8_t ble_date_time_encode(const ble_date_time_t * p_date_time,
uint8_t * p_encoded_data)
{
uint8_t len = uint16_encode(p_date_time->year, p_encoded_data);
p_encoded_data[len++] = p_date_time->month;
p_encoded_data[len++] = p_date_time->day;
p_encoded_data[len++] = p_date_time->hours;
p_encoded_data[len++] = p_date_time->minutes;
p_encoded_data[len++] = p_date_time->seconds;
return len;
}
static __INLINE uint8_t ble_date_time_decode(ble_date_time_t * p_date_time,
const uint8_t * p_encoded_data)
{
uint8_t len = sizeof(uint16_t);
p_date_time->year = uint16_decode(p_encoded_data);
p_date_time->month = p_encoded_data[len++];
p_date_time->day = p_encoded_data[len++];
p_date_time->hours = p_encoded_data[len++];
p_date_time->minutes = p_encoded_data[len++];
p_date_time->seconds = p_encoded_data[len++];
return len;
}
#endif // BLE_DATE_TIME_H__
/** @} */

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2016 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/**@file
*
* @defgroup ble_sdk_lib_gatt_db GATT Database Service Structure
* @{
* @ingroup app_common
*/
#ifndef BLE_GATT_DB_H__
#define BLE_GATT_DB_H__
#include <stdint.h>
#include "nrf_ble.h"
#include "nrf_ble_gattc.h"
#define BLE_GATT_DB_MAX_CHARS 5 /**< The maximum number of characteristics present in a service record. */
/**@brief Structure for holding the characteristic and the handle of its CCCD present on a server.
*/
typedef struct
{
ble_gattc_char_t characteristic; /**< Structure containing information about the characteristic. */
uint16_t cccd_handle; /**< CCCD Handle value for this characteristic. This will be set to BLE_GATT_HANDLE_INVALID if a CCCD is not present at the server. */
} ble_gatt_db_char_t;
/**@brief Structure for holding information about the service and the characteristics present on a
* server.
*/
typedef struct
{
ble_uuid_t srv_uuid; /**< UUID of the service. */
uint8_t char_count; /**< Number of characteristics present in the service. */
ble_gattc_handle_range_t handle_range; /**< Service Handle Range. */
ble_gatt_db_char_t charateristics[BLE_GATT_DB_MAX_CHARS]; /**< Array of information related to the characteristics present in the service. This list can extend further than one. */
} ble_gatt_db_srv_t;
#endif /* BLE_GATT_DB_H__ */
/** @} */

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 2012 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/* Attention!
* To maintain compliance with Nordic Semiconductor ASAs Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#ifndef BLE_SENSOR_LOCATION_H__
#define BLE_SENSOR_LOCATION_H__
typedef enum {
BLE_SENSOR_LOCATION_OTHER = 0 , /**<-- Other */
BLE_SENSOR_LOCATION_TOP_OF_SHOE = 1 , /**<-- Top of shoe */
BLE_SENSOR_LOCATION_IN_SHOE = 2 , /**<-- In shoe */
BLE_SENSOR_LOCATION_HIP = 3 , /**<-- Hip */
BLE_SENSOR_LOCATION_FRONT_WHEEL = 4 , /**<-- Front Wheel */
BLE_SENSOR_LOCATION_LEFT_CRANK = 5 , /**<-- Left Crank */
BLE_SENSOR_LOCATION_RIGHT_CRANK = 6 , /**<-- Right Crank */
BLE_SENSOR_LOCATION_LEFT_PEDAL = 7 , /**<-- Left Pedal */
BLE_SENSOR_LOCATION_RIGHT_PEDAL = 8 , /**<-- Right Pedal */
BLE_SENSOR_LOCATION_FRONT_HUB = 9 , /**<-- Front Hub */
BLE_SENSOR_LOCATION_REAR_DROPOUT = 10, /**<-- Rear Dropout */
BLE_SENSOR_LOCATION_CHAINSTAY = 11, /**<-- Chainstay */
BLE_SENSOR_LOCATION_REAR_WHEEL = 12, /**<-- Rear Wheel */
BLE_SENSOR_LOCATION_REAR_HUB = 13, /**<-- Rear Hub */
}ble_sensor_location_t;
#define BLE_NB_MAX_SENSOR_LOCATIONS 14
#endif // BLE_SENSOR_LOCATION_H__

View File

@ -0,0 +1,224 @@
/*
* Copyright (c) 2012 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/* Attention!
* To maintain compliance with Nordic Semiconductor ASA<EFBFBD>s Bluetooth profile
* qualification listings, this section of source code must not be modified.
*/
#include "ble_srv_common.h"
#include <string.h>
#include "nordic_common.h"
#include "app_error.h"
#include "nrf_ble.h"
uint8_t ble_srv_report_ref_encode(uint8_t * p_encoded_buffer,
const ble_srv_report_ref_t * p_report_ref)
{
uint8_t len = 0;
p_encoded_buffer[len++] = p_report_ref->report_id;
p_encoded_buffer[len++] = p_report_ref->report_type;
APP_ERROR_CHECK_BOOL(len == BLE_SRV_ENCODED_REPORT_REF_LEN);
return len;
}
void ble_srv_ascii_to_utf8(ble_srv_utf8_str_t * p_utf8, char * p_ascii)
{
p_utf8->length = (uint16_t)strlen(p_ascii);
p_utf8->p_str = (uint8_t *)p_ascii;
}
/**@brief Function for setting security requirements of a characteristic.
*
* @param[in] level required security level.
* @param[out] p_perm Characteristic security requirements.
*
* @return encoded security level and security mode.
*/
static inline void set_security_req(security_req_t level, ble_gap_conn_sec_mode_t * p_perm)
{
BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(p_perm);
switch (level)
{
case SEC_NO_ACCESS:
BLE_GAP_CONN_SEC_MODE_SET_NO_ACCESS(p_perm);
break;
case SEC_OPEN:
BLE_GAP_CONN_SEC_MODE_SET_OPEN(p_perm);
break;
case SEC_JUST_WORKS:
BLE_GAP_CONN_SEC_MODE_SET_ENC_NO_MITM(p_perm);
break;
case SEC_MITM:
BLE_GAP_CONN_SEC_MODE_SET_ENC_WITH_MITM(p_perm);
break;
case SEC_SIGNED:
BLE_GAP_CONN_SEC_MODE_SET_SIGNED_NO_MITM(p_perm);
break;
case SEC_SIGNED_MITM:
BLE_GAP_CONN_SEC_MODE_SET_SIGNED_WITH_MITM(p_perm);
break;
}
return;
}
uint32_t characteristic_add(uint16_t service_handle,
ble_add_char_params_t * p_char_props,
ble_gatts_char_handles_t * p_char_handle)
{
ble_gatts_char_md_t char_md;
ble_gatts_attr_t attr_char_value;
ble_uuid_t char_uuid;
ble_gatts_attr_md_t attr_md;
ble_gatts_attr_md_t user_descr_attr_md;
ble_gatts_attr_md_t cccd_md;
if (p_char_props->uuid_type == 0)
{
char_uuid.type = BLE_UUID_TYPE_BLE;
}
else
{
char_uuid.type = p_char_props->uuid_type;
}
char_uuid.uuid = p_char_props->uuid;
memset(&attr_md, 0, sizeof(ble_gatts_attr_md_t));
set_security_req(p_char_props->read_access, &attr_md.read_perm);
set_security_req(p_char_props->write_access, & attr_md.write_perm);
attr_md.rd_auth = (p_char_props->is_defered_read ? 1 : 0);
attr_md.wr_auth = (p_char_props->is_defered_write ? 1 : 0);
attr_md.vlen = (p_char_props->is_var_len ? 1 : 0);
attr_md.vloc = (p_char_props->is_value_user ? BLE_GATTS_VLOC_USER : BLE_GATTS_VLOC_STACK);
memset(&char_md, 0, sizeof(ble_gatts_char_md_t));
if ((p_char_props->char_props.notify == 1)||(p_char_props->char_props.indicate == 1))
{
memset(&cccd_md, 0, sizeof(cccd_md));
set_security_req(p_char_props->cccd_write_access, &cccd_md.write_perm);
BLE_GAP_CONN_SEC_MODE_SET_OPEN(&cccd_md.read_perm);
cccd_md.vloc = BLE_GATTS_VLOC_STACK;
char_md.p_cccd_md = &cccd_md;
}
char_md.char_props = p_char_props->char_props;
memset(&attr_char_value, 0, sizeof(ble_gatts_attr_t));
attr_char_value.p_uuid = &char_uuid;
attr_char_value.p_attr_md = &attr_md;
attr_char_value.max_len = p_char_props->max_len;
if (p_char_props->p_init_value != NULL)
{
attr_char_value.init_len = p_char_props->init_len;
attr_char_value.p_value = p_char_props->p_init_value;
}
if (p_char_props->p_user_descr != NULL)
{
memset(&user_descr_attr_md, 0, sizeof(ble_gatts_attr_md_t));
char_md.char_user_desc_max_size = p_char_props->p_user_descr->max_size;
char_md.char_user_desc_size = p_char_props->p_user_descr->size;
char_md.p_char_user_desc = p_char_props->p_user_descr->p_char_user_desc;
char_md.p_user_desc_md = &user_descr_attr_md;
set_security_req(p_char_props->p_user_descr->read_access, &user_descr_attr_md.read_perm);
set_security_req(p_char_props->p_user_descr->write_access, &user_descr_attr_md.write_perm);
user_descr_attr_md.rd_auth = (p_char_props->p_user_descr->is_defered_read ? 1 : 0);
user_descr_attr_md.wr_auth = (p_char_props->p_user_descr->is_defered_write ? 1 : 0);
user_descr_attr_md.vlen = (p_char_props->p_user_descr->is_var_len ? 1 : 0);
user_descr_attr_md.vloc = (p_char_props->p_user_descr->is_value_user ? BLE_GATTS_VLOC_USER : BLE_GATTS_VLOC_STACK);
}
if (p_char_props->p_presentation_format != NULL)
{
char_md.p_char_pf = p_char_props->p_presentation_format;
}
return sd_ble_gatts_characteristic_add(service_handle,
&char_md,
&attr_char_value,
p_char_handle);
}
uint32_t descriptor_add(uint16_t char_handle,
ble_add_descr_params_t * p_descr_props,
uint16_t * p_descr_handle)
{
ble_gatts_attr_t descr_params;
ble_uuid_t desc_uuid;
ble_gatts_attr_md_t attr_md;
memset(&descr_params, 0, sizeof(descr_params));
if (p_descr_props->uuid_type == 0)
{
desc_uuid.type = BLE_UUID_TYPE_BLE;
}
else
{
desc_uuid.type = p_descr_props->uuid_type;
}
desc_uuid.uuid = p_descr_props->uuid;
descr_params.p_uuid = &desc_uuid;
set_security_req(p_descr_props->read_access, &attr_md.read_perm);
set_security_req(p_descr_props->write_access,&attr_md.write_perm);
attr_md.rd_auth = (p_descr_props->is_defered_read ? 1 : 0);
attr_md.wr_auth = (p_descr_props->is_defered_write ? 1 : 0);
attr_md.vlen = (p_descr_props->is_var_len ? 1 : 0);
attr_md.vloc = (p_descr_props->is_value_user ? BLE_GATTS_VLOC_USER : BLE_GATTS_VLOC_STACK);
descr_params.p_attr_md = &attr_md;
descr_params.init_len = p_descr_props->init_len;
descr_params.init_offs = p_descr_props->init_offs;
descr_params.max_len = p_descr_props->max_len;
descr_params.p_value = p_descr_props->p_value;
return sd_ble_gatts_descriptor_add(char_handle, &descr_params, p_descr_handle);
}

View File

@ -0,0 +1,394 @@
/*
* Copyright (c) 2012 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/** @file
*
* @defgroup ble_sdk_srv_common Common service definitions
* @{
* @ingroup ble_sdk_srv
* @brief Constants, type definitions, and functions that are common to all services.
*/
#ifndef BLE_SRV_COMMON_H__
#define BLE_SRV_COMMON_H__
#include <stdint.h>
#include <stdbool.h>
#include "nrf_ble_types.h"
#include "app_util.h"
#include "nrf_ble.h"
#include "nrf_ble_gap.h"
#include "nrf_ble_gatt.h"
/** @defgroup UUID_SERVICES Service UUID definitions
* @{ */
#define BLE_UUID_ALERT_NOTIFICATION_SERVICE 0x1811 /**< Alert Notification service UUID. */
#define BLE_UUID_BATTERY_SERVICE 0x180F /**< Battery service UUID. */
#define BLE_UUID_BLOOD_PRESSURE_SERVICE 0x1810 /**< Blood Pressure service UUID. */
#define BLE_UUID_CURRENT_TIME_SERVICE 0x1805 /**< Current Time service UUID. */
#define BLE_UUID_CYCLING_SPEED_AND_CADENCE 0x1816 /**< Cycling Speed and Cadence service UUID. */
#define BLE_UUID_LOCATION_AND_NAVIGATION_SERVICE 0x1819 /**< Location and Navigation service UUID. */
#define BLE_UUID_DEVICE_INFORMATION_SERVICE 0x180A /**< Device Information service UUID. */
#define BLE_UUID_GLUCOSE_SERVICE 0x1808 /**< Glucose service UUID. */
#define BLE_UUID_HEALTH_THERMOMETER_SERVICE 0x1809 /**< Health Thermometer service UUID. */
#define BLE_UUID_HEART_RATE_SERVICE 0x180D /**< Heart Rate service UUID. */
#define BLE_UUID_HUMAN_INTERFACE_DEVICE_SERVICE 0x1812 /**< Human Interface Device service UUID. */
#define BLE_UUID_IMMEDIATE_ALERT_SERVICE 0x1802 /**< Immediate Alert service UUID. */
#define BLE_UUID_LINK_LOSS_SERVICE 0x1803 /**< Link Loss service UUID. */
#define BLE_UUID_NEXT_DST_CHANGE_SERVICE 0x1807 /**< Next Dst Change service UUID. */
#define BLE_UUID_PHONE_ALERT_STATUS_SERVICE 0x180E /**< Phone Alert Status service UUID. */
#define BLE_UUID_REFERENCE_TIME_UPDATE_SERVICE 0x1806 /**< Reference Time Update service UUID. */
#define BLE_UUID_RUNNING_SPEED_AND_CADENCE 0x1814 /**< Running Speed and Cadence service UUID. */
#define BLE_UUID_SCAN_PARAMETERS_SERVICE 0x1813 /**< Scan Parameters service UUID. */
#define BLE_UUID_TX_POWER_SERVICE 0x1804 /**< TX Power service UUID. */
#define BLE_UUID_IPSP_SERVICE 0x1820 /**< Internet Protocol Support service UUID. */
#define BLE_UUID_BMS_SERVICE 0x181E /**< BOND MANAGEMENT service UUID*/
#define BLE_UUID_CGM_SERVICE 0x181F /**< Contiunous Glucose Monitoring service UUID*/
#define BLE_UUID_PLX_SERVICE 0x1822 /**< Pulse Oximeter Service UUID*/
/** @} */
/** @defgroup UUID_CHARACTERISTICS Characteristic UUID definitions
* @{ */
#define BLE_UUID_REMOVABLE_CHAR 0x2A3A /**< Removable characteristic UUID. */
#define BLE_UUID_SERVICE_REQUIRED_CHAR 0x2A3B /**< Service Required characteristic UUID. */
#define BLE_UUID_ALERT_CATEGORY_ID_CHAR 0x2A43 /**< Alert Category Id characteristic UUID. */
#define BLE_UUID_ALERT_CATEGORY_ID_BIT_MASK_CHAR 0x2A42 /**< Alert Category Id Bit Mask characteristic UUID. */
#define BLE_UUID_ALERT_LEVEL_CHAR 0x2A06 /**< Alert Level characteristic UUID. */
#define BLE_UUID_ALERT_NOTIFICATION_CONTROL_POINT_CHAR 0x2A44 /**< Alert Notification Control Point characteristic UUID. */
#define BLE_UUID_ALERT_STATUS_CHAR 0x2A3F /**< Alert Status characteristic UUID. */
#define BLE_UUID_BATTERY_LEVEL_CHAR 0x2A19 /**< Battery Level characteristic UUID. */
#define BLE_UUID_BLOOD_PRESSURE_FEATURE_CHAR 0x2A49 /**< Blood Pressure Feature characteristic UUID. */
#define BLE_UUID_BLOOD_PRESSURE_MEASUREMENT_CHAR 0x2A35 /**< Blood Pressure Measurement characteristic UUID. */
#define BLE_UUID_BODY_SENSOR_LOCATION_CHAR 0x2A38 /**< Body Sensor Location characteristic UUID. */
#define BLE_UUID_BOOT_KEYBOARD_INPUT_REPORT_CHAR 0x2A22 /**< Boot Keyboard Input Report characteristic UUID. */
#define BLE_UUID_BOOT_KEYBOARD_OUTPUT_REPORT_CHAR 0x2A32 /**< Boot Keyboard Output Report characteristic UUID. */
#define BLE_UUID_BOOT_MOUSE_INPUT_REPORT_CHAR 0x2A33 /**< Boot Mouse Input Report characteristic UUID. */
#define BLE_UUID_CURRENT_TIME_CHAR 0x2A2B /**< Current Time characteristic UUID. */
#define BLE_UUID_DATE_TIME_CHAR 0x2A08 /**< Date Time characteristic UUID. */
#define BLE_UUID_DAY_DATE_TIME_CHAR 0x2A0A /**< Day Date Time characteristic UUID. */
#define BLE_UUID_DAY_OF_WEEK_CHAR 0x2A09 /**< Day Of Week characteristic UUID. */
#define BLE_UUID_DST_OFFSET_CHAR 0x2A0D /**< Dst Offset characteristic UUID. */
#define BLE_UUID_EXACT_TIME_256_CHAR 0x2A0C /**< Exact Time 256 characteristic UUID. */
#define BLE_UUID_FIRMWARE_REVISION_STRING_CHAR 0x2A26 /**< Firmware Revision String characteristic UUID. */
#define BLE_UUID_GLUCOSE_FEATURE_CHAR 0x2A51 /**< Glucose Feature characteristic UUID. */
#define BLE_UUID_GLUCOSE_MEASUREMENT_CHAR 0x2A18 /**< Glucose Measurement characteristic UUID. */
#define BLE_UUID_GLUCOSE_MEASUREMENT_CONTEXT_CHAR 0x2A34 /**< Glucose Measurement Context characteristic UUID. */
#define BLE_UUID_HARDWARE_REVISION_STRING_CHAR 0x2A27 /**< Hardware Revision String characteristic UUID. */
#define BLE_UUID_HEART_RATE_CONTROL_POINT_CHAR 0x2A39 /**< Heart Rate Control Point characteristic UUID. */
#define BLE_UUID_HEART_RATE_MEASUREMENT_CHAR 0x2A37 /**< Heart Rate Measurement characteristic UUID. */
#define BLE_UUID_HID_CONTROL_POINT_CHAR 0x2A4C /**< Hid Control Point characteristic UUID. */
#define BLE_UUID_HID_INFORMATION_CHAR 0x2A4A /**< Hid Information characteristic UUID. */
#define BLE_UUID_IEEE_REGULATORY_CERTIFICATION_DATA_LIST_CHAR 0x2A2A /**< IEEE Regulatory Certification Data List characteristic UUID. */
#define BLE_UUID_INTERMEDIATE_CUFF_PRESSURE_CHAR 0x2A36 /**< Intermediate Cuff Pressure characteristic UUID. */
#define BLE_UUID_INTERMEDIATE_TEMPERATURE_CHAR 0x2A1E /**< Intermediate Temperature characteristic UUID. */
#define BLE_UUID_LOCAL_TIME_INFORMATION_CHAR 0x2A0F /**< Local Time Information characteristic UUID. */
#define BLE_UUID_MANUFACTURER_NAME_STRING_CHAR 0x2A29 /**< Manufacturer Name String characteristic UUID. */
#define BLE_UUID_MEASUREMENT_INTERVAL_CHAR 0x2A21 /**< Measurement Interval characteristic UUID. */
#define BLE_UUID_MODEL_NUMBER_STRING_CHAR 0x2A24 /**< Model Number String characteristic UUID. */
#define BLE_UUID_UNREAD_ALERT_CHAR 0x2A45 /**< Unread Alert characteristic UUID. */
#define BLE_UUID_NEW_ALERT_CHAR 0x2A46 /**< New Alert characteristic UUID. */
#define BLE_UUID_PNP_ID_CHAR 0x2A50 /**< PNP Id characteristic UUID. */
#define BLE_UUID_PROTOCOL_MODE_CHAR 0x2A4E /**< Protocol Mode characteristic UUID. */
#define BLE_UUID_RECORD_ACCESS_CONTROL_POINT_CHAR 0x2A52 /**< Record Access Control Point characteristic UUID. */
#define BLE_UUID_REFERENCE_TIME_INFORMATION_CHAR 0x2A14 /**< Reference Time Information characteristic UUID. */
#define BLE_UUID_REPORT_CHAR 0x2A4D /**< Report characteristic UUID. */
#define BLE_UUID_REPORT_MAP_CHAR 0x2A4B /**< Report Map characteristic UUID. */
#define BLE_UUID_RINGER_CONTROL_POINT_CHAR 0x2A40 /**< Ringer Control Point characteristic UUID. */
#define BLE_UUID_RINGER_SETTING_CHAR 0x2A41 /**< Ringer Setting characteristic UUID. */
#define BLE_UUID_SCAN_INTERVAL_WINDOW_CHAR 0x2A4F /**< Scan Interval Window characteristic UUID. */
#define BLE_UUID_SCAN_REFRESH_CHAR 0x2A31 /**< Scan Refresh characteristic UUID. */
#define BLE_UUID_SERIAL_NUMBER_STRING_CHAR 0x2A25 /**< Serial Number String characteristic UUID. */
#define BLE_UUID_SOFTWARE_REVISION_STRING_CHAR 0x2A28 /**< Software Revision String characteristic UUID. */
#define BLE_UUID_SUPPORTED_NEW_ALERT_CATEGORY_CHAR 0x2A47 /**< Supported New Alert Category characteristic UUID. */
#define BLE_UUID_SUPPORTED_UNREAD_ALERT_CATEGORY_CHAR 0x2A48 /**< Supported Unread Alert Category characteristic UUID. */
#define BLE_UUID_SYSTEM_ID_CHAR 0x2A23 /**< System Id characteristic UUID. */
#define BLE_UUID_TEMPERATURE_MEASUREMENT_CHAR 0x2A1C /**< Temperature Measurement characteristic UUID. */
#define BLE_UUID_TEMPERATURE_TYPE_CHAR 0x2A1D /**< Temperature Type characteristic UUID. */
#define BLE_UUID_TIME_ACCURACY_CHAR 0x2A12 /**< Time Accuracy characteristic UUID. */
#define BLE_UUID_TIME_SOURCE_CHAR 0x2A13 /**< Time Source characteristic UUID. */
#define BLE_UUID_TIME_UPDATE_CONTROL_POINT_CHAR 0x2A16 /**< Time Update Control Point characteristic UUID. */
#define BLE_UUID_TIME_UPDATE_STATE_CHAR 0x2A17 /**< Time Update State characteristic UUID. */
#define BLE_UUID_TIME_WITH_DST_CHAR 0x2A11 /**< Time With Dst characteristic UUID. */
#define BLE_UUID_TIME_ZONE_CHAR 0x2A0E /**< Time Zone characteristic UUID. */
#define BLE_UUID_TX_POWER_LEVEL_CHAR 0x2A07 /**< TX Power Level characteristic UUID. */
#define BLE_UUID_CSC_FEATURE_CHAR 0x2A5C /**< Cycling Speed and Cadence Feature characteristic UUID. */
#define BLE_UUID_CSC_MEASUREMENT_CHAR 0x2A5B /**< Cycling Speed and Cadence Measurement characteristic UUID. */
#define BLE_UUID_RSC_FEATURE_CHAR 0x2A54 /**< Running Speed and Cadence Feature characteristic UUID. */
#define BLE_UUID_SC_CTRLPT_CHAR 0x2A55 /**< Speed and Cadence Control Point UUID. */
#define BLE_UUID_RSC_MEASUREMENT_CHAR 0x2A53 /**< Running Speed and Cadence Measurement characteristic UUID. */
#define BLE_UUID_SENSOR_LOCATION_CHAR 0x2A5D /**< Sensor Location characteristic UUID. */
#define BLE_UUID_EXTERNAL_REPORT_REF_DESCR 0x2907 /**< External Report Reference descriptor UUID. */
#define BLE_UUID_REPORT_REF_DESCR 0x2908 /**< Report Reference descriptor UUID. */
#define BLE_UUID_LN_FEATURE_CHAR 0x2A6A /**< Location Navigation Service, Feature characteristic UUID. */
#define BLE_UUID_LN_POSITION_QUALITY_CHAR 0x2A69 /**< Location Navigation Service, Position quality UUID. */
#define BLE_UUID_LN_LOCATION_AND_SPEED_CHAR 0x2A67 /**< Location Navigation Service, Location and Speed characteristic UUID. */
#define BLE_UUID_LN_NAVIGATION_CHAR 0x2A68 /**< Location Navigation Service, Navigation characteristic UUID. */
#define BLE_UUID_LN_CONTROL_POINT_CHAR 0x2A6B /**< Location Navigation Service, Control point characteristic UUID. */
#define BLE_UUID_BMS_CTRLPT 0x2AA4 /**< BMS Control Point characteristic UUID. */
#define BLE_UUID_BMS_FEATURE 0x2AA5 /**< BMS Feature characteristic UUID. */
#define BLE_UUID_CGM_MEASUREMENT 0x2AA7 /**< CGM Service, Measurement characteristic UUID*/
#define BLE_UUID_CGM_FEATURE 0x2AA8 /**< CGM Service, Feature characteristic UUID*/
#define BLE_UUID_CGM_STATUS 0x2AA9 /**< CGM Service, Status characteristic UUID*/
#define BLE_UUID_CGM_SESSION_START_TIME 0x2AAA /**< CGM Service, session start time characteristic UUID*/
#define BLE_UUID_CGM_SESSION_RUN_TIME 0x2AAB /**< CGM Service, session run time characteristic UUID*/
#define BLE_UUID_CGM_SPECIFIC_OPS_CTRLPT 0x2AAC /**< CGM Service, specific ops ctrlpt characteristic UUID*/
#define BLE_UUID_PLX_SPOT_CHECK_MEAS 0x2A5E /**< PLX Service, spot check measurement characteristic UUID*/
#define BLE_UUID_PLX_CONTINUOUS_MEAS 0x2A5F /**< PLX Service, continuous measurement characteristic UUID*/
#define BLE_UUID_PLX_FEATURES 0x2A60 /**< PLX Service, feature characteristic UUID*/
/** @} */
/** @defgroup ALERT_LEVEL_VALUES Definitions for the Alert Level characteristic values
* @{ */
#define BLE_CHAR_ALERT_LEVEL_NO_ALERT 0x00 /**< No Alert. */
#define BLE_CHAR_ALERT_LEVEL_MILD_ALERT 0x01 /**< Mild Alert. */
#define BLE_CHAR_ALERT_LEVEL_HIGH_ALERT 0x02 /**< High Alert. */
/** @} */
#define BLE_SRV_ENCODED_REPORT_REF_LEN 2 /**< The length of an encoded Report Reference Descriptor. */
#define BLE_CCCD_VALUE_LEN 2 /**< The length of a CCCD value. */
/**@brief Type definition for error handler function that will be called in case of an error in
* a service or a service library module. */
typedef void (*ble_srv_error_handler_t) (uint32_t nrf_error);
/**@brief Value of a Report Reference descriptor.
*
* @details This is mapping information that maps the parent characteristic to the Report ID(s) and
* Report Type(s) defined within a Report Map characteristic.
*/
typedef struct
{
uint8_t report_id; /**< Non-zero value if there is more than one instance of the same Report Type */
uint8_t report_type; /**< Type of Report characteristic (see @ref BLE_HIDS_REPORT_TYPE) */
} ble_srv_report_ref_t;
/**@brief UTF-8 string data type.
*
* @note The type can only hold a pointer to the string data (i.e. not the actual data).
*/
typedef struct
{
uint16_t length; /**< String length. */
uint8_t * p_str; /**< String data. */
} ble_srv_utf8_str_t;
/**@brief Security settings structure.
* @details This structure contains the security options needed during initialization of the
* service.
*/
typedef struct
{
ble_gap_conn_sec_mode_t read_perm; /**< Read permissions. */
ble_gap_conn_sec_mode_t write_perm; /**< Write permissions. */
} ble_srv_security_mode_t;
/**@brief Security settings structure.
* @details This structure contains the security options needed during initialization of the
* service. It can be used when the characteristics contains a CCCD.
*/
typedef struct
{
ble_gap_conn_sec_mode_t cccd_write_perm; /**< Write permissions for Client Characteristic Configuration Descriptor. */
ble_gap_conn_sec_mode_t read_perm; /**< Read permissions. */
ble_gap_conn_sec_mode_t write_perm; /**< Write permissions. */
} ble_srv_cccd_security_mode_t;
/**@brief Function for decoding a CCCD value, and then testing if notification is
* enabled.
*
* @param[in] p_encoded_data Buffer where the encoded CCCD is stored.
*
* @retval TRUE If notification is enabled.
* @retval FALSE Otherwise.
*/
static __INLINE bool ble_srv_is_notification_enabled(uint8_t const * p_encoded_data)
{
uint16_t cccd_value = uint16_decode(p_encoded_data);
return ((cccd_value & BLE_GATT_HVX_NOTIFICATION) != 0);
}
/**@brief Function for decoding a CCCD value, and then testing if indication is
* enabled.
*
* @param[in] p_encoded_data Buffer where the encoded CCCD is stored.
*
* @retval TRUE If indication is enabled.
* @retval FALSE Otherwise.
*/
static __INLINE bool ble_srv_is_indication_enabled(uint8_t const * p_encoded_data)
{
uint16_t cccd_value = uint16_decode(p_encoded_data);
return ((cccd_value & BLE_GATT_HVX_INDICATION) != 0);
}
/**@brief Function for encoding a Report Reference Descriptor.
*
* @param[in] p_encoded_buffer The buffer of the encoded data.
* @param[in] p_report_ref Report Reference value to be encoded.
*
* @return Length of the encoded data.
*/
uint8_t ble_srv_report_ref_encode(uint8_t * p_encoded_buffer,
const ble_srv_report_ref_t * p_report_ref);
/**@brief Function for making a UTF-8 structure refer to an ASCII string.
*
* @param[out] p_utf8 UTF-8 structure to be set.
* @param[in] p_ascii ASCII string to be referred to.
*/
void ble_srv_ascii_to_utf8(ble_srv_utf8_str_t * p_utf8, char * p_ascii);
/**@brief Security Access enumeration.
* @details This enumeration gives the possible requirements for accessing a characteristic value.
*/
typedef enum
{
SEC_NO_ACCESS = 0, /**< Not possible to access. */
SEC_OPEN = 1, /**< Access open. */
SEC_JUST_WORKS = 2, /**< Access possible with 'Just Works' security at least. */
SEC_MITM = 3, /**< Access possible with 'MITM' security at least. */
SEC_SIGNED = 4, /**< Access possible with 'signed' security at least. */
SEC_SIGNED_MITM = 5 /**< Access possible with 'signed and MITM' security at least. */
}security_req_t;
/**@brief Characteristic User Descriptor parameters.
* @details This structure contains the parameters for User Descriptor.
*/
typedef struct
{
uint16_t max_size; /**< Maximum size of the user descriptor*/
uint16_t size; /**< Size of the user descriptor*/
uint8_t *p_char_user_desc; /**< User descriptor content, pointer to a UTF-8 encoded string (non-NULL terminated)*/
bool is_var_len; /**< Indicates if the user descriptor has variable length.*/
ble_gatt_char_props_t char_props; /**< user descriptor properties.*/
bool is_defered_read; /**< Indicate if deferred read operations are supported.*/
bool is_defered_write; /**< Indicate if deferred write operations are supported.*/
security_req_t read_access; /**< Security requirement for reading the user descriptor.*/
security_req_t write_access; /**< Security requirement for writing the user descriptor.*/
bool is_value_user; /**< Indicate if the content of the characteristic is to be stored in the application (user) or in the stack.*/
}ble_add_char_user_desc_t;
/**@brief Add characteristic parameters structure.
* @details This structure contains the parameters needed to use the @ref characteristic_add function.
*/
typedef struct
{
uint16_t uuid; /**< Characteristic UUID (16 bits UUIDs).*/
uint8_t uuid_type; /**< Base UUID. If 0, the Bluetooth SIG UUID will be used. Otherwise, this should be a value returned by @ref sd_ble_uuid_vs_add when adding the base UUID.*/
uint16_t max_len; /**< Maximum length of the characteristic value.*/
uint16_t init_len; /**< Initial length of the characteristic value.*/
uint8_t * p_init_value; /**< Initial encoded value of the characteristic.*/
bool is_var_len; /**< Indicates if the characteristic value has variable length.*/
ble_gatt_char_props_t char_props; /**< Characteristic properties.*/
bool is_defered_read; /**< Indicate if deferred read operations are supported.*/
bool is_defered_write; /**< Indicate if deferred write operations are supported.*/
security_req_t read_access; /**< Security requirement for reading the characteristic value.*/
security_req_t write_access; /**< Security requirement for writing the characteristic value.*/
security_req_t cccd_write_access; /**< Security requirement for writing the characteristic's CCCD.*/
bool is_value_user; /**< Indicate if the content of the characteristic is to be stored in the application (user) or in the stack.*/
ble_add_char_user_desc_t *p_user_descr; /**< Pointer to user descriptor if needed*/
ble_gatts_char_pf_t *p_presentation_format; /**< Pointer to characteristic format if needed*/
} ble_add_char_params_t;
/**@brief Add descriptor parameters structure.
* @details This structure contains the parameters needed to use the @ref descriptor_add function.
*/
typedef struct
{
uint16_t uuid; /**< descriptor UUID (16 bits UUIDs).*/
uint8_t uuid_type; /**< Base UUID. If 0, the Bluetooth SIG UUID will be used. Otherwise, this should be a value returned by @ref sd_ble_uuid_vs_add when adding the base UUID.*/
bool is_defered_read; /**< Indicate if deferred read operations are supported.*/
bool is_defered_write; /**< Indicate if deferred write operations are supported.*/
bool is_var_len; /**< Indicates if the descriptor value has variable length.*/
security_req_t read_access; /**< Security requirement for reading the descriptor value.*/
security_req_t write_access; /**< Security requirement for writing the descriptor value.*/
bool is_value_user; /**< Indicate if the content of the characteristic is to be stored in the application (user) or in the stack.*/
uint16_t init_len; /**< Initial descriptor value length in bytes. */
uint16_t init_offs; /**< Initial descriptor value offset in bytes. If different from zero, the first init_offs bytes of the attribute value will be left uninitialized. */
uint16_t max_len; /**< Maximum descriptor value length in bytes, see @ref BLE_GATTS_ATTR_LENS_MAX for maximum values. */
uint8_t* p_value; /**< Pointer to the value of the descriptor*/
} ble_add_descr_params_t;
/**@brief Function for adding a characteristic to a given service.
*
* If no pointer is given for the initial value,
* the initial length parameter will be ignored and the initial length will be 0.
*
* @param[in] service_handle Handle of the service to which the characteristic is to be added.
* @param[in] p_char_props Information needed to add the characteristic.
* @param[out] p_char_handle Handle of the added characteristic.
*
* @retval NRF_SUCCESS If the characteristic was added successfully. Otherwise, an error code is returned.
*/
uint32_t characteristic_add(uint16_t service_handle,
ble_add_char_params_t * p_char_props,
ble_gatts_char_handles_t * p_char_handle);
/**@brief Function for adding a characteristic's descriptor to a given characteristic.
*
* @param[in] char_handle Handle of the characteristic to which the descriptor is to be added, if @ref BLE_GATT_HANDLE_INVALID is used, it will be placed sequentially.
* @param[in] p_descr_props Information needed to add the descriptor.
* @param[out] p_descr_handle Handle of the added descriptor.
*
* @retval NRF_SUCCESS If the characteristic was added successfully. Otherwise, an error code is returned.
*/
uint32_t descriptor_add(uint16_t char_handle,
ble_add_descr_params_t * p_descr_props,
uint16_t * p_descr_handle);
#endif // BLE_SRV_COMMON_H__
/** @} */

View File

@ -0,0 +1,126 @@
/*
* Copyright (c) 2013 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/**
* @file device_manager_cnfg.h
*
* @cond
* @defgroup device_manager_cnfg Device Manager Configuration
* @ingroup device_manager
* @{
*
* @brief Defines application specific configuration for Device Manager.
*
* @details All configurations that are specific to application have been defined
* here. Application should configuration that best suits its requirements.
*/
#ifndef DEVICE_MANAGER_CNFG_H__
#define DEVICE_MANAGER_CNFG_H__
/**
* @defgroup device_manager_inst Device Manager Instances
* @{
*/
/**
* @brief Maximum applications that Device Manager can support.
*
* @details Maximum application that the Device Manager can support.
* Currently only one application can be supported.
* Minimum value : 1
* Maximum value : 1
* Dependencies : None.
*/
#define DEVICE_MANAGER_MAX_APPLICATIONS 1
/**
* @brief Maximum connections that Device Manager should simultaneously manage.
*
* @details Maximum connections that Device Manager should simultaneously manage.
* Minimum value : 1
* Maximum value : Maximum links supported by SoftDevice.
* Dependencies : None.
*/
#define DEVICE_MANAGER_MAX_CONNECTIONS 1
/**
* @brief Maximum bonds that Device Manager should manage.
*
* @details Maximum bonds that Device Manager should manage.
* Minimum value : 1
* Maximum value : 254.
* Dependencies : None.
* @note In case of GAP Peripheral role, the Device Manager will accept bonding procedure
* requests from peers even if this limit is reached, but bonding information will not
* be stored. In such cases, application will be notified with DM_DEVICE_CONTEXT_FULL
* as event result at the completion of the security procedure.
*/
#define DEVICE_MANAGER_MAX_BONDS 7
/**
* @brief Maximum Characteristic Client Descriptors used for GATT Server.
*
* @details Maximum Characteristic Client Descriptors used for GATT Server.
* Minimum value : 1
* Maximum value : 254.
* Dependencies : None.
*/
#define DM_GATT_CCCD_COUNT 2
/**
* @brief Size of application context.
*
* @details Size of application context that Device Manager should manage for each bonded device.
* Size had to be a multiple of word size.
* Minimum value : 4.
* Maximum value : 256.
* Dependencies : Needed only if Application Context saving is used by the application.
* @note If set to zero, its an indication that application context is not required to be managed
* by the module.
*/
#define DEVICE_MANAGER_APP_CONTEXT_SIZE 0
/* @} */
/* @} */
/** @endcond */
#endif // DEVICE_MANAGER_CNFG_H__

View File

@ -0,0 +1,915 @@
/*
* Copyright (c) 2013 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
/**
* @file device_manager.h
*
* @defgroup device_manager Device Manager
* @ingroup ble_sdk_lib
* @{
* @brief Device Manager Application Interface Abstraction.
*
* @details The Device Manager module manages Active and Bonded Peers. Management of peer includes
* book keeping of contextual information like the Security Keys, GATT
* configuration and any application specific information.
*
* Active Peers are devices which are connected, and may or may not be bonded.
* Bonded Peers are devices which are bonded, and may or may not be Active (Connected).
* Active Bonded Peer refers to a device which is connected and bonded.
*
* Paired Devices refers to peer devices that are connected and have necessary context
* establishment/exchange for the current connection session. On disconnect,
* all contextual information is flushed. For example, SMP Information Exchanged during
* pairing and GATT Configuration is not retained on disconnection.
*
* Note that this module allows management of contextual information but
* does not provide an interface for connection management. Therefore, entering connectible
* mode, connection establishment, or disconnection of a link with peer is not in scope
* of this module.
*
* For bonded peers, the contextual information is required to be retained on disconnection
* and power cycling. Persistent storage of contextual information is handled by the
* module. This module categorizes the contextual information into 3 categories:
* - <b>Bonding Information</b>
* Bond information is the information exchanged between local and peer device to
* establish a bond. It also includes peer identification information,
* like the peer address or the IRK or both. From here on this category of information
* is referred to as Device Context.
* - <b>Service/Protocol Information</b>
* Service/Protocol information is the information retained for the peer to save on one-time
* procedures like the GATT Service Discovery procedures and Service Configurations.
* It allows devices to resume data exchange on subsequent reconnection without having
* to perform initial set-up procedures each time. From here on this category is
* referred to as Service Context.
* - <b>Application Information</b>
* Application information is the context that the application would like to associate with
* each of the bonded device. For example, if the application chooses to rank its peers
* in order to manage them better, the rank information could be treated as
* Application Information. This storage space is provided to save the application from
* maintaining a mapping table with each Device Instance and Application Information.
* However, if the application have no use for this, it is possible to not
* use or employ this at compile time. From here on this category of information is
* referred to as Application Context.
*/
#ifndef DEVICE_MANAGER_H__
#define DEVICE_MANAGER_H__
#include <stdint.h>
#include <stdbool.h>
#include "sdk_common.h"
#include "nrf_ble.h"
#include "nrf_ble_gap.h"
#include "device_manager_cnfg.h"
/**
* @defgroup dm_service_cntext_types Service/Protocol Types
*
* @brief Describes the possible types of Service/Protocol Contexts for a bonded/peer device.
*
* @details Possible Service/Protocol context per peer device. The Device Manager provides the
* functionality of persistently storing the Service/Protocol context and can automatically
* load them when needed.
* For example system attributes for a GATT Server. Based on the nature of the application,
* not all service types may be needed. The application can specify
* only the service/protocol context it wants to use at the time of registration.
* @{
*/
#define DM_PROTOCOL_CNTXT_NONE 0x00 /**< No Service Context, this implies the application does not want to associate any service/protocol context with the peer device */
#define DM_PROTOCOL_CNTXT_GATT_SRVR_ID 0x01 /**< GATT Server Service Context, this implies the application does associate GATT Server with the peer device and this information will be loaded when needed for a bonded device */
#define DM_PROTOCOL_CNTXT_GATT_CLI_ID 0x02 /**< GATT Client Service Context, this implies the application does associate GATT Client with the peer device and this information will be loaded when needed for a bonded device */
#define DM_PROTOCOL_CNTXT_ALL \
(DM_PROTOCOL_CNTXT_GATT_SRVR_ID | DM_PROTOCOL_CNTXT_GATT_CLI_ID) /**< All Service/Protocol Context, this implies that the application wants to associate all Service/Protocol Information with the bonded device. This is configurable based on system requirements. If the application has only one type of service, this define could be altered to reflect the same. */
/** @} */
/**
* @defgroup dm_events Device Manager Events
*
* @brief This section describes the device manager events that are notified to the application.
*
* @details The Device Manager notifies the application of various asynchronous events using the
* asynchronous event notification callback. All events has been categorized into:
* a. General.
* b. Link Status.
* c. Context Management.
*
* In the callback, these events are notified along with handle that uniquely identifies:
* application instance, active instance (if applicable), device instance
* bonding instance, (if applicable) and service instance.
* Not all events are pertaining to an active connection, for example a context deletion event could occur even if the peer
* is not connected. Also, general category of events may not be pertaining to any specific peer.
* See also \ref dm_event_cb_t and \ref dm_register.
* @{
*/
/**
* @defgroup general_events General Events
*
* @brief General or miscellaneous events.
*
* @details This category of events are general events not pertaining to a peer or context.
*
* @{
*/
#define DM_EVT_RFU 0x00 /**< Reserved for future use, is never notified. */
#define DM_EVT_ERROR 0x01 /**< Device Manager Event Error. */
/** @} */
/**
* @defgroup link_status_events Link Status Events
*
* @brief Link Status Events.
*
* @details This category of events notify the application of the link status. Event result associated
* with the event is provided along with the event in the callback to provide more details of
* whether a procedure succeeded or failed and assist the application in decision making of
* how to proceed. For example if a DM_DEVICE_CONNECT_IND is indicated with NRF_SUCCESS
* result, the application may want to proceed with discovering and association with
* service of the peer. However, if indicated with a failure result, the application may
* want to take an alternate action such as reattempting to connect or go into a
* sleep mode.
*
* @{
*/
#define DM_EVT_CONNECTION 0x11 /**< Indicates that link with the peer is established. */
#define DM_EVT_DISCONNECTION 0x12 /**< Indicates that link with peer is torn down. */
#define DM_EVT_SECURITY_SETUP 0x13 /**< Security procedure for link started indication */
#define DM_EVT_SECURITY_SETUP_COMPLETE 0x14 /**< Security procedure for link completion indication. */
#define DM_EVT_LINK_SECURED 0x15 /**< Indicates that link with the peer is secured. For bonded devices, subsequent reconnections with bonded peer will result only in this event when the link is secured and setup procedures will not occur unless the bonding information is either lost or deleted on either or both sides. */
#define DM_EVT_SECURITY_SETUP_REFRESH 0x16 /**< Indicates that the security on the link was re-established. */
/** @} */
/**
* @defgroup context_mgmt_events Context Management Events
*
* @brief Context Management Events.
*
* @details These events notify the application of the status of context loading and storing.
*
* @{
*/
#define DM_EVT_DEVICE_CONTEXT_LOADED 0x21 /**< Indicates that device context for a peer is loaded. */
#define DM_EVT_DEVICE_CONTEXT_STORED 0x22 /**< Indicates that device context is stored persistently. */
#define DM_EVT_DEVICE_CONTEXT_DELETED 0x23 /**< Indicates that device context is deleted. */
#define DM_EVT_SERVICE_CONTEXT_LOADED 0x31 /**< Indicates that service context for a peer is loaded. */
#define DM_EVT_SERVICE_CONTEXT_STORED 0x32 /**< Indicates that service context is stored persistently. */
#define DM_EVT_SERVICE_CONTEXT_DELETED 0x33 /**< Indicates that service context is deleted. */
#define DM_EVT_APPL_CONTEXT_LOADED 0x41 /**< Indicates that application context for a peer is loaded. */
#define DM_EVT_APPL_CONTEXT_STORED 0x42 /**< Indicates that application context is stored persistently. */
#define DM_EVT_APPL_CONTEXT_DELETED 0x43 /**< Indicates that application context is deleted. */
/** @} */
/** @} */
#define DM_INVALID_ID 0xFF /**< Invalid instance idenitifer. */
/**
* @defgroup dm_data_structure Device Manager Data Types
*
* @brief This section describes all the data types exposed by the module to the application.
* @{
*/
/**
* @brief Application Instance.
*
* @details Application instance uniquely identifies an application. The identifier is allocated by
* the device manager when application registers with the module. The application is
* expected to identify itself with this instance identifier when initiating subsequent
* requests. Application should use the utility API \ref dm_application_instance_set in
* order to set its application instance in dm_handle_t needed for all subsequent APIs.
* See also \ref dm_register.
*/
typedef uint8_t dm_application_instance_t;
/**
* @brief Connection Instance.
*
* @details Identifies connection instance for an active device. This instance is allocated by the
* device manager when a connection is established and is notified with DM_EVT_CONNECTION
* with the event result NRF_SUCCESS.
*/
typedef uint8_t dm_connection_instance_t;
/**
* @brief Device Instance.
*
* @details Uniquely identifies a bonded peer device. The peer device may or may not be connected.
* In case of the central: The bonded device instance to identify the peer is allocated when bonding procedure is initiated by the central using dm_security_setup_req.
* In case of the peripheral: When the bonding procedure is successful, the DM_EVT_SECURITY_SETUP_COMPLETE event with success event result, is received.
* In case the module cannot add more bonded devices, no instance is allocated, this is indicated by an appropriate error code for the API/event as the case may be. Application can choose to disconnect the link.
*/
typedef uint8_t dm_device_instance_t;
/**
* @brief Service Instance.
*
* @details Uniquely identifies a peer device. The peer device may or may not be connected. This
* instance is allocated by the device manager when a device is bonded and is notified
* when security procedures have been initiated.
* Security Procedures initiation is notified with DM_SECURITY_SETUP_IND with
* success event result. In case the event result indicates that the module cannot add more
* bonded devices, no instance is allocated. Application can chose to disconnect the link.
*/
typedef uint8_t dm_service_instance_t;
/**
* @brief Service/Protocol Type Identifier.
*
* @details Uniquely identifies a service or a protocol type. Service/Protocol Type identification
* is needed as each service/protocol can have its own contextual data.
* This allows the peer to access more than one service at a time. \ref dm_service_cntext_types describes the
* list of services/protocols supported.
*/
typedef uint8_t service_type_t;
/**@brief Device Manager Master identification and encryption information. */
typedef struct dm_enc_key
{
ble_gap_enc_info_t enc_info; /**< GAP encryption information. */
ble_gap_master_id_t master_id; /**< Master identification. */
} dm_enc_key_t;
/** @brief Device Manager identity and address information. */
typedef struct dm_id_key
{
ble_gap_irk_t id_info; /**< Identity information. */
ble_gap_addr_t id_addr_info; /**< Identity address information. */
} dm_id_key_t;
/** @brief Device Manager signing information. */
typedef struct dm_sign_key
{
ble_gap_sign_info_t sign_key; /**< GAP signing information. */
} dm_sign_key_t;
/** @brief Security keys. */
typedef struct dm_sec_keyset
{
union
{
dm_enc_key_t * p_enc_key; /**< Pointer to Device Manager encryption information structure. */
} enc_key;
dm_id_key_t * p_id_key; /**< Identity key, or NULL. */
dm_sign_key_t * p_sign_key; /**< Signing key, or NULL. */
} dm_sec_keys_t;
/** @brief Device Manager security key set. */
typedef struct
{
dm_sec_keys_t keys_periph; /**< Keys distributed by the device in the Peripheral role. */
dm_sec_keys_t keys_central; /**< Keys distributed by the device in the Central role. */
} dm_sec_keyset_t;
/**
* @brief Device Handle used for unique identification of each peer.
*
* @details This data type is used to uniquely identify each peer device. A peer device could be
* active and/or bonded. Therefore an instance for active and bonded is provided.
* However, the application is expected to treat this is an opaque structure and use this for
* all API interactions once stored on appropriate events.
* See \ref dm_events.
*/
typedef struct device_handle
{
dm_application_instance_t appl_id; /**< Identifies the application instances for the device that is being managed. */
dm_connection_instance_t connection_id; /**< Identifies the active connection instance. */
dm_device_instance_t device_id; /**< Identifies peer instance in the data base. */
dm_service_instance_t service_id; /**< Service instance identifier. */
} dm_handle_t;
/**
* @brief Definition of Data Context.
*
* @details Defines contextual data format, it consists of context data length and pointer to data.
*/
typedef struct
{
uint32_t flags; /**< Additional flags identifying data. */
uint32_t len; /**< Length of data. */
uint8_t * p_data; /**< Pointer to contextual data, a copy is made of the data. */
} dm_context_t;
/**
* @brief Device Context.
*
* @details Defines "device context" type for a device managed by device manager.
*/
typedef dm_context_t dm_device_context_t;
/**
* @brief Service Context.
*
* @details Service context data for a service identified by the 'service_type' field.
*/
typedef struct
{
service_type_t service_type; /**< Identifies the service/protocol to which the context data is related. */
dm_context_t context_data; /**< Contains length and pointer to context data */
} dm_service_context_t;
/**
* @brief Application context.
*
* @details The application context can be used by the application to map any application level
* information that is to be mapped with a particular peer.
* For bonded peers, this information will be stored by the bond manager persistently.
* Note that the device manager treats this information as an
* opaque block of bytes.
* Necessary APIs to get and set this context for a peer have been provided.
*/
typedef dm_context_t dm_application_context_t;
/**
* @brief Event parameters.
*
* @details Defines event parameters for each of the events notified by the module.
*/
typedef union
{
ble_gap_evt_t * p_gap_param; /**< All events that are triggered in device manager as a result of GAP events, like connection, disconnection and security procedures are accompanied with GAP parameters. */
dm_application_context_t * p_app_context; /**< All events that are associated with application context procedures of store, load, and deletion have this as event parameter. */
dm_service_context_t * p_service_context; /**< All events that are associated with service context procedures of store, load and deletion have this as event parameter. */
dm_device_context_t * p_device_context; /**< All events that are associated with device context procedures of store, load and deletion have this as event parameter. */
} dm_event_param_t;
/**
* @brief Asynchronous events details notified to the application by the module.
*
* @details Defines event type along with event parameters notified to the application by the
* module.
*/
typedef struct
{
uint8_t event_id; /**< Identifies the event. See \ref dm_events for details on event types and their significance. */
dm_event_param_t event_param; /**< Event parameters. Can be NULL if the event does not have any parameters. */
uint16_t event_paramlen; /**< Length of the event parameters, is zero if the event does not have any parameters. */
} dm_event_t;
/**
* @brief Event notification callback registered by application with the module.
*
* @details Event notification callback registered by application with the module when registering
* the module using \ref dm_register API.
*
* @param[in] p_handle Identifies the peer for which the event is being notified.
* @param[in] p_event Identifies the event, any associated parameters and parameter length.
* See \ref dm_events for details on event types and their significance.
* @param[in,out] event_result Provide additional information on the event.
* In addition to SDK error codes there is also a return value
* indicating if maximum number of connections has been reached when connecting or bonding.
*
* @retval NRF_SUCCESS on success, or a failure to indicate if it could handle the event
* successfully. There is no action taken in case application returns a failure.
*/
typedef ret_code_t (*dm_event_cb_t)(dm_handle_t const * p_handle,
dm_event_t const * p_event,
ret_code_t event_result);
/**
* @brief Initialization Parameters.
*
* @details Indicates the application parameters. Currently this only encompasses clearing
* all persistent data.
*/
typedef struct
{
bool clear_persistent_data; /**< Set to true in case the module should clear all persistent data. */
} dm_init_param_t;
/**
* @brief Application Registration Parameters.
*
* @details Parameters needed by the module when registering with it.
*/
typedef struct
{
dm_event_cb_t evt_handler; /**< Event Handler to be registered. It will receive asynchronous notification from the module, see \ref dm_events for asynchronous events. */
uint8_t service_type; /**< Bit mask identifying services that the application intends to support for all peers. */
ble_gap_sec_params_t sec_param; /**< Security parameters to be used for the application. */
} dm_application_param_t;
/**
* @brief Defines possible security status/states.
*
* @details Defines possible security status/states of a link when requested by application using
* the \ref dm_security_status_req.
*/
typedef enum
{
NOT_ENCRYPTED, /**< The link is not secured. */
ENCRYPTION_IN_PROGRESS, /**< Link security is being established.*/
ENCRYPTED /**< The link is secure.*/
} dm_security_status_t;
/** @} */
/**
* @defgroup dm_api Device Module APIs
*
* @brief This section describes APIs exposed by the module.
*
* @details This section describes APIs exposed by the module. The APIs have been categorized to provide
* better and specific look up for developers. Categories are:
* - Set up APIs.
* - Context Management APIs.
* - Utility APIs.
*
* MSCs describe usage of these APIs.
* See @ref dm_msc.
* @{
*/
/**
* @defgroup dm_setup_api Device Module Set-up APIs
*
* @brief Initialization & registration APIs that are pre-requisite for all other module procedures.
* @details This section describes the Module Initialization and Registration APIs needed to be set up by
* the application before device manager can start managing devices and device contexts
* for the application.
*
* @{
*/
/**
* @brief Module Initialization Routine.
*
* @details Function for initializing the module. Must called before any other APIs of the module are used.
*
* @param[in] p_init_param Initialization parameters.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
*
* @note It is mandatory that pstorage is initialized before initializing this module.
*/
ret_code_t dm_init(dm_init_param_t const * p_init_param);
/**
* @brief Function for registering the application.
*
* @details This routine is used by the application to register for asynchronous events with the
* device manager. During registration the application also indicates the services that it
* intends to support on this instance. It is possible to register multiple times with the
* device manager. At least one instance shall be registered with the device manager after
* the module has been initialized.
* Maximum number of application instances device manager can support is determined
* by DM_MAX_APPLICATIONS.
*
* All applications must be registered before initiating or accepting connections from the peer.
*
* @param[in] p_appl_param Application parameters.
* @param[out] p_appl_instance Application Instance Identifier in case registration is successful.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE If the API is called without module initialization.
* @retval NRF_ERROR_NO_MEM If module cannot support more applications.
*
* @note Currently only one application instance is supported by the module.
*/
ret_code_t dm_register(dm_application_instance_t * p_appl_instance,
dm_application_param_t const * p_appl_param);
/**
* @brief Function for handling BLE events.
*
* @details BLE Event Handler for the module. This routine should be called from BLE stack event
* dispatcher for the module to work as expected.
*
* @param[in] p_ble_evt BLE stack event being dispatched to the function.
*
*/
void dm_ble_evt_handler(ble_evt_t * p_ble_evt);
/** @} */
/**
* @defgroup dm_security_api APIs to set up or read status of security on a link.
*
* @brief This section describes APIs to set up Security. These APIs require that the peer is
* connected before the procedures can be requested.
*
* @details This group allows application to request security procedures
* or get the status of the security on a link.
* @{
*/
/**
* @brief Function for requesting setting up security on a link.
*
* @details This API initiates security procedures with a peer device.
* @note For the GAP Central role, in case peer is not bonded, request to bond/pair is
* initiated. If it is bonded, the link is re-encrypted using the existing bond information.
* For the GAP peripheral role, a Slave security request is sent.
* @details If a pairing procedure is initiated successfully, application is notified of
* @ref DM_EVT_SECURITY_SETUP_COMPLETE. A result indicating success or failure is notified along with the event.
* In case the link is re-encrypted using existing bond information, @ref DM_EVT_LINK_SECURED is
* notified to the application.
*
* @param[in] p_handle Identifies the link on which security is desired.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE If the API is called without module initialization and/or
* application registration.
* @retval NRF_ERROR_NULL If p_handle is NULL.
* @retval NRF_ERROR_INVALID_ADDR If the peer is not identified by the handle provided by the application
* or if the peer is not connected when this procedure is requested.
*/
ret_code_t dm_security_setup_req(dm_handle_t * p_handle);
/**
* @brief Function for reading the status of the security on a link.
*
* @details This API allows application to query status of security on a link.
*
* @param[in] p_handle Identifies the link on which security is desired.
* @param[out] p_status Pointer where security status is provided to the application.
* See \ref dm_security_status_t for possible statuses that can be expected.
*
* @retval NRF_SUCCESS Or appropriate error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE If the API is called without module initialization and/or
* application registration.
* @retval NRF_ERROR_NULL If p_handle or p_status is NULL.
* @retval NRF_ERROR_INVALID_ADDR If peer is not identified by the handle provided by the application
* or if peer is not connected when this procedure is requested.
*/
ret_code_t dm_security_status_req(dm_handle_t const * p_handle, dm_security_status_t * p_status);
/**
* @brief Function for creating the whitelist.
*
* @details This API allows application to create whitelist based on bonded peer devices in module
* data base.
*
* @param[in] p_handle Identifies the application requesting whitelist creation.
* @param[in,out] p_whitelist Pointer where created whitelist is provided to the application.
*
* @note 'addr_count' and 'irk_count' fields of the structure should be populated with the maximum
* number of devices that the application wishes to request in the whitelist.
* If the number of bonded devices is less than requested, the fields are updated with that number of devices.
* If the number of devices are more than requested, the module will populate the list
* with devices in the order the bond was established with the peer devices. Also, if this routine is
* called when a connection exists with one or more peer devices,
* those connected devices are not added to the whitelist.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE If the API is called without module initialization and/or
* application registration.
* @retval NRF_ERROR_NULL If p_handle or p_whitelist is NULL.
*/
ret_code_t dm_whitelist_create(dm_application_instance_t const * p_handle,
ble_gap_whitelist_t * p_whitelist);
/** @} */
/**
* @defgroup dm_cntxt_mgmt_api Context Management APIs
*
* @brief Utility APIs offered by the device manager to get information about the peer if and
* when needed.
*
* @details This group of API allow the application to access information that is not required to be
* maintained by the application but may be needed. Hence it is possible to get the
* information from the module instead of mapping all the information with a device
* context.
* @{
*/
ret_code_t dm_device_add(dm_handle_t * p_handle,
dm_device_context_t const * p_context);
/**
* @brief Function for deleting a peer device context and all related information from the database.
*
* @details Delete peer device context and all related information from database. If
* this API returns NRF_SUCCESS, DM_EVT_DEVICE_CONTEXT_DELETED event is notified to the
* application. Event result notified along with the event indicates success or failure
* of this procedure.
*
* @param[in] p_handle Identifies the peer device to be deleted.
*
* @retval NRF_SUCCESS on success, else an error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE In the API is called without module initialization and/or
* application registration.
* @retval NRF_ERROR_NULL If p_handle is NULL.
* @retval NRF_ERROR_INVALID_ADDR If peer is not identified the handle provided by the application.
*
* @note Deleting device context results in deleting service and application context for the
* bonded device. The respective events DM_EVT_SERVICE_CONTEXT_DELETED and
* DM_EVT_APPL_CONTEXT_DELETED are not notified to the application.
*/
ret_code_t dm_device_delete(dm_handle_t const * p_handle);
/**
* @brief Function for deleting all peer device context and all related information from the database.
*
* @details Delete peer device context and all related information from database. If
* this API returns NRF_SUCCESS, DM_EVT_DEVICE_CONTEXT_DELETED event is notified to the
* application for each device that is deleted from the data base. Event result
* notified along with the event indicates success or failure of this procedure.
*
* @param[in] p_handle Identifies application instance that is requesting
* the deletion of all bonded devices.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE If the API is called without module initialization and/or
* application registration.
* @retval NRF_ERROR_NULL If p_handle is NULL.
* @retval NRF_ERROR_INVALID_ADDR If peer is not identified the handle provided by the application.
*
* @note Deleting device context results in deleting both service and application context for the
* bonded device. The respective events DM_EVT_SERVICE_CONTEXT_DELETED and
* DM_EVT_APPL_CONTEXT_DELETED are not notified to the application.
*/
ret_code_t dm_device_delete_all(dm_application_instance_t const * p_handle);
/**
* @brief Function for setting Service Context for a peer device identified by 'p_handle' parameter.
*
* @details This API allows application to Set Service Context for a peer device identified by the
* 'p_handle' parameter. This API is useful when the Service Context cannot be requested
* from the SoftDevice, but needs to be assembled by the application or an another module.
* (or when service context is exchanged in an out of band way.)
* This API could also be used to trigger a storing of service context into persistent
* memory. If this is desired, a NULL pointer could be passed to the p_context.
*
* @param[in] p_handle Identifies peer device for which the procedure is requested.
* @param[in] p_context Service context being set. The context information includes length of
* data and pointer to the contextual data being set. The memory pointed to by
* the pointer to data is assumed to be resident when API is being called and
* can be freed or reused once the set procedure is complete. Set procedure
* completion is indicated by the event \ref DM_EVT_SERVICE_CONTEXT_STORED.
* The Event result is notified along with the event and indicates success or failure of
* this procedure.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE If the API is called without module initialization and/or
* application registration.
* @retval NRF_ERROR_NULL If p_handle is NULL.
* @retval NRF_ERROR_INVALID_ADDR If the peer is not identified by the handle provided by the application.
*/
ret_code_t dm_service_context_set(dm_handle_t const * p_handle,
dm_service_context_t const * p_context);
/**
* @brief Function for getting Service Context for a peer device identified by 'p_handle' parameter.
*
* @details Get Service Context for a peer device identified by the 'p_handle' parameter. If
* this API returns NRF_SUCCESS, DM_EVT_SERVICE_CONTEXT_LOADED event is notified to the
* application. The event result is notified along with the event indicates success or failure
* of this procedure.
*
* @param[in] p_handle Identifies peer device for which procedure is requested.
* @param[in] p_context Application context being requested. The context information includes length
* of the data and a pointer to the data. Note that requesting a 'get'
* of application does not need to provide memory, the pointer to data will be
* pointing to service data and hence no data movement is involved.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE In case API is called without module initialization and/or
* application registration.
* @retval NRF_ERROR_NULL If p_handle is NULL.
* @retval NRF_ERROR_INVALID_ADDR If the peer is not identified by the handle provided by the application.
*/
ret_code_t dm_service_context_get(dm_handle_t const * p_handle,
dm_service_context_t * p_context);
/**
* @brief Function for deleting a Service Context for a peer device identified by the 'p_handle' parameter.
*
* @details This API allows application to delete a Service Context identified for a peer device
* identified by the 'p_handle' parameter. If this API returns NRF_SUCCESS,
* DM_EVT_SERVICE_CONTEXT_DELETED event is notified to the application.
* Event result is notified along with the event and indicates success or failure of this
* procedure.
*
* @param[in] p_handle Identifies peer device for which procedure is requested.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE If the API is called without module initialization and/or
* application registration.
* @retval NRF_ERROR_NULL If p_handle is NULL.
* @retval NRF_ERROR_INVALID_ADDR If the peer is not identified by the handle provided by the application.
*/
ret_code_t dm_service_context_delete(dm_handle_t const * p_handle);
/**
* @brief Function for setting Application Context for a peer device identified by the 'p_handle' parameter.
*
* @details This application allows the setting of the application context for the peer device identified by
* the 'p_handle'. Application context is stored persistently by the module and can be
* requested by the application at any time using the \ref dm_application_context_get
* API. Note that this procedure is permitted only for bonded devices. If the
* device is not bonded, application context cannot be set. However, it is not mandatory
* that the bonded device is connected when requesting this procedure.
*
* @param[in] p_handle Identifies peer device for which procedure is requested.
*
* @param[in] p_context Application context being set. The context information includes length of the
* data and pointer to the contextual data being set. The memory pointed to by
* the data pointer is assumed to be resident when API is being called and
* can be freed or reused once the set procedure is complete. Set procedure
* completion is notified by the event \ref DM_EVT_APPL_CONTEXT_STORED.
* The event result is notified along with the event and indicates success or
* failure of this procedure.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE If the API is called without module initialization and/or
* application registration.
* @retval NRF_ERROR_NULL If p_handle and/or p_context is NULL.
* @retval NRF_ERROR_INVALID_ADDR If peer is not identified the handle provided by the application.
*
* @note The API returns FEATURE_NOT_ENABLED in case DEVICE_MANAGER_APP_CONTEXT_SIZE is set to zero.
*/
ret_code_t dm_application_context_set(dm_handle_t const * p_handle,
dm_application_context_t const * p_context);
/**
* @brief Function for getting Application Context for a peer device identified by the 'p_handle' parameter.
*
* @details Get Application Context for a peer device identified by the 'p_handle' parameter. If
* this API returns NRF_SUCCESS, DM_EVT_APPL_CONTEXT_LOADED event is notified to the
* application. Event result notified along with the event indicates success or failure
* of this procedure.
*
* @param[in] p_handle Identifies peer device for which procedure is requested.
* @param[in] p_context Application context being requested. The context information includes
* length of data and pointer to the contextual data is provided.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE If the API is called without module initialization and/or
* application registration.
* @retval NRF_ERROR_NULL If p_handle and/or p_context is NULL.
* @retval NRF_ERROR_INVALID_ADDR If the peer is not identified by the handle provided by the application.
* @retval DM_NO_APP_CONTEXT If no application context was set that can be fetched.
*
* @note The API returns FEATURE_NOT_ENABLED in case DEVICE_MANAGER_APP_CONTEXT_SIZE is set to
* zero.
*/
ret_code_t dm_application_context_get(dm_handle_t const * p_handle,
dm_application_context_t * p_context);
/**
* @brief Function for deleting Application Context for a peer device identified by the 'p_handle' parameter.
*
* @details Delete Application Context for a peer device identified by the 'p_handle' parameter. If
* this API returns NRF_SUCCESS, DM_EVT_APPL_CONTEXT_DELETED event is notified to the
* application. The event result notified along with the event and indicates success or failure
* of this procedure.
*
* @param[in] p_handle Identifies peer device for which procedure is requested.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE If the API is called without module initialization and/or
* application registration.
* @retval NRF_ERROR_NULL If the p_handle is NULL.
* @retval NRF_ERROR_INVALID_ADDR If peer is not identified the handle provided by the application.
* @retval DM_NO_APP_CONTEXT If no application context was set that can be deleted.
*
* @note The API returns FEATURE_NOT_ENABLED if the DEVICE_MANAGER_APP_CONTEXT_SIZE is set to zero.
*/
ret_code_t dm_application_context_delete(dm_handle_t const * p_handle);
/** @} */
/**
* @defgroup utility_api Utility APIs
* @{
* @brief This section describes the utility APIs offered by the module.
*
* @details APIs defined in this section are utility or assisting/helper APIs.
*/
/**
* @brief Function for Setting/Copying Application instance to Device Manager handle.
*
* @param[in] p_appl_instance Application instance to be set.
* @param[out] p_handle Device Manager handle for which the instance is to be copied.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE If the API is called without module initialization and/or
* application registration.
* @retval NRF_ERROR_NULL If p_handle and/or p_addr is NULL.
*/
ret_code_t dm_application_instance_set(dm_application_instance_t const * p_appl_instance,
dm_handle_t * p_handle);
/**
* @brief Function for getting a peer's device address.
*
* @param[in] p_handle Identifies the peer device whose address is requested. Can not be NULL.
* @param[out] p_addr Pointer where address is to be copied. Can not be NULL.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE If the API is called without module initialization and/or
* application registration.
* @retval NRF_ERROR_NULL If p_handle and/or p_addr is NULL.
* @retval NRF_ERROR_NOT_FOUND If the peer could not be identified.
*/
ret_code_t dm_peer_addr_get(dm_handle_t const * p_handle,
ble_gap_addr_t * p_addr);
/**
* @brief Function for setting/updating a peer's device address.
*
* @param[in] p_handle Identifies the peer device whose address is requested to be set/updated.
* @param[out] p_addr Address to be set/updated.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE If the API is called without module initialization and/or
* application registration.
* @retval NRF_ERROR_NULL If p_handle and/or p_addr is NULL.
* @retval NRF_ERROR_INVALID_ADDR If the peer is not identified by the handle provided by the application.
* @retval NRF_ERROR_INVALID_PARAM If this procedure is requested while connected to the peer or if the address
* type was set to BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE.
*
* @note Setting or updating a peer's device address is permitted
* only for a peer that is bonded and disconnected.
* @note Updated address is reflected only after DM_EVT_DEVICE_CONTEXT_STORED is notified to the
* application for this bonded device instance. In order to avoid abnormal behaviour, it is
* recommended to not invite/initiate connections on the updated address unless this event
* has been notified.
*/
ret_code_t dm_peer_addr_set(dm_handle_t const * p_handle,
ble_gap_addr_t const * p_addr);
/**
* @brief Function for initializing Device Manager handle.
*
* @param[in] p_handle Device Manager handle to be initialized.
*
* @retval NRF_SUCCESS On success.
* @retval NRF_ERROR_NULL If p_handle is NULL.
*
* @note This routine is permitted before initialization of the module.
*/
ret_code_t dm_handle_initialize(dm_handle_t * p_handle);
/**
* @brief Function for getting distributed keys for a device.
*
* @param[in] p_handle Device Manager handle identifying the peer.
* @param[out] p_key_dist Pointer to distributed keys.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
* @retval NRF_ERROR_INVALID_STATE If the API is called without module initialization and/or
* application registration.
* @retval NRF_ERROR_NULL If the p_handle and/or p_key_dist pointer is NULL.
* @retval NRF_ERROR_INVALID_ADDR If the peer is not identified by the handle provided by the application.
*/
ret_code_t dm_distributed_keys_get(dm_handle_t const * p_handle,
dm_sec_keyset_t * p_key_dist);
/**
* @brief Function for getting the corresponding dm_handle_t based on the connection handle.
*
* @param[in] conn_handle Connection handle as provided by the SoftDevice.
* @param[in,out] p_handle Pointer to the p_handle containg the application instance for the
* registered application. If the application instance is valid then
* the p_handle will be filled with requested data.
*
* @retval NRF_SUCCESS On success, else an error code indicating reason for failure.
* @retval NRF_ERROR_NULL If the p_handle pointer is NULL.
* @retval NRF_ERROR_NOT_FOUND If no p_handle is found for the provided connection handle.
*/
ret_code_t dm_handle_get(uint16_t conn_handle, dm_handle_t * p_handle);
/** @} */
/** @} */
/** @} */
#endif // DEVICE_MANAGER_H__

View File

@ -0,0 +1,595 @@
/*
* Copyright (c) 2015 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#include "gatt_cache_manager.h"
#include "nrf_ble_gap.h"
#include "ble_conn_state.h"
#include "peer_manager_types.h"
#include "peer_manager_internal.h"
#include "peer_database.h"
#include "id_manager.h"
#include "security_dispatcher.h"
#include "gatts_cache_manager.h"
#include "gattc_cache_manager.h"
#include "sdk_common.h"
/**@brief Structure containing the module variable(s) of the GCM module.
*/
typedef struct
{
gcm_evt_handler_t evt_handler; /**< The event handler to use for outbound GSCM events. */
ble_conn_state_user_flag_id_t flag_id_local_db_update_pending; /**< Flag ID for flag collection to keep track of which connections need a local DB update procedure. */
ble_conn_state_user_flag_id_t flag_id_local_db_apply_pending; /**< Flag ID for flag collection to keep track of which connections need a local DB apply procedure. */
ble_conn_state_user_flag_id_t flag_id_service_changed_pending; /**< Flag ID for flag collection to keep track of which connections need to be sent a service changed indication. */
ble_conn_state_user_flag_id_t flag_id_service_changed_sent; /**< Flag ID for flag collection to keep track of which connections have been sent a service changed indication and are waiting for a handle value confirmation. */
} gcm_t;
static gcm_t m_gcm; /**< Instantiation of module variable(s). */
#define MODULE_INITIALIZED (m_gcm.evt_handler != NULL)
#include "sdk_macros.h"
static void service_changed_pending_flags_check(void);
/**@brief Function for resetting the module variable(s) of the GSCM module.
*
* @param[out] The instance to reset.
*/
static void internal_state_reset(gcm_t * p_gcm)
{
memset(p_gcm, 0, sizeof(gcm_t));
}
/**@brief Function for checking a write event for whether a CCCD was written during the write
* operation.
*
* @param[in] p_write_evt The parameters of the write event.
*
* @return Whether the write was on a CCCD.
*/
static bool cccd_written(ble_gatts_evt_write_t * p_write_evt)
{
return ( (p_write_evt->op == BLE_GATTS_OP_WRITE_REQ)
&& (p_write_evt->uuid.type == BLE_UUID_TYPE_BLE)
&& (p_write_evt->uuid.uuid == BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG)
);
}
/**@brief Function for performing the local DB update procedure in an event context, where no return
* code can be given.
*
* @details This function will do the procedure, and check the result, set a flag if needed, and
* send an event if needed.
*
* @param[in] conn_handle The connection to perform the procedure on.
*/
static void local_db_apply_in_evt(uint16_t conn_handle)
{
bool set_procedure_as_pending = false;
ret_code_t err_code;
gcm_evt_t event;
if (conn_handle == BLE_CONN_HANDLE_INVALID)
{
return;
}
err_code = gscm_local_db_cache_apply(conn_handle);
switch(err_code)
{
case NRF_SUCCESS:
event.evt_id = GCM_EVT_LOCAL_DB_CACHE_APPLIED;
event.peer_id = im_peer_id_get_by_conn_handle(conn_handle);
event.params.local_db_cache_applied.conn_handle = conn_handle;
m_gcm.evt_handler(&event);
break;
case NRF_ERROR_BUSY:
set_procedure_as_pending = true;
break;
case NRF_ERROR_INVALID_DATA:
event.evt_id = GCM_EVT_ERROR_LOCAL_DB_CACHE_APPLY;
event.peer_id = im_peer_id_get_by_conn_handle(conn_handle);
event.params.error_local_db_cache_apply.conn_handle = conn_handle;
m_gcm.evt_handler(&event);
break;
case BLE_ERROR_INVALID_CONN_HANDLE:
/* Do nothing */
break;
default:
event.evt_id = GCM_EVT_ERROR_UNEXPECTED;
event.peer_id = im_peer_id_get_by_conn_handle(conn_handle);
event.params.error_unexpected.conn_handle = conn_handle;
event.params.error_unexpected.error = err_code;
m_gcm.evt_handler(&event);
break;
}
ble_conn_state_user_flag_set(conn_handle, m_gcm.flag_id_local_db_apply_pending, set_procedure_as_pending);
}
/**@brief Function for performing the local DB apply procedure in an event context, where no return
* code can be given.
*
* @details This function will do the procedure, and check the result, set a flag if needed, and
* send an event if needed.
*
* @param[in] conn_handle The connection to perform the procedure on.
*/
static void local_db_update_in_evt(uint16_t conn_handle)
{
gcm_evt_t event;
bool set_procedure_as_pending = false;
ret_code_t err_code = gscm_local_db_cache_update(conn_handle);
switch(err_code)
{
case NRF_SUCCESS:
event.evt_id = GCM_EVT_LOCAL_DB_CACHE_UPDATED;
event.params.local_db_cache_applied.conn_handle = conn_handle;
event.peer_id = im_peer_id_get_by_conn_handle(conn_handle);
m_gcm.evt_handler(&event);
break;
case BLE_ERROR_INVALID_CONN_HANDLE:
/* Do nothing */
break;
case NRF_ERROR_BUSY:
set_procedure_as_pending = true;
break;
case NRF_ERROR_DATA_SIZE:
event.evt_id = GCM_EVT_ERROR_DATA_SIZE;
event.params.error_data_size.conn_handle = conn_handle;
event.peer_id = im_peer_id_get_by_conn_handle(conn_handle);
m_gcm.evt_handler(&event);
break;
case NRF_ERROR_NO_MEM:
event.evt_id = GCM_EVT_ERROR_STORAGE_FULL;
event.params.error_no_mem.conn_handle = conn_handle;
event.peer_id = im_peer_id_get_by_conn_handle(conn_handle);
m_gcm.evt_handler(&event);
break;
default:
event.evt_id = GCM_EVT_ERROR_UNEXPECTED;
event.peer_id = im_peer_id_get_by_conn_handle(conn_handle);
event.params.error_unexpected.conn_handle = conn_handle;
event.params.error_unexpected.error = err_code;
m_gcm.evt_handler(&event);
break;
}
ble_conn_state_user_flag_set(conn_handle, m_gcm.flag_id_local_db_update_pending, set_procedure_as_pending);
}
/**@brief Function for sending a service changed indication in an event context, where no return
* code can be given.
*
* @details This function will do the procedure, and check the result, set a flag if needed, and
* send an event if needed.
*
* @param[in] conn_handle The connection to perform the procedure on.
*/
static void service_changed_send_in_evt(uint16_t conn_handle)
{
gcm_evt_t event;
bool sc_pending_state = true;
bool sc_sent_state = false;
ret_code_t err_code = gscm_service_changed_ind_send(conn_handle);
switch(err_code)
{
case NRF_SUCCESS:
sc_sent_state = true;
event.evt_id = GCM_EVT_SERVICE_CHANGED_IND_SENT;
event.peer_id = im_peer_id_get_by_conn_handle(conn_handle);
event.params.service_changed_ind_sent.conn_handle = conn_handle;
m_gcm.evt_handler(&event);
break;
case NRF_ERROR_BUSY:
// Do nothing.
break;
case NRF_ERROR_INVALID_STATE:
// CCCDs not enabled. Drop indication.
// Fallthrough.
case NRF_ERROR_NOT_SUPPORTED:
// Service changed not supported. Drop indication.
sc_pending_state = false;
gscm_db_change_notification_done(im_peer_id_get_by_conn_handle(conn_handle));
break;
case BLE_ERROR_GATTS_SYS_ATTR_MISSING:
local_db_apply_in_evt(conn_handle);
break;
case BLE_ERROR_INVALID_CONN_HANDLE:
// Do nothing.
break;
default:
event.evt_id = GCM_EVT_ERROR_UNEXPECTED;
event.params.error_unexpected.conn_handle = conn_handle;
event.params.error_unexpected.error = err_code;
event.peer_id = im_peer_id_get_by_conn_handle(conn_handle);
m_gcm.evt_handler(&event);
break;
}
ble_conn_state_user_flag_set(conn_handle, m_gcm.flag_id_service_changed_pending, sc_pending_state);
ble_conn_state_user_flag_set(conn_handle, m_gcm.flag_id_service_changed_sent, sc_sent_state);
}
/**@brief Callback function for events from the GATT Cache Server Manager module.
*
* @param[in] p_event The event from the GATT Cache Server Manager module.
*/
static void gscm_evt_handler(gscm_evt_t const * p_event)
{
gcm_evt_t event;
event.peer_id = p_event->peer_id;
switch (p_event->evt_id)
{
case GSCM_EVT_LOCAL_DB_CACHE_STORED:
event.evt_id = GCM_EVT_LOCAL_DB_CACHE_STORED;
m_gcm.evt_handler(&event);
local_db_apply_in_evt(im_conn_handle_get(p_event->peer_id));
break;
case GSCM_EVT_LOCAL_DB_CACHE_UPDATED:
event.evt_id = GCM_EVT_LOCAL_DB_CACHE_UPDATED;
event.params.local_db_cache_updated.conn_handle = p_event->params.local_db_cache_updated.conn_handle;
m_gcm.evt_handler(&event);
break;
case GSCM_EVT_SC_STATE_STORED:
if (p_event->params.sc_state_stored.state)
{
uint16_t conn_handle = im_conn_handle_get(p_event->peer_id);
if (conn_handle != BLE_CONN_HANDLE_INVALID)
{
ble_conn_state_user_flag_set(conn_handle, m_gcm.flag_id_service_changed_pending, true);
service_changed_pending_flags_check();
}
}
break;
}
}
/**@brief Callback function for events from the GATT Cache Client Manager module.
*
* @param[in] p_event The event from the GATT Cache Client Manager module.
*/
static void gccm_evt_handler(gccm_evt_t const * p_event)
{
}
/**@brief Callback function for events from the Identity Manager module.
*
* @param[in] p_event The event from the Identity Manager module.
*/
static void im_evt_handler(im_evt_t const * p_event)
{
switch (p_event->evt_id)
{
case IM_EVT_BONDED_PEER_CONNECTED:
local_db_apply_in_evt(p_event->conn_handle);
if (gscm_service_changed_ind_needed(p_event->conn_handle))
{
ble_conn_state_user_flag_set(p_event->conn_handle, m_gcm.flag_id_service_changed_pending, true);
}
break;
default:
break;
}
}
/**@brief Callback function for events from the Security Dispatcher module.
*
* @param[in] p_event The event from the Security Dispatcher module.
*/
static void smd_evt_handler(smd_evt_t const * p_event)
{
switch (p_event->evt_id)
{
case SMD_EVT_BONDING_INFO_STORED:
local_db_update_in_evt(p_event->conn_handle);
break;
default:
break;
}
}
ret_code_t gcm_init(gcm_evt_handler_t evt_handler)
{
VERIFY_PARAM_NOT_NULL(evt_handler);
ret_code_t err_code;
err_code = gscm_init(gscm_evt_handler);
VERIFY_SUCCESS(err_code);
err_code = gccm_init(gccm_evt_handler);
VERIFY_SUCCESS(err_code);
internal_state_reset(&m_gcm);
m_gcm.evt_handler = evt_handler;
err_code = im_register(im_evt_handler);
VERIFY_SUCCESS(err_code);
err_code = smd_register(smd_evt_handler);
VERIFY_SUCCESS(err_code);
m_gcm.flag_id_local_db_update_pending = ble_conn_state_user_flag_acquire();
m_gcm.flag_id_local_db_apply_pending = ble_conn_state_user_flag_acquire();
m_gcm.flag_id_service_changed_pending = ble_conn_state_user_flag_acquire();
m_gcm.flag_id_service_changed_sent = ble_conn_state_user_flag_acquire();
if ((m_gcm.flag_id_local_db_update_pending == BLE_CONN_STATE_USER_FLAG_INVALID)
|| (m_gcm.flag_id_local_db_apply_pending == BLE_CONN_STATE_USER_FLAG_INVALID)
|| (m_gcm.flag_id_service_changed_pending == BLE_CONN_STATE_USER_FLAG_INVALID)
|| (m_gcm.flag_id_service_changed_sent == BLE_CONN_STATE_USER_FLAG_INVALID))
{
err_code = NRF_ERROR_INTERNAL;
}
return err_code;
}
/**@brief Function for performing the Local DB apply procedure if it is pending on any connections.
*/
static void apply_pending_flags_check(void)
{
sdk_mapped_flags_t apply_pending_flags;
apply_pending_flags = ble_conn_state_user_flag_collection(m_gcm.flag_id_local_db_apply_pending);
if (sdk_mapped_flags_any_set(apply_pending_flags))
{
sdk_mapped_flags_key_list_t conn_handle_list;
conn_handle_list = ble_conn_state_conn_handles();
for (uint32_t i = 0; i < conn_handle_list.len; i++)
{
if (ble_conn_state_user_flag_get(conn_handle_list.flag_keys[i], m_gcm.flag_id_local_db_apply_pending))
{
local_db_apply_in_evt(conn_handle_list.flag_keys[i]);
}
}
}
}
/**@brief Function for performing the Local DB update procedure if it is pending on any connections.
*/
static void update_pending_flags_check(void)
{
sdk_mapped_flags_t update_pending_flags;
update_pending_flags = ble_conn_state_user_flag_collection(m_gcm.flag_id_local_db_update_pending);
if (sdk_mapped_flags_any_set(update_pending_flags))
{
sdk_mapped_flags_key_list_t conn_handle_list;
conn_handle_list = ble_conn_state_conn_handles();
for (uint32_t i = 0; i < conn_handle_list.len; i++)
{
if (ble_conn_state_user_flag_get(conn_handle_list.flag_keys[i], m_gcm.flag_id_local_db_update_pending))
{
local_db_update_in_evt(conn_handle_list.flag_keys[i]);
}
}
}
}
/**@brief Function for sending service changed indications if it is pending on any connections.
*/
static void service_changed_pending_flags_check(void)
{
sdk_mapped_flags_t service_changed_pending_flags;
service_changed_pending_flags = ble_conn_state_user_flag_collection(m_gcm.flag_id_service_changed_pending);
if (sdk_mapped_flags_any_set(service_changed_pending_flags))
{
sdk_mapped_flags_key_list_t conn_handle_list;
conn_handle_list = ble_conn_state_conn_handles();
for (uint32_t i = 0; i < conn_handle_list.len; i++)
{
if ( ble_conn_state_user_flag_get(conn_handle_list.flag_keys[i],
m_gcm.flag_id_service_changed_pending)
&& !ble_conn_state_user_flag_get(conn_handle_list.flag_keys[i],
m_gcm.flag_id_service_changed_sent))
{
service_changed_send_in_evt(conn_handle_list.flag_keys[i]);
}
}
}
}
/**@brief Callback function for BLE events from the SoftDevice.
*
* @param[in] p_ble_evt The BLE event from the SoftDevice.
*/
void gcm_ble_evt_handler(ble_evt_t * p_ble_evt)
{
gcm_evt_t event;
switch(p_ble_evt->header.evt_id)
{
case BLE_GATTS_EVT_SYS_ATTR_MISSING:
local_db_apply_in_evt(p_ble_evt->evt.gatts_evt.conn_handle);
break;
case BLE_GATTS_EVT_SC_CONFIRM:
event.evt_id = GCM_EVT_SERVICE_CHANGED_IND_CONFIRMED;
event.peer_id = im_peer_id_get_by_conn_handle(p_ble_evt->evt.gatts_evt.conn_handle);
event.params.service_changed_ind_sent.conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
gscm_db_change_notification_done(event.peer_id);
ble_conn_state_user_flag_set(p_ble_evt->evt.gatts_evt.conn_handle, m_gcm.flag_id_service_changed_pending, false);
m_gcm.evt_handler(&event);
break;
case BLE_GATTS_EVT_WRITE:
if (cccd_written(&p_ble_evt->evt.gatts_evt.params.write))
{
local_db_update_in_evt(p_ble_evt->evt.gatts_evt.conn_handle);
}
break;
}
apply_pending_flags_check();
update_pending_flags_check();
service_changed_pending_flags_check();
}
ret_code_t gcm_remote_db_store(pm_peer_id_t peer_id,
ble_gatt_db_srv_t * p_remote_db,
uint32_t n_services)
{
VERIFY_MODULE_INITIALIZED();
return gccm_remote_db_store(peer_id, p_remote_db, n_services);
}
ret_code_t gcm_remote_db_retrieve(pm_peer_id_t peer_id,
ble_gatt_db_srv_t * p_remote_db,
uint32_t * p_n_services)
{
VERIFY_MODULE_INITIALIZED();
VERIFY_PARAM_NOT_NULL(p_remote_db);
return gccm_remote_db_retrieve(peer_id, p_remote_db, p_n_services);
}
ret_code_t gcm_local_db_cache_update(uint16_t conn_handle)
{
VERIFY_MODULE_INITIALIZED();
ret_code_t err_code = gscm_local_db_cache_update(conn_handle);
bool set_procedure_as_pending = false;
if (err_code == NRF_ERROR_BUSY)
{
set_procedure_as_pending = true;
err_code = NRF_SUCCESS;
}
ble_conn_state_user_flag_set(conn_handle, m_gcm.flag_id_local_db_update_pending, set_procedure_as_pending);
return err_code;
}
ret_code_t gcm_local_db_cache_set(pm_peer_id_t peer_id, pm_peer_data_local_gatt_db_t * p_local_db)
{
VERIFY_MODULE_INITIALIZED();
return gscm_local_db_cache_set(peer_id, p_local_db);
}
ret_code_t gcm_local_db_cache_get(pm_peer_id_t peer_id, pm_peer_data_local_gatt_db_t * p_local_db)
{
VERIFY_MODULE_INITIALIZED();
return gscm_local_db_cache_get(peer_id, p_local_db);
}
void gcm_local_database_has_changed(void)
{
gscm_local_database_has_changed();
sdk_mapped_flags_key_list_t conn_handles = ble_conn_state_conn_handles();
for (uint16_t i = 0; i < conn_handles.len; i++)
{
if (im_peer_id_get_by_conn_handle(conn_handles.flag_keys[i]) == PM_PEER_ID_INVALID)
{
ble_conn_state_user_flag_set(conn_handles.flag_keys[i], m_gcm.flag_id_service_changed_pending, true);
}
}
service_changed_pending_flags_check();
}

View File

@ -0,0 +1,236 @@
/*
* Copyright (c) 2015 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#ifndef GATT_CACHE_MANAGER_H__
#define GATT_CACHE_MANAGER_H__
#include <stdint.h>
#include "sdk_errors.h"
#include "nrf_ble.h"
#include "nrf_ble_gap.h"
#include "peer_manager_types.h"
/**
* @cond NO_DOXYGEN
* @defgroup gatt_cache_manager GATT Cache Manager
* @ingroup peer_manager
* @{
* @brief An internal module of @ref peer_manager. A module for managing persistent storing of GATT
* attributes.
*/
/**@brief Events that can come from the GATT Cache Manager module.
*/
typedef enum
{
GCM_EVT_LOCAL_DB_CACHE_STORED, /**< The persistent cache for the local database has been updated with provided values, for one peer. */
GCM_EVT_LOCAL_DB_CACHE_UPDATED, /**< The persistent cache for the local database has been updated with values from the SoftDevice, for one peer. */
GCM_EVT_LOCAL_DB_CACHE_APPLIED, /**< The SoftDevice has been given local database values from the persistent cache, for one peer. */
GCM_EVT_ERROR_LOCAL_DB_CACHE_APPLY, /**< The stored local database values for a peer were rejected by the SoftDevice, which means the database has changed. */
GCM_EVT_REMOTE_DB_CACHE_UPDATED, /**< The persistent cache for the remote database has been updated with provided values, for one peer. */
GCM_EVT_SERVICE_CHANGED_IND_SENT, /**< A service changed indication has been sent to a peer. */
GCM_EVT_SERVICE_CHANGED_IND_CONFIRMED, /**< A sent service changed indication has been confirmed by a peer. */
GCM_EVT_ERROR_DATA_SIZE, /**< An operation failed because the write buffer of the Peer Database module was not large enough. This is a fatal error. */
GCM_EVT_ERROR_STORAGE_FULL, /**< An operation failed because there was no available storage room in persistent storage. Please free up room, and the operation will automatically continue. */
GCM_EVT_ERROR_UNEXPECTED, /**< An operation failed with an unexpected error. The error is provided. This is possibly a fatal error. */
} gcm_evt_id_t;
/**@brief A structure meant to be used for event parameters for multiple event types.
*/
typedef struct
{
uint16_t conn_handle; /**< The connection handle. Likely the connection handle an event pertains to. */
} gcm_evt_param_conn_handle_t;
/**@brief Structure containing an event from the GCM module.
*/
typedef struct
{
gcm_evt_id_t evt_id; /**< The type of event this is. */
pm_peer_id_t peer_id; /**< The peer ID this event pertains to. */
union
{
gcm_evt_param_conn_handle_t local_db_cache_updated;
gcm_evt_param_conn_handle_t local_db_cache_applied;
gcm_evt_param_conn_handle_t error_local_db_cache_apply;
gcm_evt_param_conn_handle_t service_changed_ind_sent;
gcm_evt_param_conn_handle_t service_changed_ind_confirmed;
gcm_evt_param_conn_handle_t error_data_size;
gcm_evt_param_conn_handle_t error_no_mem;
struct
{
uint16_t conn_handle; /**< The handle of the connection the event pertains to. */
ret_code_t error; /**< The unexpected error that occurred. */
} error_unexpected;
} params; /**< Event specific parameters. Chosen based on evt_id. */
} gcm_evt_t;
/**@brief Event handler for events from the GATT Cache Manager module.
*
* @param[in] event The event that has happened.
* @param[in] peer The id of the peer the event pertains to.
* @param[in] flags The data the event pertains to.
*/
typedef void (*gcm_evt_handler_t)(gcm_evt_t const * p_event);
/**@brief Function for initializing the GATT Cache Manager module.
*
* @param[in] evt_handler Callback for events from the GATT Cache Manager module.
*
* @retval NRF_SUCCESS Initialization was successful.
* @retval NRF_ERROR_NULL evt_handler was NULL.
*/
ret_code_t gcm_init(gcm_evt_handler_t evt_handler);
/**@brief Function for dispatching SoftDevice events to the GATT Cache Manager module.
*
* @param[in] p_ble_evt The SoftDevice event.
*/
void gcm_ble_evt_handler(ble_evt_t * p_ble_evt);
/**@brief Function for storing a discovered remote database persistently.
*
* @param[in] peer_id Peer to store the database for.
* @param[in] p_remote_db Database values to store as an array. Can be NULL if n_services is 0.
* @param[in] n_services Number of services in p_remote_db array. If 0, values are cleared.
*
* @retval NRF_SUCCESS Store procedure successfully started.
* @retval NRF_ERROR_NOT_FOUND The peer id is invalid or unallocated.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
*/
ret_code_t gcm_remote_db_store(pm_peer_id_t peer_id,
ble_gatt_db_srv_t * p_remote_db,
uint32_t n_services);
/**@brief Function for retrieving a persistently stored remote database.
*
* @param[in] peer_id Peer to retrieve data for.
* @param[out] p_remote_db If p_n_services was large enough: Copied database values.
* @param[inout] p_n_services In: Size of provided p_remote_db array. Out: Size of data in flash.
*
* @note p_n_services is always updated with the size of the data to be retrieved. The data is only
* copied if p_remote_db is large enough (p_n_services is large enough initially).
*
* @retval NRF_SUCCESS Data retrieved successfully.
* @retval NRF_ERROR_NOT_FOUND The peer ID is invalid or unallocated.
* @retval NRF_ERROR_NULL p_remote_db is NULL.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
*/
ret_code_t gcm_remote_db_retrieve(pm_peer_id_t peer_id,
ble_gatt_db_srv_t * p_remote_db,
uint32_t * p_n_services);
/**@brief Function for triggering local GATT database data to be stored persistently. Values are
* retrieved from SoftDevice and written to persistent storage.
*
* @note This function is only needed when you want to override the regular functionality of the
* module, e.g. to immediately store to flash instead of waiting for the native logic to
* perform the update.
*
* @param[in] conn_handle Connection handle to perform update on.
*
* @retval NRF_SUCCESS Store operation started.
* @retval BLE_ERROR_INVALID_CONN_HANDLE conn_handle does not refer to an active, bonded connection.
* @retval NRF_ERROR_DATA_SIZE Write buffer not large enough. Call will never work with
* this GATT database.
* @retval NRF_ERROR_NO_MEM No room in persistent_storage. Free up space; the
* operation will be automatically reattempted after the
* next compression procedure
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
*/
ret_code_t gcm_local_db_cache_update(uint16_t conn_handle);
/**@brief Function for setting new values in the local database cache.
*
* @note If the peer is connected, the values will also be applied immediately to the connection.
* @note This function is only needed when you want to override the regular functionality of the
* module.
* @note The data in the pointer must be available until the GCM_EVT_LOCAL_DB_CACHE_SET event is
* received.
*
* @param[in] peer_id Peer to set values for.
* @param[in] p_local_db Database values to apply. If NULL, the values will instead be cleared.
*
* @retval NRF_SUCCESS Operation started, and values were applied (if connected).
* @retval NRF_ERROR_NOT_FOUND The peer ID was invalid or unallocated.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
*/
ret_code_t gcm_local_db_cache_set(pm_peer_id_t peer_id, pm_peer_data_local_gatt_db_t * p_local_db);
/**@brief Function for retrieving values in the local database cache.
*
* @note This function is not needed for regular operation of the module.
*
* @param[in] peer_id Peer to get values for.
* @param[out] p_local_db Database values.
*
* @retval NRF_SUCCESS Values retrieved successfully.
* @retval NRF_ERROR_NOT_FOUND The peer ID was invalid or unallocated.
* @retval NRF_ERROR_NULL p_local_db was NULL.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
*/
ret_code_t gcm_local_db_cache_get(pm_peer_id_t peer_id, pm_peer_data_local_gatt_db_t * p_local_db);
/**@brief Function for manually informing that the local database has changed.
*
* @details This causes a service changed notification to be sent to all bonded peers that
* subscribe to it.
*/
void gcm_local_database_has_changed(void);
/** @}
* @endcond
*/
#endif /* GATT_CACHE_MANAGER_H__ */

View File

@ -0,0 +1,139 @@
/*
* Copyright (c) 2015 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#include "gattc_cache_manager.h"
#include "nrf_ble_gap.h"
#include "ble_conn_state.h"
#include "peer_manager_types.h"
#include "peer_database.h"
#include "id_manager.h"
#include "sdk_common.h"
#define MAX_SIMUL_SEC_PROCEDURES 2
typedef struct
{
gccm_evt_handler_t evt_handler;
} gccm_t;
static gccm_t m_gccm;
#define MODULE_INITIALIZED (m_gccm.evt_handler != NULL)
#include "sdk_macros.h"
static void internal_state_reset(gccm_t * gccm)
{
memset(gccm, 0, sizeof(gccm_t));
}
/**@brief Event handler for events from the peer_database module.
*
* @param[in] p_event The event that has happend with peer id and flags.
*/
static void pdb_evt_handler(pdb_evt_t const * p_event)
{
gccm_evt_t gccm_evt;
gccm_evt.evt_id = GCCM_EVT_REMOTE_DB_STORED;
gccm_evt.peer_id = p_event->peer_id;
m_gccm.evt_handler(&gccm_evt);
}
ret_code_t gccm_init(gccm_evt_handler_t evt_handler)
{
ret_code_t err_code;
if (evt_handler == NULL)
{
err_code = NRF_ERROR_NULL;
}
else
{
err_code = pdb_register(pdb_evt_handler);
if (err_code == NRF_SUCCESS)
{
internal_state_reset(&m_gccm);
m_gccm.evt_handler = evt_handler;
}
}
return err_code;
}
ret_code_t gccm_remote_db_store(pm_peer_id_t peer_id,
ble_gatt_db_srv_t * p_remote_db,
uint32_t n_services)
{
VERIFY_MODULE_INITIALIZED();
VERIFY_PARAM_NOT_NULL(p_remote_db);
// Initialize the peer_data
pm_peer_data_const_t peer_data;
memset(&peer_data, 0, sizeof(peer_data));
peer_data.data_id = PM_PEER_DATA_ID_GATT_REMOTE;
peer_data.p_remote_gatt_db = p_remote_db;
peer_data.length_words = PM_REMOTE_DB_N_WORDS(n_services);
return pdb_raw_store(peer_id, &peer_data, NULL);
}
ret_code_t gccm_remote_db_retrieve(pm_peer_id_t peer_id,
ble_gatt_db_srv_t * p_remote_db,
uint32_t * p_n_services)
{
VERIFY_MODULE_INITIALIZED();
VERIFY_PARAM_NOT_NULL(p_remote_db);
VERIFY_PARAM_NOT_NULL(p_n_services);
// Initialize the peer_data
pm_peer_data_t peer_data;
memset(&peer_data, 0, sizeof(peer_data));
peer_data.data_id = PM_PEER_DATA_ID_GATT_REMOTE;
peer_data.p_remote_gatt_db = p_remote_db;
peer_data.length_words = PM_REMOTE_DB_N_WORDS(*p_n_services);
ret_code_t err_code = pdb_raw_read(peer_id, PM_PEER_DATA_ID_GATT_REMOTE, &peer_data);
*p_n_services = PM_REMOTE_DB_N_SERVICES(peer_data.length_words);
return err_code;
}

View File

@ -0,0 +1,132 @@
/*
* Copyright (c) 2015 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#ifndef GATTC_CACHE_MANAGER_H__
#define GATTC_CACHE_MANAGER_H__
#include <stdint.h>
#include "sdk_errors.h"
#include "nrf_ble.h"
#include "nrf_ble_gap.h"
#include "peer_manager_types.h"
/**
* @cond NO_DOXYGEN
* @defgroup gattc_cache_manager GATT Client Cache Manager
* @ingroup peer_manager
* @{
* @brief An internal module of @ref peer_manager. A module for managing persistent storing of GATT
* attributes pertaining to the GATT client role of the local device.
*/
/**@brief Events that can come from the GATT Cache Manager module.
*/
typedef enum
{
GCCM_EVT_REMOTE_DB_UPDATED, /**< Values for the specified data has been updated in persistent storage. */
GCCM_EVT_REMOTE_DB_STORED, /**< New values for the specified data has been written in persistent storage. */
} gccm_evt_id_t;
typedef struct
{
gccm_evt_id_t evt_id;
pm_peer_id_t peer_id;
} gccm_evt_t;
/**@brief Event handler for events from the GATT Client Cache Manager module.
*
* @param[in] event The event that has happened.
* @param[in] peer The id of the peer the event pertains to.
* @param[in] flags The data the event pertains to.
*/
typedef void (*gccm_evt_handler_t)(gccm_evt_t const * p_event);
/**@brief Function for initializing the GATT Client Cache Manager module.
*
* @param[in] evt_handler Callback for events from the GATT Client Cache Manager module.
*
* @retval NRF_SUCCESS Initialization was successful.
* @retval NRF_ERROR_NULL evt_handler was NULL.
*/
ret_code_t gccm_init(gccm_evt_handler_t evt_handler);
/**@brief Function for storing a discovered remote database persistently.
*
* @param[in] peer_id Peer to store the database for.
* @param[in] p_remote_db Database values to store as an array. Can be NULL if n_services is 0.
* @param[in] n_services Number of services in p_remote_db array. If 0, values are cleared.
*
* @retval NRF_SUCCESS Store procedure successfully started.
* @retval NRF_ERROR_NOT_FOUND The peer id is invalid or unallocated.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
*/
ret_code_t gccm_remote_db_store(pm_peer_id_t peer_id,
ble_gatt_db_srv_t * p_remote_db,
uint32_t n_services);
/**@brief Function for retrieving a persistently stored remote database.
*
* @param[in] peer_id Peer to retrieve data for.
* @param[out] p_remote_db If p_n_services was large enough: Copied database values.
* @param[inout] p_n_services In: Size of provided p_remote_db array. Out: Size of data in flash.
*
* @note p_n_services is always updated with the size of the data to be retrieved. The data is only
* copied if p_remote_db is large enough (p_n_services is large enough initially).
*
* @retval NRF_SUCCESS Data retrieved successfully.
* @retval NRF_ERROR_NOT_FOUND The peer ID is invalid or unallocated.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
*/
ret_code_t gccm_remote_db_retrieve(pm_peer_id_t peer_id,
ble_gatt_db_srv_t * p_remote_db,
uint32_t * p_n_services);
/** @}
* @endcond
*/
#endif /* GATTC_CACHE_MANAGER_H__ */

View File

@ -0,0 +1,396 @@
/*
* Copyright (c) 2015 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#include "gatts_cache_manager.h"
#include <string.h>
#include "nrf_ble_gap.h"
#include "ble_conn_state.h"
#include "peer_manager_types.h"
#include "peer_manager_internal.h"
#include "peer_database.h"
#include "id_manager.h"
#include "sdk_common.h"
#define SYS_ATTR_SYS (BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS) /**< Shorthand define for the flag for system attributes. */
#define SYS_ATTR_USR (BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS) /**< Shorthand define for the flag for user attributes. */
#define SYS_ATTR_BOTH (SYS_ATTR_SYS | SYS_ATTR_USR) /**< Shorthand define for the combined flags for system and user attributes. */
/**@brief Structure containing the module variable(s) of the GSCM module.
*/
typedef struct
{
gscm_evt_handler_t evt_handler; /**< The event handler to use for outbound GSCM events. */
pm_peer_id_t current_sc_store_peer_id;
} gscm_t;
static gscm_t m_gscm =
{
.current_sc_store_peer_id = PM_PEER_ID_INVALID,
}; /**< Instantiation of module variable(s). */
#define MODULE_INITIALIZED (m_gscm.evt_handler != NULL)
#include "sdk_macros.h"
/**@brief Function for resetting the module variable(s) of the GSCM module.
*
* @param[out] p_gscm The instance to reset.
*/
static void internal_state_reset(gscm_t * p_gscm)
{
memset(p_gscm, 0, sizeof(gscm_t));
p_gscm->current_sc_store_peer_id = PM_PEER_ID_INVALID;
}
//lint -save -e550
/**@brief Function for storing service_changed_pending = true to flash for all peers, in sequence.
*
* This function aborts if it gets @ref NRF_ERROR_BUSY when trying to store. A subsequent call will
* continue where the last call was aborted.
*/
static void service_changed_pending_set(void)
{
VERIFY_MODULE_INITIALIZED_VOID();
static const bool service_changed_pending = true;
ret_code_t err_code;
//lint -save -e65 -e64
pm_peer_data_const_t peer_data =
{
.data_id = PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING,
.length_words = PM_SC_STATE_N_WORDS(),
.p_service_changed_pending = &service_changed_pending,
};
//lint -restore
err_code = pdb_raw_store(m_gscm.current_sc_store_peer_id, &peer_data, NULL);
while((m_gscm.current_sc_store_peer_id != PM_PEER_ID_INVALID) && (err_code != NRF_ERROR_BUSY))
{
m_gscm.current_sc_store_peer_id = pdb_next_peer_id_get(m_gscm.current_sc_store_peer_id);
err_code = pdb_raw_store(m_gscm.current_sc_store_peer_id, &peer_data, NULL);
}
}
//lint -restore
/**@brief Event handler for events from the peer_database module.
*
* @param[in] p_event The event that has happend with peer id and flags.
*/
static void pdb_evt_handler(pdb_evt_t const * p_event)
{
if (p_event->evt_id == PDB_EVT_RAW_STORED)
{
if (p_event->data_id == PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING)
{
ret_code_t err_code;
pm_peer_data_flash_t peer_data;
err_code = pdb_read_buf_get(p_event->peer_id, PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING, &peer_data, NULL);
if (err_code == NRF_SUCCESS)
{
gscm_evt_t gscm_evt;
gscm_evt.evt_id = GSCM_EVT_SC_STATE_STORED;
gscm_evt.peer_id = p_event->peer_id;
gscm_evt.params.sc_state_stored.state = &peer_data.p_service_changed_pending;
m_gscm.evt_handler(&gscm_evt);
}
}
}
if (m_gscm.current_sc_store_peer_id != PM_PEER_ID_INVALID)
{
service_changed_pending_set();
}
}
ret_code_t gscm_init(gscm_evt_handler_t evt_handler)
{
ret_code_t err_code;
if (evt_handler == NULL)
{
err_code = NRF_ERROR_NULL;
}
else
{
err_code = pdb_register(pdb_evt_handler);
if (err_code == NRF_SUCCESS)
{
internal_state_reset(&m_gscm);
m_gscm.evt_handler = evt_handler;
}
}
return err_code;
}
ret_code_t gscm_local_db_cache_update(uint16_t conn_handle)
{
VERIFY_MODULE_INITIALIZED();
pm_peer_id_t peer_id = im_peer_id_get_by_conn_handle(conn_handle);
ret_code_t err_code;
if (peer_id == PM_PEER_ID_INVALID)
{
return BLE_ERROR_INVALID_CONN_HANDLE;
}
else
{
pm_peer_data_t peer_data;
uint16_t n_bufs = 1;
bool retry_with_bigger_buffer = false;
do
{
retry_with_bigger_buffer = false;
err_code = pdb_write_buf_get(peer_id, PM_PEER_DATA_ID_GATT_LOCAL, n_bufs++, &peer_data);
if (err_code == NRF_SUCCESS)
{
pm_peer_data_local_gatt_db_t * p_local_gatt_db = peer_data.p_local_gatt_db;
p_local_gatt_db->flags = SYS_ATTR_BOTH;
err_code = sd_ble_gatts_sys_attr_get(conn_handle, &p_local_gatt_db->data[0], &p_local_gatt_db->len, p_local_gatt_db->flags);
if (err_code == NRF_SUCCESS)
{
err_code = pdb_write_buf_store(peer_id, PM_PEER_DATA_ID_GATT_LOCAL);
}
else
{
if (err_code == NRF_ERROR_DATA_SIZE)
{
// The sys attributes are bigger than the requested write buffer.
retry_with_bigger_buffer = true;
}
else if (err_code == NRF_ERROR_NOT_FOUND)
{
// There are no sys attributes in the GATT db, so nothing needs to be stored.
err_code = NRF_SUCCESS;
}
ret_code_t err_code_release = pdb_write_buf_release(peer_id, PM_PEER_DATA_ID_GATT_LOCAL);
if (err_code_release != NRF_SUCCESS)
{
err_code = NRF_ERROR_INTERNAL;
}
}
}
else if (err_code == NRF_ERROR_INVALID_PARAM)
{
// The sys attributes are bigger than the entire write buffer.
err_code = NRF_ERROR_DATA_SIZE;
}
} while (retry_with_bigger_buffer);
}
return err_code;
}
ret_code_t gscm_local_db_cache_apply(uint16_t conn_handle)
{
VERIFY_MODULE_INITIALIZED();
pm_peer_id_t peer_id = im_peer_id_get_by_conn_handle(conn_handle);
ret_code_t err_code;
pm_peer_data_flash_t peer_data;
uint8_t const * p_sys_attr_data = NULL;
uint16_t sys_attr_len = 0;
uint32_t sys_attr_flags = (SYS_ATTR_BOTH);
bool all_attributes_applied = true;
if (peer_id != PM_PEER_ID_INVALID)
{
err_code = pdb_read_buf_get(peer_id, PM_PEER_DATA_ID_GATT_LOCAL, &peer_data, NULL);
if (err_code == NRF_SUCCESS)
{
pm_peer_data_local_gatt_db_t const * p_local_gatt_db;
p_local_gatt_db = peer_data.p_local_gatt_db;
p_sys_attr_data = p_local_gatt_db->data;
sys_attr_len = p_local_gatt_db->len;
sys_attr_flags = p_local_gatt_db->flags;
}
}
do
{
err_code = sd_ble_gatts_sys_attr_set(conn_handle, p_sys_attr_data, sys_attr_len, sys_attr_flags);
if (err_code == NRF_ERROR_NO_MEM)
{
err_code = NRF_ERROR_BUSY;
}
else if (err_code == NRF_ERROR_INVALID_STATE)
{
err_code = NRF_SUCCESS;
}
else if (err_code == NRF_ERROR_INVALID_DATA)
{
all_attributes_applied = false;
if (sys_attr_flags & SYS_ATTR_USR)
{
// Try setting only system attributes.
sys_attr_flags = SYS_ATTR_SYS;
}
else if (p_sys_attr_data || sys_attr_len)
{
// Try reporting that none exist.
p_sys_attr_data = NULL;
sys_attr_len = 0;
sys_attr_flags = SYS_ATTR_BOTH;
}
else
{
err_code = NRF_ERROR_INTERNAL;
}
}
} while (err_code == NRF_ERROR_INVALID_DATA);
if (!all_attributes_applied)
{
err_code = NRF_ERROR_INVALID_DATA;
}
return err_code;
}
ret_code_t gscm_local_db_cache_set(pm_peer_id_t peer_id, pm_peer_data_local_gatt_db_t * p_local_db)
{
VERIFY_MODULE_INITIALIZED();
pm_peer_data_const_t peer_data;
memset(&peer_data, 0, sizeof(pm_peer_data_const_t));
peer_data.data_id = PM_PEER_DATA_ID_GATT_LOCAL;
peer_data.p_local_gatt_db = p_local_db;
return pdb_raw_store(peer_id, &peer_data, NULL);
}
ret_code_t gscm_local_db_cache_get(pm_peer_id_t peer_id, pm_peer_data_local_gatt_db_t * p_local_db)
{
VERIFY_MODULE_INITIALIZED();
pm_peer_data_t peer_data;
memset(&peer_data, 0, sizeof(pm_peer_data_t));
peer_data.p_local_gatt_db = p_local_db;
return pdb_raw_read(peer_id, PM_PEER_DATA_ID_GATT_LOCAL, &peer_data);
}
void gscm_local_database_has_changed(void)
{
VERIFY_MODULE_INITIALIZED_VOID();
m_gscm.current_sc_store_peer_id = pdb_next_peer_id_get(PM_PEER_ID_INVALID);
service_changed_pending_set();
}
bool gscm_service_changed_ind_needed(uint16_t conn_handle)
{
ret_code_t err_code;
pm_peer_data_flash_t peer_data;
pm_peer_id_t peer_id = im_peer_id_get_by_conn_handle(conn_handle);
err_code = pdb_read_buf_get(peer_id, PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING, &peer_data, NULL);
if (err_code != NRF_SUCCESS)
{
return false;
}
return &peer_data.p_service_changed_pending;
}
ret_code_t gscm_service_changed_ind_send(uint16_t conn_handle)
{
static uint16_t start_handle = 0x0000;
const uint16_t end_handle = 0xFFFF;
ret_code_t err_code;
do
{
err_code = sd_ble_gatts_service_changed(conn_handle, start_handle, end_handle);
if (err_code == BLE_ERROR_INVALID_ATTR_HANDLE)
{
start_handle += 1;
}
} while (err_code == BLE_ERROR_INVALID_ATTR_HANDLE);
return err_code;
}
void gscm_db_change_notification_done(pm_peer_id_t peer_id)
{
VERIFY_MODULE_INITIALIZED_VOID();
static const bool service_changed_pending = false;
//lint -save -e65 -e64
pm_peer_data_const_t peer_data =
{
.data_id = PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING,
.length_words = PM_SC_STATE_N_WORDS(),
.p_service_changed_pending = &service_changed_pending,
};
//lint -restore
// Don't need to check return code, because all error conditions can be ignored.
//lint -save -e550
(void) pdb_raw_store(peer_id, &peer_data, NULL);
//lint -restore
}

View File

@ -0,0 +1,228 @@
/*
* Copyright (c) 2015 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#ifndef GATTS_CACHE_MANAGER_H__
#define GATTS_CACHE_MANAGER_H__
#include <stdint.h>
#include "sdk_errors.h"
#include "nrf_ble.h"
#include "nrf_ble_gap.h"
#include "peer_manager_types.h"
/**
* @cond NO_DOXYGEN
* @defgroup gatts_cache_manager GATT Server Cache Manager
* @ingroup peer_manager
* @{
* @brief An internal module of @ref peer_manager. A module for managing persistent storing of GATT
* attributes pertaining to the GATT server role of the local device.
*/
/**@brief Events that can come from the GATT Server Cache Manager module.
*/
typedef enum
{
GSCM_EVT_LOCAL_DB_CACHE_STORED, /**< The persistent cache for the local database has been updated with provided values, for one peer. */
GSCM_EVT_LOCAL_DB_CACHE_UPDATED, /**< The persistent cache for the local database has been updated with values from the SoftDevice, for one peer. */
GSCM_EVT_SC_STATE_STORED, /**< The service changed pending flag in persistent storage has been updated, for one peer. */
} gscm_evt_id_t;
/**@brief Structure containing an event from the GSCM module.
*/
typedef struct
{
gscm_evt_id_t evt_id; /**< The type of event this is. */
pm_peer_id_t peer_id; /**< The peer ID this event pertains to. */
union
{
struct
{
uint16_t conn_handle; /**< The connection this event pertains to. */
} local_db_cache_updated;
struct
{
bool state; /**< The newly stored state of the Service Changed pending flag. */
} sc_state_stored;
} params; /**< Event parameters specific to certain event types. */
} gscm_evt_t;
/**@brief Event handler for events from the GATT Server Cache Manager module.
*
* @param[in] event The event that has happened.
* @param[in] peer The id of the peer the event pertains to.
* @param[in] flags The data the event pertains to.
*/
typedef void (*gscm_evt_handler_t)(gscm_evt_t const * p_event);
/**@brief Function for initializing the GATT Server Cache Manager module.
*
* @param[in] evt_handler Callback for events from the GATT Server Cache Manager module.
*
* @retval NRF_SUCCESS Initialization was successful.
* @retval NRF_ERROR_NULL evt_handler was NULL.
*/
ret_code_t gscm_init(gscm_evt_handler_t evt_handler);
/**@brief Function for triggering local GATT database data to be stored persistently. Values are
* retrieved from the SoftDevice and written to persistent storage.
*
* @param[in] conn_handle Connection handle to perform update on.
*
* @retval NRF_SUCCESS Store operation started.
* @retval BLE_ERROR_INVALID_CONN_HANDLE conn_handle does not refer to an active connection with a
* bonded peer.
* @retval NRF_ERROR_BUSY Unable to perform operation at this time. Reattempt later.
* @retval NRF_ERROR_DATA_SIZE Write buffer not large enough. Call will never work with
* this GATT database.
* @retval NRF_ERROR_NO_MEM No room in persistent_storage. Free up space; the
* operation will be automatically reattempted after the
* next compression procedure
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
*/
ret_code_t gscm_local_db_cache_update(uint16_t conn_handle);
/**@brief Function for applying stored local GATT database data to the SoftDevice. Values are
* retrieved from persistent storage and given to the SoftDevice.
*
* @param[in] conn_handle Connection handle to apply values to.
*
* @retval NRF_SUCCESS Store operation started.
* @retval BLE_ERROR_INVALID_CONN_HANDLE conn_handle does not refer to an active connection with a
* bonded peer.
* @retval NRF_ERROR_INVALID_DATA The stored data was rejected by the SoftDevice, which
* probably means that the local database has changed. The
* system part of the sys_attributes was attempted applied,
* so service changed indications can be sent to subscribers.
* @retval NRF_ERROR_BUSY Unable to perform operation at this time. Reattempt later.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
* @return An unexpected return value from an internal function call.
*/
ret_code_t gscm_local_db_cache_apply(uint16_t conn_handle);
/**@brief Function for setting new values in the local database cache.
*
* @note If the peer is connected, the values will also be applied immediately to the connection.
* @note The data in the pointer must be available until the GSCM_EVT_LOCAL_DB_STORED event is
* received.
*
* @param[in] peer_id Peer to set values for.
* @param[in] p_local_db Database values to apply. If NULL, the values will instead be cleared.
*
* @retval NRF_SUCCESS Operation started, and values were applied (if connected).
* @retval NRF_ERROR_NOT_FOUND The peer ID was invalid or unallocated.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
* @return An unexpected return value from an internal function call.
*/
ret_code_t gscm_local_db_cache_set(pm_peer_id_t peer_id, pm_peer_data_local_gatt_db_t * p_local_db);
/**@brief Function for retrieving values in the local database cache.
*
* @param[in] peer_id Peer to get values for.
* @param[inout] p_local_db Where to store the data. The length field needs to reflect the
* available buffer space. On a successful read, the length field is
* updated to match the length of the read data.
*
* @retval NRF_SUCCESS Values retrieved successfully.
* @retval NRF_ERROR_NOT_FOUND The peer ID was invalid or unallocated.
* @retval NRF_ERROR_NULL p_local_db was NULL.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
*/
ret_code_t gscm_local_db_cache_get(pm_peer_id_t peer_id, pm_peer_data_local_gatt_db_t * p_local_db);
/**@brief Function for storing the fact that the local database has changed, for all currently
* bonded peers.
*
* @note This will cause a later call to @ref gscm_service_changed_ind_needed to return true for
* a connection with a currently bonded peer.
*/
void gscm_local_database_has_changed(void);
/**@brief Function for checking if a service changed indication should be sent.
*
* @param[in] conn_handle The connection to check.
*
* @return true if a service changed indication should be sent, false if not.
*/
bool gscm_service_changed_ind_needed(uint16_t conn_handle);
/**@brief Function for sending a service changed indication to a connected peer.
*
* @param[in] conn_handle The connection to send the indication on.
*
* @retval NRF_SUCCESS Indication sent or not needed.
* @retval BLE_ERROR_INVALID_CONN_HANDLE conn_handle does not refer to an active connection.
* @retval NRF_ERROR_BUSY Unable to send indication at this time. Reattempt later.
* @retval BLE_ERROR_GATTS_SYS_ATTR_MISSING Information missing. Apply local cache, then reattempt.
* @retval NRF_ERROR_INVALID_PARAM From @ref sd_ble_gatts_service_changed. Unexpected.
* @retval NRF_ERROR_NOT_SUPPORTED Service changed characteristic is not present.
* @retval NRF_ERROR_INVALID_STATE Service changed cannot be indicated to this peer
* because the peer has not subscribed to it.
*/
ret_code_t gscm_service_changed_ind_send(uint16_t conn_handle);
/**@brief Function for specifying that a peer has been made aware of the latest local database
* change.
*
* @note After calling this, a later call to @ref gscm_service_changed_ind_needed will to return
* false for this peer unless @ref gscm_local_database_has_changed is called again.
*
* @param[in] peer_id The connection to send the indication on.
*/
void gscm_db_change_notification_done(pm_peer_id_t peer_id);
/** @}
* @endcond
*/
#endif /* GATTS_CACHE_MANAGER_H__ */

View File

@ -0,0 +1,758 @@
/*
* Copyright (c) 2015 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#include "id_manager.h"
#include <string.h>
#include "nrf_soc.h"
#include "nrf_ble_gap.h"
#include "ble_conn_state.h"
#include "peer_manager_types.h"
#include "peer_database.h"
#include "nordic_common.h"
#include "sdk_common.h"
#define IM_MAX_CONN_HANDLES 8
#define IM_NO_INVALID_CONN_HANDLES 0xFF
#define MAX_REGISTRANTS 3
#define WHITELIST_MAX_COUNT MAX(BLE_GAP_WHITELIST_ADDR_MAX_COUNT, \
BLE_GAP_WHITELIST_IRK_MAX_COUNT)
#define IM_ADDR_CLEARTEXT_LENGTH 3
#define IM_ADDR_CIPHERTEXT_LENGTH 3
typedef struct
{
pm_peer_id_t peer_id;
uint16_t conn_handle;
ble_gap_addr_t peer_address;
} im_connection_t;
typedef struct
{
im_evt_handler_t evt_handlers[MAX_REGISTRANTS];
uint8_t n_registrants;
im_connection_t connections[8];
pm_peer_id_t irk_whitelist_peer_ids[BLE_GAP_WHITELIST_IRK_MAX_COUNT];
ble_gap_irk_t whitelist_irks[BLE_GAP_WHITELIST_IRK_MAX_COUNT];
ble_gap_addr_t whitelist_addrs[BLE_GAP_WHITELIST_ADDR_MAX_COUNT];
uint8_t n_irk_whitelist_peer_ids;
ble_conn_state_user_flag_id_t conn_state_user_flag_id;
} im_t;
static im_t m_im = {.n_registrants = 0};
#define MODULE_INITIALIZED (m_im.n_registrants > 0)
#include "sdk_macros.h"
static void internal_state_reset()
{
memset(&m_im, 0, sizeof(im_t));
m_im.n_registrants = 0;
m_im.n_irk_whitelist_peer_ids = 0;
m_im.conn_state_user_flag_id = BLE_CONN_STATE_USER_FLAG_INVALID;
for (uint32_t i = 0; i < IM_MAX_CONN_HANDLES; i++)
{
m_im.connections[i].conn_handle = BLE_CONN_HANDLE_INVALID;
}
}
/**@brief Function for sending an event to all registered event handlers.
*
* @param[in] p_event The event to distribute.
*/
static void evt_send(im_evt_t * p_event)
{
for (uint32_t i = 0; i < m_im.n_registrants; i++)
{
m_im.evt_handlers[i](p_event);
}
}
/**@brief Function finding a free position in m_im.connections.
*
* @detail All connection handles in the m_im.connections array are checked against the connection
* state module. The index of the first one that is not a connection handle for a current
* connection is returned. This position in the array can safely be used for a new connection.
*
* @return Either the index of a free position in the array or IM_NO_INVALID_CONN_HANDLES if no free
position exists.
*/
uint8_t get_free_connection()
{
for (uint32_t i = 0; i < IM_MAX_CONN_HANDLES; i++)
{
// Query the connection state module to check if the connection handle does not belong to a
// valid connection.
if (!ble_conn_state_user_flag_get(m_im.connections[i].conn_handle, m_im.conn_state_user_flag_id))
{
return i;
}
}
// If all connection handles belong to a valid connection, return IM_NO_INVALID_CONN_HANDLES.
return IM_NO_INVALID_CONN_HANDLES;
}
/**@brief Function finding a particular connection handle m_im.connections.
*
* @param[in] conn_handle The handle to find.
*
* @return Either the index of the conn_handle in the array or IM_NO_INVALID_CONN_HANDLES if the
* handle was not found.
*/
uint8_t get_connection_by_conn_handle(uint16_t conn_handle)
{
if (ble_conn_state_user_flag_get(conn_handle, m_im.conn_state_user_flag_id))
{
for (uint32_t i = 0; i < IM_MAX_CONN_HANDLES; i++)
{
if (m_im.connections[i].conn_handle == conn_handle)
{
return i;
}
}
}
// If all connection handles belong to a valid connection, return IM_NO_INVALID_CONN_HANDLES.
return IM_NO_INVALID_CONN_HANDLES;
}
/**@brief Function for registering a new connection instance.
*
* @param[in] conn_handle The handle of the new connection.
* @param[in] p_ble_addr The address used to connect.
*
* @return Either the index of the new connection in the array or IM_NO_INVALID_CONN_HANDLES if no
* free position exists.
*/
uint8_t new_connection(uint16_t conn_handle, ble_gap_addr_t * p_ble_addr)
{
uint8_t conn_index = IM_NO_INVALID_CONN_HANDLES;
if ((p_ble_addr != NULL) && (conn_handle != BLE_CONN_HANDLE_INVALID))
{
ble_conn_state_user_flag_set(conn_handle, m_im.conn_state_user_flag_id, true);
conn_index = get_connection_by_conn_handle(conn_handle);
if (conn_index == IM_NO_INVALID_CONN_HANDLES)
{
conn_index = get_free_connection();
}
if (conn_index != IM_NO_INVALID_CONN_HANDLES)
{
m_im.connections[conn_index].conn_handle = conn_handle;
m_im.connections[conn_index].peer_id = PM_PEER_ID_INVALID;
m_im.connections[conn_index].peer_address = *p_ble_addr;
}
}
return conn_index;
}
/**@brief Function checking the validity of an IRK
*
* @detail An all-zero IRK is not valid. This function will check if a given IRK is valid.
*
* @param[in] irk The IRK for which the validity is going to be checked.
*
* @retval true The IRK is valid.
* @retval false The IRK is invalid.
*/
bool is_valid_irk(ble_gap_irk_t const * irk)
{
for (uint32_t i = 0; i < BLE_GAP_SEC_KEY_LEN; i++)
{
if (irk->irk[i] != 0)
{
return true;
}
}
return false;
}
/**@brief Function for comparing two addresses to determine if they are identical
*
* @note The address type need to be identical, as well as every bit in the address itself.
*
* @param[in] p_addr1 The first address to be compared.
* @param[in] p_addr2 The second address to be compared.
*
* @retval true The addresses are identical.
* @retval false The addresses are not identical.
*/
bool addr_compare(ble_gap_addr_t const * p_addr1, ble_gap_addr_t const * p_addr2)
{
if ((p_addr1 == NULL) || (p_addr2 == NULL))
{
return false;
}
// Check that the addr type is identical, return false if it is not
if (p_addr1->addr_type != p_addr2->addr_type)
{
return false;
}
// Check if the addr bytes are is identical
return (memcmp(p_addr1->addr, p_addr2->addr, BLE_GAP_ADDR_LEN) == 0);
}
void im_ble_evt_handler(ble_evt_t * ble_evt)
{
ret_code_t err_code;
switch (ble_evt->header.evt_id)
{
case BLE_GAP_EVT_CONNECTED:
{
pm_peer_id_t bonded_matching_peer_id = PM_PEER_ID_INVALID;
if (ble_evt->evt.gap_evt.params.connected.irk_match == 1)
{
// The peer was matched using a whitelist.
bonded_matching_peer_id
= m_im.irk_whitelist_peer_ids[ble_evt->evt.gap_evt.params.connected.irk_match_idx];
}
else if ( ble_evt->evt.gap_evt.params.connected.peer_addr.addr_type
!= BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE)
{
/* Search the database for bonding data matching the one that triggered the event.
* Public and static addresses can be matched on address alone, while resolvable
* random addresses can be resolved agains known IRKs. Non-resolvable random addresses
* are never matching because they are not longterm form of identification.
*/
pm_peer_id_t compared_peer_id = pdb_next_peer_id_get(PM_PEER_ID_INVALID);
while ( (compared_peer_id != PM_PEER_ID_INVALID)
&& (bonded_matching_peer_id == PM_PEER_ID_INVALID))
{
pm_peer_data_flash_t compared_data;
switch (ble_evt->evt.gap_evt.params.connected.peer_addr.addr_type)
{
case BLE_GAP_ADDR_TYPE_PUBLIC:
/* fall-through */
case BLE_GAP_ADDR_TYPE_RANDOM_STATIC:
err_code = pdb_read_buf_get(compared_peer_id,
PM_PEER_DATA_ID_BONDING,
&compared_data,
NULL);
if ((err_code == NRF_SUCCESS) &&
addr_compare(&ble_evt->evt.gap_evt.params.connected.peer_addr,
&compared_data.p_bonding_data->peer_id.id_addr_info)
)
{
bonded_matching_peer_id = compared_peer_id;
}
break;
case BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE:
err_code = pdb_read_buf_get(compared_peer_id,
PM_PEER_DATA_ID_BONDING,
&compared_data,
NULL);
if (err_code == NRF_SUCCESS &&
im_address_resolve(&ble_evt->evt.gap_evt.params.connected.peer_addr,
&compared_data.p_bonding_data->peer_id.id_info)
)
{
bonded_matching_peer_id = compared_peer_id;
}
break;
case BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE:
// Should not happen.
break;
default:
break;
}
compared_peer_id = pdb_next_peer_id_get(compared_peer_id);
}
}
uint8_t new_index = new_connection(ble_evt->evt.gap_evt.conn_handle, &ble_evt->evt.gap_evt.params.connected.peer_addr);
UNUSED_VARIABLE(new_index);
if (bonded_matching_peer_id != PM_PEER_ID_INVALID)
{
im_new_peer_id(ble_evt->evt.gap_evt.conn_handle, bonded_matching_peer_id);
// Send a bonded peer event
im_evt_t im_evt;
im_evt.conn_handle = ble_evt->evt.gap_evt.conn_handle;
im_evt.evt_id = IM_EVT_BONDED_PEER_CONNECTED;
evt_send(&im_evt);
}
}
}
}
/**@brief Function to compare two sets of bonding data to check if they belong to the same device.
* @note Invalid irks will never match even though they are identical.
*
* @param[in] p_bonding_data1 First bonding data for comparison
* @param[in] p_bonding_data2 Second bonding data for comparison
*
* @return True if the input matches, false if it does not.
*/
bool is_duplicate_bonding_data(pm_peer_data_bonding_t const * p_bonding_data1,
pm_peer_data_bonding_t const * p_bonding_data2)
{
bool valid_irk = is_valid_irk(&p_bonding_data1->peer_id.id_info);
bool duplicate_irk = valid_irk &&
(memcmp(p_bonding_data1->peer_id.id_info.irk,
p_bonding_data2->peer_id.id_info.irk,
BLE_GAP_SEC_KEY_LEN) == 0
);
bool duplicate_addr = addr_compare(&p_bonding_data1->peer_id.id_addr_info,
&p_bonding_data2->peer_id.id_addr_info
);
return duplicate_irk || duplicate_addr;
}
/**@brief Event handler for events from the peer_database module.
*
* @param[in] p_event The event that has happend with peer id and flags.
*/
static void pdb_evt_handler(pdb_evt_t const * p_event)
{
ret_code_t err_code;
if ((p_event != NULL) && (p_event->evt_id == PDB_EVT_WRITE_BUF_STORED))
{
// If new data about peer id has been stored it is compared to other peers peer ids in
// search of duplicates.
if (p_event->data_id == PM_PEER_DATA_ID_BONDING)
{
pm_peer_data_flash_t written_data;
err_code = pdb_read_buf_get(p_event->peer_id, PM_PEER_DATA_ID_BONDING, &written_data, NULL);
if (err_code == NRF_SUCCESS)
{
pm_peer_id_t compared_peer_id = pdb_next_peer_id_get(PM_PEER_ID_INVALID);
while (compared_peer_id != PM_PEER_ID_INVALID)
{
pm_peer_data_flash_t compared_data;
err_code = pdb_read_buf_get(compared_peer_id,
PM_PEER_DATA_ID_BONDING,
&compared_data,
NULL);
if ( err_code == NRF_SUCCESS &&
p_event->peer_id != compared_peer_id &&
is_duplicate_bonding_data(written_data.p_bonding_data,
compared_data.p_bonding_data)
)
{
im_evt_t im_evt;
im_evt.conn_handle = im_conn_handle_get(p_event->peer_id);
im_evt.evt_id = IM_EVT_DUPLICATE_ID;
im_evt.params.duplicate_id.peer_id_1 = p_event->peer_id;
im_evt.params.duplicate_id.peer_id_2 = compared_peer_id;
evt_send(&im_evt);
}
compared_peer_id = pdb_next_peer_id_get(compared_peer_id);
}
}
}
}
}
ret_code_t im_register(im_evt_handler_t evt_handler)
{
VERIFY_PARAM_NOT_NULL(evt_handler);
ret_code_t err_code = NRF_SUCCESS;
if (!MODULE_INITIALIZED)
{
internal_state_reset();
m_im.conn_state_user_flag_id = ble_conn_state_user_flag_acquire();
if (m_im.conn_state_user_flag_id == BLE_CONN_STATE_USER_FLAG_INVALID)
{
err_code = NRF_ERROR_NO_MEM;
}
else
{
err_code = pdb_register(pdb_evt_handler);
}
}
if (err_code == NRF_SUCCESS)
{
if ((m_im.n_registrants < MAX_REGISTRANTS))
{
m_im.evt_handlers[m_im.n_registrants++] = evt_handler;
}
else
{
err_code = NRF_ERROR_NO_MEM;
}
}
return err_code;
}
pm_peer_id_t im_peer_id_get_by_conn_handle(uint16_t conn_handle)
{
uint8_t conn_index = get_connection_by_conn_handle(conn_handle);
if (MODULE_INITIALIZED && (conn_index != IM_NO_INVALID_CONN_HANDLES))
{
return m_im.connections[conn_index].peer_id;
}
return PM_PEER_ID_INVALID;
}
ret_code_t im_ble_addr_get(uint16_t conn_handle, ble_gap_addr_t * p_ble_addr)
{
VERIFY_MODULE_INITIALIZED();
VERIFY_PARAM_NOT_NULL(p_ble_addr);
uint8_t conn_index = get_connection_by_conn_handle(conn_handle);
if (conn_index != IM_NO_INVALID_CONN_HANDLES)
{
*p_ble_addr = m_im.connections[conn_index].peer_address;
return NRF_SUCCESS;
}
return NRF_ERROR_NOT_FOUND;
}
bool im_master_ids_compare(ble_gap_master_id_t const * p_master_id1,
ble_gap_master_id_t const * p_master_id2)
{
if(!im_master_id_is_valid(p_master_id1))
{
return false;
}
if (p_master_id1->ediv != p_master_id2->ediv)
{
return false;
}
return (memcmp(p_master_id1->rand, p_master_id2->rand, BLE_GAP_SEC_RAND_LEN) == 0);
}
pm_peer_id_t im_peer_id_get_by_master_id(ble_gap_master_id_t * p_master_id)
{
ret_code_t err_code;
// For each stored peer, check if the master_id match p_master_id
pm_peer_id_t compared_peer_id = pdb_next_peer_id_get(PM_PEER_ID_INVALID);
while (compared_peer_id != PM_PEER_ID_INVALID)
{
pm_peer_data_flash_t compared_data;
ble_gap_master_id_t const * p_compared_master_id;
err_code = pdb_read_buf_get(compared_peer_id, PM_PEER_DATA_ID_BONDING, &compared_data, NULL);
if (err_code == NRF_SUCCESS)
{
p_compared_master_id = &compared_data.p_bonding_data->own_ltk.master_id;
if (im_master_ids_compare(p_master_id, p_compared_master_id))
{
// If a matching master_id is found return the peer_id
return compared_peer_id;
}
p_compared_master_id = &compared_data.p_bonding_data->peer_ltk.master_id;
if (im_master_ids_compare(p_master_id, p_compared_master_id))
{
// If a matching master_id is found return the peer_id
return compared_peer_id;
}
}
compared_peer_id = pdb_next_peer_id_get(compared_peer_id);
}
// If no matching master_id is found return the PM_PEER_ID_INVALID
return PM_PEER_ID_INVALID;
}
pm_peer_id_t im_peer_id_get_by_irk_match_idx(uint8_t irk_match_idx)
{
// Verify that the requested idx is within the list
if (irk_match_idx < m_im.n_irk_whitelist_peer_ids)
{
// Return the peer_id from the white list
return m_im.irk_whitelist_peer_ids[irk_match_idx];
}
else
{
// Return PM_PEER_ID_INVALID to indicate that there was no peer with the requested idx
return PM_PEER_ID_INVALID;
}
}
uint16_t im_conn_handle_get(pm_peer_id_t peer_id)
{
for (uint32_t i = 0; i < IM_MAX_CONN_HANDLES; i++)
{
if (peer_id == m_im.connections[i].peer_id)
{
return m_im.connections[i].conn_handle;
}
}
return BLE_CONN_HANDLE_INVALID;
}
bool im_master_id_is_valid(ble_gap_master_id_t const * p_master_id)
{
if (p_master_id->ediv != 0)
{
return true;
}
for (uint32_t i = 0; i < BLE_GAP_SEC_RAND_LEN; i++)
{
if (p_master_id->rand[i] != 0)
{
return true;
}
}
return false;
}
/**@brief Function to set the peer ID associated with a connection handle.
*
* @param[in] conn_handle The connection handle.
* @param[in] peer_id The peer ID to associate with @c conn_handle.
*/
static void peer_id_set(uint16_t conn_handle, pm_peer_id_t peer_id)
{
uint8_t conn_index = get_connection_by_conn_handle(conn_handle);
if (conn_index != IM_NO_INVALID_CONN_HANDLES)
{
m_im.connections[conn_index].peer_id = peer_id;
}
}
void im_new_peer_id(uint16_t conn_handle, pm_peer_id_t peer_id)
{
peer_id_set(conn_handle, peer_id);
}
ret_code_t im_peer_free(pm_peer_id_t peer_id)
{
VERIFY_MODULE_INITIALIZED();
uint16_t conn_handle = im_conn_handle_get(peer_id);
ret_code_t err_code = pdb_peer_free(peer_id);
if ((conn_handle != BLE_CONN_HANDLE_INVALID) && (err_code == NRF_SUCCESS))
{
peer_id_set(conn_handle, PM_PEER_ID_INVALID);
}
return err_code;
}
ret_code_t im_whitelist_create(pm_peer_id_t * p_peer_ids,
uint8_t n_peer_ids,
ble_gap_whitelist_t * p_whitelist)
{
VERIFY_MODULE_INITIALIZED();
VERIFY_PARAM_NOT_NULL(p_whitelist);
ret_code_t err_code;
p_whitelist->addr_count = 0;
p_whitelist->irk_count = 0;
m_im.n_irk_whitelist_peer_ids = 0;
for (uint32_t peer_index = 0; peer_index < n_peer_ids; peer_index++)
{
uint16_t conn_handle = im_conn_handle_get(p_peer_ids[peer_index]);
if (ble_conn_state_status(conn_handle) != BLE_CONN_STATUS_CONNECTED)
{
pm_peer_data_flash_t peer_data;
err_code = pdb_read_buf_get(p_peer_ids[peer_index], PM_PEER_DATA_ID_BONDING, &peer_data, NULL);
if (err_code == NRF_ERROR_INVALID_PARAM || err_code == NRF_ERROR_NOT_FOUND)
{
return NRF_ERROR_INVALID_PARAM;
}
if (p_whitelist->pp_addrs != NULL &&
peer_data.p_bonding_data->peer_id.id_addr_info.addr_type
!= BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE &&
peer_data.p_bonding_data->peer_id.id_addr_info.addr_type
!= BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_NON_RESOLVABLE
)
{
memcpy(m_im.whitelist_addrs[peer_index].addr,
peer_data.p_bonding_data->peer_id.id_addr_info.addr,
BLE_GAP_ADDR_LEN
);
m_im.whitelist_addrs[peer_index].addr_type =
peer_data.p_bonding_data->peer_id.id_addr_info.addr_type;
p_whitelist->pp_addrs[peer_index] = &m_im.whitelist_addrs[peer_index];
p_whitelist->addr_count++;
}
if (p_whitelist->pp_irks != NULL &&
is_valid_irk(&(peer_data.p_bonding_data->peer_id.id_info))
)
{
memcpy(m_im.whitelist_irks[peer_index].irk,
peer_data.p_bonding_data->peer_id.id_info.irk,
BLE_GAP_SEC_KEY_LEN
);
p_whitelist->pp_irks[peer_index] = &m_im.whitelist_irks[peer_index];
p_whitelist->irk_count++;
m_im.irk_whitelist_peer_ids[peer_index] = p_peer_ids[peer_index];
m_im.n_irk_whitelist_peer_ids++;
}
}
}
return NRF_SUCCESS;
}
ret_code_t im_whitelist_custom(ble_gap_whitelist_t const * p_whitelist)
{
ret_code_t err_code;
pm_peer_id_t new_irk_whitelist_peer_ids[BLE_GAP_WHITELIST_IRK_MAX_COUNT];
uint32_t n_new_irk_whitelist_peer_ids = 0;
VERIFY_PARAM_NOT_NULL(p_whitelist);
for (uint32_t i = 0; i < BLE_GAP_WHITELIST_IRK_MAX_COUNT; i++)
{
new_irk_whitelist_peer_ids[i] = PM_PEER_ID_INVALID;
}
pm_peer_id_t compared_peer_id = pdb_next_peer_id_get(PM_PEER_ID_INVALID);
while (compared_peer_id != PM_PEER_ID_INVALID)
{
pm_peer_data_flash_t compared_data;
err_code = pdb_read_buf_get(compared_peer_id, PM_PEER_DATA_ID_BONDING, &compared_data, NULL);
if (err_code == NRF_SUCCESS)
{
for (uint32_t i = 0; i < p_whitelist->irk_count; i++)
{
bool valid_irk = is_valid_irk(&compared_data.p_bonding_data->peer_id.id_info);
bool duplicate_irk = valid_irk &&
(memcmp(p_whitelist->pp_irks[i]->irk,
compared_data.p_bonding_data->peer_id.id_info.irk,
BLE_GAP_SEC_KEY_LEN) == 0
);
if (duplicate_irk)
{
new_irk_whitelist_peer_ids[i] = compared_peer_id;
n_new_irk_whitelist_peer_ids++;
}
}
}
compared_peer_id = pdb_next_peer_id_get(compared_peer_id);
}
if (n_new_irk_whitelist_peer_ids != p_whitelist->irk_count)
{
return NRF_ERROR_NOT_FOUND;
}
else
{
for (uint32_t i = 0; i < n_new_irk_whitelist_peer_ids; i++)
{
m_im.irk_whitelist_peer_ids[i] = new_irk_whitelist_peer_ids[i];
}
m_im.n_irk_whitelist_peer_ids = n_new_irk_whitelist_peer_ids;
return NRF_SUCCESS;
}
}
/**@brief Function for calculating the ah() hash function described in Bluetooth core specification
* 4.2 section 3.H.2.2.2.
*
* @detail BLE uses a hash function to calculate the first half of a resolvable address
* from the second half of the address and an irk. This function will use the ECB
* periferal to hash these data acording to the Bluetooth core specification.
*
* @note The ECB expect little endian input and output.
* This function expect big endian and will reverse the data as necessary.
*
* @param[in] p_k The key used in the hash function.
* For address resolution this is should be the irk.
* The array must have a length of 16.
* @param[in] p_r The rand used in the hash function. For generating a new address
* this would be a random number. For resolving a resolvable address
* this would be the last half of the address being resolved.
* The array must have a length of 3.
* @param[out] p_local_hash The result of the hash operation. For address resolution this
* will match the first half of the address being resolved if and only
* if the irk used in the hash function is the same one used to generate
* the address.
* The array must have a length of 16.
*/
void ah(uint8_t const * p_k, uint8_t const * p_r, uint8_t * p_local_hash)
{
ret_code_t err_code;
nrf_ecb_hal_data_t ecb_hal_data;
for (uint32_t i = 0; i < SOC_ECB_KEY_LENGTH; i++)
{
ecb_hal_data.key[i] = p_k[SOC_ECB_KEY_LENGTH - 1 - i];
}
memset(ecb_hal_data.cleartext, 0, SOC_ECB_KEY_LENGTH - IM_ADDR_CLEARTEXT_LENGTH);
for (uint32_t i = 0; i < IM_ADDR_CLEARTEXT_LENGTH; i++)
{
ecb_hal_data.cleartext[SOC_ECB_KEY_LENGTH - 1 - i] = p_r[i];
}
err_code = sd_ecb_block_encrypt(&ecb_hal_data); // Can only return NRF_SUCCESS.
UNUSED_VARIABLE(err_code);
for (uint32_t i = 0; i < IM_ADDR_CIPHERTEXT_LENGTH; i++)
{
p_local_hash[i] = ecb_hal_data.ciphertext[SOC_ECB_KEY_LENGTH - 1 - i];
}
}
bool im_address_resolve(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * p_irk)
{
if (p_addr->addr_type != BLE_GAP_ADDR_TYPE_RANDOM_PRIVATE_RESOLVABLE)
{
return false;
}
uint8_t hash[IM_ADDR_CIPHERTEXT_LENGTH];
uint8_t local_hash[IM_ADDR_CIPHERTEXT_LENGTH];
uint8_t prand[IM_ADDR_CLEARTEXT_LENGTH];
memcpy(hash, p_addr->addr, IM_ADDR_CIPHERTEXT_LENGTH);
memcpy(prand, &p_addr->addr[IM_ADDR_CIPHERTEXT_LENGTH], IM_ADDR_CLEARTEXT_LENGTH);
ah(p_irk->irk, prand, local_hash);
return (memcmp(hash, local_hash, IM_ADDR_CIPHERTEXT_LENGTH) == 0);
}

View File

@ -0,0 +1,301 @@
/*
* Copyright (c) 2015 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#ifndef PEER_ID_MANAGER_H__
#define PEER_ID_MANAGER_H__
#include <stdint.h>
#include "sdk_errors.h"
#include "nrf_ble.h"
#include "nrf_ble_gap.h"
#include "peer_manager_types.h"
/**
* @cond NO_DOXYGEN
* @defgroup id_manager ID Manager
* @ingroup peer_manager
* @{
* @brief An internal module of @ref peer_manager. A module for keeping track of peer identities
* (IRK and peer address).
*/
/**@brief Events that can come from the ID Manager module.
*/
typedef enum
{
IM_EVT_DUPLICATE_ID, /**< The ID Manager module has detected that two stored peers represent the same peer. */
IM_EVT_BONDED_PEER_CONNECTED, /**< A connected peer has been identified as one of the bonded peers. This can happen immediately on connection, or at a later time. */
} im_evt_id_t;
typedef struct
{
im_evt_id_t evt_id;
uint16_t conn_handle;
union
{
struct
{
pm_peer_id_t peer_id_1;
pm_peer_id_t peer_id_2;
} duplicate_id;
} params;
} im_evt_t;
/**@brief Event handler for events from the ID Manager module.
*
* @param[in] p_event The event that has happened.
*/
typedef void (*im_evt_handler_t)(im_evt_t const * p_event);
/**@brief Function for registering for events from the ID Manager module.
*
* @note This will also initialize the module if needed.
*
* @param[in] evt_handler Callback for events from the ID Manager module.
*
* @retval NRF_SUCCESS Registration was successful.
* @retval NRF_ERROR_NO_MEM No more registrations possible.
* @retval NRF_ERROR_NULL evt_handler was NULL.
*/
ret_code_t im_register(im_evt_handler_t evt_handler);
/**@brief Function for dispatching SoftDevice events to the ID Manager module.
*
* @param[in] p_ble_evt The SoftDevice event.
*/
void im_ble_evt_handler(ble_evt_t * p_ble_evt);
/**@brief Function for getting the corresponding peer ID from a connection handle.
*
* @param[in] conn_handle The connection handle.
*
* @return The corresponding peer ID, or @ref PM_PEER_ID_INVALID if none could be resolved.
*/
pm_peer_id_t im_peer_id_get_by_conn_handle(uint16_t conn_handle);
/**@brief Function for getting the corresponding peer ID from a master ID (EDIV and rand).
*
* @param[in] p_master_id The master ID.
*
* @return The corresponding peer ID, or @ref PM_PEER_ID_INVALID if none could be resolved.
*/
pm_peer_id_t im_peer_id_get_by_master_id(ble_gap_master_id_t * p_master_id);
/**@brief Function for getting the corresponding peer ID from an IRK match index, see @ref
* ble_gap_evt_connected_t.
*
* @param[in] irk_match_idx The IRK match index.
*
* @return The corresponding peer ID, or @ref PM_PEER_ID_INVALID if none could be resolved.
*/
pm_peer_id_t im_peer_id_get_by_irk_match_idx(uint8_t irk_match_idx);
/**@brief Function for getting the corresponding connection handle from a peer ID.
*
* @param[in] peer_id The peer ID.
*
* @return The corresponding connection handle, or @ref BLE_CONN_HANDLE_INVALID if none could be
* resolved.
*/
uint16_t im_conn_handle_get(pm_peer_id_t peer_id);
/**@brief Function for comparing two master ids
* @note Two invalid master IDs will not match.
*
* @param[in] p_master_id1 First master id for comparison
* @param[in] p_master_id2 Second master id for comparison
*
* @return True if the input matches, false if it does not.
*/
bool im_master_ids_compare(ble_gap_master_id_t const * p_master_id1,
ble_gap_master_id_t const * p_master_id2);
/**@brief Function for getting the BLE address used by the peer when connecting.
*
* @param[in] conn_handle The connection handle.
* @param[out] p_ble_addr The BLE address used by the peer when the connection specified by
* conn_handle was established.
*
* @retval NRF_SUCCESS The address was found and copied.
* @retval NRF_ERROR_INVALID_STATE Module not initialized.
* @retval BLE_ERROR_CONN_HANDLE_INVALID conn_handle does not refer to an active connection.
* @retval NRF_ERROR_NULL p_ble_addr was NULL.
*/
ret_code_t im_ble_addr_get(uint16_t conn_handle, ble_gap_addr_t * p_ble_addr);
/**@brief Function for checking whether a master ID is valid or invalid
*
* @param[in] p_master_id The master ID.
*
* @retval true The master id is valid.
* @retval true The master id is invalid (i.e. all zeros).
*/
bool im_master_id_is_valid(ble_gap_master_id_t const * p_master_id);
/**@brief Function for reporting that a new peer ID has been allocated for a specified connection.
*
* @param[in] conn_handle The connection.
* @param[in] peer_id The new peer ID.
*/
void im_new_peer_id(uint16_t conn_handle, pm_peer_id_t peer_id);
/**@brief Function for deleting all of a peer's data from flash and disassociating it from any
* connection handles it is associated with.
*
* @param[in] peer_id The peer to free.
*
* @return Any error code returned by @ref pdb_peer_free.
*/
ret_code_t im_peer_free(pm_peer_id_t peer_id);
/**@brief Function for informing this module of what whitelist will be used.
*
* @details This function is meant to be used when the app wants to use a custom whitelist.
* When using peer manager, this function must be used if a custom whitelist is used.
* Only whitelisted IRKs are of any importance for this function.
*
* @note When using a whitelist, always use the whitelist created/set by the most recent
* call to @ref im_whitelist_create or to this function, whichever happened most recently.
* @note Do not call this function while scanning with another whitelist.
* @note Do not add any irks to the whitelist that are not present in the bonding data of a peer in
* the peer database.
* @note The whitelist is not altered in any way by calling this function. Only the internal state
* of the module is changed.
*
* @param[in] p_whitelist The whitelist.
*
* @retval NRF_SUCCESS Whitelist successfully set.
* @retval NRF_ERROR_NULL p_whitelist was NULL.
* @retval NRF_ERROR_NOT_FOUND One or more of the whitelists irks was not found in the peer_database.
*/
ret_code_t im_whitelist_custom(ble_gap_whitelist_t const * p_whitelist);
/**
* @brief Function for constructing a whitelist for use when advertising.
*
* @note When advertising with whitelist, always use the whitelist created/set by the most recent
* call to this function or to @ref im_whitelist_custom, whichever happened most recently.
* @note Do not call this function while advertising with another whitelist.
*
* @param[in] p_peer_ids The ids of the peers to be added to the whitelist.
* @param[in] n_peer_ids The number of peer ids in p_peer_ids.
* @param[in,out] p_whitelist The constructed whitelist. Note that p_adv_whitelist->pp_addrs
* must be NULL or point to an array with size @ref
* BLE_GAP_WHITELIST_ADDR_MAX_COUNT and p_adv_whitelist->pp_irks
* must be NULL or point to an array with size @ref
* BLE_GAP_WHITELIST_IRK_MAX_COUNT.
*
* @retval NRF_SUCCESS Whitelist successfully created.
* @retval NRF_ERROR_NULL p_whitelist was NULL.
*/
ret_code_t im_whitelist_create(pm_peer_id_t * p_peer_ids,
uint8_t n_peer_ids,
ble_gap_whitelist_t * p_whitelist);
/**
* @brief Function for resolving a resolvable address with an identity resolution key (IRK).
*
* @details This function will use the ECB peripheral to resolve a resolvable address.
* This can be used to resolve the identity of a device distributing a random
* resolvable address based on any IRKs you have received earlier. If an address is
* resolved by an IRK, the device disributing the address must also know the IRK.
*
* @param[in] p_addr A random resolvable address.
* @param[in] p_irk An identity resolution key (IRK).
*
* @retval true The irk used matched the one used to create the address.
* @retval false The irk used did not match the one used to create the address, or an argument was
* NULL.
*/
bool im_address_resolve(ble_gap_addr_t const * p_addr, ble_gap_irk_t const * p_irk);
/**@brief Function for calculating the ah() hash function described in Bluetooth core specification
* 4.2 section 3.H.2.2.2.
*
* @detail BLE uses a hash function to calculate the first half of a resolvable address
* from the second half of the address and an irk. This function will use the ECB
* periferal to hash these data acording to the Bluetooth core specification.
*
* @note The ECB expect little endian input and output.
* This function expect big endian and will reverse the data as necessary.
*
* @param[in] p_k The key used in the hash function.
* For address resolution this is should be the irk.
* The array must have a length of 16.
* @param[in] p_r The rand used in the hash function. For generating a new address
* this would be a random number. For resolving a resolvable address
* this would be the last half of the address being resolved.
* The array must have a length of 3.
* @param[out] p_local_hash The result of the hash operation. For address resolution this
* will match the first half of the address being resolved if and only
* if the irk used in the hash function is the same one used to generate
* the address.
* The array must have a length of 16.
*
* @note ====IMPORTANT====
* This is a special modification to the original nRF5x SDK required by the mbed BLE API
* to be able to generate BLE private resolvable addresses. This function is used by
* the BLE API implementation for nRF5xSecurityManager::getAddressFromBondTable() in the
* ble-nrf52832 yotta module.
* =================
*/
void ah(uint8_t const * p_k, uint8_t const * p_r, uint8_t * p_local_hash);
/** @}
* @endcond
*/
#endif /* PEER_ID_MANAGER_H__ */

View File

@ -0,0 +1,92 @@
/*
* Copyright (c) 2015 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#include "peer_data.h"
#include "peer_manager_types.h"
#include "fds.h"
#include "sdk_common.h"
void peer_data_parts_get(pm_peer_data_const_t const * p_peer_data, fds_record_chunk_t * p_chunks, uint16_t * p_n_chunks)
{
if (p_n_chunks == NULL)
{
}
else if ((p_peer_data == NULL) || (p_chunks == NULL))
{
*p_n_chunks = 0;
}
else
{
p_chunks[0].p_data = p_peer_data->p_all_data;
p_chunks[0].length_words = p_peer_data->length_words;
*p_n_chunks = 1;
}
}
ret_code_t peer_data_deserialize(pm_peer_data_flash_t const * p_in_data, pm_peer_data_t * p_out_data)
{
ret_code_t err_code = NRF_SUCCESS;
if ((p_in_data == NULL) || (p_out_data == NULL))
{
err_code = NRF_ERROR_NULL;
}
else
{
if (p_out_data->length_words < p_in_data->length_words)
{
p_out_data->length_words = p_in_data->length_words;
err_code = NRF_ERROR_NO_MEM;
}
else
{
p_out_data->length_words = p_in_data->length_words;
p_out_data->data_id = p_in_data->data_id;
memcpy(p_out_data->p_all_data, p_in_data->p_all_data, p_in_data->length_words * 4);
}
}
return err_code;
}

View File

@ -0,0 +1,84 @@
/*
* Copyright (c) 2015 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#ifndef PEER_DATA_H__
#define PEER_DATA_H__
#include <stdint.h>
#include "peer_manager_types.h"
#include "peer_manager_internal.h"
#include "fds.h"
/**
* @cond NO_DOXYGEN
* @defgroup peer_data Peer Data
* @ingroup peer_manager
* @{
* @brief An internal module of @ref peer_manager. This module defines the structure of the data
* that is managed by the @ref peer_manager. It also provides functions for parsing the data.
*/
/**@brief Function for enumerating the separate (non-contiguous) parts of the peer data.
*
* @param[in] p_peer_data The peer data to enumerate.
* @param[out] p_chunks The resulting chunks. This must be an array of at least 2 elements.
* @param[out] p_n_chunks The number of chunks. If this is 0, something went wrong.
*/
void peer_data_parts_get(pm_peer_data_const_t const * p_peer_data, fds_record_chunk_t * p_chunks, uint16_t * p_n_chunks);
/**@brief Function for converting @ref pm_peer_data_flash_t into @ref pm_peer_data_t.
*
* @param[in] p_in_data The source data.
* @param[out] p_out_data The target data structure.
*
* @retval NRF_SUCCESS Successful conversion.
* @retval NRF_ERROR_NULL A parameter was NULL.
* @retval NRF_ERROR_NO_MEM A buffer was not large enough.
*/
ret_code_t peer_data_deserialize(pm_peer_data_flash_t const * p_in_data, pm_peer_data_t * p_out_data);
/** @}
* @endcond
*/
#endif /* PEER_DATA_H__ */

View File

@ -0,0 +1,787 @@
/*
* Copyright (c) 2015 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#include "peer_data_storage.h"
#include <stdint.h>
#include <string.h>
#include "sdk_errors.h"
#include "peer_manager_types.h"
#include "peer_manager_internal.h"
#include "peer_id.h"
#include "peer_data.h"
#include "fds.h"
#include "sdk_common.h"
// The number of user that can register with the module.
#define MAX_REGISTRANTS 6
// Macro for verifying that param is not zero.
#define VERIFY_PARAM_NOT_ZERO(param) \
do \
{ \
if (param == 0) \
{ \
return NRF_ERROR_NULL; \
} \
} while(0)
// Macro for verifying that the peer id is within a valid range.
#define VERIFY_PEER_ID_IN_RANGE(id) \
do \
{ \
if (id >= PM_PEER_ID_N_AVAILABLE_IDS) \
{ \
return NRF_ERROR_INVALID_PARAM; \
} \
} while (0)
// Macro for verifying that the peer data id is withing a valid range.
#define VERIFY_PEER_DATA_ID_IN_RANGE(id) \
do \
{ \
if (!PM_PEER_DATA_ID_IS_VALID(id)) \
{ \
return NRF_ERROR_INVALID_PARAM; \
} \
} while (0)
// Macro for initializing the peer ID tracking system if it is not already initialized.
#define PEER_IDS_INITIALIZE() \
do \
{ \
if (!m_pds.peer_ids_initialized) \
{ \
peer_ids_init(); \
} \
} while (0)
typedef struct
{
bool peer_ids_initialized;
pds_evt_handler_t evt_handlers[MAX_REGISTRANTS];
uint8_t n_registrants;
bool clearing;
bool clear_queued;
} pds_t;
static pds_t m_pds = { .n_registrants = 0 };
#define MODULE_INITIALIZED (m_pds.n_registrants > 0) /**< Expression which is true when the module is initialized. */
#include "sdk_macros.h"
static void internal_state_reset(pds_t * p_pds)
{
memset(p_pds, 0, sizeof(pds_t));
}
// Function for dispatching outbound events to all registered event handlers.
static void pds_evt_send(pds_evt_t * p_event)
{
for (uint32_t i = 0; i < m_pds.n_registrants; i++)
{
m_pds.evt_handlers[i](p_event);
}
}
// Function to convert peer IDs to file IDs.
static uint16_t peer_id_to_file_id(pm_peer_id_t peer_id)
{
return (uint16_t)(peer_id + PEER_ID_TO_FILE_ID);
}
// Function to convert peer data id to type id.
static pm_peer_id_t file_id_to_peer_id(uint16_t file_id)
{
return (pm_peer_id_t)(file_id + FILE_ID_TO_PEER_ID);
}
// Function to convert peer data IDs to record keys.
static uint16_t peer_data_id_to_record_key(pm_peer_data_id_t peer_data_id)
{
return (uint16_t)peer_data_id + (uint16_t)PEER_DATA_ID_TO_RECORD_KEY;
}
// Function to convert record keys to peer data IDs.
static pm_peer_data_id_t record_key_to_peer_data_id(uint16_t record_key)
{
return (pm_peer_data_id_t)(record_key + RECORD_KEY_TO_PEER_DATA_ID);
}
// Function for clearing all peer data of one peer.
// These operations will be sent to FDS one at a time.
static void peer_data_clear()
{
ret_code_t retval;
uint16_t file_id;
fds_record_desc_t desc;
fds_find_token_t token = {0};
pm_peer_id_t peer_id = peer_id_get_next_deleted(PM_PEER_ID_INVALID);
while ( (peer_id != PM_PEER_ID_INVALID)
&& (fds_record_find_in_file(peer_id_to_file_id(peer_id), &desc, &token)
== FDS_ERR_NOT_FOUND))
{
peer_id_free(peer_id);
peer_id = peer_id_get_next_deleted(peer_id);
}
if (!m_pds.clearing && (peer_id != PM_PEER_ID_INVALID))
{
file_id = peer_id_to_file_id(peer_id);
retval = fds_file_delete(file_id);
if (retval == FDS_SUCCESS)
{
m_pds.clearing = true;
}
else if (retval == FDS_ERR_NO_SPACE_IN_QUEUES)
{
m_pds.clear_queued = true;
}
else
{
pds_evt_t pds_evt;
pds_evt.evt_id = PDS_EVT_ERROR_UNEXPECTED;
pds_evt.peer_id = peer_id;
pds_evt.data_id = PM_PEER_DATA_ID_INVALID;
pds_evt.store_token = PM_STORE_TOKEN_INVALID;
pds_evt.result = retval;
pds_evt_send(&pds_evt);
}
}
}
static ret_code_t find_fds_item(pm_peer_id_t peer_id,
pm_peer_data_id_t data_id,
fds_record_desc_t * const p_desc)
{
fds_find_token_t find_tok = {0};
VERIFY_PEER_ID_IN_RANGE(peer_id);
VERIFY_PEER_DATA_ID_IN_RANGE(data_id);
// pp_record verified by caller.
uint16_t file_id = peer_id_to_file_id(peer_id);
uint16_t record_key = peer_data_id_to_record_key(data_id);
return fds_record_find(file_id, record_key, p_desc, &find_tok);
}
static void peer_ids_init()
{
fds_record_desc_t record_desc;
fds_flash_record_t record;
fds_find_token_t find_tok = {0};
uint16_t const record_key = peer_data_id_to_record_key(PM_PEER_DATA_ID_BONDING);
if (!m_pds.peer_ids_initialized)
{
while(fds_record_find_by_key(record_key, &record_desc, &find_tok) == FDS_SUCCESS)
{
pm_peer_id_t peer_id;
// It is safe to ignore the return value since we just obtained
// this descriptor and also 'record' is different from NULL.
(void)fds_record_open(&record_desc, &record);
peer_id = file_id_to_peer_id(record.p_header->ic.file_id);
(void)fds_record_close(&record_desc);
(void)peer_id_allocate(peer_id);
}
m_pds.peer_ids_initialized = true;
}
}
static void fds_evt_handler(fds_evt_t const * const p_fds_evt)
{
pds_evt_t pds_evt;
bool send_event = true;
pds_evt.result = (p_fds_evt->result == FDS_SUCCESS);
switch(p_fds_evt->id)
{
case FDS_EVT_WRITE:
pds_evt.evt_id = (p_fds_evt->result == FDS_SUCCESS) ? PDS_EVT_STORED :
PDS_EVT_ERROR_STORE;
pds_evt.peer_id = file_id_to_peer_id(p_fds_evt->write.file_id);
pds_evt.data_id = record_key_to_peer_data_id(p_fds_evt->write.record_key);
pds_evt.result = p_fds_evt->result;
pds_evt.store_token = p_fds_evt->write.record_id;
break;
case FDS_EVT_UPDATE:
pds_evt.evt_id = (p_fds_evt->result == FDS_SUCCESS) ? PDS_EVT_UPDATED :
PDS_EVT_ERROR_UPDATE;
pds_evt.peer_id = file_id_to_peer_id(p_fds_evt->write.file_id);
pds_evt.data_id = record_key_to_peer_data_id(p_fds_evt->write.record_key);
pds_evt.result = p_fds_evt->result;
pds_evt.store_token = p_fds_evt->write.record_id;
break;
case FDS_EVT_DEL_RECORD:
pds_evt.evt_id = (p_fds_evt->result == FDS_SUCCESS) ? PDS_EVT_CLEARED :
PDS_EVT_ERROR_CLEAR;
pds_evt.peer_id = file_id_to_peer_id(p_fds_evt->del.file_id);
pds_evt.data_id = record_key_to_peer_data_id(p_fds_evt->del.record_key);
pds_evt.store_token = p_fds_evt->del.record_id;
break;
case FDS_EVT_DEL_FILE:
{
if ((p_fds_evt->del.record_key == FDS_RECORD_KEY_DIRTY) &&
(p_fds_evt->del.file_id != FDS_FILE_ID_INVALID))
{
pds_evt.peer_id = file_id_to_peer_id(p_fds_evt->del.file_id);
pds_evt.data_id = record_key_to_peer_data_id(p_fds_evt->del.record_key);
pds_evt.data_id = PM_PEER_DATA_ID_INVALID;
if (p_fds_evt->result == FDS_SUCCESS)
{
pds_evt.evt_id = PDS_EVT_PEER_ID_CLEAR;
peer_id_free(pds_evt.peer_id);
}
else
{
pds_evt.evt_id = PDS_EVT_ERROR_PEER_ID_CLEAR;
}
m_pds.clearing = false;
m_pds.clear_queued = false;
peer_data_clear();
}
}
break;
case FDS_EVT_GC:
pds_evt.evt_id = PDS_EVT_COMPRESSED;
break;
default:
send_event = false;
break;
}
if (send_event)
{
pds_evt_send(&pds_evt);
}
if (m_pds.clear_queued)
{
m_pds.clear_queued = false;
peer_data_clear();
}
}
ret_code_t pds_register(pds_evt_handler_t evt_handler)
{
if (m_pds.n_registrants >= MAX_REGISTRANTS)
{
return NRF_ERROR_NO_MEM;
}
VERIFY_PARAM_NOT_NULL(evt_handler);
if (!MODULE_INITIALIZED)
{
ret_code_t retval;
internal_state_reset(&m_pds);
peer_id_init();
retval = fds_register(fds_evt_handler);
if (retval != FDS_SUCCESS)
{
return NRF_ERROR_NO_MEM;
}
retval = fds_init();
if (retval != FDS_SUCCESS)
{
return NRF_ERROR_INTERNAL;
}
}
m_pds.evt_handlers[m_pds.n_registrants] = evt_handler;
m_pds.n_registrants += 1;
return NRF_SUCCESS;
}
ret_code_t pds_peer_data_read_ptr_get(pm_peer_id_t peer_id,
pm_peer_data_id_t data_id,
pm_peer_data_flash_t * p_data,
pm_store_token_t * p_token)
{
ret_code_t retval;
fds_flash_record_t record;
fds_record_desc_t record_desc;
VERIFY_MODULE_INITIALIZED();
VERIFY_PEER_ID_IN_RANGE(peer_id);
VERIFY_PEER_DATA_ID_IN_RANGE(data_id);
VERIFY_PARAM_NOT_NULL(p_data);
retval = find_fds_item(peer_id, data_id, &record_desc);
if (retval != FDS_SUCCESS)
{
return NRF_ERROR_NOT_FOUND;
}
// Shouldn't fail, unless the record was deleted.
(void)fds_record_open(&record_desc, &record);
if (p_data != NULL)
{
p_data->data_id = data_id;
p_data->length_words = record.p_header->tl.length_words;
p_data->p_all_data = record.p_data;
}
if (p_token != NULL)
{
*p_token = (uint32_t)record.p_header->record_id;
}
// Shouldn't fail, unless the record was already closed.
(void)fds_record_close(&record_desc);
return NRF_SUCCESS;
}
ret_code_t pds_peer_data_lock(pm_store_token_t store_token)
{
VERIFY_MODULE_INITIALIZED();
VERIFY_PARAM_NOT_ZERO(store_token);
// TODO: Not implemented in fds yet.
return NRF_SUCCESS;
}
ret_code_t pds_peer_data_verify(pm_store_token_t store_token)
{
VERIFY_MODULE_INITIALIZED();
VERIFY_PARAM_NOT_ZERO(store_token);
// TODO: Not implemented in fds yet.
return NRF_SUCCESS;
}
ret_code_t pds_peer_data_read(pm_peer_id_t peer_id,
pm_peer_data_id_t data_id,
pm_peer_data_t * p_data,
uint16_t * p_len_words)
{
ret_code_t retval;
pm_peer_data_flash_t peer_data_flash;
VERIFY_PEER_ID_IN_RANGE(peer_id);
VERIFY_PEER_DATA_ID_IN_RANGE(data_id);
VERIFY_PARAM_NOT_NULL(p_len_words);
VERIFY_PARAM_NOT_NULL(p_data);
retval = pds_peer_data_read_ptr_get(peer_id, data_id, &peer_data_flash, NULL);
if (retval != NRF_SUCCESS)
{
return retval;
}
if ((*p_len_words) == 0)
{
(*p_len_words) = peer_data_flash.length_words;
return NRF_SUCCESS;
}
else if ((*p_len_words) < peer_data_flash.length_words)
{
return NRF_ERROR_NO_MEM;
}
VERIFY_PARAM_NOT_NULL(p_data->p_all_data);
retval = peer_data_deserialize(&peer_data_flash, p_data);
return retval;
}
ret_code_t pds_peer_data_write_prepare(pm_peer_data_const_t const * p_peer_data,
pm_prepare_token_t * p_prepare_token)
{
ret_code_t retval;
VERIFY_MODULE_INITIALIZED();
VERIFY_PARAM_NOT_NULL(p_peer_data);
VERIFY_PEER_DATA_ID_IN_RANGE(p_peer_data->data_id);
//VERIFY_PARAM_NOT_NULL(p_prepare_token); redundant, see fds_reserve().
retval = fds_reserve((fds_reserve_token_t*)p_prepare_token, p_peer_data->length_words);
switch (retval)
{
case FDS_SUCCESS:
return NRF_SUCCESS;
case FDS_ERR_NULL_ARG:
return NRF_ERROR_NULL;
case FDS_ERR_RECORD_TOO_LARGE:
return NRF_ERROR_INVALID_LENGTH;
case FDS_ERR_NO_SPACE_IN_FLASH:
return NRF_ERROR_NO_MEM;
default:
return NRF_ERROR_INTERNAL;
}
}
ret_code_t pds_peer_data_write_prepare_cancel(pm_prepare_token_t prepare_token)
{
ret_code_t retval;
VERIFY_MODULE_INITIALIZED();
VERIFY_PARAM_NOT_ZERO(prepare_token);
retval = fds_reserve_cancel((fds_reserve_token_t*)&prepare_token);
switch (retval)
{
case FDS_SUCCESS:
return NRF_SUCCESS;
case FDS_ERR_NULL_ARG:
return NRF_ERROR_NULL;
default:
return NRF_ERROR_INTERNAL;
}
}
ret_code_t pds_peer_data_write_prepared(pm_peer_id_t peer_id,
pm_peer_data_const_t const * p_peer_data,
pm_prepare_token_t prepare_token,
pm_store_token_t * p_store_token)
{
ret_code_t retval;
fds_record_t record;
fds_record_desc_t record_desc;
fds_record_chunk_t chunks[2];
uint16_t n_chunks;
VERIFY_MODULE_INITIALIZED();
VERIFY_PEER_ID_IN_RANGE(peer_id);
VERIFY_PARAM_NOT_NULL(p_peer_data);
VERIFY_PEER_DATA_ID_IN_RANGE(p_peer_data->data_id);
VERIFY_PARAM_NOT_ZERO(prepare_token);
// Create chunks.
peer_data_parts_get(p_peer_data, chunks, &n_chunks);
// Prepare the record to be written.
record.file_id = peer_id_to_file_id(peer_id);
record.key = peer_data_id_to_record_key(p_peer_data->data_id);
record.data.p_chunks = chunks;
record.data.num_chunks = n_chunks;
retval = fds_record_write_reserved(&record_desc,
&record,
(fds_reserve_token_t*)&prepare_token);
if ((retval == FDS_SUCCESS) && (p_store_token != NULL))
{
// If fds_record_write_reserved() returned sucessfully, it is safe
// to ignore the return value from fds_record_id_from_desc() since
// the descriptor is valid, and also p_store_token is different from NULL.
(void)fds_record_id_from_desc(&record_desc, (uint32_t*)p_store_token);
}
switch (retval)
{
case FDS_SUCCESS:
return NRF_SUCCESS;
case FDS_ERR_BUSY:
case FDS_ERR_NO_SPACE_IN_QUEUES:
return NRF_ERROR_BUSY;
default:
return NRF_ERROR_INTERNAL;
}
}
ret_code_t pds_peer_data_write(pm_peer_id_t peer_id,
pm_peer_data_const_t const * p_peer_data,
pm_store_token_t * p_store_token)
{
ret_code_t retval;
fds_record_t record;
fds_record_desc_t record_desc;
fds_record_chunk_t chunks[2];
uint16_t n_chunks;
VERIFY_MODULE_INITIALIZED();
VERIFY_PEER_ID_IN_RANGE(peer_id);
VERIFY_PARAM_NOT_NULL(p_peer_data);
VERIFY_PEER_DATA_ID_IN_RANGE(p_peer_data->data_id);
// Create chunks.
peer_data_parts_get(p_peer_data, chunks, &n_chunks);
// Prepare the record to be written.
record.file_id = peer_id_to_file_id(peer_id);
record.key = peer_data_id_to_record_key(p_peer_data->data_id);
record.data.p_chunks = chunks;
record.data.num_chunks = n_chunks;
retval = fds_record_write(&record_desc, &record);
if ((retval == FDS_SUCCESS) && (p_store_token != NULL))
{
// If fds_record_write() returned sucessfully, it is safe
// to ignore the return value from fds_record_id_from_desc() since
// the descriptor is valid, and also p_store_token is different from NULL.
(void)fds_record_id_from_desc(&record_desc, (uint32_t*)p_store_token);
}
switch (retval)
{
case FDS_SUCCESS:
return NRF_SUCCESS;
case FDS_ERR_BUSY:
case FDS_ERR_NO_SPACE_IN_QUEUES:
return NRF_ERROR_BUSY;
case FDS_ERR_NO_SPACE_IN_FLASH:
return NRF_ERROR_NO_MEM;
default:
return NRF_ERROR_INTERNAL;
}
}
ret_code_t pds_peer_data_update(pm_peer_id_t peer_id,
pm_peer_data_const_t const * p_peer_data,
pm_store_token_t old_token,
pm_store_token_t * p_store_token)
{
ret_code_t retval;
fds_record_t record;
fds_record_desc_t record_desc;
fds_record_chunk_t chunks[2];
uint16_t n_chunks;
VERIFY_MODULE_INITIALIZED();
VERIFY_PEER_ID_IN_RANGE(peer_id);
VERIFY_PARAM_NOT_NULL(p_peer_data);
VERIFY_PEER_DATA_ID_IN_RANGE(p_peer_data->data_id);
// Create chunks.
peer_data_parts_get(p_peer_data, chunks, &n_chunks);
// Prepare the record to be written.
record.file_id = peer_id_to_file_id(peer_id);
record.key = peer_data_id_to_record_key(p_peer_data->data_id);
record.data.p_chunks = chunks;
record.data.num_chunks = n_chunks;
// Obtain the descriptor of the record to be updated.
// It is safe to ignore the return value if record_desc is different from NULL.
(void)fds_descriptor_from_rec_id(&record_desc, (uint32_t)old_token);
retval = fds_record_update(&record_desc, &record);
if ((retval == FDS_SUCCESS) && (p_store_token != NULL))
{
// If fds_record_update() returned sucessfully, it is safe
// to ignore the return value from fds_record_id_from_desc() since
// the descriptor is valid, and also p_store_token is different from NULL.
(void)fds_record_id_from_desc(&record_desc, (uint32_t*)p_store_token);
}
switch (retval)
{
case FDS_SUCCESS:
return NRF_SUCCESS;
case FDS_ERR_BUSY:
case FDS_ERR_NO_SPACE_IN_QUEUES:
return NRF_ERROR_BUSY;
case FDS_ERR_NO_SPACE_IN_FLASH:
return NRF_ERROR_NO_MEM;
default:
return NRF_ERROR_INTERNAL;
}
}
ret_code_t pds_peer_data_clear(pm_peer_id_t peer_id, pm_peer_data_id_t data_id)
{
ret_code_t retval;
uint16_t file_id;
uint16_t record_key;
fds_record_desc_t record_desc;
fds_find_token_t find_tok = {0};
VERIFY_MODULE_INITIALIZED();
VERIFY_PEER_ID_IN_RANGE(peer_id);
VERIFY_PEER_DATA_ID_IN_RANGE(data_id);
file_id = peer_id_to_file_id(peer_id);
record_key = peer_data_id_to_record_key(data_id);
retval = fds_record_find(file_id, record_key, &record_desc, &find_tok);
if(retval != FDS_SUCCESS)
{
return NRF_ERROR_NOT_FOUND;
}
retval = fds_record_delete(&record_desc);
switch (retval)
{
case FDS_SUCCESS:
return NRF_SUCCESS;
case FDS_ERR_NO_SPACE_IN_QUEUES:
return NRF_ERROR_BUSY;
default:
return NRF_ERROR_INTERNAL;
}
}
pm_peer_id_t pds_peer_id_allocate(void)
{
if (!MODULE_INITIALIZED)
{
return PM_PEER_ID_INVALID;
}
PEER_IDS_INITIALIZE();
return peer_id_allocate(PM_PEER_ID_INVALID);
}
ret_code_t pds_peer_id_free(pm_peer_id_t peer_id)
{
VERIFY_MODULE_INITIALIZED();
VERIFY_PEER_ID_IN_RANGE(peer_id);
PEER_IDS_INITIALIZE();
(void)peer_id_delete(peer_id);
peer_data_clear();
return NRF_SUCCESS;
}
bool pds_peer_id_is_allocated(pm_peer_id_t peer_id)
{
if (!MODULE_INITIALIZED)
{
return false;
}
PEER_IDS_INITIALIZE();
return peer_id_is_allocated(peer_id);
}
pm_peer_id_t pds_next_peer_id_get(pm_peer_id_t prev_peer_id)
{
if (!MODULE_INITIALIZED)
{
return PM_PEER_ID_INVALID;
}
PEER_IDS_INITIALIZE();
return peer_id_get_next_used(prev_peer_id);
}
uint32_t pds_n_peers(void)
{
if (!MODULE_INITIALIZED)
{
return 0;
}
PEER_IDS_INITIALIZE();
return peer_id_n_ids();
}
//lint -restore

View File

@ -0,0 +1,381 @@
/*
* Copyright (c) 2015 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#ifndef PEER_DATA_STORAGE_H__
#define PEER_DATA_STORAGE_H__
#include <stdint.h>
#include "sdk_errors.h"
#include "nrf_ble_gap.h"
#include "peer_manager_types.h"
#include "peer_manager_internal.h"
/**
* @cond NO_DOXYGEN
* @defgroup peer_data_storage Peer Data Storage
* @ingroup peer_manager
* @{
* @brief An internal module of @ref peer_manager. This module provides a Peer Manager-specific API
* to the persistent storage.
*/
#define PDS_PREPARE_TOKEN_INVALID 0 /**< Invalid value for prepare token. */
enum
{
PEER_ID_TO_FILE_ID = 0xC000,
FILE_ID_TO_PEER_ID = -PEER_ID_TO_FILE_ID,
PEER_DATA_ID_TO_RECORD_KEY = 0xC000,
RECORD_KEY_TO_PEER_DATA_ID = -PEER_DATA_ID_TO_RECORD_KEY,
};
/**@brief The types of events that can come from the peer_data_storage module.
*/
typedef enum
{
PDS_EVT_STORED, /**< The specified data has been successfully stored. */
PDS_EVT_UPDATED, /**< The specified data has been successfully updated. */
PDS_EVT_CLEARED, /**< The specified data has been successfully cleared. */
PDS_EVT_ERROR_STORE, /**< The specified data could not be stored. */
PDS_EVT_ERROR_UPDATE, /**< The specified data could not be updated. */
PDS_EVT_ERROR_CLEAR, /**< The specified data could not be cleared. */
PDS_EVT_PEER_ID_CLEAR, /**< The peer id has been successfully cleared. */
PDS_EVT_ERROR_PEER_ID_CLEAR, /**< The peer id has been successfully cleared. */
PDS_EVT_COMPRESSED, /**< A compress procedure has finished successfully. */
PDS_EVT_ERROR_UNEXPECTED, /**< An unexpected, possibly fatal error occurred. The unexpected error is included in the event structure. */
} pds_evt_id_t;
/**@brief Events that can come from the peer_data_storage module.
*/
typedef struct
{
pds_evt_id_t evt_id; /**< The type of event. */
pm_peer_id_t peer_id; /**< The peer the event pertains to. */
pm_peer_data_id_t data_id; /**< The data the event pertains to. */
pm_store_token_t store_token; /**< A unique identifier for the operation. Can be compare to the token received when starting the operation. */
ret_code_t result; /**< The result of the operation, or the unexpected error. */
} pds_evt_t;
/**@brief Event handler for events from the peer_data_storage module.
*
* @param[in] event The event that has happened.
* @param[in] peer_id The id of the peer the event pertains to.
* @param[in] flags The data the event pertains to.
*/
typedef void (*pds_evt_handler_t)(pds_evt_t const * p_event);
/**@brief Function for registering for events from the peer database.
*
* @note This function will initialize the module if it is not already initialized.
*
* @param[in] evt_handler Event handler to register.
*
* @retval NRF_SUCCESS Registration successful.
* @retval NRF_ERROR_NO_MEM No more event handlers can be registered.
* @retval NRF_ERROR_NULL evt_handler was NULL.
* @retval NRF_ERROR_INTERNAL An unexpected error happened.
* @retval NRF_ERROR_INTERNAL Unexpected error.
*/
ret_code_t pds_register(pds_evt_handler_t evt_handler);
/**@brief Function for retrieving a direct pointer to peer data in persistent storage.
*
* @param[in] peer_id The id of the peer whose data to read.
* @param[in] data_id Which data to get.
* @param[out] p_data The peer data pointer.
* @param[out] p_token Token that can be used to lock data in flash and check data validity.
*
* @retval NRF_SUCCESS The pointer was successfully retrieved.
* @retval NRF_ERROR_INVALID_PARAM Invalid data_id.
* @retval NRF_ERROR_NOT_FOUND The requested data was not found in persistent storage.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
*/
ret_code_t pds_peer_data_read_ptr_get(pm_peer_id_t peer_id,
pm_peer_data_id_t data_id,
pm_peer_data_flash_t * p_data,
pm_store_token_t * p_token);
#if 0
// @TODO: Finish documentation
/**@brief Function to lock the flash data (to defer compression from invalidating data)
*
* @param[in] store_token The token representing the item to lock
*
* @retval NRF_SUCCESS Successfully locked
*/
ret_code_t pds_peer_data_lock(pm_store_token_t store_token);
/**@brief Function to verify flash data integrity
*
* @param[in] store_token The token representing the item to lock
*
* @retval NRF_SUCCESS The data integrity is valid.
* @retval NRF_ERROR_NULL The token is invalid.
* @retval NRF_ERROR_INVALID_DATA The data integrity is not valid.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
*/
ret_code_t pds_peer_data_verify(pm_store_token_t store_token);
#endif
/**@brief Function for retrieving peer data from persistent storage by making a copy.
*
* @param[in] peer_id The id of the peer whose data to read.
* @param[in] data_id Which piece of data to read.
* @param[out] p_data Pointer to the peer data.
* @param[in,out] p_len_words Length available to copy to (in words).
* If set to NULL, then no copy will be made and the
* length will be reflected in p_len_words after the call returns.
*
* @retval NRF_SUCCESS The read was successful.
* @retval NRF_ERROR_INVALID_PARAM Invalid data_id or peer_id.
* @retval NRF_ERROR_NULL Either \c p_data or \c p_len_words were \c NULL, or \c p_data
* contained a NULL pointer.
* @retval NRF_ERROR_NOT_FOUND The requested data was not found in persistent storage.
* @retval NRF_ERROR_NO_MEM The length of stored data too large to copy out.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
*/
ret_code_t pds_peer_data_read(pm_peer_id_t peer_id,
pm_peer_data_id_t data_id,
pm_peer_data_t * p_data,
uint16_t * p_len_words);
/**@brief Function for preparing persistent storage for a write.
*
* @details If this call succeeds, space is reserved in persistent storage, so the write will fit.
*
* @note If space has already been prepared for this peer_id/data_id pair, no new space will be
* reserved, unless the previous reservation had too small size.
*
* @param[in] p_peer_data Data to prepare for. The data needs not be ready, but length and type
* values must.
* @param[out] p_prepare_token A token identifying the prepared memory area.
*
* @retval NRF_SUCCESS The call was successful.
* @retval NRF_ERROR_NULL Either \c p_peer_data or \c p_prepare code were \c NULL.
* @retval NRF_ERROR_INVALID_PARAM Invalid data ID.
* @retval NRF_ERROR_INVALID_LENGTH Data length exceeds the maximum length allowed.
* @retval NRF_ERROR_NO_MEM No space available in persistent storage.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
* @retval NRF_ERROR_INTERNAL Internal error.
*/
ret_code_t pds_peer_data_write_prepare(pm_peer_data_const_t const * p_peer_data,
pm_prepare_token_t * p_prepare_token);
/**@brief Function for undoing a previous call to @ref pds_peer_data_write_prepare.
*
* @param[in] prepare_token A token identifying the prepared memory area to cancel.
*
* @retval NRF_SUCCESS The call was successful.
* @retval NRF_ERROR_NULL Invalid value for \c prepare_token.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
* @retval NRF_ERROR_INTERNAL Internal error.
*/
ret_code_t pds_peer_data_write_prepare_cancel(pm_prepare_token_t prepare_token);
/**@brief Function for writing prepared (reserved) peer data to persistent storage.
*
* @details Writing happens asynchronously. Expect a @ref PDS_EVT_STORED or @ref PDS_EVT_ERROR_STORE
* event.
*
* @param[in] peer_id The id of the peer the data pertains to.
* @param[in] p_peer_data The peer data.
* @param[in] prepare_token A token identifying the prepared memory area to write into. If
* the prepare token is invalid, e.g. PDS_PREPARE_TOKEN_INVALID, the
* prepare/write sequence will happen atomically.
* @param[out] p_store_token A token identifying this particular store operation. The token can be
* used to identify events pertaining to this operation.
*
* @retval NRF_SUCCESS The write was initiated successfully.
* @retval NRF_ERROR_INVALID_PARAM Invalid peer ID or data ID.
* @retval NRF_ERROR_NULL \c p_peer_data was \c NULL or contained a \c NULL pointer or
* \c prepare_token was zero.
* @retval NRF_ERROR_NO_MEM No space available in persistent storage. This can only happen
* if \c p_prepare_token is \c NULL.
* @retval NRF_ERROR_BUSY FDS or underlying modules are busy and can't take any
* more requests.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
* @retval NRF_ERROR_INTERNAL Internal error.
*/
ret_code_t pds_peer_data_write_prepared(pm_peer_id_t peer_id,
pm_peer_data_const_t const * p_peer_data,
pm_prepare_token_t prepare_token,
pm_store_token_t * p_store_token);
/**@brief Function for writing peer data to persistent storage.
*
* @details Writing happens asynchronously. Expect a @ref PDS_EVT_STORED or @ref PDS_EVT_ERROR_STORE
* event.
*
* @param[in] peer_id The id of the peer the data pertains to.
* @param[in] p_peer_data The peer data.
* @param[out] p_store_token A token identifying this particular store operation. The token can be
* used to identify events pertaining to this operation.
*
* @retval NRF_SUCCESS The write was initiated successfully.
* @retval NRF_ERROR_INVALID_PARAM Invalid data ID or peer ID.
* @retval NRF_ERROR_NULL \c p_peer_data was \c NULL or data contained a \c NULL pointer.
* @retval NRF_ERROR_NO_MEM No space available in persistent storage.
* @retval NRF_ERROR_BUSY FDS or underlying modules are busy and can't take any
* more requests.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
* @retval NRF_ERROR_INTERNAL Internal error.
*/
ret_code_t pds_peer_data_write(pm_peer_id_t peer_id,
pm_peer_data_const_t const * p_peer_data,
pm_store_token_t * p_store_token);
/**@brief Function for updating currently stored peer data to a new version
*
* @details Updating happens asynchronously.
* Expect a @ref PDS_EVT_STORED or @ref PDS_EVT_ERROR_STORE for the store token
* and a @ref PDS_EVT_ERROR_CLEAR or @ref PDS_EVT_ERROR_CLEAR for the old token
*
* @param[in] peer_id The peer which the data is associated to.
* @param[in] p_peer_data New data.
* @param[in] old_token Store token for the old data.
* @param[out] p_store_token Store token for the new data.
*
* @retval NRF_SUCESS The update was initiated successfully
* @retval NRF_ERROR_NULL \c p_peer_data was \c NULL or data contained a \c NULL pointer.
* @retval NRF_ERROR_NO_MEM No space available in persistent storage.
* @retval NRF_ERROR_BUSY FDS or underlying modules are busy and can't take any
* more requests at this moment.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
* @retval NRF_ERROR_INTERNAL Internal error.
*/
ret_code_t pds_peer_data_update(pm_peer_id_t peer_id,
pm_peer_data_const_t const * p_peer_data,
pm_store_token_t old_token,
pm_store_token_t * p_store_token);
/**@brief Function for clearing peer data from persistent storage.
*
* @details Clearing happens asynchronously. Expect a @ref PDS_EVT_CLEARED or @ref PDS_EVT_ERROR_CLEAR
* event.
*
* @param[in] peer_id The id of the peer the data pertains to.
* @param[in] data_id Which data to clear.
*
* @retval NRF_SUCCESS The clear was initiated successfully.
* @retval NRF_ERROR_INVALID_PARAM Data ID or peer ID was invalid.
* @retval NRF_ERROR_NOT_FOUND Nothing to clear for this peer ID.
* @retval NRF_ERROR_BUSY FDS or underlying modules are busy and can't take any
* more requests at this moment.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
* @retval NRF_ERROR_INTERNAL Internal error.
*/
ret_code_t pds_peer_data_clear(pm_peer_id_t peer_id, pm_peer_data_id_t data_id);
/**@brief Function for claiming an unused peer ID.
*
* @return The first unused peer ID.
* @retval PM_PEER_ID_INVALID If no peer ID is available or module is not initialized.
*/
pm_peer_id_t pds_peer_id_allocate(void);
/**@brief Function for freeing a peer ID and clearing all data associated with it in persistent
* storage.
*
* @param[in] peer_id Peer ID to free.
*
* @retval NRF_SUCCESS The clear was initiated successfully.
* @retval NRF_ERROR_INVALID_STATE Module not initialized.
* @retval NRF_ERROR_INVALID_PARAM Invalid peer ID.
*/
ret_code_t pds_peer_id_free(pm_peer_id_t peer_id);
/**@brief Function for finding out whether a peer ID is in use.
*
* @param[in] peer_id The peer ID to inquire about.
*
* @retval true peer_id is in use.
* @retval false peer_id is free, or the module is not initialized.
*/
bool pds_peer_id_is_allocated(pm_peer_id_t peer_id);
/**@brief Function for getting the next peer ID in the sequence of all used peer IDs. Can be
* used to loop through all used peer IDs.
*
* @note @ref PM_PEER_ID_INVALID is considered to be before the first and after the last ordinary
* peer ID.
*
* @param[in] prev_peer_id The previous peer ID.
*
* @return The next peer ID.
* @return The first ordinary peer ID if prev_peer_id was @ref PM_PEER_ID_INVALID.
* @retval PM_PEER_ID_INVALID if prev_peer_id was the last ordinary peer ID or the module
* is not initialized.
*/
pm_peer_id_t pds_next_peer_id_get(pm_peer_id_t prev_peer_id);
/**@brief Function for querying the number of valid peer IDs available. I.E the number of peers
* in persistent storage.
*
* @return The number of valid peer IDs, or 0 if module is not initialized.
*/
uint32_t pds_n_peers(void);
/** @}
* @endcond
*/
#endif /* PEER_DATA_STORAGE_H__ */

View File

@ -0,0 +1,804 @@
/*
* Copyright (c) 2015 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#include "peer_database.h"
#include <string.h>
#include "app_util.h"
#include "peer_manager_types.h"
#include "peer_manager_internal.h"
#include "peer_data_storage.h"
#include "pm_buffer.h"
#include "sdk_common.h"
#define MAX_REGISTRANTS 6 /**< The number of user that can register with the module. */
#define N_WRITE_BUFFERS 8 /**< The number of write buffers available. */
#define N_WRITE_BUFFER_RECORDS (N_WRITE_BUFFERS) /**< The number of write buffer records. */
/**@brief Macro for verifying that the data ID is among the values eligible for using the write buffer.
*
* @param[in] data_id The data ID to verify.
*/
#define VERIFY_DATA_ID_WRITE_BUF(data_id) \
do \
{ \
if (((data_id) != PM_PEER_DATA_ID_BONDING) && ((data_id) != PM_PEER_DATA_ID_GATT_LOCAL)) \
{ \
return NRF_ERROR_INVALID_PARAM; \
} \
} while(0)
/**@brief Struct for keeping track of one write buffer, from allocation, until it is fully written
* or cancelled.
*/
typedef struct
{
pm_peer_id_t peer_id; /**< The peer ID this buffer belongs to. */
pm_peer_data_id_t data_id; /**< The data ID this buffer belongs to. */
uint8_t buffer_block_id; /**< The index of the first (or only) buffer block containing peer data. */
uint32_t n_bufs; /**< The number of buffer blocks containing peer data. */
uint8_t store_busy : 1; /**< Flag indicating that the buffer was attempted written to flash, but a busy error was returned and the operation should be retried. */
uint8_t store_flash_full : 1; /**< Flag indicating that the buffer was attempted written to flash, but a flash full error was returned and the operation should be retried after room has been made. */
uint8_t store_requested : 1; /**< Flag indicating that the buffer is being written to flash. */
pm_prepare_token_t prepare_token; /**< Token given by Peer Data Storage if room in flash has been reserved. */
pm_store_token_t store_token; /**< Token given by Peer Data Storage when a flash write has been successfully requested. */
} pdb_buffer_record_t;
/**@brief Struct for keeping track of the state of the module.
*/
typedef struct
{
pdb_evt_handler_t evt_handlers[MAX_REGISTRANTS]; /**< All registered event handlers. */
uint8_t n_registrants; /**< The number of registered event handlers. */
pm_buffer_t write_buffer; /**< The state of the write buffer. */
pdb_buffer_record_t write_buffer_records[N_WRITE_BUFFER_RECORDS]; /**< The available write buffer records. */
uint32_t n_writes; /**< The number of pending (Not yet successfully requested in Peer Data Storage) store operations. */
} pdb_t;
static pdb_t m_pdb = {.n_registrants = 0}; /**< The state of the module. */
#define MODULE_INITIALIZED (m_pdb.n_registrants > 0) /**< Expression which is true when the module is initialized. */
#include "sdk_macros.h"
/**@brief Function for invalidating a record of a write buffer allocation.
*
* @param[in] p_record The record to invalidate.
*/
static void write_buffer_record_invalidate(pdb_buffer_record_t * p_record)
{
p_record->peer_id = PM_PEER_ID_INVALID;
p_record->data_id = PM_PEER_DATA_ID_INVALID;
p_record->buffer_block_id = BUFFER_INVALID_ID;
p_record->store_busy = false;
p_record->store_flash_full = false;
p_record->store_requested = false;
p_record->n_bufs = 0;
p_record->prepare_token = PDS_PREPARE_TOKEN_INVALID;
p_record->store_token = PM_STORE_TOKEN_INVALID;
}
/**@brief Function for finding a record of a write buffer allocation.
*
* @param[in] peer_id The peer ID in the record.
* @param[inout] p_index In: The starting index, out: The index of the record
*
* @return A pointer to the matching record, or NULL if none was found.
*/
static pdb_buffer_record_t * write_buffer_record_find_next(pm_peer_id_t peer_id, int * p_index)
{
for (uint32_t i = *p_index; i < N_WRITE_BUFFER_RECORDS; i++)
{
if ((m_pdb.write_buffer_records[i].peer_id == peer_id))
{
return &m_pdb.write_buffer_records[i];
}
}
return NULL;
}
/**@brief Function for finding a record of a write buffer allocation.
*
* @param[in] peer_id The peer ID in the record.
* @param[in] data_id The data ID in the record.
*
* @return A pointer to the matching record, or NULL if none was found.
*/
static pdb_buffer_record_t * write_buffer_record_find(pm_peer_id_t peer_id,
pm_peer_data_id_t data_id)
{
int index = 0;
pdb_buffer_record_t * p_record = write_buffer_record_find_next(peer_id, &index);
while ((p_record != NULL) && (p_record->data_id != data_id))
{
index++;
p_record = write_buffer_record_find_next(peer_id, &index);
}
return p_record;
}
/**@brief Function for finding an available record for write buffer allocation.
*
* @return A pointer to the available record, or NULL if none was found.
*/
static pdb_buffer_record_t * write_buffer_record_find_unused(void)
{
return write_buffer_record_find(PM_PEER_ID_INVALID, PM_PEER_DATA_ID_INVALID);
}
/**@brief Function for gracefully deactivating a write buffer record.
*
* @details This function will first release any buffers, then invalidate the record.
*
* @param[inout] p_write_buffer_record The record to release.
*
* @return A pointer to the matching record, or NULL if none was found.
*/
static void write_buffer_record_release(pdb_buffer_record_t * p_write_buffer_record)
{
for (uint32_t i = 0; i < p_write_buffer_record->n_bufs; i++)
{
pm_buffer_release(&m_pdb.write_buffer, p_write_buffer_record->buffer_block_id + i);
}
write_buffer_record_invalidate(p_write_buffer_record);
}
/**@brief Function for claiming and activating a write buffer record.
*
* @param[out] pp_write_buffer_record The claimed record.
* @param[in] peer_id The peer ID this record should have.
* @param[in] data_id The data ID this record should have.
*/
static void write_buffer_record_get(pdb_buffer_record_t ** pp_write_buffer_record, pm_peer_id_t peer_id, pm_peer_data_id_t data_id)
{
if (pp_write_buffer_record == NULL)
{
return;
}
*pp_write_buffer_record = write_buffer_record_find_unused();
if (*pp_write_buffer_record == NULL)
{
// This also means the buffer is full.
return;
}
(*pp_write_buffer_record)->peer_id = peer_id;
(*pp_write_buffer_record)->data_id = data_id;
}
/**@brief Function for dispatching outbound events to all registered event handlers.
*
* @param[in] p_event The event to dispatch.
*/
static void pdb_evt_send(pdb_evt_t * p_event)
{
for (uint32_t i = 0; i < m_pdb.n_registrants; i++)
{
m_pdb.evt_handlers[i](p_event);
}
}
/**@brief Function for resetting the internal state of the Peer Database module.
*
* @param[out] p_event The event to dispatch.
*/
static void internal_state_reset(pdb_t * pdb)
{
memset(pdb, 0, sizeof(pdb_t));
for (uint32_t i = 0; i < N_WRITE_BUFFER_RECORDS; i++)
{
write_buffer_record_invalidate(&pdb->write_buffer_records[i]);
}
}
/**@brief Function for handling events from the Peer Data Storage module.
*
* @param[in] p_event The event to handle.
*/
static void pds_evt_handler(pds_evt_t const * p_event)
{
ret_code_t err_code;
pdb_buffer_record_t * p_write_buffer_record;
bool retry_flash_full = false;
pdb_evt_t event =
{
.peer_id = p_event->peer_id,
.data_id = p_event->data_id,
};
p_write_buffer_record = write_buffer_record_find(p_event->peer_id, p_event->data_id);
switch (p_event->evt_id)
{
case PDS_EVT_STORED:
case PDS_EVT_UPDATED:
if ( (p_write_buffer_record != NULL)
//&& (p_write_buffer_record->store_token == p_event->store_token)
&& (p_write_buffer_record->store_requested))
{
write_buffer_record_release(p_write_buffer_record);
event.evt_id = PDB_EVT_WRITE_BUF_STORED;
event.params.write_buf_stored_evt.update = (p_event->evt_id == PDS_EVT_UPDATED);
pdb_evt_send(&event);
}
else
{
event.evt_id = PDB_EVT_RAW_STORED;
event.params.raw_stored_evt.store_token = p_event->store_token;
pdb_evt_send(&event);
}
break;
case PDS_EVT_ERROR_STORE:
case PDS_EVT_ERROR_UPDATE:
if ( (p_write_buffer_record != NULL)
&& (p_write_buffer_record->store_token == p_event->store_token)
&& (p_write_buffer_record->store_requested))
{
// Retry if internal buffer.
m_pdb.n_writes++;
p_write_buffer_record->store_requested = false;
p_write_buffer_record->store_busy = true;
}
else
{
event.evt_id = PDB_EVT_RAW_STORE_FAILED;
event.params.error_raw_store_evt.err_code = p_event->result;
pdb_evt_send(&event);
}
break;
case PDS_EVT_CLEARED:
event.evt_id = PDB_EVT_CLEARED;
pdb_evt_send(&event);
break;
case PDS_EVT_ERROR_CLEAR:
event.evt_id = PDB_EVT_CLEAR_FAILED;
event.params.clear_failed_evt.err_code = p_event->result;
pdb_evt_send(&event);
break;
case PDS_EVT_PEER_ID_CLEAR:
event.evt_id = PDB_EVT_PEER_FREED;
pdb_evt_send(&event);
break;
case PDS_EVT_ERROR_PEER_ID_CLEAR:
event.evt_id = PDB_EVT_PEER_FREE_FAILED;
event.params.peer_free_failed_evt.err_code = p_event->result;
pdb_evt_send(&event);
break;
case PDS_EVT_COMPRESSED:
retry_flash_full = true;
event.evt_id = PDB_EVT_COMPRESSED;
pdb_evt_send(&event);
break;
case PDS_EVT_ERROR_UNEXPECTED:
event.params.error_unexpected.err_code = p_event->result;
break;
default:
break;
}
if (m_pdb.n_writes > 0)
{
for (uint32_t i = 0; i < N_WRITE_BUFFER_RECORDS; i++)
{
if ((m_pdb.write_buffer_records[i].store_busy)
|| (m_pdb.write_buffer_records[i].store_flash_full && retry_flash_full))
{
err_code = pdb_write_buf_store(m_pdb.write_buffer_records[i].peer_id,
m_pdb.write_buffer_records[i].data_id);
if (err_code != NRF_SUCCESS)
{
event.peer_id = m_pdb.write_buffer_records[i].peer_id;
event.data_id = m_pdb.write_buffer_records[i].data_id;
if (err_code == NRF_ERROR_NO_MEM)
{
event.evt_id = PDB_EVT_ERROR_NO_MEM;
}
else
{
event.evt_id = PDB_EVT_ERROR_UNEXPECTED;
event.params.error_unexpected.err_code = err_code;
}
pdb_evt_send(&event);
break;
}
}
}
}
}
ret_code_t pdb_register(pdb_evt_handler_t evt_handler)
{
if (m_pdb.n_registrants >= MAX_REGISTRANTS)
{
return NRF_ERROR_NO_MEM;
}
VERIFY_PARAM_NOT_NULL(evt_handler);
if (!MODULE_INITIALIZED)
{
ret_code_t err_code;
internal_state_reset(&m_pdb);
err_code = pds_register(pds_evt_handler);
if (err_code != NRF_SUCCESS)
{
return NRF_ERROR_INTERNAL;
}
PM_BUFFER_INIT(&m_pdb.write_buffer, N_WRITE_BUFFERS, PDB_WRITE_BUF_SIZE, err_code);
if (err_code != NRF_SUCCESS)
{
return NRF_ERROR_INTERNAL;
}
}
m_pdb.evt_handlers[m_pdb.n_registrants] = evt_handler;
m_pdb.n_registrants += 1;
return NRF_SUCCESS;
}
pm_peer_id_t pdb_peer_allocate(void)
{
if (!MODULE_INITIALIZED)
{
return PM_PEER_ID_INVALID;
}
return pds_peer_id_allocate();
}
ret_code_t pdb_peer_free(pm_peer_id_t peer_id)
{
VERIFY_MODULE_INITIALIZED();
ret_code_t err_code_in = NRF_SUCCESS;
ret_code_t err_code_out = NRF_SUCCESS;
int index = 0;
pdb_buffer_record_t * p_record = write_buffer_record_find_next(peer_id, &index);
while (p_record != NULL)
{
err_code_in = pdb_write_buf_release(peer_id, p_record->data_id);
if ( (err_code_in != NRF_SUCCESS)
&& (err_code_in != NRF_ERROR_NOT_FOUND))
{
err_code_out = NRF_ERROR_INTERNAL;
}
index++;
p_record = write_buffer_record_find_next(peer_id, &index);
}
if (err_code_out == NRF_SUCCESS)
{
err_code_in = pds_peer_id_free(peer_id);
if (err_code_in == NRF_SUCCESS)
{
// No action needed.
}
else if (err_code_in == NRF_ERROR_INVALID_PARAM)
{
err_code_out = NRF_ERROR_INVALID_PARAM;
}
else
{
err_code_out = NRF_ERROR_INTERNAL;
}
}
return err_code_out;
}
ret_code_t pdb_read_buf_get(pm_peer_id_t peer_id,
pm_peer_data_id_t data_id,
pm_peer_data_flash_t * p_peer_data,
pm_store_token_t * p_token)
{
VERIFY_MODULE_INITIALIZED();
return pds_peer_data_read_ptr_get(peer_id, data_id, p_peer_data, p_token);
}
static void peer_data_point_to_buffer(pm_peer_data_t * p_peer_data, pm_peer_data_id_t data_id, uint8_t * p_buffer_memory, uint16_t n_bufs)
{
uint16_t n_bytes = n_bufs * PDB_WRITE_BUF_SIZE;
p_peer_data->data_id = data_id;
p_peer_data->p_all_data = (pm_peer_data_bonding_t *)p_buffer_memory;
p_peer_data->length_words = BYTES_TO_WORDS(n_bytes);
}
static void peer_data_const_point_to_buffer(pm_peer_data_const_t * p_peer_data, pm_peer_data_id_t data_id, uint8_t * p_buffer_memory, uint32_t n_bufs)
{
peer_data_point_to_buffer((pm_peer_data_t*)p_peer_data, data_id, p_buffer_memory, n_bufs);
}
static void write_buf_length_words_set(pm_peer_data_const_t * p_peer_data)
{
switch (p_peer_data->data_id)
{
case PM_PEER_DATA_ID_BONDING:
p_peer_data->length_words = PM_BONDING_DATA_N_WORDS();
break;
case PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING:
p_peer_data->length_words = PM_SC_STATE_N_WORDS();
break;
case PM_PEER_DATA_ID_PEER_RANK:
p_peer_data->length_words = PM_USAGE_INDEX_N_WORDS();
break;
case PM_PEER_DATA_ID_GATT_LOCAL:
p_peer_data->length_words = PM_LOCAL_DB_N_WORDS(p_peer_data->p_local_gatt_db->len);
break;
default:
// No action needed.
break;
}
}
ret_code_t pdb_write_buf_get(pm_peer_id_t peer_id,
pm_peer_data_id_t data_id,
uint32_t n_bufs,
pm_peer_data_t * p_peer_data)
{
VERIFY_MODULE_INITIALIZED();
VERIFY_PARAM_NOT_NULL(p_peer_data);
VERIFY_DATA_ID_WRITE_BUF(data_id);
if ( (n_bufs == 0)
|| (n_bufs > N_WRITE_BUFFERS)
|| !pds_peer_id_is_allocated(peer_id))
{
return NRF_ERROR_INVALID_PARAM;
}
pdb_buffer_record_t * write_buffer_record;
uint8_t * p_buffer_memory;
bool new_record = false;
write_buffer_record = write_buffer_record_find(peer_id, data_id);
if ((write_buffer_record != NULL) && (write_buffer_record->n_bufs < n_bufs))
{
// @TODO: Copy?
// Existing buffer is too small.
for (uint8_t i = 0; i < write_buffer_record->n_bufs; i++)
{
pm_buffer_release(&m_pdb.write_buffer, write_buffer_record->buffer_block_id + i);
}
write_buffer_record_invalidate(write_buffer_record);
write_buffer_record = NULL;
}
else if ((write_buffer_record != NULL) && write_buffer_record->n_bufs > n_bufs)
{
// Release excess blocks.
for (uint8_t i = n_bufs; i < write_buffer_record->n_bufs; i++)
{
pm_buffer_release(&m_pdb.write_buffer, write_buffer_record->buffer_block_id + i);
}
}
if (write_buffer_record == NULL)
{
write_buffer_record_get(&write_buffer_record, peer_id, data_id);
if (write_buffer_record == NULL)
{
return NRF_ERROR_BUSY;
}
}
if (write_buffer_record->buffer_block_id == BUFFER_INVALID_ID)
{
write_buffer_record->buffer_block_id = pm_buffer_block_acquire(&m_pdb.write_buffer, n_bufs);
if (write_buffer_record->buffer_block_id == BUFFER_INVALID_ID)
{
write_buffer_record_invalidate(write_buffer_record);
return NRF_ERROR_BUSY;
}
new_record = true;
}
write_buffer_record->n_bufs = n_bufs;
p_buffer_memory = pm_buffer_ptr_get(&m_pdb.write_buffer, write_buffer_record->buffer_block_id);
if (p_buffer_memory == NULL)
{
return NRF_ERROR_INTERNAL;
}
peer_data_point_to_buffer(p_peer_data, data_id, p_buffer_memory, n_bufs);
if (new_record && (data_id == PM_PEER_DATA_ID_GATT_LOCAL))
{
p_peer_data->p_local_gatt_db->len = PM_LOCAL_DB_LEN(p_peer_data->length_words);
}
return NRF_SUCCESS;
}
ret_code_t pdb_write_buf_release(pm_peer_id_t peer_id, pm_peer_data_id_t data_id)
{
VERIFY_MODULE_INITIALIZED();
ret_code_t err_code = NRF_SUCCESS;
pdb_buffer_record_t * p_write_buffer_record;
p_write_buffer_record = write_buffer_record_find(peer_id, data_id);
if (p_write_buffer_record == NULL)
{
return NRF_ERROR_NOT_FOUND;
}
if (p_write_buffer_record->prepare_token != PDS_PREPARE_TOKEN_INVALID)
{
err_code = pds_peer_data_write_prepare_cancel(p_write_buffer_record->prepare_token);
if (err_code != NRF_SUCCESS)
{
err_code = NRF_ERROR_INTERNAL;
}
}
write_buffer_record_release(p_write_buffer_record);
return err_code;
}
ret_code_t pdb_write_buf_store_prepare(pm_peer_id_t peer_id, pm_peer_data_id_t data_id)
{
VERIFY_MODULE_INITIALIZED();
VERIFY_DATA_ID_WRITE_BUF(data_id);
ret_code_t err_code = NRF_SUCCESS;
pdb_buffer_record_t * p_write_buffer_record;
p_write_buffer_record = write_buffer_record_find(peer_id, data_id);
if (p_write_buffer_record == NULL)
{
return NRF_ERROR_NOT_FOUND;
}
if (p_write_buffer_record->prepare_token == PDS_PREPARE_TOKEN_INVALID)
{
uint8_t * p_buffer_memory = pm_buffer_ptr_get(&m_pdb.write_buffer, p_write_buffer_record->buffer_block_id);
pm_peer_data_const_t peer_data = {.data_id = data_id};
if (p_buffer_memory == NULL)
{
return NRF_ERROR_INTERNAL;
}
peer_data_const_point_to_buffer(&peer_data, data_id, p_buffer_memory, p_write_buffer_record->n_bufs);
write_buf_length_words_set(&peer_data);
err_code = pds_peer_data_write_prepare(&peer_data, &p_write_buffer_record->prepare_token);
if (err_code == NRF_ERROR_INVALID_LENGTH)
{
return NRF_ERROR_INTERNAL;
}
}
return err_code;
}
static ret_code_t write_or_update(pm_peer_id_t peer_id,
pm_peer_data_id_t data_id,
pm_peer_data_const_t * p_peer_data,
pm_store_token_t * p_store_token,
pm_prepare_token_t prepare_token)
{
pm_peer_data_flash_t old_peer_data;
pm_store_token_t old_store_token;
ret_code_t err_code = pds_peer_data_read_ptr_get(peer_id, data_id, &old_peer_data, &old_store_token);
if (err_code == NRF_SUCCESS)
{
err_code = pds_peer_data_write_prepare_cancel(prepare_token);
if ((err_code == NRF_SUCCESS) || (err_code == NRF_ERROR_NULL))
{
err_code = pds_peer_data_update(peer_id, p_peer_data, old_store_token, p_store_token);
}
else
{
err_code = NRF_ERROR_INTERNAL;
}
}
else if (err_code == NRF_ERROR_NOT_FOUND)
{
if (prepare_token == PDS_PREPARE_TOKEN_INVALID)
{
err_code = pds_peer_data_write(peer_id, p_peer_data, p_store_token);
}
else
{
err_code = pds_peer_data_write_prepared(peer_id, p_peer_data, prepare_token, p_store_token);
}
}
return err_code;
}
ret_code_t pdb_write_buf_store(pm_peer_id_t peer_id,
pm_peer_data_id_t data_id)
{
VERIFY_MODULE_INITIALIZED();
VERIFY_DATA_ID_WRITE_BUF(data_id);
ret_code_t err_code = NRF_SUCCESS;
pdb_buffer_record_t * p_write_buffer_record;
uint8_t * p_buffer_memory;
pm_peer_data_const_t peer_data = {.data_id = data_id};
p_write_buffer_record = write_buffer_record_find(peer_id, data_id);
if (p_write_buffer_record == NULL)
{
return NRF_ERROR_NOT_FOUND;
}
if (p_write_buffer_record->store_requested)
{
return NRF_SUCCESS;
}
p_buffer_memory = pm_buffer_ptr_get(&m_pdb.write_buffer, p_write_buffer_record->buffer_block_id);
if (p_buffer_memory == NULL)
{
return NRF_ERROR_INTERNAL;
}
peer_data_const_point_to_buffer(&peer_data, data_id, p_buffer_memory, p_write_buffer_record->n_bufs);
write_buf_length_words_set(&peer_data);
err_code = write_or_update(peer_id, data_id, &peer_data, &p_write_buffer_record->store_token, p_write_buffer_record->prepare_token);
if (p_write_buffer_record->store_busy && p_write_buffer_record->store_flash_full)
{
m_pdb.n_writes--;
}
if (err_code == NRF_SUCCESS)
{
p_write_buffer_record->store_requested = true;
p_write_buffer_record->store_busy = false;
p_write_buffer_record->store_flash_full = false;
}
else
{
if (err_code == NRF_ERROR_BUSY)
{
m_pdb.n_writes++;
p_write_buffer_record->store_busy = true;
p_write_buffer_record->store_flash_full = false;
err_code = NRF_SUCCESS;
}
else if (err_code == NRF_ERROR_NO_MEM)
{
m_pdb.n_writes++;
p_write_buffer_record->store_busy = false;
p_write_buffer_record->store_flash_full = true;
}
else if ((err_code != NRF_ERROR_NO_MEM) && (err_code != NRF_ERROR_INVALID_PARAM))
{
err_code = NRF_ERROR_INTERNAL;
}
}
return err_code;
}
ret_code_t pdb_clear(pm_peer_id_t peer_id, pm_peer_data_id_t data_id)
{
VERIFY_MODULE_INITIALIZED();
return pds_peer_data_clear(peer_id, data_id);
}
uint32_t pdb_n_peers(void)
{
if (!MODULE_INITIALIZED)
{
return 0;
}
return pds_n_peers();
}
pm_peer_id_t pdb_next_peer_id_get(pm_peer_id_t prev_peer_id)
{
if (!MODULE_INITIALIZED)
{
return PM_PEER_ID_INVALID;
}
return pds_next_peer_id_get(prev_peer_id);
}
ret_code_t pdb_raw_read(pm_peer_id_t peer_id,
pm_peer_data_id_t data_id,
pm_peer_data_t * p_peer_data)
{
VERIFY_MODULE_INITIALIZED();
return pds_peer_data_read(peer_id, data_id, p_peer_data, &p_peer_data->length_words);
}
ret_code_t pdb_raw_store(pm_peer_id_t peer_id,
pm_peer_data_const_t * p_peer_data,
pm_store_token_t * p_store_token)
{
VERIFY_MODULE_INITIALIZED();
return write_or_update(peer_id, p_peer_data->data_id, p_peer_data, p_store_token, PDS_PREPARE_TOKEN_INVALID);
}

View File

@ -0,0 +1,385 @@
/*
* Copyright (c) 2015 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#ifndef PEER_DATABASE_H__
#define PEER_DATABASE_H__
#include <stdint.h>
#include "peer_manager_types.h"
#include "peer_manager_internal.h"
#include "sdk_errors.h"
/**
* @cond NO_DOXYGEN
* @defgroup peer_database Peer Database
* @ingroup peer_manager
* @{
* @brief An internal module of @ref peer_manager. A module for simple management of reading and
* writing of peer data into persistent storage.
*
*/
#define PDB_WRITE_BUF_SIZE (sizeof(pm_peer_data_bonding_t))
/**@brief Events that can come from the peer_database module.
*/
typedef enum
{
PDB_EVT_WRITE_BUF_STORED, /**< A @ref pdb_write_buf_store operation has completed successfully. */
PDB_EVT_RAW_STORED, /**< A @ref pdb_raw_store operation has completed successfully. */
PDB_EVT_RAW_STORE_FAILED, /**< A @ref pdb_raw_store operation has failed. */
PDB_EVT_CLEARED, /**< A @ref pdb_clear operation has completed successfully. */
PDB_EVT_CLEAR_FAILED, /**< A @ref pdb_clear operation has failed. */
PDB_EVT_PEER_FREED, /**< A @ref pdb_peer_free operation has completed successfully. All associated data has been erased. */
PDB_EVT_PEER_FREE_FAILED, /**< A @ref pdb_peer_free operation has failed. */
PDB_EVT_COMPRESSED, /**< A compress procedure has completed. */
PDB_EVT_ERROR_NO_MEM, /**< An operation is blocked because the flash is full. It will be reattempted automatically after the next compress procedure. */
PDB_EVT_ERROR_UNEXPECTED, /**< An unexpected error occurred. This is a fatal error. */
} pdb_evt_id_t;
/**@brief Events that can come from the peer_database module.
*/
typedef struct
{
pdb_evt_id_t evt_id; /**< The event that has happened. */
pm_peer_id_t peer_id; /**< The id of the peer the event pertains to. */
pm_peer_data_id_t data_id; /**< The data the event pertains to. */
union
{
struct
{
bool update; /**< If true, an existing value was overwritten. */
} write_buf_stored_evt; /**< Additional information pertaining to the @ref PDB_EVT_WRITE_BUF_STORED event. */
struct
{
pm_store_token_t store_token; /**< A token identifying the store operation this event pertains to. */
} raw_stored_evt; /**< Additional information pertaining to the @ref PDB_EVT_RAW_STORED event. */
struct
{
pm_store_token_t store_token; /**< A token identifying the store operation this event pertains to. */
ret_code_t err_code; /**< Error code specifying what went wrong. */
} error_raw_store_evt; /**< Additional information pertaining to the @ref PDB_EVT_RAW_STORE_FAILED event. */
struct
{
ret_code_t err_code; /**< The error that occurred. */
} clear_failed_evt; /**< Additional information pertaining to the @ref PDB_EVT_CLEAR_FAILED event. */
struct
{
ret_code_t err_code; /**< The error that occurred. */
} peer_free_failed_evt; /**< Additional information pertaining to the @ref PDB_EVT_PEER_FREE_FAILED event. */
struct
{
ret_code_t err_code; /**< The unexpected error that occurred. */
} error_unexpected; /**< Additional information pertaining to the @ref PDB_EVT_ERROR_UNEXPECTED event. */
} params;
} pdb_evt_t;
/**@brief Event handler for events from the peer_data_storage module.
*
* @param[in] p_event The event that has happened.
*/
typedef void (*pdb_evt_handler_t)(pdb_evt_t const * p_event);
/**@brief Function for registering for events from the peer database.
*
* @note This function will initialize the module if it is not already initialized.
*
* @param[in] evt_handler Event handler to register.
*
* @retval NRF_SUCCESS Registration successful.
* @retval NRF_ERROR_NO_MEM No more event handlers can be registered.
* @retval NRF_ERROR_NULL evt_handler was NULL.
* @retval NRF_ERROR_INTERNAL An unexpected error happened.
*/
ret_code_t pdb_register(pdb_evt_handler_t evt_handler);
/**@brief Function for allocating persistent bond storage for a peer.
*
* @return The ID of the newly allocated storage.
* @retval PM_PEER_ID_INVALID If no peer ID is available.
*/
pm_peer_id_t pdb_peer_allocate(void);
/**@brief Function for freeing a peer's persistent bond storage.
*
* @note This function will call @ref pdb_write_buf_release on the data for this peer.
*
* @param[in] peer_id ID to be freed.
*
* @retval NRF_SUCCESS Peer ID was released and clear operation was initiated successfully.
* @retval NRF_ERROR_INVALID_PARAM Peer ID was invalid.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
*/
ret_code_t pdb_peer_free(pm_peer_id_t peer_id);
/**@brief Function for retrieving pointers to read-only peer data.
*
* @note Reading this pointer is not safe in the strictest sense. If a safe read is required:
* - Disable interrupts
* - Call this function. If the return code is @ref NRF_SUCCESS, the following read is safe.
* - Read memory.
* - Enable interrupts.
* @note This buffer does not need to be released. It is a pointer directly to flash.
*
* @param[in] peer_id ID of peer to retrieve data for.
* @param[in] data_id Which piece of data to get.
* @param[out] p_peer_data Pointer to immutable peer data.
* @param[out] p_token Token that can be used to lock data in flash and check data validity.
*
* @retval NRF_SUCCESS Data retrieved successfully.
* @retval NRF_ERROR_INVALID_PARAM Data ID or Peer ID was invalid or unallocated.
* @retval NRF_ERROR_NULL p_peer_data was NULL.
* @retval NRF_ERROR_NOT_FOUND This data was not found for this peer ID.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
*/
ret_code_t pdb_read_buf_get(pm_peer_id_t peer_id,
pm_peer_data_id_t data_id,
pm_peer_data_flash_t * p_peer_data,
pm_store_token_t * p_token);
/**@brief Function for retrieving pointers to a write buffer for peer data.
*
* @details This function will provide pointers to a buffer of the data. The data buffer will not be
* written to persistent storage until @ref pdb_write_buf_store is called. The buffer is
* released by calling either @ref pdb_write_buf_release, @ref pdb_write_buf_store, or
* @ref pdb_peer_free.
*
* When the data_id refers to a variable length data type, the available size is written
* to the data, both the top-level, and any internal length fields.
*
* @note Calling this function on a peer_id/data_id pair that already has a buffer created will
* give the same buffer, not create a new one. If n_bufs was increased since last time, the
* buffer might be relocated to be able to provide additional room. In this case, the data
* will be copied. If n_bufs was increased since last time, this function might return @ref
* NRF_ERROR_BUSY. In that case, the buffer is automatically released.
*
* @param[in] peer_id ID of peer to get a write buffer for.
* @param[in] data_id Which piece of data to get.
* @param[in] n_bufs The number of contiguous buffers needed.
* @param[out] p_peer_data Pointers to mutable peer data.
*
* @retval NRF_SUCCESS Data retrieved successfully.
* @retval NRF_ERROR_INVALID_PARAM Data ID or Peer ID was invalid or unallocated, or n_bufs was 0
* or more than the total available buffers.
* @retval NRF_ERROR_NULL p_peer_data was NULL.
* @retval NRF_ERROR_BUSY Not enough buffer(s) available.
* @retval NRF_ERROR_INTERNAL Unexpected internal error.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
*/
ret_code_t pdb_write_buf_get(pm_peer_id_t peer_id,
pm_peer_data_id_t data_id,
uint32_t n_bufs,
pm_peer_data_t * p_peer_data);
/**@brief Function for freeing a write buffer allocated with @ref pdb_write_buf_get.
*
* @note This function will not write peer data to persistent memory. Data in released buffer will
* be lost.
*
* @note This function will undo any previous call to @ref pdb_write_buf_store_prepare for this
* piece of data.
*
* @param[in] peer_id ID of peer to release buffer for.
* @param[in] data_id Which piece of data to release buffer for.
*
* @retval NRF_SUCCESS Successfully released buffer.
* @retval NRF_ERROR_NOT_FOUND No buffer was allocated for this peer ID/data ID pair.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
* @retval NRF_ERROR_INTERNAL Unexpected internal error.
*/
ret_code_t pdb_write_buf_release(pm_peer_id_t peer_id, pm_peer_data_id_t data_id);
/**@brief Function for reserving space in persistent storage for data in a buffer.
*
* @note This function only works for data which has a write buffer allocated. If the write buffer
* is released, this prepare is undone.
*
* @note If space has already been reserved for this data, nothing is done.
*
* @param[in] peer_id The peer whose data to reserve space for.
* @param[in] data_id The type of data to reserve space for.
*
* @retval NRF_SUCCESS Successfully reserved space in persistent storage.
* @retval NRF_ERROR_NO_MEM Not enough room in persistent storage.
* @retval NRF_ERROR_BUSY Could not process request at this time. Reattempt later.
* @retval NRF_ERROR_NOT_FOUND No buffer has been allocated for this peer ID/data ID pair.
* @retval NRF_ERROR_INVALID_PARAM Data ID or Peer ID was invalid or unallocated.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
*/
ret_code_t pdb_write_buf_store_prepare(pm_peer_id_t peer_id, pm_peer_data_id_t data_id);
/**@brief Function for writing data into persistent storage. Writing happens asynchronously.
*
* @note This will unlock the data after it has been written.
*
* @param[in] peer_id ID of peer to store data for.
* @param[in] data_id Which piece of data to store.
*
* @retval NRF_SUCCESS Data storing was successfully started.
* @retval NRF_ERROR_NO_MEM No space available in persistent storage. Please clear some
* space, the operation will be reattempted after the next compress
* procedure. This error will not happen if
* @ref pdb_write_buf_store_prepare is called beforehand.
* @retval NRF_ERROR_INVALID_PARAM Data ID was invalid.
* @retval NRF_ERROR_NOT_FOUND No buffer has been allocated for this peer ID/data ID pair.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
* @retval NRF_ERROR_INTERNAL Unexpected internal error.
*/
ret_code_t pdb_write_buf_store(pm_peer_id_t peer_id,
pm_peer_data_id_t data_id);
/**@brief Function for clearing data from persistent storage.
*
* @param[in] peer_id ID of peer to clear data for.
* @param[in] data_id Which piece of data to clear.
*
* @retval NRF_SUCCESS The clear was initiated successfully.
* @retval NRF_ERROR_INVALID_PARAM Data ID or peer ID was invalid.
* @retval NRF_ERROR_NOT_FOUND Nothing to clear for this peer ID/data ID combination.
* @retval NRF_ERROR_BUSY Underlying modules are busy and can't take any more requests at
* this moment.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
* @retval NRF_ERROR_INTERNAL Internal error.
*/
ret_code_t pdb_clear(pm_peer_id_t peer_id, pm_peer_data_id_t data_id);
/**@brief Function for querying the number of valid peer IDs available. I.E the number of peers
* in persistent storage.
*
* @return The number of valid peer IDs.
*/
uint32_t pdb_n_peers(void);
/**@brief Function for getting the next peer ID in the sequence of all used peer IDs. Can be
* used to loop through all used peer IDs.
*
* @note @ref PM_PEER_ID_INVALID is considered to be before the first and after the last ordinary
* peer ID.
*
* @param[in] prev_peer_id The previous peer ID.
*
* @return The next peer ID.
* @return The first ordinary peer ID if prev_peer_id was @ref PM_PEER_ID_INVALID.
* @retval PM_PEER_ID_INVALID if prev_peer_id was the last ordinary peer ID.
*/
pm_peer_id_t pdb_next_peer_id_get(pm_peer_id_t prev_peer_id);
/**@brief Function for updating currently stored peer data to a new version
*
* @details Updating happens asynchronously.
* Expect a @ref PDS_EVT_STORED or @ref PDS_EVT_ERROR_STORE for the store token
* and a @ref PDS_EVT_ERROR_CLEAR or @ref PDS_EVT_ERROR_CLEAR for the old token
*
* @param[in] peer_data New data
* @param[in] old_token Store token for the old data
* @param[out] p_store_token Store token for the new data
*
* @retval NRF_SUCESS The update was initiated successfully
* @retval NRF_ERROR_NOT_FOUND The old store token was invalid.
* @retval NRF_ERROR_NULL Data contained a NULL pointer.
* @retval NRF_ERROR_NO_MEM No space available in persistent storage.
* @retval NRF_ERROR_BUSY FDS or underlying modules are busy and can't take any
* more requests
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
*/
ret_code_t pdb_peer_data_update(pm_peer_data_const_t peer_data,
pm_store_token_t old_token,
pm_store_token_t * p_store_token);
/**@brief Function for reading data directly from persistent storage to external memory.
*
* @param[in] peer_id ID of peer to read data for.
* @param[in] data_id Which piece of data to read.
* @param[inout] p_peer_data Where to store the data. If the data to be read has variable length,
* the appropriate length field needs to reflect the available buffer
* space. On a successful read, the length field is updated to match the
* length of the read data.
*
* @retval NRF_SUCCESS Data successfully read.
* @retval NRF_ERROR_INVALID_PARAM Data ID or Peer ID was invalid or unallocated.
* @retval NRF_ERROR_NULL p_peer_data contained a NULL pointer.
* @retval NRF_ERROR_NOT_FOUND This data was not found for this peer ID.
* @retval NRF_ERROR_DATA_SIZE The provided buffer was not large enough.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
*/
ret_code_t pdb_raw_read(pm_peer_id_t peer_id,
pm_peer_data_id_t data_id,
pm_peer_data_t * p_peer_data);
/**@brief Function for writing data directly to persistent storage from external memory.
*
* @param[in] peer_id ID of peer to write data for.
* @param[in] p_peer_data Data to store.
* @param[out] p_store_token A token identifying this particular store operation. The token can be
* used to identify events pertaining to this operation.
*
* @retval NRF_SUCCESS Data successfully written.
* @retval NRF_ERROR_INVALID_PARAM Data ID or Peer ID was invalid or unallocated.
* @retval NRF_ERROR_NULL p_peer_data contained a NULL pointer.
* @retval NRF_ERROR_NO_MEM No space available in persistent storage.
* @retval NRF_ERROR_INVALID_LENGTH Data length above the maximum allowed.
* @retval NRF_ERROR_INVALID_STATE Module is not initialized.
* @retval NRF_ERROR_BUSY Unable to perform operation at this time.
*/
ret_code_t pdb_raw_store(pm_peer_id_t peer_id,
pm_peer_data_const_t * p_peer_data,
pm_store_token_t * p_store_token);
/** @}
* @endcond
*/
#endif /* PEER_DATABASE_H__ */

View File

@ -0,0 +1,186 @@
/*
* Copyright (c) 2015 Nordic Semiconductor ASA
* All rights reserved.
*
* 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, except as embedded into a Nordic Semiconductor ASA
* integrated circuit in a product or a software update for such product, 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 Nordic Semiconductor ASA nor the names of its contributors may be
* used to endorse or promote products derived from this software without specific prior
* written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary or object form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* 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.
*
*/
#include "peer_id.h"
#include <stdint.h>
#include <string.h>
#include "sdk_errors.h"
#include "peer_manager_types.h"
#include "pm_mutex.h"
typedef struct
{
uint8_t active_peer_ids[MUTEX_STORAGE_SIZE(PM_PEER_ID_N_AVAILABLE_IDS)]; /**< Bitmap designating which peer IDs are in use. */
uint8_t deleted_peer_ids[MUTEX_STORAGE_SIZE(PM_PEER_ID_N_AVAILABLE_IDS)]; /**< Bitmap designating which peer IDs are marked for deletion. */
} pi_t;
static pi_t m_pi = {{0}, {0}};
static void internal_state_reset(pi_t * p_pi)
{
memset(p_pi, 0, sizeof(pi_t));
}
void peer_id_init(void)
{
internal_state_reset(&m_pi);
pm_mutex_init(m_pi.active_peer_ids, PM_PEER_ID_N_AVAILABLE_IDS);
pm_mutex_init(m_pi.deleted_peer_ids, PM_PEER_ID_N_AVAILABLE_IDS);
}
static pm_peer_id_t claim(pm_peer_id_t peer_id, uint8_t * mutex_group)
{
pm_peer_id_t allocated_peer_id = PM_PEER_ID_INVALID;
if (peer_id == PM_PEER_ID_INVALID)
{
allocated_peer_id = pm_mutex_lock_first_available(mutex_group, PM_PEER_ID_N_AVAILABLE_IDS);
if (allocated_peer_id == PM_PEER_ID_N_AVAILABLE_IDS)
{
allocated_peer_id = PM_PEER_ID_INVALID;
}
}
else if (peer_id < PM_PEER_ID_N_AVAILABLE_IDS)
{
bool lock_success = pm_mutex_lock(mutex_group, peer_id);
allocated_peer_id = lock_success ? peer_id : PM_PEER_ID_INVALID;
}
return allocated_peer_id;
}
static void release(pm_peer_id_t peer_id, uint8_t * mutex_group)
{
if (peer_id < PM_PEER_ID_N_AVAILABLE_IDS)
{
pm_mutex_unlock(mutex_group, peer_id);
}
}
pm_peer_id_t peer_id_allocate(pm_peer_id_t peer_id)
{
return claim(peer_id, m_pi.active_peer_ids);
}
bool peer_id_delete(pm_peer_id_t peer_id)
{
if (peer_id == PM_PEER_ID_INVALID)
{
return false;
}
pm_peer_id_t deleted_id = claim(peer_id, m_pi.deleted_peer_ids);
return (deleted_id == peer_id);
}
void peer_id_free(pm_peer_id_t peer_id)
{
release(peer_id, m_pi.active_peer_ids);
release(peer_id, m_pi.deleted_peer_ids);
}
bool peer_id_is_allocated(pm_peer_id_t peer_id)
{
if (peer_id < PM_PEER_ID_N_AVAILABLE_IDS)
{
return pm_mutex_lock_status_get(m_pi.active_peer_ids, peer_id);
}
return false;
}
bool peer_id_is_deleted(pm_peer_id_t peer_id)
{
if (peer_id < PM_PEER_ID_N_AVAILABLE_IDS)
{
return pm_mutex_lock_status_get(m_pi.deleted_peer_ids, peer_id);
}
return false;
}
pm_peer_id_t next_id_get(pm_peer_id_t prev_peer_id, uint8_t * mutex_group)
{
pm_peer_id_t i = (prev_peer_id == PM_PEER_ID_INVALID) ? 0 : (prev_peer_id + 1);
for (; i < PM_PEER_ID_N_AVAILABLE_IDS; i++)
{
if (pm_mutex_lock_status_get(mutex_group, i))
{
return i;
}
}
return PM_PEER_ID_INVALID;
}
pm_peer_id_t peer_id_get_next_used(pm_peer_id_t prev_peer_id)
{
return next_id_get(prev_peer_id, m_pi.active_peer_ids);
}
pm_peer_id_t peer_id_get_next_deleted(pm_peer_id_t prev_peer_id)
{
return next_id_get(prev_peer_id, m_pi.deleted_peer_ids);
}
uint32_t peer_id_n_ids(void)
{
uint32_t n_ids = 0;
for (pm_peer_id_t i = 0; i < PM_PEER_ID_N_AVAILABLE_IDS; i++)
{
n_ids += pm_mutex_lock_status_get(m_pi.active_peer_ids, i);
}
return n_ids;
}

Some files were not shown because too many files have changed in this diff Show More