mirror of https://github.com/ARMmbed/mbed-os.git
Merge branch 'master' into palsm
commit
dd7bc50e4b
|
@ -16,6 +16,9 @@ BUILD/
|
||||||
.mbed
|
.mbed
|
||||||
venv/
|
venv/
|
||||||
|
|
||||||
|
# Mbedls
|
||||||
|
.mbedls-mock.lock
|
||||||
|
|
||||||
# Eclipse Project Files
|
# Eclipse Project Files
|
||||||
.cproject
|
.cproject
|
||||||
.project
|
.project
|
||||||
|
@ -44,6 +47,8 @@ pip-log.txt
|
||||||
.coverage
|
.coverage
|
||||||
.tox
|
.tox
|
||||||
nosetests.xml
|
nosetests.xml
|
||||||
|
.cache
|
||||||
|
.hypothesis
|
||||||
|
|
||||||
# Translations
|
# Translations
|
||||||
*.mo
|
*.mo
|
||||||
|
@ -72,6 +77,9 @@ debug.log
|
||||||
# Cscope
|
# Cscope
|
||||||
cscope.*
|
cscope.*
|
||||||
|
|
||||||
|
# Ctags
|
||||||
|
tags
|
||||||
|
|
||||||
# vim swap files
|
# vim swap files
|
||||||
*.swp
|
*.swp
|
||||||
*~
|
*~
|
||||||
|
|
29
.travis.yml
29
.travis.yml
|
@ -10,7 +10,7 @@ env:
|
||||||
--data @- << DATA\n{
|
--data @- << DATA\n{
|
||||||
"state": "$0",
|
"state": "$0",
|
||||||
"description": "$1",
|
"description": "$1",
|
||||||
"context": "travis-ci/$NAME",
|
"context": "travis-ci/$NAME/$(python --version)",
|
||||||
"target_url": "https://travis-ci.org/$TRAVIS_REPO_SLUG/jobs/$TRAVIS_JOB_ID"
|
"target_url": "https://travis-ci.org/$TRAVIS_REPO_SLUG/jobs/$TRAVIS_JOB_ID"
|
||||||
}\nDATA'
|
}\nDATA'
|
||||||
|
|
||||||
|
@ -73,6 +73,10 @@ matrix:
|
||||||
|
|
||||||
- env:
|
- env:
|
||||||
- NAME=tools
|
- NAME=tools
|
||||||
|
python:
|
||||||
|
- '2.7'
|
||||||
|
- '3.5'
|
||||||
|
- '3.6'
|
||||||
install:
|
install:
|
||||||
# Install dependencies
|
# Install dependencies
|
||||||
- sudo apt-get install gcc-arm-embedded
|
- sudo apt-get install gcc-arm-embedded
|
||||||
|
@ -108,6 +112,10 @@ matrix:
|
||||||
# Check that example compiles
|
# Check that example compiles
|
||||||
- sed -n '/``` cpp/,/```/{/```$/Q;/```/d;p;}' $EVENTS/README.md > main.cpp
|
- sed -n '/``` cpp/,/```/{/```$/Q;/```/d;p;}' $EVENTS/README.md > main.cpp
|
||||||
- python tools/make.py -t GCC_ARM -m K64F --source=. --build=BUILD/K64F/GCC_ARM -j0
|
- python tools/make.py -t GCC_ARM -m K64F --source=. --build=BUILD/K64F/GCC_ARM -j0
|
||||||
|
# Check that example compiles without rtos
|
||||||
|
- sed -n '/``` cpp/,/```/{/```$/Q;/```/d;p;}' $EVENTS/README.md > main.cpp
|
||||||
|
- rm -r rtos features/netsocket features/frameworks BUILD
|
||||||
|
- python tools/make.py -t GCC_ARM -m DISCO_F401VC --source=. --build=BUILD/DISCO_F401VC/GCC_ARM -j0
|
||||||
# Run local equeue tests
|
# Run local equeue tests
|
||||||
- make -C $EVENTS/equeue test
|
- make -C $EVENTS/equeue test
|
||||||
|
|
||||||
|
@ -127,6 +135,7 @@ matrix:
|
||||||
before_script:
|
before_script:
|
||||||
# Setup and patch littlefs-fuse
|
# Setup and patch littlefs-fuse
|
||||||
- git clone https://github.com/geky/littlefs-fuse littlefs_fuse
|
- git clone https://github.com/geky/littlefs-fuse littlefs_fuse
|
||||||
|
- git -C littlefs_fuse checkout 3f1ed6e37799e49e3710830dc6abb926d5503cf2
|
||||||
- echo '*' > littlefs_fuse/.mbedignore
|
- echo '*' > littlefs_fuse/.mbedignore
|
||||||
- rm -rf littlefs_fuse/littlefs/*
|
- rm -rf littlefs_fuse/littlefs/*
|
||||||
- cp -r $(git ls-tree --name-only HEAD $LITTLEFS/littlefs/) littlefs_fuse/littlefs
|
- cp -r $(git ls-tree --name-only HEAD $LITTLEFS/littlefs/) littlefs_fuse/littlefs
|
||||||
|
@ -142,11 +151,10 @@ matrix:
|
||||||
# Run local littlefs tests
|
# Run local littlefs tests
|
||||||
- CFLAGS="-Wno-format" make -C$LITTLEFS/littlefs test QUIET=1
|
- CFLAGS="-Wno-format" make -C$LITTLEFS/littlefs test QUIET=1
|
||||||
# Run local littlefs tests with set of variations
|
# Run local littlefs tests with set of variations
|
||||||
- CFLAGS="-Wno-format -DLFS_READ_SIZE=64 -DLFS_PROG_SIZE=64" make -C$LITTLEFS/littlefs test QUIET=1
|
- CFLAGS="-Wno-format -DLFS_READ_SIZE=64 -DLFS_PROG_SIZE=64" make -C$LITTLEFS/littlefs test QUIET=1
|
||||||
- CFLAGS="-Wno-format -DLFS_READ_SIZE=1 -DLFS_PROG_SIZE=1" make -C$LITTLEFS/littlefs test QUIET=1
|
- CFLAGS="-Wno-format -DLFS_READ_SIZE=1 -DLFS_PROG_SIZE=1" make -C$LITTLEFS/littlefs test QUIET=1
|
||||||
- CFLAGS="-Wno-format -DLFS_READ_SIZE=512 -DLFS_PROG_SIZE=512" make -C$LITTLEFS/littlefs test QUIET=1
|
- CFLAGS="-Wno-format -DLFS_READ_SIZE=512 -DLFS_PROG_SIZE=512" make -C$LITTLEFS/littlefs test QUIET=1
|
||||||
- CFLAGS="-Wno-format -DLFS_BLOCK_COUNT=1023" make -C$LITTLEFS/littlefs test QUIET=1
|
- CFLAGS="-Wno-format -DLFS_BLOCK_COUNT=1023 -DLFS_LOOKAHEAD=2048" make -C$LITTLEFS/littlefs test QUIET=1
|
||||||
- CFLAGS="-Wno-format -DLFS_LOOKAHEAD=2048" make -C$LITTLEFS/littlefs test QUIET=1
|
|
||||||
# Self-hosting littlefs fuzz test with littlefs-fuse
|
# Self-hosting littlefs fuzz test with littlefs-fuse
|
||||||
- make -Clittlefs_fuse
|
- make -Clittlefs_fuse
|
||||||
- littlefs_fuse/lfs --format /dev/loop0
|
- littlefs_fuse/lfs --format /dev/loop0
|
||||||
|
@ -175,7 +183,7 @@ matrix:
|
||||||
- mkdir BUILD
|
- mkdir BUILD
|
||||||
script:
|
script:
|
||||||
# Run local mbed 2 testing
|
# Run local mbed 2 testing
|
||||||
- python2 -u tools/build_travis.py --vendor "${NAME#mbed2-}"
|
- python -u tools/build_travis.py --vendor "${NAME#mbed2-}"
|
||||||
- <<: *mbed-2
|
- <<: *mbed-2
|
||||||
env: NAME=mbed2-STM
|
env: NAME=mbed2-STM
|
||||||
- <<: *mbed-2
|
- <<: *mbed-2
|
||||||
|
@ -188,3 +196,10 @@ matrix:
|
||||||
env: NAME=mbed2-ATMEL
|
env: NAME=mbed2-ATMEL
|
||||||
- <<: *mbed-2
|
- <<: *mbed-2
|
||||||
env: NAME=mbed2-NUVOTON
|
env: NAME=mbed2-NUVOTON
|
||||||
|
- <<: *mbed-2
|
||||||
|
env: NAME=mbed2-RENESAS
|
||||||
|
# Change python version here only because 3x the other jobs does not add any more coverage
|
||||||
|
python:
|
||||||
|
- '2.7'
|
||||||
|
- '3.5'
|
||||||
|
- '3.6'
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
Copyright 2017 Arm Limited and affiliates.
|
||||||
|
|
||||||
|
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 the copyright holder 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.
|
|
@ -28,7 +28,7 @@ The [release notes](https://os.mbed.com/releases) detail the current release. Yo
|
||||||
|
|
||||||
## Getting started for developers
|
## Getting started for developers
|
||||||
|
|
||||||
We have a [developer webiste](https://os.mbed.com) for asking questions, engaging with others, finding information on boards and components, using an online IDE and compiler, reading the documentation and learning about what's new and what's coming next in Mbed OS.
|
We have a [developer website](https://os.mbed.com) for asking questions, engaging with others, finding information on boards and components, using an online IDE and compiler, reading the documentation and learning about what's new and what's coming next in Mbed OS.
|
||||||
|
|
||||||
## Getting started for contributors
|
## Getting started for contributors
|
||||||
|
|
||||||
|
|
|
@ -107,7 +107,10 @@ void semaphore_timing_test() {
|
||||||
equeue_sema_wait(&sema, delay);
|
equeue_sema_wait(&sema, delay);
|
||||||
int taken = timer.read_us() - start;
|
int taken = timer.read_us() - start;
|
||||||
|
|
||||||
printf("delay %dms => error %dus\r\n", delay, abs(1000*delay - taken));
|
if (taken < (delay * 1000 - 5000) || taken > (delay * 1000 + 5000)) {
|
||||||
|
printf("delay %dms => error %dus\r\n", delay, abs(1000 * delay - taken));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_ASSERT_INT_WITHIN(5000, taken, delay * 1000);
|
TEST_ASSERT_INT_WITHIN(5000, taken, delay * 1000);
|
||||||
|
|
||||||
led = !led;
|
led = !led;
|
||||||
|
|
|
@ -47,9 +47,14 @@ class RTC_time_calc_test(BaseHostTest):
|
||||||
|
|
||||||
edge_date = datetime.datetime(2100, 2, 28, 0, 0, 0)
|
edge_date = datetime.datetime(2100, 2, 28, 0, 0, 0)
|
||||||
|
|
||||||
years = [1970, 1971, 1972, 1973, 1974, 1975, 1976, 1977, 1978, 1979, 1980,
|
# Test the following years:
|
||||||
2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
# - first - 1970
|
||||||
2099, 2100, 2101, 2102, 2103, 2104, 2105, 2106]
|
# - example not leap year (not divisible by 4)
|
||||||
|
# - example leap year (divisible by 4 and by 100 and by 400)
|
||||||
|
# - example leap year (divisible by 4 and not by 100)
|
||||||
|
# - example not leap year (divisible by 4 and by 100)
|
||||||
|
# - last fully supported - 2105
|
||||||
|
years = [1970, 1971, 2000, 2096, 2100, 2105]
|
||||||
year_id = 0
|
year_id = 0
|
||||||
|
|
||||||
|
|
||||||
|
@ -123,6 +128,9 @@ class RTC_time_calc_test(BaseHostTest):
|
||||||
self.date += datetime.timedelta(days = 1)
|
self.date += datetime.timedelta(days = 1)
|
||||||
if (self.date.month == 1):
|
if (self.date.month == 1):
|
||||||
self.year_id += 1
|
self.year_id += 1
|
||||||
|
if (len(self.years) == self.year_id):
|
||||||
|
# All years were processed, no need to calc next date
|
||||||
|
return
|
||||||
self.date = self.date.replace(year = self.years[self.year_id])
|
self.date = self.date.replace(year = self.years[self.year_id])
|
||||||
self.date = self.date.replace(day = 1, minute = 0, second = 0)
|
self.date = self.date.replace(day = 1, minute = 0, second = 0)
|
||||||
self.first = not self.first
|
self.first = not self.first
|
||||||
|
@ -130,9 +138,3 @@ class RTC_time_calc_test(BaseHostTest):
|
||||||
def setup(self):
|
def setup(self):
|
||||||
self.register_callback('timestamp', self._verify_timestamp)
|
self.register_callback('timestamp', self._verify_timestamp)
|
||||||
self.register_callback('leap_year_setup', self._set_leap_year_support)
|
self.register_callback('leap_year_setup', self._set_leap_year_support)
|
||||||
|
|
||||||
def result(self):
|
|
||||||
return self.__result
|
|
||||||
|
|
||||||
def teardown(self):
|
|
||||||
pass
|
|
||||||
|
|
|
@ -51,13 +51,17 @@ extern uint32_t SystemCoreClock;
|
||||||
* For K64F DELTA = (80000 / 120000000) * 1000000 = 666[us]
|
* For K64F DELTA = (80000 / 120000000) * 1000000 = 666[us]
|
||||||
* For NUCLEO_F070RB DELTA = (80000 / 48000000) * 1000000 = 1666[us]
|
* For NUCLEO_F070RB DELTA = (80000 / 48000000) * 1000000 = 1666[us]
|
||||||
* For NRF51_DK DELTA = (80000 / 16000000) * 1000000 = 5000[us]
|
* For NRF51_DK DELTA = (80000 / 16000000) * 1000000 = 5000[us]
|
||||||
|
*
|
||||||
|
* As low power timer cannot be too much accurate, this DELTA should not be more precise than 500us,
|
||||||
|
* which corresponds to a maximum CPU clock around 130MHz
|
||||||
*/
|
*/
|
||||||
#define US_PER_SEC 1000000
|
#define US_PER_SEC 1000000
|
||||||
#define US_PER_MSEC 1000
|
#define US_PER_MSEC 1000
|
||||||
#define TOLERANCE_FACTOR 80000.0f
|
#define TOLERANCE_FACTOR 80000.0f
|
||||||
#define US_FACTOR 1000000.0f
|
#define US_FACTOR 1000000.0f
|
||||||
|
#define CLOCK_MAX 130000000
|
||||||
|
|
||||||
static const int delta_sys_clk_us = ((int) (TOLERANCE_FACTOR / (float) SystemCoreClock * US_FACTOR));
|
static const int delta_sys_clk_us = (SystemCoreClock < CLOCK_MAX? ((int) (TOLERANCE_FACTOR / (float) SystemCoreClock * US_FACTOR)):((int) (TOLERANCE_FACTOR / (float) CLOCK_MAX * US_FACTOR)));
|
||||||
|
|
||||||
/* When test performs time measurement using Timer in sequence, then measurement error accumulates
|
/* When test performs time measurement using Timer in sequence, then measurement error accumulates
|
||||||
* in the successive attempts. */
|
* in the successive attempts. */
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2016, ARM Limited, All Rights Reserved
|
* Copyright (c) 2013-2017, ARM Limited, All Rights Reserved
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
@ -28,15 +28,27 @@
|
||||||
#error [NOT_SUPPORTED] test not supported
|
#error [NOT_SUPPORTED] test not supported
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace utest::v1;
|
using utest::v1::Case;
|
||||||
|
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
/* Helper functions and data structures */
|
/* Helper functions and data structures */
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#define THREAD_STACK_SIZE 384
|
||||||
|
#define NUM_TEST_THREADS 3
|
||||||
|
|
||||||
|
template<osPriority PRIORITY, uint32_t STACK_SIZE>
|
||||||
|
class TestThread : public Thread {
|
||||||
|
uint8_t stack[STACK_SIZE];
|
||||||
|
public:
|
||||||
|
TestThread() : Thread(PRIORITY, STACK_SIZE, stack) { }
|
||||||
|
};
|
||||||
|
|
||||||
// This structure keeps data about the various memory allocation operations,
|
// This structure keeps data about the various memory allocation operations,
|
||||||
// as traced by 'test_trace_cb' below.
|
// as traced by 'test_trace_cb' below.
|
||||||
#define TEST_MAX_MEMORY_OPS 10
|
#define TEST_MAX_MEMORY_OPS 10
|
||||||
|
|
||||||
// Trace results for all possible operations
|
// Trace results for all possible operations
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t op;
|
uint8_t op;
|
||||||
|
@ -58,24 +70,28 @@ typedef struct {
|
||||||
} free_info;
|
} free_info;
|
||||||
};
|
};
|
||||||
} mem_trace_data_t;
|
} mem_trace_data_t;
|
||||||
|
|
||||||
// Memory operation statistics
|
// Memory operation statistics
|
||||||
typedef struct {
|
typedef struct {
|
||||||
mem_trace_data_t op_data[TEST_MAX_MEMORY_OPS];
|
mem_trace_data_t op_data[TEST_MAX_MEMORY_OPS];
|
||||||
uint32_t total_ops;
|
uint32_t total_ops;
|
||||||
bool invalid_op, overflow;
|
bool invalid_op, overflow;
|
||||||
} stats_t;
|
} stats_t;
|
||||||
|
|
||||||
static stats_t stats;
|
static stats_t stats;
|
||||||
|
|
||||||
|
|
||||||
// Clear all the memory statistics
|
// Clear all the memory statistics
|
||||||
static void test_clear_stats() {
|
static void test_clear_stats()
|
||||||
|
{
|
||||||
memset(&stats, 0, sizeof(stats));
|
memset(&stats, 0, sizeof(stats));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Memory tracer callback that records each operation in "stats" (above)
|
// Memory tracer callback that records each operation in "stats" (above)
|
||||||
extern "C" void test_trace_cb(uint8_t op, void *res, void *caller, ...) {
|
extern "C" void test_trace_cb(uint8_t op, void *res, void *caller, ...)
|
||||||
|
{
|
||||||
va_list va;
|
va_list va;
|
||||||
mem_trace_data_t *pmem = stats.op_data + stats.total_ops;
|
mem_trace_data_t *pmem = stats.op_data + stats.total_ops;
|
||||||
|
|
||||||
if (stats.total_ops >= TEST_MAX_MEMORY_OPS) {
|
if (stats.total_ops >= TEST_MAX_MEMORY_OPS) {
|
||||||
stats.overflow = true;
|
stats.overflow = true;
|
||||||
return;
|
return;
|
||||||
|
@ -110,180 +126,305 @@ extern "C" void test_trace_cb(uint8_t op, void *res, void *caller, ...) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generic sanity checks for the tracer
|
// Generic sanity checks for the tracer
|
||||||
static void check_sanity(uint32_t expected_ops) {
|
static void check_sanity(uint32_t expected_ops)
|
||||||
|
{
|
||||||
TEST_ASSERT_FALSE(stats.overflow);
|
TEST_ASSERT_FALSE(stats.overflow);
|
||||||
TEST_ASSERT_FALSE(stats.invalid_op);
|
TEST_ASSERT_FALSE(stats.invalid_op);
|
||||||
TEST_ASSERT_EQUAL_UINT32(stats.total_ops, expected_ops);
|
TEST_ASSERT_EQUAL_UINT32(expected_ops, stats.total_ops);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check a "malloc" operation
|
// Check a "malloc" operation
|
||||||
static void check_malloc_op(const mem_trace_data_t *p, void *expected_res, size_t expected_arg_size) {
|
static void check_malloc_op(const mem_trace_data_t *p, void *expected_res, size_t expected_arg_size)
|
||||||
TEST_ASSERT_EQUAL_UINT8(p->op, MBED_MEM_TRACE_MALLOC);
|
{
|
||||||
TEST_ASSERT_EQUAL_PTR(p->res, expected_res);
|
TEST_ASSERT_EQUAL_UINT8(MBED_MEM_TRACE_MALLOC, p->op);
|
||||||
TEST_ASSERT_EQUAL_UINT32(p->malloc_info.arg_size, expected_arg_size);
|
TEST_ASSERT_EQUAL_PTR(expected_res, p->res);
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(expected_arg_size, p->malloc_info.arg_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check a "free" operation
|
// Check a "free" operation
|
||||||
static void check_free_op(const mem_trace_data_t *p, void *expected_arg_ptr) {
|
static void check_free_op(const mem_trace_data_t *p, void *expected_arg_ptr)
|
||||||
TEST_ASSERT_EQUAL_UINT8(p->op, MBED_MEM_TRACE_FREE);
|
{
|
||||||
TEST_ASSERT_EQUAL_PTR(p->free_info.arg_ptr, expected_arg_ptr);
|
TEST_ASSERT_EQUAL_UINT8(MBED_MEM_TRACE_FREE, p->op);
|
||||||
|
TEST_ASSERT_EQUAL_PTR(expected_arg_ptr, p->free_info.arg_ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check a "realloc" operation
|
// Check a "realloc" operation
|
||||||
static void check_realloc_op(const mem_trace_data_t *p, void *expected_res, void *expected_arg_ptr, size_t expected_arg_size) {
|
static void check_realloc_op(const mem_trace_data_t *p, void *expected_res, void *expected_arg_ptr, size_t expected_arg_size)
|
||||||
TEST_ASSERT_EQUAL_UINT8(p->op, MBED_MEM_TRACE_REALLOC);
|
{
|
||||||
TEST_ASSERT_EQUAL_PTR(p->res, expected_res);
|
TEST_ASSERT_EQUAL_UINT8(MBED_MEM_TRACE_REALLOC, p->op);
|
||||||
TEST_ASSERT_EQUAL_UINT32(p->realloc_info.arg_ptr, expected_arg_ptr);
|
TEST_ASSERT_EQUAL_PTR(expected_res, p->res);
|
||||||
TEST_ASSERT_EQUAL_UINT32(p->realloc_info.arg_size, expected_arg_size);
|
TEST_ASSERT_EQUAL_UINT32(expected_arg_ptr, p->realloc_info.arg_ptr);
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(expected_arg_size, p->realloc_info.arg_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check a "calloc" operation
|
// Check a "calloc" operation
|
||||||
static void check_calloc_op(const mem_trace_data_t *p, void *expected_res, size_t expected_arg_nmemb, size_t expected_arg_size) {
|
static void check_calloc_op(const mem_trace_data_t *p, void *expected_res, size_t expected_arg_nmemb, size_t expected_arg_size)
|
||||||
TEST_ASSERT_EQUAL_UINT8(p->op, MBED_MEM_TRACE_CALLOC);
|
{
|
||||||
TEST_ASSERT_EQUAL_PTR(p->res, expected_res);
|
TEST_ASSERT_EQUAL_UINT8(MBED_MEM_TRACE_CALLOC, p->op);
|
||||||
TEST_ASSERT_EQUAL_UINT32(p->calloc_info.arg_nmemb, expected_arg_nmemb);
|
TEST_ASSERT_EQUAL_PTR(expected_res, p->res);
|
||||||
TEST_ASSERT_EQUAL_UINT32(p->calloc_info.arg_size, expected_arg_size);
|
TEST_ASSERT_EQUAL_UINT32(expected_arg_nmemb, p->calloc_info.arg_nmemb);
|
||||||
|
TEST_ASSERT_EQUAL_UINT32(expected_arg_size, p->calloc_info.arg_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************/
|
// Memory tracer callback to test thread safety
|
||||||
/* Tests */
|
extern "C" void test_trace_cb_multithread(uint8_t op, void *res, void *caller, ...)
|
||||||
/******************************************************************************/
|
{
|
||||||
|
volatile static int trace_guard = 0;
|
||||||
|
trace_guard++;
|
||||||
|
TEST_ASSERT_TRUE_MESSAGE(trace_guard == 1, "Race condition occurred !!!!");
|
||||||
|
trace_guard--;
|
||||||
|
}
|
||||||
|
|
||||||
// Allocate a single buffer, then free it. Check that tracing matches the operations.
|
// Thread function
|
||||||
static void test_case_single_malloc_free() {
|
void malloc_free(volatile bool *thread_continue)
|
||||||
|
{
|
||||||
|
const size_t block_size = 126;
|
||||||
|
|
||||||
|
while(*thread_continue) {
|
||||||
|
void *p = malloc(block_size);
|
||||||
|
TEST_ASSERT_NOT_EQUAL(p, NULL);
|
||||||
|
free(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Test single malloc/free tracing
|
||||||
|
*
|
||||||
|
* Given a memory trace mechanism
|
||||||
|
* When perform single memory allocation/deallocation using malloc/free
|
||||||
|
* Then tracing matches the operations
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void test_case_single_malloc_free()
|
||||||
|
{
|
||||||
|
const uint32_t num_op = 2;
|
||||||
const size_t block_size = 126;
|
const size_t block_size = 126;
|
||||||
const mem_trace_data_t *pmem = stats.op_data;
|
const mem_trace_data_t *pmem = stats.op_data;
|
||||||
|
|
||||||
test_clear_stats();
|
test_clear_stats();
|
||||||
mbed_mem_trace_set_callback(test_trace_cb);
|
mbed_mem_trace_set_callback(test_trace_cb);
|
||||||
|
|
||||||
// Allocate a single memory block
|
// Allocate a single memory block
|
||||||
void *p = malloc(block_size);
|
void *p = malloc(block_size);
|
||||||
TEST_ASSERT_NOT_EQUAL(p, NULL);
|
TEST_ASSERT_NOT_EQUAL(p, NULL);
|
||||||
|
|
||||||
// Free the memory block
|
// Free the memory block
|
||||||
free(p);
|
free(p);
|
||||||
|
|
||||||
// Stop tracing
|
// Stop tracing
|
||||||
mbed_mem_trace_set_callback(NULL);
|
mbed_mem_trace_set_callback(NULL);
|
||||||
|
|
||||||
// Check tracer result
|
// Check tracer result
|
||||||
check_sanity(2);
|
check_sanity(num_op);
|
||||||
check_malloc_op(pmem ++, p, block_size);
|
check_malloc_op(pmem++, p, block_size);
|
||||||
check_free_op(pmem, p);
|
check_free_op(pmem, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test all memory operations (malloc, realloc, free, calloc)
|
|
||||||
static void test_case_all_memory_ops() {
|
/** Test all memory operations (malloc, realloc, free, calloc) tracing
|
||||||
|
*
|
||||||
|
* Given a memory trace mechanism
|
||||||
|
* When perform all memory operations
|
||||||
|
* Then tracing matches the operations
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void test_case_all_memory_ops()
|
||||||
|
{
|
||||||
|
const uint32_t num_op = 5;
|
||||||
const size_t malloc_size = 40, realloc_size = 80, nmemb = 25, size = 10;
|
const size_t malloc_size = 40, realloc_size = 80, nmemb = 25, size = 10;
|
||||||
const mem_trace_data_t *pmem = stats.op_data;
|
const mem_trace_data_t *pmem = stats.op_data;
|
||||||
|
|
||||||
test_clear_stats();
|
test_clear_stats();
|
||||||
mbed_mem_trace_set_callback(test_trace_cb);
|
mbed_mem_trace_set_callback(test_trace_cb);
|
||||||
|
|
||||||
// Allocate a single memory block, the realloc it
|
// Allocate a single memory block, the realloc it
|
||||||
void *p_malloc = malloc(malloc_size);
|
void *p_malloc = malloc(malloc_size);
|
||||||
TEST_ASSERT_NOT_EQUAL(p_malloc, NULL);
|
TEST_ASSERT_NOT_EQUAL(p_malloc, NULL);
|
||||||
void *p_realloc = realloc(p_malloc, realloc_size);
|
void *p_realloc = realloc(p_malloc, realloc_size);
|
||||||
TEST_ASSERT_NOT_EQUAL(p_realloc, NULL);
|
TEST_ASSERT_NOT_EQUAL(p_realloc, NULL);
|
||||||
|
|
||||||
// Use calloc() now
|
// Use calloc() now
|
||||||
void *p_calloc = calloc(nmemb, size);
|
void *p_calloc = calloc(nmemb, size);
|
||||||
//TEST_ASSERT_NOT_EQUAL(p_calloc, NULL);
|
TEST_ASSERT_NOT_EQUAL(p_calloc, NULL);
|
||||||
|
|
||||||
// Free the realloc() pointer first, then the calloc() one
|
// Free the realloc() pointer first, then the calloc() one
|
||||||
free(p_realloc);
|
free(p_realloc);
|
||||||
free(p_calloc);
|
free(p_calloc);
|
||||||
|
|
||||||
// Stop tracing
|
// Stop tracing
|
||||||
mbed_mem_trace_set_callback(NULL);
|
mbed_mem_trace_set_callback(NULL);
|
||||||
|
|
||||||
// Check tracer result
|
// Check tracer result
|
||||||
check_sanity(6);
|
check_sanity(num_op);
|
||||||
check_malloc_op(pmem ++, p_malloc, malloc_size);
|
check_malloc_op(pmem++, p_malloc, malloc_size);
|
||||||
check_realloc_op(pmem ++, p_realloc, p_malloc, realloc_size);
|
check_realloc_op(pmem++, p_realloc, p_malloc, realloc_size);
|
||||||
// calloc() calls malloc() internally
|
check_calloc_op(pmem++, p_calloc, nmemb, size);
|
||||||
check_malloc_op(pmem ++, p_calloc, nmemb * size);
|
check_free_op(pmem++, p_realloc);
|
||||||
check_calloc_op(pmem ++, p_calloc, nmemb, size);
|
|
||||||
check_free_op(pmem ++, p_realloc);
|
|
||||||
check_free_op(pmem, p_calloc);
|
check_free_op(pmem, p_calloc);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that tracing is off when using a NULL callback
|
|
||||||
static void test_case_trace_off() {
|
/** Test that tracing is off when using a NULL callback
|
||||||
|
*
|
||||||
|
* Given a memory trace mechanism
|
||||||
|
* When tracing is turned off
|
||||||
|
* Then performed memory operations doesn't report any tracing
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void test_case_trace_off()
|
||||||
|
{
|
||||||
|
const uint32_t num_op = 0;
|
||||||
const size_t malloc_size = 10;
|
const size_t malloc_size = 10;
|
||||||
|
|
||||||
test_clear_stats();
|
test_clear_stats();
|
||||||
// We don't want any tracing
|
// We don't want any tracing
|
||||||
mbed_mem_trace_set_callback(NULL);
|
mbed_mem_trace_set_callback(NULL);
|
||||||
|
|
||||||
// Allocate a buffer and free it
|
// Allocate a buffer and free it
|
||||||
void *p_malloc = malloc(malloc_size);
|
void *p_malloc = malloc(malloc_size);
|
||||||
TEST_ASSERT_NOT_EQUAL(p_malloc, NULL);
|
TEST_ASSERT_NOT_EQUAL(p_malloc, NULL);
|
||||||
free(p_malloc);
|
free(p_malloc);
|
||||||
|
|
||||||
// Check that we didn't trace anything
|
// Check that we didn't trace anything
|
||||||
check_sanity(0);
|
check_sanity(num_op);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test partial tracing (start tracing, stop tracing, restart later)
|
|
||||||
static void test_case_partial_trace() {
|
/** Test partial tracing
|
||||||
|
*
|
||||||
|
* Given a memory trace mechanism
|
||||||
|
* When perform memory operations while tracing is on then off and on again
|
||||||
|
* Then tracing report only part of operations
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void test_case_partial_trace()
|
||||||
|
{
|
||||||
|
const uint32_t num_op = 2;
|
||||||
const size_t malloc_size_1 = 20, malloc_size_2 = 30;
|
const size_t malloc_size_1 = 20, malloc_size_2 = 30;
|
||||||
const mem_trace_data_t *pmem = stats.op_data;
|
const mem_trace_data_t *pmem = stats.op_data;
|
||||||
|
|
||||||
test_clear_stats();
|
test_clear_stats();
|
||||||
|
|
||||||
// Start tracing
|
// Start tracing
|
||||||
mbed_mem_trace_set_callback(test_trace_cb);
|
mbed_mem_trace_set_callback(test_trace_cb);
|
||||||
|
|
||||||
// Allocate a buffer
|
// Allocate a buffer
|
||||||
void *p_malloc_1 = malloc(malloc_size_1);
|
void *p_malloc_1 = malloc(malloc_size_1);
|
||||||
TEST_ASSERT_NOT_EQUAL(p_malloc_1, NULL);
|
TEST_ASSERT_NOT_EQUAL(p_malloc_1, NULL);
|
||||||
|
|
||||||
// Disable tracing before freeing the first buffer
|
// Disable tracing before freeing the first buffer
|
||||||
mbed_mem_trace_set_callback(NULL);
|
mbed_mem_trace_set_callback(NULL);
|
||||||
free(p_malloc_1);
|
free(p_malloc_1);
|
||||||
|
|
||||||
// Allocate another buffer (still not traced)
|
// Allocate another buffer (still not traced)
|
||||||
void *p_malloc_2 = malloc(malloc_size_2);
|
void *p_malloc_2 = malloc(malloc_size_2);
|
||||||
TEST_ASSERT_NOT_EQUAL(p_malloc_2, NULL);
|
TEST_ASSERT_NOT_EQUAL(p_malloc_2, NULL);
|
||||||
|
|
||||||
// Re-enable tracing
|
// Re-enable tracing
|
||||||
mbed_mem_trace_set_callback(test_trace_cb);
|
mbed_mem_trace_set_callback(test_trace_cb);
|
||||||
|
|
||||||
// And free the second buffer (this operation should be tracer)
|
// And free the second buffer (this operation should be tracer)
|
||||||
free(p_malloc_2);
|
free(p_malloc_2);
|
||||||
|
|
||||||
// Stop tracing
|
// Stop tracing
|
||||||
mbed_mem_trace_set_callback(NULL);
|
mbed_mem_trace_set_callback(NULL);
|
||||||
|
|
||||||
// Check tracer result
|
// Check tracer result
|
||||||
check_sanity(2);
|
check_sanity(num_op);
|
||||||
check_malloc_op(pmem ++, p_malloc_1, malloc_size_1);
|
check_malloc_op(pmem++, p_malloc_1, malloc_size_1);
|
||||||
check_free_op(pmem, p_malloc_2);
|
check_free_op(pmem, p_malloc_2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test new/delete tracing
|
|
||||||
static void test_case_new_delete() {
|
/** Test new/delete tracing
|
||||||
|
*
|
||||||
|
* Given a memory trace mechanism
|
||||||
|
* When memory allocation/deallocation is performed using new/delete
|
||||||
|
* Then tracing matches the operations
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void test_case_new_delete()
|
||||||
|
{
|
||||||
|
const uint32_t num_op = 4;
|
||||||
const mem_trace_data_t *pmem = stats.op_data;
|
const mem_trace_data_t *pmem = stats.op_data;
|
||||||
|
|
||||||
test_clear_stats();
|
test_clear_stats();
|
||||||
|
|
||||||
// Start tracing
|
// Start tracing
|
||||||
mbed_mem_trace_set_callback(test_trace_cb);
|
mbed_mem_trace_set_callback(test_trace_cb);
|
||||||
|
|
||||||
// Test new, new[], delete and delete[]
|
// Test new, new[], delete and delete[]
|
||||||
int *p_int = new int;
|
int *p_int = new int;
|
||||||
int *p_int_array = new int[10];
|
int *p_int_array = new int[10];
|
||||||
delete p_int;
|
delete p_int;
|
||||||
delete[] p_int_array;
|
delete[] p_int_array;
|
||||||
|
|
||||||
// Stop tracing
|
// Stop tracing
|
||||||
mbed_mem_trace_set_callback(NULL);
|
mbed_mem_trace_set_callback(NULL);
|
||||||
|
|
||||||
// Check tracer result
|
// Check tracer result
|
||||||
check_sanity(4);
|
check_sanity(num_op);
|
||||||
check_malloc_op(pmem ++, p_int, sizeof(int));
|
check_malloc_op(pmem++, p_int, sizeof(int));
|
||||||
check_malloc_op(pmem ++, p_int_array, 10 * sizeof(int));
|
check_malloc_op(pmem++, p_int_array, 10 * sizeof(int));
|
||||||
check_free_op(pmem ++, p_int);
|
check_free_op(pmem++, p_int);
|
||||||
check_free_op(pmem ++, p_int_array);
|
check_free_op(pmem, p_int_array);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Case cases[] = {
|
|
||||||
Case("single malloc/free", test_case_single_malloc_free),
|
/** Test tracing thread safety
|
||||||
Case("all memory operations", test_case_all_memory_ops),
|
*
|
||||||
Case("trace off", test_case_trace_off),
|
* Given a memory trace mechanism and multiple threads are started in parallel
|
||||||
Case("partial trace", test_case_partial_trace),
|
* When each of the threads perform memory allocation/deallocation (thus uses memory trace mechanisms)
|
||||||
Case("test new/delete", test_case_new_delete)
|
* Then tracing is protected against simultaneous multithreaded access
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static void test_case_multithread_malloc_free()
|
||||||
|
{
|
||||||
|
const uint32_t wait_time_us = 10000;
|
||||||
|
volatile bool threads_continue;
|
||||||
|
TestThread<osPriorityNormal, THREAD_STACK_SIZE> threads[NUM_TEST_THREADS];
|
||||||
|
|
||||||
|
mbed_mem_trace_set_callback(test_trace_cb_multithread);
|
||||||
|
|
||||||
|
threads_continue = true;
|
||||||
|
for (int i = 0; i < NUM_TEST_THREADS; i++) {
|
||||||
|
threads[i].start(callback(malloc_free, &threads_continue));
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread::wait(wait_time_us);
|
||||||
|
threads_continue = false;
|
||||||
|
|
||||||
|
for (int i = 0; i < NUM_TEST_THREADS; i++) {
|
||||||
|
threads[i].join();
|
||||||
|
}
|
||||||
|
|
||||||
|
mbed_mem_trace_set_callback(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static Case cases[] =
|
||||||
|
{
|
||||||
|
Case("Test single malloc/free trace", test_case_single_malloc_free),
|
||||||
|
Case("Test all memory operations trace", test_case_all_memory_ops),
|
||||||
|
Case("Test trace off", test_case_trace_off),
|
||||||
|
Case("Test partial trace", test_case_partial_trace),
|
||||||
|
Case("Test new/delete trace", test_case_new_delete),
|
||||||
|
Case("Test multithreaded trace", test_case_multithread_malloc_free)
|
||||||
};
|
};
|
||||||
|
|
||||||
static status_t greentea_test_setup(const size_t number_of_cases) {
|
static utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
|
||||||
GREENTEA_SETUP(20, "default_auto");
|
{
|
||||||
return greentea_test_setup_handler(number_of_cases);
|
GREENTEA_SETUP(15, "default_auto");
|
||||||
|
return utest::v1::greentea_test_setup_handler(number_of_cases);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
|
static utest::v1::Specification specification(greentea_test_setup, cases, utest::v1::greentea_test_teardown_handler);
|
||||||
|
|
||||||
int main() {
|
int main()
|
||||||
|
{
|
||||||
// Disable stdout buffering to prevent any unwanted allocations
|
// Disable stdout buffering to prevent any unwanted allocations
|
||||||
setvbuf(stdout, NULL, _IONBF, 0);
|
setvbuf(stdout, NULL, _IONBF, 0);
|
||||||
Harness::run(specification);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
return !utest::v1::Harness::run(specification);
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2016, ARM Limited, All Rights Reserved
|
* Copyright (c) 2017, ARM Limited, All Rights Reserved
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
* Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
|
@ -16,41 +16,480 @@
|
||||||
*/
|
*/
|
||||||
#include "mbed.h"
|
#include "mbed.h"
|
||||||
#include "greentea-client/test_env.h"
|
#include "greentea-client/test_env.h"
|
||||||
#include "unity/unity.h"
|
#include "unity.h"
|
||||||
#include "utest/utest.h"
|
#include "utest.h"
|
||||||
|
#include "rtos.h"
|
||||||
|
#include "rtc_api.h"
|
||||||
|
|
||||||
|
#if !DEVICE_RTC
|
||||||
|
#error [NOT_SUPPORTED] test not supported
|
||||||
|
#endif
|
||||||
|
|
||||||
using namespace utest::v1;
|
using namespace utest::v1;
|
||||||
|
|
||||||
#define CUSTOM_TIME 1256729737
|
/* On some boards RTC counter can not be
|
||||||
|
* Initialised with 0 value in such case
|
||||||
|
* drivers sets RTC counter to 1. */
|
||||||
|
#define CUSTOM_TIME_0 1
|
||||||
|
#define CUSTOM_TIME_1 1256729737
|
||||||
|
#define CUSTOM_TIME_2 2147483637
|
||||||
|
|
||||||
void test_case_rtc_strftime() {
|
#define DELAY_10_SEC 10
|
||||||
greentea_send_kv("timestamp", CUSTOM_TIME);
|
#define MS_PER_SEC 1000
|
||||||
|
#define RTC_DELTA 1
|
||||||
|
|
||||||
char buffer[32] = {0};
|
static volatile int rtc_enabled_ret;
|
||||||
char kv_buff[64] = {0};
|
static volatile time_t rtc_time_val;
|
||||||
set_time(CUSTOM_TIME); // Set RTC time to Wed, 28 Oct 2009 11:35:37
|
static volatile bool rtc_read_called;
|
||||||
|
static volatile bool rtc_write_called;
|
||||||
|
static volatile bool rtc_init_called;
|
||||||
|
static volatile bool rtc_isenabled_called;
|
||||||
|
|
||||||
for (int i=0; i<10; ++i) {
|
/* Stub of RTC read function. */
|
||||||
time_t seconds = time(NULL);
|
static time_t read_rtc_stub(void)
|
||||||
sprintf(kv_buff, "[%ld] ", seconds);
|
{
|
||||||
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S %p", localtime(&seconds));
|
rtc_read_called = true;
|
||||||
strcat(kv_buff, buffer);
|
|
||||||
greentea_send_kv("rtc", kv_buff);
|
return rtc_time_val;
|
||||||
wait(1);
|
}
|
||||||
}
|
|
||||||
|
/* Stub of RTC write function. */
|
||||||
|
static void write_rtc_stub(time_t t)
|
||||||
|
{
|
||||||
|
rtc_write_called = true;
|
||||||
|
|
||||||
|
rtc_time_val = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stub of RTC init function. */
|
||||||
|
static void init_rtc_stub(void)
|
||||||
|
{
|
||||||
|
rtc_init_called = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Stub of RTC isenabled function. */
|
||||||
|
static int isenabled_rtc_stub(void)
|
||||||
|
{
|
||||||
|
rtc_isenabled_called = true;
|
||||||
|
|
||||||
|
return rtc_enabled_ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This test verifies if attach_rtc provides availability to
|
||||||
|
* connect specific RTC driver functions.
|
||||||
|
*
|
||||||
|
* This is unit test to verify if correct functions are used
|
||||||
|
* to support RTC.
|
||||||
|
*
|
||||||
|
* Given specific RTC driver functions have been attached (stubs).
|
||||||
|
* When set_time/time functions are called.
|
||||||
|
* Then set_time/time functions use attached RTC functions.
|
||||||
|
*/
|
||||||
|
void test_attach_RTC_stub_funtions()
|
||||||
|
{
|
||||||
|
time_t seconds = 0;
|
||||||
|
|
||||||
|
/* Attache RTC read/write/init/isenabled stubs. */
|
||||||
|
attach_rtc(read_rtc_stub, write_rtc_stub, init_rtc_stub, isenabled_rtc_stub);
|
||||||
|
|
||||||
|
/* Init stub variables/set to unexpected. */
|
||||||
|
rtc_write_called = false;
|
||||||
|
rtc_init_called = false;
|
||||||
|
|
||||||
|
/* Call set_time() function. We expect that init and write RTC stubs
|
||||||
|
* will be executed.
|
||||||
|
*/
|
||||||
|
set_time(CUSTOM_TIME_1);
|
||||||
|
|
||||||
|
/* Verify results. */
|
||||||
|
TEST_ASSERT_EQUAL(true, rtc_write_called);
|
||||||
|
TEST_ASSERT_EQUAL(true, rtc_init_called);
|
||||||
|
|
||||||
|
/* Init stub variables/set to unexpected. */
|
||||||
|
rtc_time_val = CUSTOM_TIME_1;
|
||||||
|
rtc_enabled_ret = true;
|
||||||
|
rtc_isenabled_called = false;
|
||||||
|
rtc_read_called = false;
|
||||||
|
|
||||||
|
/* Call time() function. We expect that isenabled and read RTC stubs
|
||||||
|
* are be executed.
|
||||||
|
*/
|
||||||
|
time(NULL);
|
||||||
|
|
||||||
|
/* Verify results. */
|
||||||
|
TEST_ASSERT_EQUAL(true, rtc_isenabled_called);
|
||||||
|
TEST_ASSERT_EQUAL(true, rtc_read_called);
|
||||||
|
|
||||||
|
/* This part of the test can be executed only on RTC devices. */
|
||||||
|
|
||||||
|
/* Restore env. */
|
||||||
|
attach_rtc(rtc_read, rtc_write, rtc_init, rtc_isenabled);
|
||||||
|
|
||||||
|
/* Set to unexpected. */
|
||||||
|
rtc_write_called = false;
|
||||||
|
rtc_init_called = false;
|
||||||
|
rtc_isenabled_called = false;
|
||||||
|
rtc_init_called = false;
|
||||||
|
|
||||||
|
/* Set time. */
|
||||||
|
set_time(CUSTOM_TIME_1);
|
||||||
|
|
||||||
|
/* Get time. */
|
||||||
|
seconds = time(NULL);
|
||||||
|
|
||||||
|
/* Stub RTC functions should not be called now. */
|
||||||
|
TEST_ASSERT_EQUAL(false, rtc_isenabled_called);
|
||||||
|
TEST_ASSERT_EQUAL(false, rtc_init_called);
|
||||||
|
TEST_ASSERT_EQUAL(false, rtc_write_called);
|
||||||
|
TEST_ASSERT_EQUAL(false, rtc_init_called);
|
||||||
|
|
||||||
|
/* Check if time has been successfully set and retrieved. */
|
||||||
|
TEST_ASSERT_EQUAL(CUSTOM_TIME_1, seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This test verifies if attach_rtc provides availability to
|
||||||
|
* connect specific RTC driver functions.
|
||||||
|
*
|
||||||
|
* This is unit test to verify if correct functions are used
|
||||||
|
* to support RTC.
|
||||||
|
*
|
||||||
|
* Given specific RTC driver functions have been attached (original).
|
||||||
|
* When set_time/time functions are called.
|
||||||
|
* Then set_time/time functions use attached RTC functions.
|
||||||
|
*/
|
||||||
|
void test_attach_RTC_org_funtions()
|
||||||
|
{
|
||||||
|
time_t seconds = 0;
|
||||||
|
|
||||||
|
/* Attache original driver functions. */
|
||||||
|
attach_rtc(rtc_read, rtc_write, rtc_init, rtc_isenabled);
|
||||||
|
|
||||||
|
/* Set to unexpected. */
|
||||||
|
rtc_write_called = false;
|
||||||
|
rtc_init_called = false;
|
||||||
|
rtc_isenabled_called = false;
|
||||||
|
rtc_init_called = false;
|
||||||
|
|
||||||
|
/* Set time. */
|
||||||
|
set_time(CUSTOM_TIME_1);
|
||||||
|
|
||||||
|
/* Get time. */
|
||||||
|
seconds = time(NULL);
|
||||||
|
|
||||||
|
/* Stub RTC functions should not be called now. */
|
||||||
|
TEST_ASSERT_EQUAL(false, rtc_isenabled_called);
|
||||||
|
TEST_ASSERT_EQUAL(false, rtc_init_called);
|
||||||
|
TEST_ASSERT_EQUAL(false, rtc_write_called);
|
||||||
|
TEST_ASSERT_EQUAL(false, rtc_init_called);
|
||||||
|
|
||||||
|
/* Check if time has been successfully set and retrieved. */
|
||||||
|
TEST_ASSERT_EQUAL(CUSTOM_TIME_1, seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This test verifies if time() function returns
|
||||||
|
* current time when all RTC functions are
|
||||||
|
* defined and RTC is enabled.
|
||||||
|
*
|
||||||
|
* Note: Stubs are used instead of original RTC functions.
|
||||||
|
*
|
||||||
|
* Given environment has RTC functions defined and RTC is enabled.
|
||||||
|
* When time() functions is called.
|
||||||
|
* Then current time is returned.
|
||||||
|
*/
|
||||||
|
void test_time_RTC_func_defined_RTC_is_enabled()
|
||||||
|
{
|
||||||
|
time_t seconds = 0;
|
||||||
|
|
||||||
|
/* Attache RTC read/write/init/isenabled stubs. */
|
||||||
|
attach_rtc(read_rtc_stub, write_rtc_stub, init_rtc_stub, isenabled_rtc_stub);
|
||||||
|
|
||||||
|
/* Simulate that RTC is enabled. */
|
||||||
|
rtc_enabled_ret = true;
|
||||||
|
|
||||||
|
/* Simulate current time. */
|
||||||
|
rtc_time_val = CUSTOM_TIME_1;
|
||||||
|
|
||||||
|
/* Try to get current time. */
|
||||||
|
seconds = time(NULL);
|
||||||
|
|
||||||
|
/* Check if expected value has been returned. */
|
||||||
|
TEST_ASSERT_EQUAL(CUSTOM_TIME_1, seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This test verifies if time() function resets time
|
||||||
|
* when RTC functions are defined and RTC is disabled.
|
||||||
|
*
|
||||||
|
* Note: Stubs are used instead of original RTC functions.
|
||||||
|
*
|
||||||
|
* Given environment has RTC functions defined and RTC is disabled.
|
||||||
|
* When time() functions is called.
|
||||||
|
* Then function result is 0.
|
||||||
|
*/
|
||||||
|
void test_time_RTC_func_defined_RTC_is_disabled()
|
||||||
|
{
|
||||||
|
time_t seconds = 0;
|
||||||
|
|
||||||
|
/* Attache RTC read/write/init/isenabled stubs. */
|
||||||
|
attach_rtc(read_rtc_stub, write_rtc_stub, init_rtc_stub, isenabled_rtc_stub);
|
||||||
|
|
||||||
|
/* Simulate that RTC is disabled. */
|
||||||
|
rtc_enabled_ret = false;
|
||||||
|
|
||||||
|
/* Simulate current time. */
|
||||||
|
rtc_time_val = CUSTOM_TIME_1;
|
||||||
|
|
||||||
|
/* Try to get current time. */
|
||||||
|
seconds = time(NULL);
|
||||||
|
|
||||||
|
/* Check if expected value has been returned. */
|
||||||
|
TEST_ASSERT_EQUAL(0, seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This test verifies if time() function can be successfully
|
||||||
|
* executed when isenabled RTC function is undefined.
|
||||||
|
*
|
||||||
|
* Note: Stubs are used instead of original RTC functions.
|
||||||
|
*
|
||||||
|
* Given environment has isenabled RTC function undefined.
|
||||||
|
* When time() functions is called.
|
||||||
|
* Then current time is returned.
|
||||||
|
*/
|
||||||
|
void test_time_isenabled_RTC_func_undefined()
|
||||||
|
{
|
||||||
|
time_t seconds = 0;
|
||||||
|
|
||||||
|
/* Attache RTC read/write/init stubs. */
|
||||||
|
attach_rtc(read_rtc_stub, write_rtc_stub, init_rtc_stub, NULL);
|
||||||
|
|
||||||
|
/* Simulate current time. */
|
||||||
|
rtc_time_val = CUSTOM_TIME_1;
|
||||||
|
|
||||||
|
/* Try to get current time. */
|
||||||
|
seconds = time(NULL);
|
||||||
|
|
||||||
|
/* Check if expected value has been returned. */
|
||||||
|
TEST_ASSERT_EQUAL(CUSTOM_TIME_1, seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This test verifies if time() function returns -1 if
|
||||||
|
* read RTC function is undefined.
|
||||||
|
*
|
||||||
|
* Note: Stubs are used instead of original RTC functions.
|
||||||
|
*
|
||||||
|
* Given environment has read RTC function undefined.
|
||||||
|
* When time() functions is called.
|
||||||
|
* Then -1 is returned.
|
||||||
|
*/
|
||||||
|
void test_time_read_RTC_func_undefined()
|
||||||
|
{
|
||||||
|
time_t seconds = 0;
|
||||||
|
|
||||||
|
/* Attache RTC write/init/isenabled stubs. */
|
||||||
|
attach_rtc(NULL, write_rtc_stub, init_rtc_stub, isenabled_rtc_stub);
|
||||||
|
|
||||||
|
/* Simulate current time. */
|
||||||
|
rtc_time_val = CUSTOM_TIME_1;
|
||||||
|
|
||||||
|
/* Try to get current time. */
|
||||||
|
seconds = time(NULL);
|
||||||
|
|
||||||
|
/* Check if expected value has been returned. */
|
||||||
|
TEST_ASSERT_EQUAL((time_t)-1, seconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This test verifies if time() function stores
|
||||||
|
* the result in given time buffer (if specified).
|
||||||
|
*
|
||||||
|
* Note: Stubs are used instead original RTC functions.
|
||||||
|
* Other test cases calls time() routine with
|
||||||
|
* undefined time buffer.
|
||||||
|
*
|
||||||
|
* Given environment has all RTC function defined, RTC is enabled and time buffer is passed to time() function.
|
||||||
|
* When time() functions is called.
|
||||||
|
* Then current time is stored in the specified buffer.
|
||||||
|
*/
|
||||||
|
void test_time_called_with_param()
|
||||||
|
{
|
||||||
|
time_t seconds = 0;
|
||||||
|
time_t buffer = 0;
|
||||||
|
|
||||||
|
/* Attache RTC read/write/init/isenabled stubs. */
|
||||||
|
attach_rtc(read_rtc_stub, write_rtc_stub, init_rtc_stub, isenabled_rtc_stub);
|
||||||
|
|
||||||
|
/* Simulate that RTC is enabled. */
|
||||||
|
rtc_enabled_ret = true;
|
||||||
|
|
||||||
|
/* Simulate current time. */
|
||||||
|
rtc_time_val = CUSTOM_TIME_1;
|
||||||
|
|
||||||
|
/* Try to get current time. */
|
||||||
|
seconds = time(&buffer);
|
||||||
|
|
||||||
|
/* Check if expected value has been returned. */
|
||||||
|
TEST_ASSERT_EQUAL(CUSTOM_TIME_1, seconds);
|
||||||
|
TEST_ASSERT_EQUAL(CUSTOM_TIME_1, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This test verifies if set_time() function inits the RTC
|
||||||
|
* and writes current time if RTC functions are defined.
|
||||||
|
*
|
||||||
|
* Note: Stubs are used instead of original RTC functions.
|
||||||
|
*
|
||||||
|
* Given environment has RTC functions defined.
|
||||||
|
* When set_time() functions is called.
|
||||||
|
* Then function initialises RTC and sets RTC time.
|
||||||
|
*/
|
||||||
|
void test_set_time_RTC_func_defined()
|
||||||
|
{
|
||||||
|
/* Attache RTC read/write/init/isenabled stubs. */
|
||||||
|
attach_rtc(read_rtc_stub, write_rtc_stub, init_rtc_stub, isenabled_rtc_stub);
|
||||||
|
|
||||||
|
/* Set to unexpected. */
|
||||||
|
rtc_time_val = 123;
|
||||||
|
rtc_init_called = false;
|
||||||
|
|
||||||
|
/* Set current time. */
|
||||||
|
rtc_time_val = 123;
|
||||||
|
|
||||||
|
/* Set new RTC time. */
|
||||||
|
set_time(CUSTOM_TIME_1);
|
||||||
|
|
||||||
|
/* Check if RTC init has been performed and RTC time has been updated. */
|
||||||
|
TEST_ASSERT_EQUAL(true, rtc_init_called);
|
||||||
|
TEST_ASSERT_EQUAL(CUSTOM_TIME_1, time(NULL));
|
||||||
|
TEST_ASSERT_EQUAL(CUSTOM_TIME_1, rtc_time_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This test verifies if set_time() function can be
|
||||||
|
* successfully executed when init RTC function is undefined.
|
||||||
|
*
|
||||||
|
* Note: Stubs are used instead of original RTC functions.
|
||||||
|
*
|
||||||
|
* Given environment has init RTC function undefined.
|
||||||
|
* When set_time() functions is called.
|
||||||
|
* Then function sets RTC time.
|
||||||
|
*/
|
||||||
|
void test_set_time_init_RTC_func_undefined()
|
||||||
|
{
|
||||||
|
/* Attache RTC read/write/isenabled stubs. */
|
||||||
|
attach_rtc(read_rtc_stub, write_rtc_stub, NULL, isenabled_rtc_stub);
|
||||||
|
|
||||||
|
/* Set to unexpected. */
|
||||||
|
rtc_time_val = 123;
|
||||||
|
|
||||||
|
/* Set new RTC time. */
|
||||||
|
set_time(CUSTOM_TIME_1);
|
||||||
|
|
||||||
|
/* Check if RTC time has been updated. */
|
||||||
|
TEST_ASSERT_EQUAL(CUSTOM_TIME_1, time(NULL));
|
||||||
|
TEST_ASSERT_EQUAL(CUSTOM_TIME_1, rtc_time_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This test verifies if set_time() function can be
|
||||||
|
* successfully executed when write RTC function is undefined.
|
||||||
|
*
|
||||||
|
* Note: Stubs are used instead original RTC functions.
|
||||||
|
*
|
||||||
|
* Given environemt has write RTC function undefined.
|
||||||
|
* When set_time() function is called.
|
||||||
|
* Then function inits RTC and does not modify RTC time.
|
||||||
|
*/
|
||||||
|
void test_set_time_write_RTC_func_undefined()
|
||||||
|
{
|
||||||
|
/* Attache RTC read/write/init/isenabled stubs. */
|
||||||
|
attach_rtc(read_rtc_stub, NULL, init_rtc_stub, isenabled_rtc_stub);
|
||||||
|
|
||||||
|
/* Set to unexpected. */
|
||||||
|
rtc_time_val = 123;
|
||||||
|
rtc_init_called = false;
|
||||||
|
|
||||||
|
/* Set new RTC time. */
|
||||||
|
set_time(CUSTOM_TIME_1);
|
||||||
|
|
||||||
|
/* Check if RTC has been initialized and RTC time has not been updated. */
|
||||||
|
TEST_ASSERT_EQUAL(true, rtc_init_called);
|
||||||
|
TEST_ASSERT_EQUAL(123, time(NULL));
|
||||||
|
TEST_ASSERT_EQUAL(123, rtc_time_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This test verifies if RTC time can be successfully set.
|
||||||
|
*
|
||||||
|
* Note: Original RTC functions are used in this test.
|
||||||
|
*
|
||||||
|
* Given environment has RTC available.
|
||||||
|
* When set_time() functions is called.
|
||||||
|
* Then RTC time is retrieved.
|
||||||
|
*/
|
||||||
|
template<uint32_t timeValue>
|
||||||
|
void test_functional_set()
|
||||||
|
{
|
||||||
|
/* Set original RTC functions. */
|
||||||
|
attach_rtc(rtc_read, rtc_write, rtc_init, rtc_isenabled);
|
||||||
|
|
||||||
|
/* Set new RTC time. */
|
||||||
|
set_time(timeValue);
|
||||||
|
|
||||||
|
/* Get current time and verify that new value has been set. */
|
||||||
|
TEST_ASSERT_EQUAL(timeValue, time(NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This test verifies if RTC counts seconds.
|
||||||
|
*
|
||||||
|
* Note: Original RTC functions are used in this test.
|
||||||
|
*
|
||||||
|
* Given RTC has time set.
|
||||||
|
* When some time has passed (seconds).
|
||||||
|
* Then RTC time is updated.
|
||||||
|
*/
|
||||||
|
void test_functional_count()
|
||||||
|
{
|
||||||
|
time_t seconds = 0;
|
||||||
|
|
||||||
|
/* Set original RTC functions. */
|
||||||
|
attach_rtc(rtc_read, rtc_write, rtc_init, rtc_isenabled);
|
||||||
|
|
||||||
|
/* Set new RTC time. */
|
||||||
|
set_time(CUSTOM_TIME_2);
|
||||||
|
|
||||||
|
/* Wait 10 sec. */
|
||||||
|
wait_ms(DELAY_10_SEC * MS_PER_SEC);
|
||||||
|
|
||||||
|
/* Get time. */
|
||||||
|
seconds = time(NULL);
|
||||||
|
|
||||||
|
/* Verify that RTC counts seconds. */
|
||||||
|
TEST_ASSERT_UINT_WITHIN(RTC_DELTA, (unsigned int)seconds, CUSTOM_TIME_2 + DELAY_10_SEC);
|
||||||
|
}
|
||||||
|
|
||||||
|
utest::v1::status_t test_setup(const size_t number_of_cases)
|
||||||
|
{
|
||||||
|
GREENTEA_SETUP(20, "default_auto");
|
||||||
|
return verbose_test_setup_handler(number_of_cases);
|
||||||
}
|
}
|
||||||
|
|
||||||
Case cases[] = {
|
Case cases[] = {
|
||||||
Case("RTC strftime", test_case_rtc_strftime),
|
Case("Unit Test: attach stub RTC functions.", test_attach_RTC_stub_funtions),
|
||||||
|
Case("Unit Test: attach original RTC functions.", test_attach_RTC_org_funtions),
|
||||||
|
|
||||||
|
Case("Unit Test: time() - RTC functions are defined, RTC is enabled.", test_time_RTC_func_defined_RTC_is_enabled),
|
||||||
|
Case("Unit Test: time() - RTC functions are defined, RTC is disabled.", test_time_RTC_func_defined_RTC_is_disabled),
|
||||||
|
Case("Unit Test: time() - isenabled RTC function is undefined.", test_time_isenabled_RTC_func_undefined),
|
||||||
|
Case("Unit Test: time() - read RTC function is undefined.", test_time_read_RTC_func_undefined),
|
||||||
|
Case("Unit Test: time() - result is stored in given buffer.", test_time_called_with_param),
|
||||||
|
|
||||||
|
Case("Unit Test: set_time() - RTC functions are defined.", test_set_time_RTC_func_defined),
|
||||||
|
Case("Unit Test: set_time() - init RTC function is undefined.", test_set_time_init_RTC_func_undefined),
|
||||||
|
Case("Unit Test: set_time() - write RTC function is undefined.", test_set_time_write_RTC_func_undefined),
|
||||||
|
|
||||||
|
Case("Functional Test: set time - CUSTOM_TIME_0.", test_functional_set<CUSTOM_TIME_0>),
|
||||||
|
Case("Functional Test: set time - CUSTOM_TIME_1.", test_functional_set<CUSTOM_TIME_1>),
|
||||||
|
Case("Functional Test: set time - CUSTOM_TIME_2.", test_functional_set<CUSTOM_TIME_2>),
|
||||||
|
|
||||||
|
Case("Functional Test: RTC counts seconds.", test_functional_count),
|
||||||
};
|
};
|
||||||
|
|
||||||
utest::v1::status_t greentea_test_setup(const size_t number_of_cases) {
|
Specification specification(test_setup, cases);
|
||||||
GREENTEA_SETUP(20, "rtc_auto");
|
|
||||||
return greentea_test_setup_handler(number_of_cases);
|
|
||||||
}
|
|
||||||
|
|
||||||
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
|
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
Harness::run(specification);
|
return !Harness::run(specification);
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,50 +38,36 @@ volatile uint32_t multi_counter;
|
||||||
DigitalOut led1(LED1);
|
DigitalOut led1(LED1);
|
||||||
DigitalOut led2(LED2);
|
DigitalOut led2(LED2);
|
||||||
|
|
||||||
Ticker *volatile ticker1;
|
|
||||||
Ticker *volatile ticker2;
|
|
||||||
Timer gtimer;
|
Timer gtimer;
|
||||||
|
|
||||||
volatile int ticker_count = 0;
|
volatile int ticker_count = 0;
|
||||||
volatile bool print_tick = false;
|
|
||||||
|
|
||||||
void ticker_callback_1_switch_to_2(void);
|
|
||||||
void ticker_callback_2_switch_to_1(void);
|
|
||||||
|
|
||||||
void increment_ticker_counter(void)
|
|
||||||
{
|
|
||||||
++callback_trigger_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
void switch_led1_state(void)
|
void switch_led1_state(void)
|
||||||
{
|
{
|
||||||
led1 = !led1;
|
// blink 3 times per second
|
||||||
|
if((callback_trigger_count % 333) == 0) {
|
||||||
|
led1 = !led1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void switch_led2_state(void)
|
void switch_led2_state(void)
|
||||||
{
|
{
|
||||||
led2 = !led2;
|
// blink 3 times per second
|
||||||
|
// make led2 blink at the same callback_trigger_count value as led1
|
||||||
|
if(((callback_trigger_count - 1) % 333) == 0) {
|
||||||
|
led2 = !led2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ticker_callback_1_switch_to_2(void)
|
void ticker_callback_1(void)
|
||||||
{
|
{
|
||||||
++callback_trigger_count;
|
++callback_trigger_count;
|
||||||
// If ticker is NULL then it is being or has been deleted
|
|
||||||
if (ticker1) {
|
|
||||||
ticker1->detach();
|
|
||||||
ticker1->attach_us(ticker_callback_2_switch_to_1, ONE_MILLI_SEC);
|
|
||||||
}
|
|
||||||
switch_led1_state();
|
switch_led1_state();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ticker_callback_2_switch_to_1(void)
|
void ticker_callback_2(void)
|
||||||
{
|
{
|
||||||
++callback_trigger_count;
|
++callback_trigger_count;
|
||||||
// If ticker is NULL then it is being or has been deleted
|
|
||||||
if (ticker2) {
|
|
||||||
ticker2->detach();
|
|
||||||
ticker2->attach_us(ticker_callback_1_switch_to_2, ONE_MILLI_SEC);
|
|
||||||
}
|
|
||||||
switch_led2_state();
|
switch_led2_state();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,9 +92,8 @@ void increment_multi_counter(void)
|
||||||
|
|
||||||
/* Tests is to measure the accuracy of Ticker over a period of time
|
/* Tests is to measure the accuracy of Ticker over a period of time
|
||||||
*
|
*
|
||||||
* 1) DUT would start to update callback_trigger_count every milli sec, in 2x callback we use 2 tickers
|
* 1) DUT would start to update callback_trigger_count every milli sec
|
||||||
* to update the count alternatively.
|
* 2) Host would query what is current count base_time, Device responds by the callback_trigger_count.
|
||||||
* 2) Host would query what is current count base_time, Device responds by the callback_trigger_count
|
|
||||||
* 3) Host after waiting for measurement stretch. It will query for device time again final_time.
|
* 3) Host after waiting for measurement stretch. It will query for device time again final_time.
|
||||||
* 4) Host computes the drift considering base_time, final_time, transport delay and measurement stretch
|
* 4) Host computes the drift considering base_time, final_time, transport delay and measurement stretch
|
||||||
* 5) Finally host send the results back to device pass/fail based on tolerance.
|
* 5) Finally host send the results back to device pass/fail based on tolerance.
|
||||||
|
@ -119,9 +104,14 @@ void test_case_1x_ticker()
|
||||||
char _key[11] = { };
|
char _key[11] = { };
|
||||||
char _value[128] = { };
|
char _value[128] = { };
|
||||||
int expected_key = 1;
|
int expected_key = 1;
|
||||||
|
Ticker ticker;
|
||||||
|
|
||||||
|
led1 = 1;
|
||||||
|
led2 = 1;
|
||||||
|
callback_trigger_count = 0;
|
||||||
|
|
||||||
greentea_send_kv("timing_drift_check_start", 0);
|
greentea_send_kv("timing_drift_check_start", 0);
|
||||||
ticker1->attach_us(&increment_ticker_counter, ONE_MILLI_SEC);
|
ticker.attach_us(&ticker_callback_1, ONE_MILLI_SEC);
|
||||||
|
|
||||||
// wait for 1st signal from host
|
// wait for 1st signal from host
|
||||||
do {
|
do {
|
||||||
|
@ -140,18 +130,32 @@ void test_case_1x_ticker()
|
||||||
TEST_ASSERT_EQUAL_STRING_MESSAGE("pass", _key,"Host side script reported a fail...");
|
TEST_ASSERT_EQUAL_STRING_MESSAGE("pass", _key,"Host side script reported a fail...");
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_case_2x_callbacks()
|
/* Tests is to measure the accuracy of Ticker over a period of time
|
||||||
|
*
|
||||||
|
* 1) DUT would start to update callback_trigger_count every milli sec, we use 2 tickers
|
||||||
|
* to update the count alternatively.
|
||||||
|
* 2) Host would query what is current count base_time, Device responds by the callback_trigger_count
|
||||||
|
* 3) Host after waiting for measurement stretch. It will query for device time again final_time.
|
||||||
|
* 4) Host computes the drift considering base_time, final_time, transport delay and measurement stretch
|
||||||
|
* 5) Finally host send the results back to device pass/fail based on tolerance.
|
||||||
|
* 6) More details on tests can be found in timing_drift_auto.py
|
||||||
|
*/
|
||||||
|
void test_case_2x_ticker()
|
||||||
{
|
{
|
||||||
char _key[11] = { };
|
char _key[11] = { };
|
||||||
char _value[128] = { };
|
char _value[128] = { };
|
||||||
int expected_key = 1;
|
int expected_key = 1;
|
||||||
|
Ticker ticker1, ticker2;
|
||||||
|
|
||||||
led1 = 0;
|
led1 = 0;
|
||||||
led2 = 0;
|
led2 = 1;
|
||||||
callback_trigger_count = 0;
|
callback_trigger_count = 0;
|
||||||
|
|
||||||
|
ticker1.attach_us(ticker_callback_1, 2 * ONE_MILLI_SEC);
|
||||||
|
// delay second ticker to have a pair of tickers tick every one millisecond
|
||||||
|
wait_us(ONE_MILLI_SEC);
|
||||||
greentea_send_kv("timing_drift_check_start", 0);
|
greentea_send_kv("timing_drift_check_start", 0);
|
||||||
ticker1->attach_us(ticker_callback_1_switch_to_2, ONE_MILLI_SEC);
|
ticker2.attach_us(ticker_callback_2, 2 * ONE_MILLI_SEC);
|
||||||
|
|
||||||
// wait for 1st signal from host
|
// wait for 1st signal from host
|
||||||
do {
|
do {
|
||||||
|
@ -303,39 +307,6 @@ void test_attach_us_time(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
utest::v1::status_t one_ticker_case_setup_handler_t(const Case *const source, const size_t index_of_case)
|
|
||||||
{
|
|
||||||
ticker1 = new Ticker();
|
|
||||||
return greentea_case_setup_handler(source, index_of_case);
|
|
||||||
}
|
|
||||||
|
|
||||||
utest::v1::status_t two_ticker_case_setup_handler_t(const Case *const source, const size_t index_of_case)
|
|
||||||
{
|
|
||||||
ticker1 = new Ticker();
|
|
||||||
ticker2 = new Ticker();
|
|
||||||
return utest::v1::greentea_case_setup_handler(source, index_of_case);
|
|
||||||
}
|
|
||||||
|
|
||||||
utest::v1::status_t one_ticker_case_teardown_handler_t(const Case *const source, const size_t passed, const size_t failed, const utest::v1::failure_t reason)
|
|
||||||
{
|
|
||||||
Ticker *temp1 = ticker1;
|
|
||||||
ticker1 = NULL;
|
|
||||||
delete temp1;
|
|
||||||
return utest::v1::greentea_case_teardown_handler(source, passed, failed, reason);
|
|
||||||
}
|
|
||||||
|
|
||||||
utest::v1::status_t two_ticker_case_teardown_handler_t(const Case *const source, const size_t passed, const size_t failed, const utest::v1::failure_t reason)
|
|
||||||
{
|
|
||||||
Ticker *temp1 = ticker1;
|
|
||||||
Ticker *temp2 = ticker2;
|
|
||||||
ticker1 = NULL;
|
|
||||||
ticker2 = NULL;
|
|
||||||
delete temp1;
|
|
||||||
delete temp2;
|
|
||||||
return utest::v1::greentea_case_teardown_handler(source, passed, failed, reason);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Test cases
|
// Test cases
|
||||||
Case cases[] = {
|
Case cases[] = {
|
||||||
Case("Test attach for 0.01s and time measure", test_attach_time<10000>),
|
Case("Test attach for 0.01s and time measure", test_attach_time<10000>),
|
||||||
|
@ -347,8 +318,8 @@ Case cases[] = {
|
||||||
Case("Test detach", test_detach),
|
Case("Test detach", test_detach),
|
||||||
Case("Test multi call and time measure", test_multi_call_time),
|
Case("Test multi call and time measure", test_multi_call_time),
|
||||||
Case("Test multi ticker", test_multi_ticker),
|
Case("Test multi ticker", test_multi_ticker),
|
||||||
Case("Test timers: 1x ticker", one_ticker_case_setup_handler_t,test_case_1x_ticker, one_ticker_case_teardown_handler_t),
|
Case("Test timers: 1x ticker", test_case_1x_ticker),
|
||||||
Case("Test timers: 2x callbacks", two_ticker_case_setup_handler_t,test_case_2x_callbacks, two_ticker_case_teardown_handler_t)
|
Case("Test timers: 2x ticker", test_case_2x_ticker)
|
||||||
};
|
};
|
||||||
|
|
||||||
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
|
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* Copyright (c) 2018 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** \addtogroup hal_critical_tests
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef MBED_CRITICAL_SECTION_TEST_H
|
||||||
|
#define MBED_CRITICAL_SECTION_TEST_H
|
||||||
|
|
||||||
|
/** Template for HAL critical section tests
|
||||||
|
*
|
||||||
|
* Test critical section
|
||||||
|
* Given a critical section HAL mechanism
|
||||||
|
* When before critical section
|
||||||
|
* Then interrupts are enabled
|
||||||
|
* When inside critical section
|
||||||
|
* Then interrupts are disabled
|
||||||
|
* When after critical section
|
||||||
|
* Then interrupts are enabled again
|
||||||
|
*
|
||||||
|
* Test critical section - nested lock
|
||||||
|
* Given a critical section HAL mechanism
|
||||||
|
* When before critical section
|
||||||
|
* Then interrupts are enabled
|
||||||
|
* When inside nested critical section
|
||||||
|
* Then interrupts are disabled
|
||||||
|
* When after nested critical section
|
||||||
|
* Then interrupts are enabled again
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
template <int N>
|
||||||
|
void test_critical_section();
|
||||||
|
|
||||||
|
|
||||||
|
/**@}*/
|
||||||
|
|
||||||
|
#endif // MBED_CRITICAL_SECTION_TEST_H
|
|
@ -0,0 +1,84 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* Copyright (c) 2018 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 "critical_section_test.h"
|
||||||
|
#include "hal/critical_section_api.h"
|
||||||
|
#include "utest/utest.h"
|
||||||
|
#include "unity/unity.h"
|
||||||
|
#include "greentea-client/test_env.h"
|
||||||
|
#include "mbed.h"
|
||||||
|
#include "cmsis.h"
|
||||||
|
#ifdef TARGET_NRF5 // for all NRF5x targets
|
||||||
|
#include "nrf_nvic.h" // for __NRF_NVIC_APP_IRQS_0 / __NRF_NVIC_APP_IRQS_1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
using utest::v1::Case;
|
||||||
|
|
||||||
|
bool test_are_interrupts_enabled(void)
|
||||||
|
{
|
||||||
|
// NRF5x targets don't disable interrupts when in critical section, instead they mask application interrupts this is due to BLE stack
|
||||||
|
// (BLE to be operational requires some interrupts to be always enabled)
|
||||||
|
#ifdef TARGET_NRF52_DK
|
||||||
|
// check if APP interrupts are masked for NRF52_DK board
|
||||||
|
return (((NVIC->ISER[0] & __NRF_NVIC_APP_IRQS_0) != 0) || ((NVIC->ISER[1] & __NRF_NVIC_APP_IRQS_1) != 0));
|
||||||
|
#elif TARGET_NRF5
|
||||||
|
// check if APP interrupts are masked for other NRF5 boards
|
||||||
|
return ((NVIC->ISER[0] & __NRF_NVIC_APP_IRQS_0) != 0);
|
||||||
|
#else
|
||||||
|
#if defined(__CORTEX_A9)
|
||||||
|
return ((__get_CPSR() & 0x80) == 0);
|
||||||
|
#else
|
||||||
|
return ((__get_PRIMASK() & 0x1) == 0);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<int N>
|
||||||
|
void test_critical_section()
|
||||||
|
{
|
||||||
|
TEST_ASSERT_FALSE(hal_in_critical_section());
|
||||||
|
TEST_ASSERT_TRUE(test_are_interrupts_enabled());
|
||||||
|
|
||||||
|
for (int i = 0; i < N; i++) {
|
||||||
|
hal_critical_section_enter();
|
||||||
|
TEST_ASSERT_TRUE(hal_in_critical_section());
|
||||||
|
TEST_ASSERT_FALSE(test_are_interrupts_enabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
// assumed to be called once (according API)
|
||||||
|
hal_critical_section_exit();
|
||||||
|
|
||||||
|
TEST_ASSERT_FALSE(hal_in_critical_section());
|
||||||
|
TEST_ASSERT_TRUE(test_are_interrupts_enabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
Case cases[] = {
|
||||||
|
Case("Test critical section single lock", test_critical_section<1>),
|
||||||
|
Case("Test critical section nested lock", test_critical_section<10>)
|
||||||
|
};
|
||||||
|
|
||||||
|
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
|
||||||
|
{
|
||||||
|
GREENTEA_SETUP(10, "timing_drift_auto");
|
||||||
|
return utest::v1::greentea_test_setup_handler(number_of_cases);
|
||||||
|
}
|
||||||
|
|
||||||
|
utest::v1::Specification specification(greentea_test_setup, cases);
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
return !utest::v1::Harness::run(specification);
|
||||||
|
}
|
|
@ -28,7 +28,7 @@
|
||||||
using namespace utest::v1;
|
using namespace utest::v1;
|
||||||
|
|
||||||
#define TEST_CYCLES 1000000
|
#define TEST_CYCLES 1000000
|
||||||
#define ALLOWED_DRIFT_PPM 1000 //0.1%
|
#define ALLOWED_DRIFT_PPM 5000 //0.5%
|
||||||
|
|
||||||
/*
|
/*
|
||||||
return values to be checked are documented at:
|
return values to be checked are documented at:
|
||||||
|
|
|
@ -83,9 +83,7 @@ void test_case_mktime_localtime()
|
||||||
char _value[128] =
|
char _value[128] =
|
||||||
{ };
|
{ };
|
||||||
|
|
||||||
size_t years[] = {70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
|
size_t years[] = {70, 71, 100, 196, 200, 205};
|
||||||
100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
|
|
||||||
199, 200, 201, 202, 203, 204, 205};
|
|
||||||
|
|
||||||
/* Inform host part of the test about tested RTC type. */
|
/* Inform host part of the test about tested RTC type. */
|
||||||
greentea_send_kv("leap_year_setup", rtc_leap_year_support);
|
greentea_send_kv("leap_year_setup", rtc_leap_year_support);
|
||||||
|
|
|
@ -0,0 +1,145 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* Copyright (c) 2018 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_TESTFILEHANDLE_H
|
||||||
|
#define MBED_TESTFILEHANDLE_H
|
||||||
|
|
||||||
|
#include "platform/FileHandle.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define POS_IS_VALID(pos) (pos >= 0 && pos < _end)
|
||||||
|
#define NEW_POS_IS_VALID(pos) (pos >= 0 && pos < (int32_t)FILE_SIZE)
|
||||||
|
#define SEEK_POS_IS_VALID(pos) (pos >= 0 && pos <= _end)
|
||||||
|
#define INVALID_POS (-1)
|
||||||
|
|
||||||
|
template<uint32_t FILE_SIZE>
|
||||||
|
class TestFile : public FileHandle {
|
||||||
|
public:
|
||||||
|
TestFile(): _pos(0), _end(0) {}
|
||||||
|
~TestFile() {}
|
||||||
|
|
||||||
|
enum FunctionName {
|
||||||
|
fnNone, fnRead, fnWrite, fnSeek, fnClose, fnIsatty
|
||||||
|
};
|
||||||
|
|
||||||
|
virtual ssize_t read(void *buffer, size_t size)
|
||||||
|
{
|
||||||
|
ssize_t read;
|
||||||
|
_fnCalled = fnRead;
|
||||||
|
|
||||||
|
for(read = 0; (size_t)read < size; read++)
|
||||||
|
{
|
||||||
|
if(POS_IS_VALID(_pos)) {
|
||||||
|
((uint8_t*)buffer)[read] = _data[_pos++];
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} // for
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ssize_t write(const void *buffer, size_t size)
|
||||||
|
{
|
||||||
|
ssize_t written;
|
||||||
|
_fnCalled = fnWrite;
|
||||||
|
|
||||||
|
for(written = 0; (size_t)written < size; written++)
|
||||||
|
{
|
||||||
|
if(NEW_POS_IS_VALID(_pos)) {
|
||||||
|
_data[_pos++] = ((uint8_t*)buffer)[written];
|
||||||
|
} else {
|
||||||
|
if(0 == written) {
|
||||||
|
return -ENOSPC;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(_end < _pos) {
|
||||||
|
_end++;
|
||||||
|
}
|
||||||
|
} // for
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual off_t seek(off_t offset, int whence)
|
||||||
|
{
|
||||||
|
_fnCalled = fnSeek;
|
||||||
|
int32_t new_pos = INVALID_POS;
|
||||||
|
|
||||||
|
switch(whence)
|
||||||
|
{
|
||||||
|
case SEEK_SET:
|
||||||
|
new_pos = offset;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SEEK_CUR:
|
||||||
|
new_pos = _pos + offset;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SEEK_END:
|
||||||
|
new_pos = _end - offset;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// nothing todo
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(SEEK_POS_IS_VALID(new_pos)) {
|
||||||
|
_pos = new_pos;
|
||||||
|
} else {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int close()
|
||||||
|
{
|
||||||
|
_fnCalled = fnClose;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void resetFunctionCallHistory()
|
||||||
|
{
|
||||||
|
_fnCalled = fnNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool functionCalled(FunctionName name)
|
||||||
|
{
|
||||||
|
return (name == _fnCalled);
|
||||||
|
}
|
||||||
|
|
||||||
|
static FunctionName getFunctionCalled()
|
||||||
|
{
|
||||||
|
return _fnCalled;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// stores last function call name
|
||||||
|
static FunctionName _fnCalled;
|
||||||
|
|
||||||
|
// file storage
|
||||||
|
uint8_t _data[FILE_SIZE];
|
||||||
|
|
||||||
|
int32_t _pos, _end;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<uint32_t FILE_SIZE>
|
||||||
|
typename TestFile<FILE_SIZE>::FunctionName TestFile<FILE_SIZE>::_fnCalled;
|
||||||
|
|
||||||
|
|
||||||
|
#endif // MBED_TESTFILEHANDLE_H
|
|
@ -0,0 +1,504 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* Copyright (c) 2018 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 "greentea-client/test_env.h"
|
||||||
|
#include "utest/utest.h"
|
||||||
|
#include "unity/unity.h"
|
||||||
|
#include "TestFile.h"
|
||||||
|
#include "mbed.h"
|
||||||
|
|
||||||
|
using utest::v1::Case;
|
||||||
|
|
||||||
|
|
||||||
|
/** Test fopen and fclose
|
||||||
|
*
|
||||||
|
* Given a file to be opened
|
||||||
|
*
|
||||||
|
* When the file is open
|
||||||
|
* Then returned file descriptor is valid
|
||||||
|
*
|
||||||
|
* When the file is closed
|
||||||
|
* Then underneath retargeting layer function is called
|
||||||
|
* and the fclose function return with succeed
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void test_fopen_fclose()
|
||||||
|
{
|
||||||
|
std::FILE *file;
|
||||||
|
const uint32_t FS = 5;
|
||||||
|
TestFile<FS> fh;
|
||||||
|
|
||||||
|
file = fdopen(&fh, "w+");
|
||||||
|
TEST_ASSERT_NOT_NULL(file);
|
||||||
|
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
int ret = std::fclose(file);
|
||||||
|
TEST_ASSERT_TRUE(TestFile<FS>::functionCalled(TestFile<FS>::fnClose));
|
||||||
|
TEST_ASSERT_EQUAL_INT(0, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Test fwrite and fread
|
||||||
|
*
|
||||||
|
* Given already opened file
|
||||||
|
*
|
||||||
|
* When write some data to file
|
||||||
|
* Then underneath retargeting layer write function is called
|
||||||
|
* fwrite return number of successfully written elements
|
||||||
|
* when not all elements were written stream error is set
|
||||||
|
*
|
||||||
|
* When read previously written data from file
|
||||||
|
* Then underneath retargeting layer read function is called
|
||||||
|
* fread return number of successfully read elements
|
||||||
|
* read data match previously written
|
||||||
|
* when read less then expected stream eof is set
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void test_fwrite_fread()
|
||||||
|
{
|
||||||
|
std::FILE *file;
|
||||||
|
const uint32_t FS = 5;
|
||||||
|
TestFile<FS> fh;
|
||||||
|
char read_buf[16];
|
||||||
|
const char *str1 = "abc";
|
||||||
|
const char *str2 = "def";
|
||||||
|
const uint32_t str1_size = strlen(str1);
|
||||||
|
const uint32_t str2_size = strlen(str2);
|
||||||
|
std::size_t write_ret;
|
||||||
|
std::size_t read_ret;
|
||||||
|
|
||||||
|
file = fdopen(&fh, "w+");
|
||||||
|
TEST_ASSERT_NOT_NULL(file);
|
||||||
|
std::setbuf(file, NULL);
|
||||||
|
|
||||||
|
// write 3; expected written 3
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
write_ret = std::fwrite(str1, 1, str1_size, file);
|
||||||
|
TEST_ASSERT_TRUE(TestFile<FS>::functionCalled(TestFile<FS>::fnWrite));
|
||||||
|
TEST_ASSERT_EQUAL_INT(str1_size, write_ret);
|
||||||
|
|
||||||
|
#ifndef __ICCARM__ // prevents IAR infinite loop
|
||||||
|
// write 3; expected written 2
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
write_ret = std::fwrite(str2, 1, str2_size, file);
|
||||||
|
TEST_ASSERT_TRUE(TestFile<FS>::functionCalled(TestFile<FS>::fnWrite));
|
||||||
|
TEST_ASSERT_TRUE(std::ferror(file) != 0);
|
||||||
|
std::clearerr(file); // for ARMCC
|
||||||
|
#ifndef __ARMCC_VERSION
|
||||||
|
// ARMCC returns 0 here instead of number of elements successfully written
|
||||||
|
TEST_ASSERT_EQUAL_INT(str2_size - 1, write_ret);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// write 3; expected written 0
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
write_ret = std::fwrite(str1, 1, str1_size, file);
|
||||||
|
TEST_ASSERT_TRUE(TestFile<FS>::functionCalled(TestFile<FS>::fnWrite));
|
||||||
|
TEST_ASSERT_TRUE(std::ferror(file) != 0);
|
||||||
|
TEST_ASSERT_EQUAL_INT(0, write_ret);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::rewind(file);
|
||||||
|
|
||||||
|
// read 3; expected read 3
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
read_ret = std::fread(read_buf, 1, str1_size, file);
|
||||||
|
TEST_ASSERT_TRUE(TestFile<FS>::functionCalled(TestFile<FS>::fnRead));
|
||||||
|
TEST_ASSERT_EQUAL_INT(str1_size, read_ret);
|
||||||
|
TEST_ASSERT_EQUAL_INT(0, strncmp(str1, read_buf, str1_size));
|
||||||
|
|
||||||
|
#ifndef __ICCARM__
|
||||||
|
// read 3; expected read 2
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
read_ret = std::fread(read_buf, 1, str2_size, file);
|
||||||
|
TEST_ASSERT_TRUE(TestFile<FS>::functionCalled(TestFile<FS>::fnRead));
|
||||||
|
TEST_ASSERT_TRUE(std::feof(file) != 0);
|
||||||
|
std::clearerr(file); // for ARMCC
|
||||||
|
TEST_ASSERT_EQUAL_INT(str2_size - 1, read_ret);
|
||||||
|
TEST_ASSERT_EQUAL_INT(0, strncmp(str2, read_buf, str2_size - 1));
|
||||||
|
|
||||||
|
// read 3; expected read 0
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
read_ret = std::fread(read_buf, 1, str2_size, file);
|
||||||
|
TEST_ASSERT_TRUE(TestFile<FS>::functionCalled(TestFile<FS>::fnRead));
|
||||||
|
TEST_ASSERT_TRUE(std::feof(file) != 0);
|
||||||
|
TEST_ASSERT_EQUAL_INT(0, read_ret);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::fclose(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test fputc and fgetc
|
||||||
|
*
|
||||||
|
* Given already opened file
|
||||||
|
*
|
||||||
|
* When write some data to file
|
||||||
|
* Then underneath retargeting layer write function is called
|
||||||
|
* fputc return written element
|
||||||
|
* on failure, returns EOF and stream error is sets
|
||||||
|
*
|
||||||
|
* When read previously written data from file
|
||||||
|
* Then underneath retargeting layer read function is called
|
||||||
|
* fgetc return read element
|
||||||
|
* read data match previously written
|
||||||
|
* on failure, returns EOF and stream error/eof is sets respectively
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void test_fputc_fgetc()
|
||||||
|
{
|
||||||
|
std::FILE *file;
|
||||||
|
const uint32_t FS = 3;
|
||||||
|
TestFile<FS> fh;
|
||||||
|
char char_buf[3] = {'a', 'b', 'c' };
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
file = fdopen(&fh, "w+");
|
||||||
|
TEST_ASSERT_NOT_NULL(file);
|
||||||
|
std::setbuf(file, NULL);
|
||||||
|
|
||||||
|
|
||||||
|
// write 1; expected written 1
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
ret = std::fputc(char_buf[0], file);
|
||||||
|
TEST_ASSERT_TRUE(TestFile<FS>::functionCalled(TestFile<FS>::fnWrite));
|
||||||
|
TEST_ASSERT_EQUAL_INT(char_buf[0], ret);
|
||||||
|
|
||||||
|
// write 1; expected written 1
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
ret = std::fputc(char_buf[1], file);
|
||||||
|
TEST_ASSERT_TRUE(TestFile<FS>::functionCalled(TestFile<FS>::fnWrite));
|
||||||
|
TEST_ASSERT_EQUAL_INT(char_buf[1], ret);
|
||||||
|
|
||||||
|
// write 1; expected written 1
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
ret = std::fputc(char_buf[2], file);
|
||||||
|
TEST_ASSERT_TRUE(TestFile<FS>::functionCalled(TestFile<FS>::fnWrite));
|
||||||
|
TEST_ASSERT_EQUAL_INT(char_buf[2], ret);
|
||||||
|
|
||||||
|
#ifndef __ICCARM__ // prevents IAR infinite loop
|
||||||
|
// write 1; expected written 0
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
ret = std::fputc(char_buf[0], file);
|
||||||
|
TEST_ASSERT_TRUE(TestFile<FS>::functionCalled(TestFile<FS>::fnWrite));
|
||||||
|
TEST_ASSERT_TRUE(std::ferror(file) != 0);
|
||||||
|
TEST_ASSERT_EQUAL_INT(EOF, ret);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::rewind(file);
|
||||||
|
|
||||||
|
// read 1; expected read 1
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
ret = std::fgetc(file);
|
||||||
|
TEST_ASSERT_TRUE(TestFile<FS>::functionCalled(TestFile<FS>::fnRead));
|
||||||
|
TEST_ASSERT_EQUAL_INT(char_buf[0], ret);
|
||||||
|
|
||||||
|
// read 1; expected read 1
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
ret = std::fgetc(file);
|
||||||
|
#ifndef __ICCARM__
|
||||||
|
// IAR optimize reads
|
||||||
|
TEST_ASSERT_TRUE(TestFile<FS>::functionCalled(TestFile<FS>::fnRead));
|
||||||
|
#endif
|
||||||
|
TEST_ASSERT_EQUAL_INT(char_buf[1], ret);
|
||||||
|
|
||||||
|
// read 1; expected read 1
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
ret = std::fgetc(file);
|
||||||
|
#ifndef __ICCARM__
|
||||||
|
// IAR optimize reads
|
||||||
|
TEST_ASSERT_TRUE(TestFile<FS>::functionCalled(TestFile<FS>::fnRead));
|
||||||
|
#endif
|
||||||
|
TEST_ASSERT_EQUAL_INT(char_buf[2], ret);
|
||||||
|
|
||||||
|
#ifndef __ICCARM__
|
||||||
|
// read 1; expected read 0
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
ret = std::fgetc(file);
|
||||||
|
TEST_ASSERT_TRUE(TestFile<FS>::functionCalled(TestFile<FS>::fnRead));
|
||||||
|
TEST_ASSERT_TRUE(std::feof(file) != 0);
|
||||||
|
TEST_ASSERT_EQUAL_INT(EOF, ret);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::fclose(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test fputs and fgets
|
||||||
|
*
|
||||||
|
* Given already opened file
|
||||||
|
*
|
||||||
|
* When write some data to file
|
||||||
|
* Then underneath retargeting layer write function is called
|
||||||
|
* on success, returns a non-negative value
|
||||||
|
* on failure, returns EOF and set stream error
|
||||||
|
*
|
||||||
|
* When read previously written data from file
|
||||||
|
* Then underneath retargeting layer read function is called
|
||||||
|
* fgets return valid buffer, and read data match previously written
|
||||||
|
* when read less then expected stream EOF is set
|
||||||
|
* on failure, stream error is sets
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void test_fputs_fgets()
|
||||||
|
{
|
||||||
|
std::FILE *file;
|
||||||
|
const uint32_t FS = 5;
|
||||||
|
TestFile<FS> fh;
|
||||||
|
const char *str1 = "abc";
|
||||||
|
const char *str2 = "def";
|
||||||
|
const uint32_t str1_size = strlen(str1);
|
||||||
|
const uint32_t str2_size = strlen(str2);
|
||||||
|
char read_buf[16];
|
||||||
|
int fputs_ret;
|
||||||
|
char *fgets_ret;
|
||||||
|
|
||||||
|
file = fdopen(&fh, "w+");
|
||||||
|
TEST_ASSERT_NOT_NULL(file);
|
||||||
|
std::setbuf(file, NULL);
|
||||||
|
|
||||||
|
// write 3; expected written 3
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
fputs_ret = std::fputs(str1, file);
|
||||||
|
TEST_ASSERT_TRUE(TestFile<FS>::functionCalled(TestFile<FS>::fnWrite));
|
||||||
|
TEST_ASSERT_TRUE(fputs_ret >= 0);
|
||||||
|
|
||||||
|
#ifndef __ICCARM__ // prevents IAR infinite loop
|
||||||
|
// write 3; expected written 2
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
fputs_ret = std::fputs(str2, file);
|
||||||
|
TEST_ASSERT_TRUE(TestFile<FS>::functionCalled(TestFile<FS>::fnWrite));
|
||||||
|
TEST_ASSERT_TRUE(std::ferror(file) != 0);
|
||||||
|
std::clearerr(file); // for ARMCC
|
||||||
|
TEST_ASSERT_EQUAL_INT(EOF, fputs_ret);
|
||||||
|
|
||||||
|
// write 3; expected written 0
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
fputs_ret = std::fputs(str1, file);
|
||||||
|
TEST_ASSERT_TRUE(TestFile<FS>::functionCalled(TestFile<FS>::fnWrite));
|
||||||
|
TEST_ASSERT_TRUE(std::ferror(file) != 0);
|
||||||
|
TEST_ASSERT_EQUAL_INT(EOF, fputs_ret);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::rewind(file);
|
||||||
|
|
||||||
|
// read 3; expected read 3
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
fgets_ret = std::fgets(read_buf, str1_size + 1, file);
|
||||||
|
TEST_ASSERT_TRUE(TestFile<FS>::functionCalled(TestFile<FS>::fnRead));
|
||||||
|
TEST_ASSERT_EQUAL_INT(read_buf, fgets_ret);
|
||||||
|
TEST_ASSERT_EQUAL_INT(0, strncmp(read_buf, str1, str1_size));
|
||||||
|
|
||||||
|
#ifndef __ICCARM__
|
||||||
|
// read 3; expected read 2
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
fgets_ret = std::fgets(read_buf, str2_size + 1, file);
|
||||||
|
TEST_ASSERT_TRUE(TestFile<FS>::functionCalled(TestFile<FS>::fnRead));
|
||||||
|
TEST_ASSERT_TRUE(std::feof(file) != 0);
|
||||||
|
std::clearerr(file); // for ARMCC
|
||||||
|
TEST_ASSERT_EQUAL_INT(read_buf, fgets_ret);
|
||||||
|
TEST_ASSERT_EQUAL_INT(0, strncmp(read_buf, str2, str2_size - 2));
|
||||||
|
|
||||||
|
// read 3; expected read 0
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
fgets_ret = std::fgets(read_buf, str2_size + 1, file);
|
||||||
|
TEST_ASSERT_TRUE(TestFile<FS>::functionCalled(TestFile<FS>::fnRead));
|
||||||
|
TEST_ASSERT_TRUE(std::feof(file) != 0);
|
||||||
|
TEST_ASSERT_EQUAL_INT(NULL, fgets_ret);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::fclose(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test fprintf and fscanf
|
||||||
|
*
|
||||||
|
* Given already opened file
|
||||||
|
*
|
||||||
|
* When write some data to file
|
||||||
|
* Then underneath retargeting layer write function is called
|
||||||
|
* fprintf return number of written components
|
||||||
|
* fprintf return negative value if an error occurred and set stream error
|
||||||
|
*
|
||||||
|
* When read previously written data from file
|
||||||
|
* Then underneath retargeting layer read function is called
|
||||||
|
* fscanf return number of read components, and read data match previously written
|
||||||
|
* when read less then expected stream EOF is set
|
||||||
|
* on failure, stream error is sets
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void test_fprintf_fscanf()
|
||||||
|
{
|
||||||
|
std::FILE *file;
|
||||||
|
const uint32_t FS = 5;
|
||||||
|
TestFile<FS> fh;
|
||||||
|
const char *str1 = "abc";
|
||||||
|
const char *str2 = "def";
|
||||||
|
const uint32_t str1_size = strlen(str1);
|
||||||
|
const uint32_t str2_size = strlen(str2);
|
||||||
|
char read_buf[16];
|
||||||
|
int fprintf_ret;
|
||||||
|
int fscanf_ret;
|
||||||
|
|
||||||
|
file = fdopen(&fh, "w+");
|
||||||
|
TEST_ASSERT_NOT_NULL(file);
|
||||||
|
std::setbuf(file, NULL);
|
||||||
|
|
||||||
|
// write 3; expected written 3
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
fprintf_ret = fprintf(file, "%s", str1);
|
||||||
|
TEST_ASSERT_TRUE(TestFile<FS>::functionCalled(TestFile<FS>::fnWrite));
|
||||||
|
TEST_ASSERT_EQUAL_INT(str1_size, fprintf_ret);
|
||||||
|
|
||||||
|
#ifndef __ICCARM__ // prevents IAR infinite loop
|
||||||
|
// write 3; expected written 2
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
fprintf_ret = fprintf(file, "%s", str2);
|
||||||
|
TEST_ASSERT_TRUE(TestFile<FS>::functionCalled(TestFile<FS>::fnWrite));
|
||||||
|
TEST_ASSERT_TRUE(std::ferror(file) != 0);
|
||||||
|
std::clearerr(file); // for ARMCC
|
||||||
|
TEST_ASSERT_TRUE(fprintf_ret < 0);
|
||||||
|
|
||||||
|
// write 3; expected written 0
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
fprintf_ret = fprintf(file, "%s", str2);
|
||||||
|
TEST_ASSERT_TRUE(TestFile<FS>::functionCalled(TestFile<FS>::fnWrite));
|
||||||
|
TEST_ASSERT_TRUE(std::ferror(file) != 0);
|
||||||
|
TEST_ASSERT_TRUE(fprintf_ret < 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::rewind(file);
|
||||||
|
|
||||||
|
// read 3; expected read 3
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
fscanf_ret = fscanf(file, "%3s", read_buf);
|
||||||
|
TEST_ASSERT_TRUE(TestFile<FS>::functionCalled(TestFile<FS>::fnRead));
|
||||||
|
TEST_ASSERT_EQUAL_INT(1, fscanf_ret);
|
||||||
|
TEST_ASSERT_EQUAL_INT(0, strncmp(read_buf, str1, str1_size));
|
||||||
|
|
||||||
|
#ifndef __ICCARM__
|
||||||
|
// read 3; expected read 2
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
fscanf_ret = fscanf(file, "%3s", read_buf);
|
||||||
|
TEST_ASSERT_TRUE(TestFile<FS>::functionCalled(TestFile<FS>::fnRead));
|
||||||
|
TEST_ASSERT_TRUE(std::feof(file) != 0);
|
||||||
|
std::clearerr(file); // for ARMCC
|
||||||
|
TEST_ASSERT_EQUAL_INT(1, fscanf_ret);
|
||||||
|
TEST_ASSERT_EQUAL_INT(0, strncmp(read_buf, str2, str2_size - 1));
|
||||||
|
|
||||||
|
// read 3; expected read 0
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
fscanf_ret = fscanf(file, "%3s", read_buf);
|
||||||
|
TEST_ASSERT_TRUE(TestFile<FS>::functionCalled(TestFile<FS>::fnRead));
|
||||||
|
TEST_ASSERT_TRUE(std::feof(file) != 0);
|
||||||
|
TEST_ASSERT_EQUAL_INT(EOF, fscanf_ret);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::fclose(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test fseek and ftell
|
||||||
|
*
|
||||||
|
* Given already opened file is empty
|
||||||
|
*
|
||||||
|
* When set the file position indicator via fseek
|
||||||
|
* Then underneath retargeting layer seek function is called
|
||||||
|
* fseek return with succeed and ftell return already set position
|
||||||
|
*
|
||||||
|
* Given already opened file is not empty
|
||||||
|
*
|
||||||
|
* When set the file position indicator via fseek
|
||||||
|
* Then underneath retargeting layer seek function is called
|
||||||
|
* fseek return with succeed and ftell return already set position
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void test_fseek_ftell()
|
||||||
|
{
|
||||||
|
std::FILE *file;
|
||||||
|
long ftell_ret;
|
||||||
|
int fssek_ret;
|
||||||
|
const uint32_t FS = 128;
|
||||||
|
TestFile<FS> fh;
|
||||||
|
|
||||||
|
file = fdopen(&fh, "w+");
|
||||||
|
TEST_ASSERT_NOT_NULL(file);
|
||||||
|
std::setbuf(file, NULL);
|
||||||
|
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
ftell_ret = std::ftell(file);
|
||||||
|
TEST_ASSERT_EQUAL(0, ftell_ret);
|
||||||
|
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
fssek_ret = std::fseek(file, 0, SEEK_CUR);
|
||||||
|
TEST_ASSERT_EQUAL(0, fssek_ret);
|
||||||
|
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
fssek_ret = std::fseek(file, 0, SEEK_SET);
|
||||||
|
TEST_ASSERT_EQUAL(0, fssek_ret);
|
||||||
|
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
fssek_ret = std::fseek(file, 0, SEEK_END);
|
||||||
|
TEST_ASSERT_TRUE(TestFile<FS>::functionCalled(TestFile<FS>::fnSeek));
|
||||||
|
TEST_ASSERT_EQUAL(0, fssek_ret);
|
||||||
|
|
||||||
|
const char *str = "Hello world";
|
||||||
|
const std::size_t size = std::strlen(str);
|
||||||
|
|
||||||
|
std::fwrite(str, 1, size, file);
|
||||||
|
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
ftell_ret = std::ftell(file);
|
||||||
|
TEST_ASSERT_EQUAL(size, ftell_ret);
|
||||||
|
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
fssek_ret = std::fseek(file, 5, SEEK_SET);
|
||||||
|
TEST_ASSERT_EQUAL(0, fssek_ret);
|
||||||
|
ftell_ret = std::ftell(file);
|
||||||
|
TEST_ASSERT_EQUAL(5, ftell_ret);
|
||||||
|
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
fssek_ret = std::fseek(file, -5, SEEK_CUR);
|
||||||
|
TEST_ASSERT_EQUAL(0, fssek_ret);
|
||||||
|
ftell_ret = std::ftell(file);
|
||||||
|
TEST_ASSERT_EQUAL(0, ftell_ret);
|
||||||
|
|
||||||
|
TestFile<FS>::resetFunctionCallHistory();
|
||||||
|
fssek_ret = std::fseek(file, 0, SEEK_END);
|
||||||
|
TEST_ASSERT_TRUE(TestFile<FS>::functionCalled(TestFile<FS>::fnSeek));
|
||||||
|
TEST_ASSERT_EQUAL(0, fssek_ret);
|
||||||
|
ftell_ret = std::ftell(file);
|
||||||
|
TEST_ASSERT_EQUAL(size, ftell_ret);
|
||||||
|
|
||||||
|
std::fclose(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
utest::v1::status_t test_setup(const size_t number_of_cases)
|
||||||
|
{
|
||||||
|
GREENTEA_SETUP(10, "default_auto");
|
||||||
|
return utest::v1::verbose_test_setup_handler(number_of_cases);
|
||||||
|
}
|
||||||
|
|
||||||
|
Case cases[] = {
|
||||||
|
Case("Test fopen/fclose", test_fopen_fclose),
|
||||||
|
Case("Test fwrite/fread", test_fwrite_fread),
|
||||||
|
Case("Test fputc/fgetc", test_fputc_fgetc),
|
||||||
|
Case("Test fputs/fgets", test_fputs_fgets),
|
||||||
|
Case("Test fprintf/fscanf", test_fprintf_fscanf),
|
||||||
|
Case("Test fseek/ftell", test_fseek_ftell)
|
||||||
|
};
|
||||||
|
|
||||||
|
utest::v1::Specification specification(test_setup, cases);
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
return !utest::v1::Harness::run(specification);
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* Copyright (c) 2018 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.h"
|
||||||
|
#include "greentea-client/test_env.h"
|
||||||
|
#include "utest/utest.h"
|
||||||
|
#include "unity/unity.h"
|
||||||
|
#include "platform/Transaction.h"
|
||||||
|
|
||||||
|
using utest::v1::Case;
|
||||||
|
|
||||||
|
static void dummy_callback(int)
|
||||||
|
{
|
||||||
|
/* do nothing. */
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test Transaction class - creation with initialisation
|
||||||
|
*
|
||||||
|
* Given is Transaction class.
|
||||||
|
* When object of the Transaction class is created and initialised.
|
||||||
|
* Then get_object() returns object's instance for the transaction and get_transaction() returns the transaction.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
template<typename Type>
|
||||||
|
void test_Transaction_init()
|
||||||
|
{
|
||||||
|
Type object;
|
||||||
|
const size_t tx_buffer_size = 24;
|
||||||
|
const size_t rx_buffer_size = 16;
|
||||||
|
const uint32_t event_id = 123;
|
||||||
|
const uint8_t word_width = 8;
|
||||||
|
unsigned char tx_buffer[tx_buffer_size];
|
||||||
|
unsigned char rx_buffer[rx_buffer_size];
|
||||||
|
const event_callback_t& callback = dummy_callback;
|
||||||
|
transaction_t transaction_data =
|
||||||
|
{ tx_buffer, tx_buffer_size, rx_buffer, rx_buffer_size, event_id, callback, word_width };
|
||||||
|
|
||||||
|
Transaction<Type> test_transaction(&object, transaction_data);
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL(&object, test_transaction.get_object());
|
||||||
|
|
||||||
|
TEST_ASSERT_EQUAL((void*)tx_buffer, test_transaction.get_transaction()->tx_buffer);
|
||||||
|
TEST_ASSERT_EQUAL((void*)rx_buffer, test_transaction.get_transaction()->rx_buffer);
|
||||||
|
TEST_ASSERT_EQUAL(tx_buffer_size, test_transaction.get_transaction()->tx_length);
|
||||||
|
TEST_ASSERT_EQUAL(rx_buffer_size, test_transaction.get_transaction()->rx_length);
|
||||||
|
TEST_ASSERT_EQUAL(event_id, test_transaction.get_transaction()->event);
|
||||||
|
TEST_ASSERT_EQUAL(word_width, test_transaction.get_transaction()->width);
|
||||||
|
TEST_ASSERT_EQUAL(callback, test_transaction.get_transaction()->callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Test Transaction class - creation without initialisation
|
||||||
|
*
|
||||||
|
* Given is Transaction class.
|
||||||
|
* When object of the Transaction class is created.
|
||||||
|
* Then this operation is successful.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
template<typename Type>
|
||||||
|
void test_Transaction_empty()
|
||||||
|
{
|
||||||
|
Type object;
|
||||||
|
|
||||||
|
Transaction<Type> test_transaction;
|
||||||
|
|
||||||
|
/* Just indicate successful execution of the test case. */
|
||||||
|
TEST_ASSERT_TRUE(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
utest::v1::status_t test_setup(const size_t number_of_cases)
|
||||||
|
{
|
||||||
|
GREENTEA_SETUP(10, "default_auto");
|
||||||
|
return utest::v1::verbose_test_setup_handler(number_of_cases);
|
||||||
|
}
|
||||||
|
|
||||||
|
Case cases[] = {
|
||||||
|
Case("Test Transaction - init <Timer>", test_Transaction_init<Timer>),
|
||||||
|
Case("Test Transaction - init <Ticker>", test_Transaction_init<Ticker>),
|
||||||
|
Case("Test Transaction - no init <Timer>", test_Transaction_empty<Timer>),
|
||||||
|
Case("Test Transaction - no init <Ticker>", test_Transaction_empty<Ticker>),
|
||||||
|
};
|
||||||
|
|
||||||
|
utest::v1::Specification specification(test_setup, cases);
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
return !utest::v1::Harness::run(specification);
|
||||||
|
}
|
|
@ -0,0 +1,230 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* Copyright (c) 2017 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.h"
|
||||||
|
#include "greentea-client/test_env.h"
|
||||||
|
#include "unity/unity.h"
|
||||||
|
#include "utest/utest.h"
|
||||||
|
|
||||||
|
|
||||||
|
using utest::v1::Case;
|
||||||
|
|
||||||
|
|
||||||
|
volatile bool callback_called;
|
||||||
|
|
||||||
|
void tiemout_callback(void)
|
||||||
|
{
|
||||||
|
callback_called = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<int N>
|
||||||
|
void critical_section_raii_recursive(Timeout &timeout)
|
||||||
|
{
|
||||||
|
static uint32_t depth = 0;
|
||||||
|
CriticalSectionLock cs;
|
||||||
|
|
||||||
|
depth++;
|
||||||
|
TEST_ASSERT_TRUE(core_util_in_critical_section());
|
||||||
|
|
||||||
|
if(depth < N) {
|
||||||
|
critical_section_raii_recursive<N>(timeout);
|
||||||
|
} else {
|
||||||
|
// max depth reached - do the test
|
||||||
|
const us_timestamp_t timeout_time_us = 1;
|
||||||
|
const int wait_time_us = timeout_time_us * 100;
|
||||||
|
|
||||||
|
timeout.attach_us(callback(tiemout_callback), timeout_time_us);
|
||||||
|
wait_us(wait_time_us);
|
||||||
|
}
|
||||||
|
TEST_ASSERT_TRUE(core_util_in_critical_section());
|
||||||
|
TEST_ASSERT_FALSE(callback_called);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** Template for tests
|
||||||
|
|
||||||
|
Test C API of critical section
|
||||||
|
Given a Timeout with callback attached
|
||||||
|
When before critical section
|
||||||
|
Then interrupts are enabled and timeout callback is fired
|
||||||
|
When inside critical section
|
||||||
|
Then interrupts are disabled and timeout callback is blocked
|
||||||
|
When after critical section
|
||||||
|
Then interrupts are enabled and timeout callback is fired
|
||||||
|
|
||||||
|
Test C API of critical section - nested lock
|
||||||
|
Given a Timeout with callback attached
|
||||||
|
When before critical section
|
||||||
|
Then interrupts are enabled and timeout callback is fired
|
||||||
|
When inside nested critical section
|
||||||
|
Then interrupts are disabled and timeout callback is blocked
|
||||||
|
When after critical section
|
||||||
|
Then interrupts are enabled and timeout callback is fired
|
||||||
|
*/
|
||||||
|
template<int N>
|
||||||
|
void test_C_API(void)
|
||||||
|
{
|
||||||
|
Timeout timeout;
|
||||||
|
const us_timestamp_t timeout_time_us = 1;
|
||||||
|
const int wait_time_us = timeout_time_us * 100;
|
||||||
|
|
||||||
|
TEST_ASSERT_FALSE(core_util_in_critical_section());
|
||||||
|
|
||||||
|
callback_called = false;
|
||||||
|
timeout.attach_us(callback(tiemout_callback), timeout_time_us);
|
||||||
|
wait_us(wait_time_us);
|
||||||
|
TEST_ASSERT_TRUE(callback_called);
|
||||||
|
|
||||||
|
for(int i = 0; i < N; i++) {
|
||||||
|
core_util_critical_section_enter();
|
||||||
|
TEST_ASSERT_TRUE(core_util_in_critical_section());
|
||||||
|
}
|
||||||
|
|
||||||
|
callback_called = false;
|
||||||
|
timeout.attach_us(callback(tiemout_callback), timeout_time_us);
|
||||||
|
wait_us(wait_time_us);
|
||||||
|
TEST_ASSERT_FALSE(callback_called);
|
||||||
|
TEST_ASSERT_TRUE(core_util_in_critical_section());
|
||||||
|
|
||||||
|
for(int i = 0; i < N - 1; i++) {
|
||||||
|
core_util_critical_section_exit();
|
||||||
|
TEST_ASSERT_TRUE(core_util_in_critical_section());
|
||||||
|
TEST_ASSERT_FALSE(callback_called);
|
||||||
|
}
|
||||||
|
|
||||||
|
core_util_critical_section_exit();
|
||||||
|
TEST_ASSERT_FALSE(core_util_in_critical_section());
|
||||||
|
TEST_ASSERT_TRUE(callback_called);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Template for tests
|
||||||
|
|
||||||
|
Test C++ API of critical section constructor/destructor
|
||||||
|
Given a Timeout with callback attached
|
||||||
|
When before critical section
|
||||||
|
Then interrupts are enabled and timeout callback is fired
|
||||||
|
When inside critical section
|
||||||
|
Then interrupts are disabled and timeout callback is blocked
|
||||||
|
When after critical section
|
||||||
|
Then interrupts are enabled and timeout callback is fired
|
||||||
|
|
||||||
|
Test C++ API of critical section constructor/destructor - nested lock
|
||||||
|
Given a Timeout with callback attached
|
||||||
|
When before critical section
|
||||||
|
Then interrupts are enabled and timeout callback is fired
|
||||||
|
When inside nested critical section
|
||||||
|
Then interrupts are disabled and timeout callback is blocked
|
||||||
|
When after critical section
|
||||||
|
Then interrupts are enabled and timeout callback is fired
|
||||||
|
*/
|
||||||
|
template<int N>
|
||||||
|
void test_CPP_API_constructor_destructor(void)
|
||||||
|
{
|
||||||
|
Timeout timeout;
|
||||||
|
const us_timestamp_t timeout_time_us = 1;
|
||||||
|
const int wait_time_us = timeout_time_us * 100;
|
||||||
|
|
||||||
|
TEST_ASSERT_FALSE(core_util_in_critical_section());
|
||||||
|
|
||||||
|
callback_called = false;
|
||||||
|
timeout.attach_us(callback(tiemout_callback), timeout_time_us);
|
||||||
|
wait_us(wait_time_us);
|
||||||
|
TEST_ASSERT_TRUE(callback_called);
|
||||||
|
|
||||||
|
callback_called = false;
|
||||||
|
critical_section_raii_recursive<N>(timeout);
|
||||||
|
|
||||||
|
TEST_ASSERT_FALSE(core_util_in_critical_section());
|
||||||
|
TEST_ASSERT_TRUE(callback_called);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Template for tests
|
||||||
|
|
||||||
|
Test C++ API of critical section enable/disable
|
||||||
|
Given a Timeout with attached callback
|
||||||
|
When before critical section
|
||||||
|
Then interrupts are enabled and timeout callback is fired
|
||||||
|
When inside critical section
|
||||||
|
Then interrupts are disabled and timeout callback is blocked
|
||||||
|
When after critical section
|
||||||
|
Then interrupts are enabled and timeout callback is fired
|
||||||
|
|
||||||
|
Test C++ API of critical section enable/disable - nested lock
|
||||||
|
Given a Timeout with attached callback
|
||||||
|
When before critical section
|
||||||
|
Then interrupts are enabled and timeout callback is fired
|
||||||
|
When inside nested critical section
|
||||||
|
Then interrupts are disabled and timeout callback is blocked
|
||||||
|
When after critical section
|
||||||
|
Then interrupts are enabled and timeout callback is fired
|
||||||
|
*/
|
||||||
|
template<int N>
|
||||||
|
void test_CPP_API_enable_disable(void)
|
||||||
|
{
|
||||||
|
Timeout timeout;
|
||||||
|
const us_timestamp_t timeout_time_us = 1;
|
||||||
|
const int wait_time_us = timeout_time_us * 100;
|
||||||
|
|
||||||
|
TEST_ASSERT_FALSE(core_util_in_critical_section());
|
||||||
|
|
||||||
|
callback_called = false;
|
||||||
|
timeout.attach_us(callback(tiemout_callback), timeout_time_us);
|
||||||
|
wait_us(wait_time_us);
|
||||||
|
TEST_ASSERT_TRUE(callback_called);
|
||||||
|
|
||||||
|
for(int i = 0; i < N; i++) {
|
||||||
|
CriticalSectionLock::enable();
|
||||||
|
TEST_ASSERT_TRUE(core_util_in_critical_section());
|
||||||
|
}
|
||||||
|
|
||||||
|
callback_called = false;
|
||||||
|
timeout.attach_us(callback(tiemout_callback), timeout_time_us);
|
||||||
|
wait_us(wait_time_us);
|
||||||
|
TEST_ASSERT_FALSE(callback_called);
|
||||||
|
TEST_ASSERT_TRUE(core_util_in_critical_section());
|
||||||
|
|
||||||
|
for(int i = 0; i < N - 1; i++) {
|
||||||
|
CriticalSectionLock::disable();
|
||||||
|
TEST_ASSERT_TRUE(core_util_in_critical_section());
|
||||||
|
TEST_ASSERT_FALSE(callback_called);
|
||||||
|
}
|
||||||
|
|
||||||
|
CriticalSectionLock::disable();
|
||||||
|
TEST_ASSERT_FALSE(core_util_in_critical_section());
|
||||||
|
TEST_ASSERT_TRUE(callback_called);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
utest::v1::status_t test_setup(const size_t number_of_cases)
|
||||||
|
{
|
||||||
|
GREENTEA_SETUP(10, "default_auto");
|
||||||
|
return utest::v1::verbose_test_setup_handler(number_of_cases);
|
||||||
|
}
|
||||||
|
|
||||||
|
Case cases[] = {
|
||||||
|
Case("Test critical section C API", test_C_API<1>),
|
||||||
|
Case("Test critical section C API nested lock", test_C_API<10>),
|
||||||
|
Case("Test critical section C++ API constructor/destructor", test_CPP_API_constructor_destructor<1>),
|
||||||
|
Case("Test critical section C++ API constructor/destructor nested lock", test_CPP_API_constructor_destructor<10>),
|
||||||
|
Case("Test critical section C++ API enable/disable", test_CPP_API_enable_disable<1>),
|
||||||
|
Case("Test critical section C++ API enable/disable nested lock", test_CPP_API_enable_disable<10>)
|
||||||
|
};
|
||||||
|
|
||||||
|
utest::v1::Specification specification(test_setup, cases);
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
return !utest::v1::Harness::run(specification);
|
||||||
|
}
|
|
@ -16,7 +16,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if defined(TARGET_CORTEX_A)
|
#if defined(TARGET_CORTEX_A)
|
||||||
#error [NOT_SUPPORTED] This function not supported for this target
|
#error [NOT_SUPPORTED] This function not supported for this target
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
|
@ -32,7 +32,7 @@ volatile bool thread_should_continue = true;
|
||||||
#define THREAD_MALLOC_SIZE 100
|
#define THREAD_MALLOC_SIZE 100
|
||||||
|
|
||||||
#if defined(__CORTEX_A9)
|
#if defined(__CORTEX_A9)
|
||||||
#define THREAD_STACK_SIZE DEFAULT_STACK_SIZE
|
#define THREAD_STACK_SIZE 512
|
||||||
#else
|
#else
|
||||||
#define THREAD_STACK_SIZE 256
|
#define THREAD_STACK_SIZE 256
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -26,7 +26,11 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define THREAD_STACK_SIZE 512
|
#define THREAD_STACK_SIZE 512
|
||||||
|
#if defined(__CORTEX_A9)
|
||||||
|
#define PARALLEL_THREAD_STACK_SIZE 512
|
||||||
|
#else
|
||||||
#define PARALLEL_THREAD_STACK_SIZE 384
|
#define PARALLEL_THREAD_STACK_SIZE 384
|
||||||
|
#endif
|
||||||
#define CHILD_THREAD_STACK_SIZE 384
|
#define CHILD_THREAD_STACK_SIZE 384
|
||||||
|
|
||||||
using namespace utest::v1;
|
using namespace utest::v1;
|
||||||
|
|
|
@ -23,6 +23,67 @@
|
||||||
|
|
||||||
#include "mbedtls/sha256.h"
|
#include "mbedtls/sha256.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \name SECTION: Compatibility code
|
||||||
|
*
|
||||||
|
* Depending on whether the alternative (hatdware accelerated) hashing
|
||||||
|
* functions are provided or not, different API should be used for hashing.
|
||||||
|
* \{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(MBEDTLS_SHA256_ALT)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief This function starts a SHA-256 checksum calculation.
|
||||||
|
*
|
||||||
|
* \deprecated Superseded by mbedtls_sha256_starts_ret() in 2.7.0.
|
||||||
|
*
|
||||||
|
* \param ctx The SHA-256 context to initialize.
|
||||||
|
* \param is224 Determines which function to use.
|
||||||
|
* <ul><li>0: Use SHA-256.</li>
|
||||||
|
* <li>1: Use SHA-224.</li></ul>
|
||||||
|
*/
|
||||||
|
void mbedtls_sha256_starts( mbedtls_sha256_context *ctx,
|
||||||
|
int is224 )
|
||||||
|
{
|
||||||
|
mbedtls_sha256_starts_ret( ctx, is224 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief This function feeds an input buffer into an ongoing
|
||||||
|
* SHA-256 checksum calculation.
|
||||||
|
*
|
||||||
|
* \deprecated Superseded by mbedtls_sha256_update_ret() in 2.7.0.
|
||||||
|
*
|
||||||
|
* \param ctx The SHA-256 context to initialize.
|
||||||
|
* \param input The buffer holding the data.
|
||||||
|
* \param ilen The length of the input data.
|
||||||
|
*/
|
||||||
|
void mbedtls_sha256_update( mbedtls_sha256_context *ctx,
|
||||||
|
const unsigned char *input,
|
||||||
|
size_t ilen )
|
||||||
|
{
|
||||||
|
mbedtls_sha256_update_ret( ctx, input, ilen );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief This function finishes the SHA-256 operation, and writes
|
||||||
|
* the result to the output buffer.
|
||||||
|
*
|
||||||
|
* \deprecated Superseded by mbedtls_sha256_finish_ret() in 2.7.0.
|
||||||
|
*
|
||||||
|
* \param ctx The SHA-256 context.
|
||||||
|
* \param output The SHA-224or SHA-256 checksum result.
|
||||||
|
*/
|
||||||
|
void mbedtls_sha256_finish( mbedtls_sha256_context *ctx,
|
||||||
|
unsigned char output[32] )
|
||||||
|
{
|
||||||
|
mbedtls_sha256_finish_ret( ctx, output );
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* defined(MBEDTLS_SHA256_ALT) */
|
||||||
|
|
||||||
|
/* \} name SECTION: Compatibility code */
|
||||||
|
|
||||||
using namespace utest::v1;
|
using namespace utest::v1;
|
||||||
|
|
||||||
|
|
|
@ -67,16 +67,17 @@ bool find_substring(const char *first, const char *last, const char *s_first, co
|
||||||
void get_data(TCPSocket* sock){
|
void get_data(TCPSocket* sock){
|
||||||
bool result = false;
|
bool result = false;
|
||||||
// Server will respond with HTTP GET's success code
|
// Server will respond with HTTP GET's success code
|
||||||
const int ret = sock->recv(buffer, sizeof(buffer) - 1);
|
int len = 0;
|
||||||
if(ret <= 0)
|
int ret;
|
||||||
return;
|
while((ret = sock->recv(buffer+len, sizeof(buffer) - 1 - len)) > 0) {
|
||||||
|
len += ret;
|
||||||
buffer[ret] = '\0';
|
}
|
||||||
|
buffer[len] = '\0';
|
||||||
|
|
||||||
// Find 200 OK HTTP status in reply
|
// Find 200 OK HTTP status in reply
|
||||||
bool found_200_ok = find_substring(buffer, buffer + ret, HTTP_OK_STR, HTTP_OK_STR + strlen(HTTP_OK_STR));
|
bool found_200_ok = find_substring(buffer, buffer + len, HTTP_OK_STR, HTTP_OK_STR + strlen(HTTP_OK_STR));
|
||||||
// Find "Hello World!" string in reply
|
// Find "Hello World!" string in reply
|
||||||
bool found_hello = find_substring(buffer, buffer + ret, HTTP_HELLO_STR, HTTP_HELLO_STR + strlen(HTTP_HELLO_STR));
|
bool found_hello = find_substring(buffer, buffer + len, HTTP_HELLO_STR, HTTP_HELLO_STR + strlen(HTTP_HELLO_STR));
|
||||||
|
|
||||||
TEST_ASSERT_TRUE(found_200_ok);
|
TEST_ASSERT_TRUE(found_200_ok);
|
||||||
TEST_ASSERT_TRUE(found_hello);
|
TEST_ASSERT_TRUE(found_hello);
|
||||||
|
@ -85,7 +86,7 @@ void get_data(TCPSocket* sock){
|
||||||
|
|
||||||
TEST_ASSERT_EQUAL(result, true);
|
TEST_ASSERT_EQUAL(result, true);
|
||||||
|
|
||||||
printf("HTTP: Received %d chars from server\r\n", ret);
|
printf("HTTP: Received %d chars from server\r\n", len);
|
||||||
printf("HTTP: Received 200 OK status ... %s\r\n", found_200_ok ? "[OK]" : "[FAIL]");
|
printf("HTTP: Received 200 OK status ... %s\r\n", found_200_ok ? "[OK]" : "[FAIL]");
|
||||||
printf("HTTP: Received '%s' status ... %s\r\n", HTTP_HELLO_STR, found_hello ? "[OK]" : "[FAIL]");
|
printf("HTTP: Received '%s' status ... %s\r\n", HTTP_HELLO_STR, found_hello ? "[OK]" : "[FAIL]");
|
||||||
printf("HTTP: Received message:\r\n");
|
printf("HTTP: Received message:\r\n");
|
||||||
|
@ -109,7 +110,7 @@ void test_socket_attach() {
|
||||||
|
|
||||||
// Dispatch event queue
|
// Dispatch event queue
|
||||||
Thread eventThread;
|
Thread eventThread;
|
||||||
EventQueue queue(4*EVENTS_EVENT_SIZE);
|
EventQueue queue(10*EVENTS_EVENT_SIZE);
|
||||||
eventThread.start(callback(&queue, &EventQueue::dispatch_forever));
|
eventThread.start(callback(&queue, &EventQueue::dispatch_forever));
|
||||||
|
|
||||||
printf("TCP client IP Address is %s\r\n", net->get_ip_address());
|
printf("TCP client IP Address is %s\r\n", net->get_ip_address());
|
||||||
|
|
|
@ -28,13 +28,13 @@
|
||||||
|
|
||||||
using namespace utest::v1;
|
using namespace utest::v1;
|
||||||
|
|
||||||
#ifndef MBED_CFG_TCP_CLIENT_ECHO_BUFFER_SIZE
|
#ifndef MBED_CONF_APP_TCP_CLIENT_ECHO_BUFFER_SIZE
|
||||||
#define MBED_CFG_TCP_CLIENT_ECHO_BUFFER_SIZE 256
|
#define MBED_CONF_APP_TCP_CLIENT_ECHO_BUFFER_SIZE 256
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
char tx_buffer[MBED_CFG_TCP_CLIENT_ECHO_BUFFER_SIZE] = {0};
|
char tx_buffer[MBED_CONF_APP_TCP_CLIENT_ECHO_BUFFER_SIZE] = {0};
|
||||||
char rx_buffer[MBED_CFG_TCP_CLIENT_ECHO_BUFFER_SIZE] = {0};
|
char rx_buffer[MBED_CONF_APP_TCP_CLIENT_ECHO_BUFFER_SIZE] = {0};
|
||||||
}
|
}
|
||||||
|
|
||||||
void prep_buffer(char *tx_buffer, size_t tx_size) {
|
void prep_buffer(char *tx_buffer, size_t tx_size) {
|
||||||
|
@ -44,7 +44,7 @@ void prep_buffer(char *tx_buffer, size_t tx_size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_tcp_echo() {
|
void test_tcp_echo() {
|
||||||
|
int n = 0;
|
||||||
NetworkInterface* net = MBED_CONF_APP_OBJECT_CONSTRUCTION;
|
NetworkInterface* net = MBED_CONF_APP_OBJECT_CONSTRUCTION;
|
||||||
int err = MBED_CONF_APP_CONNECT_STATEMENT;
|
int err = MBED_CONF_APP_CONNECT_STATEMENT;
|
||||||
|
|
||||||
|
@ -86,7 +86,12 @@ void test_tcp_echo() {
|
||||||
|
|
||||||
prep_buffer(tx_buffer, sizeof(tx_buffer));
|
prep_buffer(tx_buffer, sizeof(tx_buffer));
|
||||||
#if defined(MBED_CONF_APP_TCP_ECHO_PREFIX)
|
#if defined(MBED_CONF_APP_TCP_ECHO_PREFIX)
|
||||||
sock.recv(rx_buffer, sizeof(MBED_CONF_APP_TCP_ECHO_PREFIX));
|
n = sock.recv(rx_buffer, sizeof(MBED_CONF_APP_TCP_ECHO_PREFIX));
|
||||||
|
if (n >= 0) {
|
||||||
|
printf("recv-ed prefix: %d bytes - %.*s \n", n, n, rx_buffer);
|
||||||
|
} else {
|
||||||
|
printf("Network error in receiving prefix: %d\n", n);
|
||||||
|
}
|
||||||
#endif /* MBED_CONF_APP_TCP_ECHO_PREFIX */
|
#endif /* MBED_CONF_APP_TCP_ECHO_PREFIX */
|
||||||
const int ret = sock.send(tx_buffer, sizeof(tx_buffer));
|
const int ret = sock.send(tx_buffer, sizeof(tx_buffer));
|
||||||
if (ret >= 0) {
|
if (ret >= 0) {
|
||||||
|
@ -95,7 +100,7 @@ void test_tcp_echo() {
|
||||||
printf("Network error %d\n", ret);
|
printf("Network error %d\n", ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
int n = sock.recv(rx_buffer, sizeof(rx_buffer));
|
n = sock.recv(rx_buffer, sizeof(rx_buffer));
|
||||||
if (n >= 0) {
|
if (n >= 0) {
|
||||||
printf("recv %d bytes - %.*s \n", n, n, rx_buffer);
|
printf("recv %d bytes - %.*s \n", n, n, rx_buffer);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -76,9 +76,15 @@ void test_tcp_hello_world() {
|
||||||
sock.send(buffer, strlen(buffer));
|
sock.send(buffer, strlen(buffer));
|
||||||
|
|
||||||
// Server will respond with HTTP GET's success code
|
// Server will respond with HTTP GET's success code
|
||||||
const int ret = sock.recv(buffer, sizeof(buffer) - 1);
|
int ret = 0;
|
||||||
buffer[ret] = '\0';
|
int bytes_recvd = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
ret += bytes_recvd;
|
||||||
|
bytes_recvd = sock.recv(buffer+ret, sizeof(buffer) - 1 - ret);
|
||||||
|
}while(bytes_recvd > 0);
|
||||||
|
buffer[ret] = '\0';
|
||||||
|
|
||||||
// Find 200 OK HTTP status in reply
|
// Find 200 OK HTTP status in reply
|
||||||
bool found_200_ok = find_substring(buffer, buffer + ret, HTTP_OK_STR, HTTP_OK_STR + strlen(HTTP_OK_STR));
|
bool found_200_ok = find_substring(buffer, buffer + ret, HTTP_OK_STR, HTTP_OK_STR + strlen(HTTP_OK_STR));
|
||||||
// Find "Hello World!" string in reply
|
// Find "Hello World!" string in reply
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
# Description
|
||||||
|
|
||||||
|
This document describes how to run EMAC tests. The EMAC test cases are made using Ethernet Configuration Testing Protocol (CTP). To run the tests, one device in the Ethernet segment needs to be configured to be a CTP echo server. The devices running the test cases, use the echo server to forward the CTP Ethernet frames back.
|
||||||
|
|
||||||
|
# Configuring CTP echo server
|
||||||
|
|
||||||
|
A device can be configured to be a CTP echo server by enabling `echo-server` setting in the test environment's application `json` file. When device is configured to be a CTP echo server, it starts to forward CTP messages automatically after power up and will continue forwarding until power down.
|
||||||
|
|
||||||
|
# Test cases
|
||||||
|
|
||||||
|
## EMAC interface initialise
|
||||||
|
|
||||||
|
Initializes EMAC interface driver.
|
||||||
|
|
||||||
|
For WLAN installs test case so that it can intercept incoming Ethernet messages from the WLAN driver. Incoming CTP frames are handed by the test case and other frames are forwarded to the LWIP stack.
|
||||||
|
|
||||||
|
## EMAC interface broadcast
|
||||||
|
|
||||||
|
Sends three 100 byte CTP broadcast messages, waits for three seconds and sends three 50 byte CTP broadcast messages. Listens for the CTP echo server responses and stores the addresses of the echo servers if replies are received. The test case will pass if there are no responses from echo server, but further test cases will be skipped.
|
||||||
|
|
||||||
|
## EMAC interface unicast
|
||||||
|
|
||||||
|
Sends three CTP unicast messages to the CTP echo server. Verifies that all are replied.
|
||||||
|
|
||||||
|
## EMAC interface unicast frame length
|
||||||
|
|
||||||
|
Sends CTP unicast messages with Ethernet message length from 100 bytes to maximum. Verifies that all are replied.
|
||||||
|
|
|
@ -0,0 +1,143 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017, 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 "greentea-client/test_env.h"
|
||||||
|
#include "unity/unity.h"
|
||||||
|
#include "utest.h"
|
||||||
|
|
||||||
|
#if MBED_CONF_APP_TEST_WIFI || MBED_CONF_APP_TEST_ETHERNET
|
||||||
|
|
||||||
|
#include "mbed.h"
|
||||||
|
|
||||||
|
#include "lwip/opt.h" /* ETH_PAD_SIZE */
|
||||||
|
|
||||||
|
#include "emac_stack_mem.h"
|
||||||
|
#include "emac_api.h"
|
||||||
|
|
||||||
|
#include "emac_tests.h"
|
||||||
|
#include "emac_ctp.h"
|
||||||
|
|
||||||
|
#include "emac_initialize.h"
|
||||||
|
#include "emac_util.h"
|
||||||
|
#include "emac_membuf.h"
|
||||||
|
|
||||||
|
using namespace utest::v1;
|
||||||
|
|
||||||
|
// Unique identifier for message
|
||||||
|
static int receipt_number = 0;
|
||||||
|
|
||||||
|
static int emac_if_ctp_header_build(unsigned char *eth_frame, const unsigned char *dest_addr, const unsigned char *origin_addr, const unsigned char *forward_addr)
|
||||||
|
{
|
||||||
|
memcpy(ð_frame[0], dest_addr, 6);
|
||||||
|
memcpy(ð_frame[6], origin_addr, 6);
|
||||||
|
|
||||||
|
eth_frame[12] = 0x90; /* loop back */
|
||||||
|
eth_frame[13] = 0x00;
|
||||||
|
|
||||||
|
eth_frame[14] = 0x00; /* skip count */
|
||||||
|
eth_frame[15] = 0x00;
|
||||||
|
|
||||||
|
eth_frame[16] = 0x02; /* function, forward */
|
||||||
|
eth_frame[17] = 0x00;
|
||||||
|
|
||||||
|
memcpy(ð_frame[18], forward_addr, 6);
|
||||||
|
|
||||||
|
eth_frame[24] = 0x01; /* function, reply */
|
||||||
|
eth_frame[25] = 0x00;
|
||||||
|
|
||||||
|
receipt_number++;
|
||||||
|
|
||||||
|
eth_frame[26] = receipt_number; /* receipt number */
|
||||||
|
eth_frame[27] = receipt_number >> 8;
|
||||||
|
|
||||||
|
return receipt_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
ctp_function emac_if_ctp_header_handle(unsigned char *eth_input_frame, unsigned char *eth_output_frame, unsigned char *origin_addr, int *receipt_number)
|
||||||
|
{
|
||||||
|
if (eth_input_frame[12] != 0x90 || eth_input_frame[13] != 0x00) {
|
||||||
|
return CTP_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int skip_count = eth_input_frame[15] << 8 | eth_input_frame[14];
|
||||||
|
unsigned char *ethernet_ptr = ð_input_frame[16] + skip_count;
|
||||||
|
|
||||||
|
int function = ethernet_ptr[1] << 8 | ethernet_ptr[0];
|
||||||
|
ethernet_ptr += 2;
|
||||||
|
|
||||||
|
// Forward
|
||||||
|
if (function == 0x0002) {
|
||||||
|
memcpy(eth_output_frame, eth_input_frame, ETH_FRAME_HEADER_LEN);
|
||||||
|
// Update skip count
|
||||||
|
skip_count += 8;
|
||||||
|
eth_output_frame[14] = skip_count;
|
||||||
|
eth_output_frame[15] = skip_count >> 8;
|
||||||
|
// Set forward address to destination address
|
||||||
|
memcpy(ð_output_frame[0], ethernet_ptr, 6);
|
||||||
|
// Copy own address to origin
|
||||||
|
memcpy(ð_output_frame[6], origin_addr, 6);
|
||||||
|
return CTP_FORWARD;
|
||||||
|
// reply
|
||||||
|
} else if (function == 0x0001) {
|
||||||
|
*receipt_number = ethernet_ptr[1] << 8 | ethernet_ptr[0];
|
||||||
|
return CTP_REPLY;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CTP_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void emac_if_ctp_msg_build(int eth_frame_len, const unsigned char *dest_addr, const unsigned char *origin_addr, const unsigned char *forward_addr)
|
||||||
|
{
|
||||||
|
if (eth_frame_len < ETH_FRAME_HEADER_LEN) {
|
||||||
|
eth_frame_len = ETH_FRAME_HEADER_LEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("message sent %x:%x:%x:%x:%x:%x\r\n\r\n", dest_addr[0], dest_addr[1], dest_addr[2], dest_addr[3], dest_addr[4], dest_addr[5]);
|
||||||
|
|
||||||
|
int outgoing_msg_index = emac_if_add_outgoing_msg(eth_frame_len);
|
||||||
|
|
||||||
|
if (outgoing_msg_index < 0) {
|
||||||
|
SET_ERROR_FLAGS(OUT_OF_MSG_DATA);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
emac_stack_mem_chain_t *mem_chain_p = emac_stack_mem_alloc(0, eth_frame_len + ETH_PAD_SIZE, 0);
|
||||||
|
|
||||||
|
if (!mem_chain_p) {
|
||||||
|
SET_ERROR_FLAGS(NO_FREE_MEM_BUF);
|
||||||
|
emac_if_free_outgoing_msg(outgoing_msg_index);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memcmp(dest_addr, eth_mac_broadcast_addr, 6) == 0) {
|
||||||
|
emac_if_set_outgoing_msg_flags(outgoing_msg_index, BROADCAST);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char eth_output_frame_data[ETH_FRAME_HEADER_LEN];
|
||||||
|
int receipt_number = emac_if_ctp_header_build(eth_output_frame_data, dest_addr, origin_addr, forward_addr);
|
||||||
|
emac_if_set_outgoing_msg_receipt_num(outgoing_msg_index, receipt_number);
|
||||||
|
|
||||||
|
emac_if_memory_buffer_write(mem_chain_p, eth_output_frame_data, true);
|
||||||
|
|
||||||
|
//emac_if->ops.link_out(hw_driver, mem_chain_p);
|
||||||
|
emac_if_get()->ops.link_out(emac_if_get(), mem_chain_p);
|
||||||
|
|
||||||
|
emac_stack_mem_free(0, mem_chain_p);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017, 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EMAC_CTP_H
|
||||||
|
#define EMAC_CTP_H
|
||||||
|
|
||||||
|
enum ctp_function {
|
||||||
|
CTP_NONE,
|
||||||
|
CTP_FORWARD,
|
||||||
|
CTP_REPLY
|
||||||
|
};
|
||||||
|
|
||||||
|
ctp_function emac_if_ctp_header_handle(unsigned char *eth_input_frame, unsigned char *eth_output_frame, unsigned char *origin_addr, int *receipt_number);
|
||||||
|
void emac_if_ctp_msg_build(int eth_frame_len, const unsigned char *dest_addr, const unsigned char *origin_addr, const unsigned char *forward_addr);
|
||||||
|
void emac_if_ctp_reply_handle(int lenght, int invalid_data_index);
|
||||||
|
|
||||||
|
#endif /* EMAC_CTP_H */
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017, 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EMAC_INITIALIZE_H
|
||||||
|
#define EMAC_INITIALIZE_H
|
||||||
|
|
||||||
|
uint8_t *emac_if_get_hw_addr(void);
|
||||||
|
emac_interface_t *emac_if_get(void);
|
||||||
|
|
||||||
|
#endif /* EMAC_INITIALIZE_H */
|
|
@ -0,0 +1,83 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017, 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 "mbed.h"
|
||||||
|
#include "greentea-client/test_env.h"
|
||||||
|
#include "unity.h"
|
||||||
|
#include "utest.h"
|
||||||
|
|
||||||
|
#if MBED_CONF_APP_TEST_WIFI || MBED_CONF_APP_TEST_ETHERNET
|
||||||
|
|
||||||
|
#include "lwip/opt.h" /* ETH_PAD_SIZE */
|
||||||
|
|
||||||
|
#include "emac_api.h"
|
||||||
|
#include "emac_stack_mem.h"
|
||||||
|
|
||||||
|
#include "emac_membuf.h"
|
||||||
|
#include "emac_util.h"
|
||||||
|
|
||||||
|
int emac_if_memory_buffer_read(emac_stack_mem_chain_t *mem_chain_p, unsigned char *eth_frame)
|
||||||
|
{
|
||||||
|
int eth_frame_index = 0;
|
||||||
|
int invalid_data_index = 0;
|
||||||
|
int index = ETH_PAD_SIZE;
|
||||||
|
|
||||||
|
for (emac_stack_mem_t *mem_p = emac_stack_mem_chain_dequeue(0, &mem_chain_p); mem_p != NULL; mem_p = emac_stack_mem_chain_dequeue(0, &mem_chain_p)) {
|
||||||
|
unsigned char *buf_payload = (unsigned char *) emac_stack_mem_ptr(0, mem_p);
|
||||||
|
int buf_payload_len = emac_stack_mem_len(0, mem_p);
|
||||||
|
|
||||||
|
for (; index < buf_payload_len; index++) {
|
||||||
|
if (eth_frame_index < ETH_FRAME_HEADER_LEN) {
|
||||||
|
eth_frame[eth_frame_index] = buf_payload[index];
|
||||||
|
} else {
|
||||||
|
if (buf_payload[index] != (uint8_t) eth_frame_index) {
|
||||||
|
invalid_data_index = eth_frame_index;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
eth_frame_index++;
|
||||||
|
}
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return invalid_data_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
void emac_if_memory_buffer_write(emac_stack_mem_chain_t *mem_chain_p, unsigned char *eth_frame, bool write_data)
|
||||||
|
{
|
||||||
|
int eth_frame_index = 0;
|
||||||
|
int index = ETH_PAD_SIZE;
|
||||||
|
|
||||||
|
for (emac_stack_mem_t *mem_p = emac_stack_mem_chain_dequeue(0, &mem_chain_p); mem_p != NULL; mem_p = emac_stack_mem_chain_dequeue(0, &mem_chain_p)) {
|
||||||
|
unsigned char *buf_payload = (unsigned char *) emac_stack_mem_ptr(0, mem_p);
|
||||||
|
int buf_payload_len = emac_stack_mem_len(0, mem_p);
|
||||||
|
|
||||||
|
for (; index < buf_payload_len; index++) {
|
||||||
|
if (eth_frame_index < ETH_FRAME_HEADER_LEN) {
|
||||||
|
buf_payload[index] = eth_frame[eth_frame_index];
|
||||||
|
} else if (write_data) {
|
||||||
|
buf_payload[index] = (char) eth_frame_index;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
eth_frame_index++;
|
||||||
|
}
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017, 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EMAC_MEMBUF_H
|
||||||
|
#define EMAC_MEMBUF_H
|
||||||
|
|
||||||
|
int emac_if_memory_buffer_read(emac_stack_mem_chain_t *mem_chain_p, unsigned char *eth_frame);
|
||||||
|
void emac_if_memory_buffer_write(emac_stack_mem_chain_t *mem_chain_p, unsigned char *eth_frame, bool write_data);
|
||||||
|
|
||||||
|
#endif /* EMAC_MEMBUF_H */
|
|
@ -0,0 +1,73 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017, 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 "mbed.h"
|
||||||
|
#include "greentea-client/test_env.h"
|
||||||
|
#include "unity.h"
|
||||||
|
#include "utest.h"
|
||||||
|
|
||||||
|
#if MBED_CONF_APP_TEST_WIFI || MBED_CONF_APP_TEST_ETHERNET
|
||||||
|
|
||||||
|
#include "emac_tests.h"
|
||||||
|
#include "emac_util.h"
|
||||||
|
#include "emac_ctp.h"
|
||||||
|
|
||||||
|
using namespace utest::v1;
|
||||||
|
|
||||||
|
void test_emac_broadcast_cb(void)
|
||||||
|
{
|
||||||
|
emac_if_validate_outgoing_msg();
|
||||||
|
|
||||||
|
static int counter = 0;
|
||||||
|
|
||||||
|
// Send three broadcast
|
||||||
|
if (counter < 3) {
|
||||||
|
emac_if_ctp_msg_build(100, eth_mac_broadcast_addr, emac_if_get_own_addr(), emac_if_get_own_addr());
|
||||||
|
counter++;
|
||||||
|
} else if (counter < 6) {
|
||||||
|
counter++;
|
||||||
|
} else if (counter < 9) {
|
||||||
|
emac_if_ctp_msg_build(50, eth_mac_broadcast_addr, emac_if_get_own_addr(), emac_if_get_own_addr());
|
||||||
|
counter++;
|
||||||
|
} else if (counter < 12) {
|
||||||
|
counter++;
|
||||||
|
} else if (counter == 12) {
|
||||||
|
emac_if_reset_outgoing_msg();
|
||||||
|
// ignore errors since just probing
|
||||||
|
RESET_ERROR_FLAGS;
|
||||||
|
#if MBED_CONF_APP_ECHO_SERVER
|
||||||
|
printf("echo server started successfully\r\n\r\n");
|
||||||
|
counter = 255;
|
||||||
|
#else
|
||||||
|
worker_loop_end();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_emac_broadcast(void)
|
||||||
|
{
|
||||||
|
RESET_ERROR_FLAGS;
|
||||||
|
SET_TRACE_LEVEL(TRACE_ETH_FRAMES | TRACE_SUCCESS | TRACE_FAILURE);
|
||||||
|
|
||||||
|
worker_loop_start(test_emac_broadcast_cb, 10 * SECOND_TO_MS);
|
||||||
|
|
||||||
|
PRINT_ERROR_FLAGS;
|
||||||
|
TEST_ASSERT_FALSE(ERROR_FLAGS);
|
||||||
|
RESET_OUTGOING_MSG_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,140 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017, 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 "mbed.h"
|
||||||
|
#include "greentea-client/test_env.h"
|
||||||
|
#include "unity.h"
|
||||||
|
#include "utest.h"
|
||||||
|
|
||||||
|
#if MBED_CONF_APP_TEST_WIFI || MBED_CONF_APP_TEST_ETHERNET
|
||||||
|
|
||||||
|
#include "inttypes.h"
|
||||||
|
|
||||||
|
#if MBED_CONF_APP_TEST_WIFI
|
||||||
|
#ifdef TARGET_UBLOX_EVK_ODIN_W2
|
||||||
|
#include "wifi_emac_api.h"
|
||||||
|
#include "OdinWiFiInterface.h"
|
||||||
|
#endif
|
||||||
|
#ifdef TARGET_REALTEK_RTL8195AM
|
||||||
|
#include "rtw_emac.h"
|
||||||
|
#include "RTWInterface.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "emac_api.h"
|
||||||
|
#include "emac_tests.h"
|
||||||
|
#include "emac_util.h"
|
||||||
|
|
||||||
|
using namespace utest::v1;
|
||||||
|
|
||||||
|
static unsigned char eth_mac_addr[ETH_MAC_ADDR_LEN];
|
||||||
|
|
||||||
|
static char emac_if_link_state_change_cb_data[] = "link_state_change_cb_data";
|
||||||
|
static char emac_if_link_input_cb_data[] = "link_input_cb_data";
|
||||||
|
|
||||||
|
static bool emac_if_init(void);
|
||||||
|
|
||||||
|
void test_emac_initialize()
|
||||||
|
{
|
||||||
|
#if MBED_CONF_APP_TEST_WIFI
|
||||||
|
static WiFiInterface *wifi;
|
||||||
|
|
||||||
|
#ifdef TARGET_UBLOX_EVK_ODIN_W2
|
||||||
|
wifi = new OdinWiFiInterface;
|
||||||
|
#endif
|
||||||
|
#ifdef TARGET_REALTEK_RTL8195AM
|
||||||
|
wifi = new RTWInterface;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MBED_CONF_APP_WIFI_SCAN
|
||||||
|
WiFiAccessPoint ap[30];
|
||||||
|
|
||||||
|
int size = wifi->scan(ap, 30);
|
||||||
|
|
||||||
|
for (int i=0; i<size; i++) {
|
||||||
|
const char *ssid = ap[i].get_ssid();
|
||||||
|
nsapi_security_t security = ap[i].get_security();
|
||||||
|
int8_t rssi = ap[i].get_rssi();
|
||||||
|
char ch = ap[i].get_channel();
|
||||||
|
|
||||||
|
printf("BS %i\r\n", i);
|
||||||
|
printf("ssid %s\r\n", ssid);
|
||||||
|
printf("security %i\r\n", security);
|
||||||
|
printf("rssi %i\r\n", rssi);
|
||||||
|
printf("ch %i\r\n\r\n", ch);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
wifi->set_credentials(MBED_CONF_APP_WIFI_SSID, MBED_CONF_APP_WIFI_PASSWORD, MBED_CONF_APP_WIFI_SECURITY);
|
||||||
|
wifi->connect();
|
||||||
|
|
||||||
|
const char *ip_addr = wifi->get_ip_address();
|
||||||
|
printf("connected IP %s\r\n\r\n", ip_addr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
TEST_ASSERT(emac_if_init());
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char *emac_if_get_hw_addr(void)
|
||||||
|
{
|
||||||
|
return ð_mac_addr[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
emac_interface_t *emac_if_get(void)
|
||||||
|
{
|
||||||
|
#if MBED_CONF_APP_TEST_WIFI
|
||||||
|
#ifdef TARGET_UBLOX_EVK_ODIN_W2
|
||||||
|
return wifi_emac_get_interface();
|
||||||
|
#endif
|
||||||
|
#ifdef TARGET_REALTEK_RTL8195AM
|
||||||
|
return wlan_emac_init_interface();
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool emac_if_init(void)
|
||||||
|
{
|
||||||
|
emac_interface_t *emac_if = emac_if_get();
|
||||||
|
|
||||||
|
emac_if->ops.set_link_input_cb(emac_if, emac_if_link_input_cb, emac_if_link_input_cb_data);
|
||||||
|
emac_if->ops.set_link_state_cb(emac_if, emac_if_link_state_change_cb, emac_if_link_state_change_cb_data);
|
||||||
|
|
||||||
|
int hwaddr_len = emac_if->ops.get_hwaddr_size(emac_if);
|
||||||
|
printf("emac hwaddr length %i\r\n\r\n", hwaddr_len);
|
||||||
|
|
||||||
|
if (hwaddr_len == 6) {
|
||||||
|
emac_if->ops.get_hwaddr(emac_if, eth_mac_addr);
|
||||||
|
printf("emac hwaddr %x:%x:%x:%x:%x:%x\r\n\r\n", eth_mac_addr[0],eth_mac_addr[1],eth_mac_addr[2],eth_mac_addr[3],eth_mac_addr[4],eth_mac_addr[5]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mtu = emac_if->ops.get_mtu_size(emac_if);
|
||||||
|
printf("emac mtu %i\r\n\r\n", mtu);
|
||||||
|
|
||||||
|
char hw_name[11];
|
||||||
|
emac_if->ops.get_ifname(emac_if, hw_name, 10);
|
||||||
|
printf("emac if name %s\r\n\r\n", hw_name);
|
||||||
|
|
||||||
|
if (!emac_if->ops.power_up(emac_if)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,67 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017, 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 "mbed.h"
|
||||||
|
#include "greentea-client/test_env.h"
|
||||||
|
#include "unity.h"
|
||||||
|
#include "utest.h"
|
||||||
|
|
||||||
|
#if MBED_CONF_APP_TEST_WIFI || MBED_CONF_APP_TEST_ETHERNET
|
||||||
|
|
||||||
|
#include "emac_tests.h"
|
||||||
|
#include "emac_util.h"
|
||||||
|
#include "emac_ctp.h"
|
||||||
|
|
||||||
|
using namespace utest::v1;
|
||||||
|
|
||||||
|
void test_emac_unicast_cb(void)
|
||||||
|
{
|
||||||
|
emac_if_validate_outgoing_msg();
|
||||||
|
|
||||||
|
static uint8_t counter = 0;
|
||||||
|
|
||||||
|
// Send three unicast
|
||||||
|
if (counter < 3) {
|
||||||
|
emac_if_ctp_msg_build(100, emac_if_get_echo_server_addr(0), emac_if_get_own_addr(), emac_if_get_own_addr());
|
||||||
|
}
|
||||||
|
|
||||||
|
// End test
|
||||||
|
if (counter > 10) {
|
||||||
|
worker_loop_end();
|
||||||
|
|
||||||
|
if (emac_if_count_outgoing_msg() != 0) {
|
||||||
|
SET_ERROR_FLAGS(TEST_FAILED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_emac_unicast()
|
||||||
|
{
|
||||||
|
RESET_ERROR_FLAGS;
|
||||||
|
SET_TRACE_LEVEL(TRACE_ETH_FRAMES | TRACE_SUCCESS | TRACE_FAILURE);
|
||||||
|
|
||||||
|
if (emac_if_count_echo_server_addr()) {
|
||||||
|
worker_loop_start(test_emac_unicast_cb, 1 * SECOND_TO_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
PRINT_ERROR_FLAGS;
|
||||||
|
TEST_ASSERT_FALSE(ERROR_FLAGS);
|
||||||
|
RESET_OUTGOING_MSG_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017, 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 "mbed.h"
|
||||||
|
#include "greentea-client/test_env.h"
|
||||||
|
#include "unity.h"
|
||||||
|
#include "utest.h"
|
||||||
|
|
||||||
|
#if MBED_CONF_APP_TEST_WIFI || MBED_CONF_APP_TEST_ETHERNET
|
||||||
|
|
||||||
|
#include "emac_tests.h"
|
||||||
|
#include "emac_util.h"
|
||||||
|
#include "emac_ctp.h"
|
||||||
|
|
||||||
|
using namespace utest::v1;
|
||||||
|
|
||||||
|
void test_emac_unicast_frame_len_cb(void)
|
||||||
|
{
|
||||||
|
emac_if_validate_outgoing_msg();
|
||||||
|
|
||||||
|
static uint32_t counter = 0;
|
||||||
|
|
||||||
|
// Send unicast to echo server
|
||||||
|
if (counter < 16) {
|
||||||
|
static uint32_t msg_len = 0;
|
||||||
|
|
||||||
|
emac_if_ctp_msg_build(msg_len, emac_if_get_echo_server_addr(0), emac_if_get_own_addr(), emac_if_get_own_addr());
|
||||||
|
|
||||||
|
msg_len += 100;
|
||||||
|
|
||||||
|
if (msg_len > 1514) {
|
||||||
|
msg_len = 1514;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (counter > 18) {
|
||||||
|
if (emac_if_count_outgoing_msg() == 0) {
|
||||||
|
worker_loop_end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
counter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_emac_unicast_frame_len()
|
||||||
|
{
|
||||||
|
RESET_ERROR_FLAGS;
|
||||||
|
SET_TRACE_LEVEL(TRACE_SUCCESS | TRACE_FAILURE);
|
||||||
|
|
||||||
|
if (emac_if_count_echo_server_addr()) {
|
||||||
|
worker_loop_start(test_emac_unicast_frame_len_cb, 1 * SECOND_TO_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
PRINT_ERROR_FLAGS;
|
||||||
|
TEST_ASSERT_FALSE(ERROR_FLAGS);
|
||||||
|
RESET_OUTGOING_MSG_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017, 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EMAC_TESTS_H
|
||||||
|
#define EMAC_TESTS_H
|
||||||
|
|
||||||
|
void test_emac_initialize();
|
||||||
|
void test_emac_broadcast();
|
||||||
|
void test_emac_unicast();
|
||||||
|
void test_emac_unicast_frame_len();
|
||||||
|
|
||||||
|
#endif /* EMAC_TESTS_H */
|
|
@ -0,0 +1,436 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017, 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 "mbed.h"
|
||||||
|
#include "greentea-client/test_env.h"
|
||||||
|
#include "unity.h"
|
||||||
|
#include "utest.h"
|
||||||
|
|
||||||
|
#if MBED_CONF_APP_TEST_WIFI || MBED_CONF_APP_TEST_ETHERNET
|
||||||
|
|
||||||
|
extern "C" { // netif input
|
||||||
|
#include "tcpip.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "emac_api.h"
|
||||||
|
#include "emac_stack_mem.h"
|
||||||
|
|
||||||
|
#include "emac_tests.h"
|
||||||
|
#include "emac_initialize.h"
|
||||||
|
#include "emac_util.h"
|
||||||
|
#include "emac_membuf.h"
|
||||||
|
#include "emac_ctp.h"
|
||||||
|
|
||||||
|
using namespace utest::v1;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int length;
|
||||||
|
int receipt_number;
|
||||||
|
unsigned short flags;
|
||||||
|
unsigned short lifetime;
|
||||||
|
} outgoing_msg_t;
|
||||||
|
|
||||||
|
#define ECHO_SERVER_COUNT 5
|
||||||
|
|
||||||
|
#define OUTGOING_MSG_COUNT 100
|
||||||
|
|
||||||
|
// Event flags
|
||||||
|
#define LINK_UP 0x01
|
||||||
|
#define LINK_DOWN 0x02
|
||||||
|
|
||||||
|
// Hook to lwip input function
|
||||||
|
extern struct netif *netif_list;
|
||||||
|
|
||||||
|
// Broadcast address
|
||||||
|
const unsigned char eth_mac_broadcast_addr[ETH_MAC_ADDR_LEN] = {0xff,0xff,0xff,0xff,0xff,0xff};
|
||||||
|
|
||||||
|
// Event queue
|
||||||
|
static EventQueue worker_loop_event_queue;
|
||||||
|
static void worker_loop_event_cb(int event);
|
||||||
|
static Event<void(int)> worker_loop_event(&worker_loop_event_queue, worker_loop_event_cb);
|
||||||
|
static void link_input_event_cb(emac_stack_mem_chain_t *mem_chain_p);
|
||||||
|
static Event<void(emac_stack_mem_chain_t *)> link_input_event(&worker_loop_event_queue, link_input_event_cb);
|
||||||
|
|
||||||
|
// Found echo server addresses
|
||||||
|
static unsigned char eth_mac_echo_server_addr[ECHO_SERVER_COUNT][ETH_MAC_ADDR_LEN];
|
||||||
|
static int etc_mac_echo_server_free_index = 0;
|
||||||
|
|
||||||
|
// Outgoing messages
|
||||||
|
static outgoing_msg_t outgoing_msgs[OUTGOING_MSG_COUNT];
|
||||||
|
|
||||||
|
static unsigned int trace_level = 0;
|
||||||
|
static unsigned int error_flags = 0;
|
||||||
|
static unsigned int no_response_cnt = 0;
|
||||||
|
|
||||||
|
int emac_if_find_outgoing_msg(int receipt_number)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < OUTGOING_MSG_COUNT; i++) {
|
||||||
|
if (outgoing_msgs[i].length && outgoing_msgs[i].receipt_number == receipt_number) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void emac_if_free_outgoing_msg(int index)
|
||||||
|
{
|
||||||
|
outgoing_msgs[index].length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int emac_if_count_outgoing_msg(void)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < OUTGOING_MSG_COUNT; i++) {
|
||||||
|
if (outgoing_msgs[i].length) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void emac_if_reset_outgoing_msg(void)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < OUTGOING_MSG_COUNT; i++) {
|
||||||
|
if (outgoing_msgs[i].length) {
|
||||||
|
outgoing_msgs[i].length = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int emac_if_add_outgoing_msg(int length)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < OUTGOING_MSG_COUNT; i++) {
|
||||||
|
if (!outgoing_msgs[i].length) {
|
||||||
|
outgoing_msgs[i].receipt_number = 0;
|
||||||
|
outgoing_msgs[i].length = length;
|
||||||
|
outgoing_msgs[i].flags = 0;
|
||||||
|
outgoing_msgs[i].lifetime = 10;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void emac_if_set_outgoing_msg_receipt_num(int index, int receipt_number)
|
||||||
|
{
|
||||||
|
outgoing_msgs[index].receipt_number = receipt_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
void emac_if_set_outgoing_msg_flags(int index, int flags)
|
||||||
|
{
|
||||||
|
outgoing_msgs[index].flags |= flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
void emac_if_timeout_outgoing_msg(void)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < OUTGOING_MSG_COUNT; i++) {
|
||||||
|
if (outgoing_msgs[i].length) {
|
||||||
|
if (outgoing_msgs[i].lifetime) {
|
||||||
|
outgoing_msgs[i].lifetime--;
|
||||||
|
if (outgoing_msgs[i].lifetime == 0) {
|
||||||
|
SET_ERROR_FLAGS(NO_RESPONSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void emac_if_validate_outgoing_msg(void)
|
||||||
|
{
|
||||||
|
static char broadcast_resp_count = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < OUTGOING_MSG_COUNT; i++) {
|
||||||
|
if (outgoing_msgs[i].length) {
|
||||||
|
|
||||||
|
if (outgoing_msgs[i].flags & RESPONSE_RECEIVED) {
|
||||||
|
|
||||||
|
int failure = outgoing_msgs[i].flags & (INVALID_LENGHT | INVALID_DATA);
|
||||||
|
|
||||||
|
if (failure) {
|
||||||
|
SET_ERROR_FLAGS(MSG_VALID_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(outgoing_msgs[i].flags & PRINTED)) {
|
||||||
|
if ((trace_level & TRACE_SUCCESS) || ((trace_level & TRACE_FAILURE) && failure)) {
|
||||||
|
printf("response: receipt number %i %s %s %s\r\n\r\n", outgoing_msgs[i].receipt_number,
|
||||||
|
outgoing_msgs[i].flags & INVALID_LENGHT ? "LENGTH INVALID" : "LENGTH OK",
|
||||||
|
outgoing_msgs[i].flags & INVALID_DATA ? "DATA INVALID" : "DATA OK",
|
||||||
|
outgoing_msgs[i].flags & BROADCAST ? "BROADCAST" : "UNICAST");
|
||||||
|
outgoing_msgs[i].flags |= PRINTED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outgoing_msgs[i].flags & BROADCAST) {
|
||||||
|
outgoing_msgs[i].lifetime = 2;
|
||||||
|
broadcast_resp_count++;
|
||||||
|
if (broadcast_resp_count > 5) {
|
||||||
|
emac_if_free_outgoing_msg(i);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
emac_if_free_outgoing_msg(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!outgoing_msgs[i].lifetime) {
|
||||||
|
if (!(outgoing_msgs[i].flags & RESPONSE_RECEIVED) && (trace_level & TRACE_FAILURE)) {
|
||||||
|
printf("NO RESPONSE: receipt number %i\r\n\r\n", outgoing_msgs[i].receipt_number);
|
||||||
|
}
|
||||||
|
emac_if_free_outgoing_msg(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void emac_if_update_reply_to_outgoing_msg(int receipt_number, int lenght, int invalid_data_index)
|
||||||
|
{
|
||||||
|
int32_t outgoing_msg_index = emac_if_find_outgoing_msg(receipt_number);
|
||||||
|
|
||||||
|
if (outgoing_msg_index >= 0) {
|
||||||
|
outgoing_msgs[outgoing_msg_index].flags |= RESPONSE_RECEIVED;
|
||||||
|
|
||||||
|
#if MBED_CONF_APP_TEST_ETHERNET
|
||||||
|
if (outgoing_msgs[outgoing_msg_index].length < ETH_FRAME_MIN_LEN) {
|
||||||
|
if (lenght != ETH_FRAME_MIN_LEN) {
|
||||||
|
outgoing_msgs[outgoing_msg_index].flags |= INVALID_LENGHT;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
#endif
|
||||||
|
if (outgoing_msgs[outgoing_msg_index].length != lenght) {
|
||||||
|
outgoing_msgs[outgoing_msg_index].flags |= INVALID_LENGHT;
|
||||||
|
}
|
||||||
|
#if MBED_CONF_APP_TEST_ETHERNET
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (invalid_data_index && invalid_data_index < outgoing_msgs[outgoing_msg_index].length) {
|
||||||
|
outgoing_msgs[outgoing_msg_index].flags |= INVALID_DATA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void emac_if_add_echo_server_addr(unsigned char *addr)
|
||||||
|
{
|
||||||
|
if (etc_mac_echo_server_free_index == ECHO_SERVER_COUNT) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < etc_mac_echo_server_free_index; i++) {
|
||||||
|
if (memcmp(ð_mac_echo_server_addr[i][0], addr, ETH_MAC_ADDR_LEN) == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(ð_mac_echo_server_addr[etc_mac_echo_server_free_index][0], addr, ETH_MAC_ADDR_LEN);
|
||||||
|
etc_mac_echo_server_free_index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
int emac_if_count_echo_server_addr(void)
|
||||||
|
{
|
||||||
|
return etc_mac_echo_server_free_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char *emac_if_get_echo_server_addr(int index)
|
||||||
|
{
|
||||||
|
if (index < etc_mac_echo_server_free_index) {
|
||||||
|
return ð_mac_echo_server_addr[index][0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void emac_if_set_error_flags(unsigned int error_flags_value)
|
||||||
|
{
|
||||||
|
error_flags |= error_flags_value;
|
||||||
|
|
||||||
|
if (error_flags_value & NO_RESPONSE) {
|
||||||
|
no_response_cnt++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int emac_if_get_error_flags(void)
|
||||||
|
{
|
||||||
|
int error_flags_value = error_flags;
|
||||||
|
|
||||||
|
// Indicate no response error only if more than three messages are lost
|
||||||
|
if (error_flags_value & NO_RESPONSE) {
|
||||||
|
if (no_response_cnt < 3) {
|
||||||
|
error_flags_value &= ~NO_RESPONSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return error_flags_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void emac_if_reset_error_flags(void)
|
||||||
|
{
|
||||||
|
error_flags = 0;
|
||||||
|
no_response_cnt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void emac_if_print_error_flags(void)
|
||||||
|
{
|
||||||
|
int error_flags_value = emac_if_get_error_flags();
|
||||||
|
|
||||||
|
char no_resp_message[50];
|
||||||
|
if (error_flags_value & NO_RESPONSE) {
|
||||||
|
snprintf(no_resp_message, 50, "no response from echo server, counter: %i", no_response_cnt);
|
||||||
|
} else if (no_response_cnt > 0) {
|
||||||
|
printf("no response from echo server, counter: %i\r\n\r\n", no_response_cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("test result: %s%s%s%s%s%s\r\n\r\n",
|
||||||
|
error_flags_value ? "Test FAILED, reason: ": "PASS",
|
||||||
|
error_flags_value & TEST_FAILED ? "test failed ": "",
|
||||||
|
error_flags_value & MSG_VALID_ERROR ? "message content validation error ": "",
|
||||||
|
error_flags_value & OUT_OF_MSG_DATA ? "out of message validation data storage ": "",
|
||||||
|
error_flags_value & NO_FREE_MEM_BUF ? "no free memory buffers ": "",
|
||||||
|
error_flags_value & NO_RESPONSE ? no_resp_message: "");
|
||||||
|
}
|
||||||
|
|
||||||
|
void emac_if_set_trace_level(char trace_level_value)
|
||||||
|
{
|
||||||
|
trace_level = trace_level_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void emac_if_trace_to_ascii_hex_dump(const char *prefix, int len, unsigned char *data)
|
||||||
|
{
|
||||||
|
int line_len = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < len; i++) {
|
||||||
|
if ((line_len % 14) == 0) {
|
||||||
|
if (line_len != 0) {
|
||||||
|
printf("\r\n");
|
||||||
|
}
|
||||||
|
printf("%s %06x", prefix, line_len);
|
||||||
|
}
|
||||||
|
line_len++;
|
||||||
|
printf(" %02x", data[i]);
|
||||||
|
}
|
||||||
|
printf("\r\n\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void emac_if_link_state_change_cb(void *data, bool up)
|
||||||
|
{
|
||||||
|
if (up) {
|
||||||
|
worker_loop_event.post(LINK_UP);
|
||||||
|
} else {
|
||||||
|
worker_loop_event.post(LINK_DOWN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void emac_if_link_input_cb(void *data, emac_stack_mem_chain_t *mem_chain_p)
|
||||||
|
{
|
||||||
|
link_input_event.post(mem_chain_p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void link_input_event_cb(emac_stack_mem_chain_t *mem_chain_p)
|
||||||
|
{
|
||||||
|
int lenght = emac_stack_mem_len(0, mem_chain_p);
|
||||||
|
|
||||||
|
if (lenght >= ETH_FRAME_HEADER_LEN) {
|
||||||
|
// Ethernet input frame
|
||||||
|
unsigned char eth_input_frame_data[ETH_FRAME_HEADER_LEN];
|
||||||
|
memset(eth_input_frame_data, 0, ETH_FRAME_HEADER_LEN);
|
||||||
|
|
||||||
|
int invalid_data_index = emac_if_memory_buffer_read(mem_chain_p, eth_input_frame_data);
|
||||||
|
|
||||||
|
if (eth_input_frame_data[12] == 0x90 && eth_input_frame_data[13] == 0x00) {
|
||||||
|
unsigned char eth_output_frame_data[ETH_FRAME_HEADER_LEN];
|
||||||
|
int receipt_number;
|
||||||
|
|
||||||
|
ctp_function function = emac_if_ctp_header_handle(eth_input_frame_data, eth_output_frame_data, emac_if_get_hw_addr(), &receipt_number);
|
||||||
|
|
||||||
|
if (function == CTP_REPLY) {
|
||||||
|
emac_if_update_reply_to_outgoing_msg(receipt_number, lenght, invalid_data_index);
|
||||||
|
#if MBED_CONF_APP_ECHO_SERVER
|
||||||
|
// Echoes only if configured as echo server
|
||||||
|
} else if (function == CTP_FORWARD) {
|
||||||
|
emac_if_memory_buffer_write(mem_chain_p, eth_output_frame_data, false);
|
||||||
|
emac_if_get()->ops.link_out(emac_if_get(), mem_chain_p);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
emac_if_add_echo_server_addr(ð_input_frame_data[6]);
|
||||||
|
|
||||||
|
emac_stack_mem_free(0, mem_chain_p);
|
||||||
|
|
||||||
|
if (trace_level & TRACE_ETH_FRAMES) {
|
||||||
|
printf("LEN %i\r\n\r\n", lenght);
|
||||||
|
const char trace_type[] = "INP>";
|
||||||
|
emac_if_trace_to_ascii_hex_dump(trace_type, ETH_FRAME_HEADER_LEN, eth_input_frame_data);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forward other than CTP frames to lwip
|
||||||
|
struct netif *netif;
|
||||||
|
|
||||||
|
/* loop through netif's */
|
||||||
|
netif = netif_list;
|
||||||
|
if (netif != NULL) {
|
||||||
|
struct pbuf *p = (struct pbuf *)mem_chain_p;
|
||||||
|
|
||||||
|
/* pass all packets to ethernet_input, which decides what packets it supports */
|
||||||
|
if (netif->input(p, netif) != ERR_OK) {
|
||||||
|
emac_stack_mem_free(0, mem_chain_p);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
emac_stack_mem_free(0, mem_chain_p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void worker_loop_start(void (*test_step_cb_fnc)(void), int timeout)
|
||||||
|
{
|
||||||
|
int test_step_cb_timer = worker_loop_event_queue.call_every(timeout, test_step_cb_fnc);
|
||||||
|
int timeout_outgoing_msg_timer = worker_loop_event_queue.call_every(1000, emac_if_timeout_outgoing_msg);
|
||||||
|
|
||||||
|
#if MBED_CONF_APP_ECHO_SERVER
|
||||||
|
worker_loop_event_queue.dispatch_forever();
|
||||||
|
#else
|
||||||
|
worker_loop_event_queue.dispatch(600 * SECOND_TO_MS);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
worker_loop_event_queue.cancel(test_step_cb_timer);
|
||||||
|
worker_loop_event_queue.cancel(timeout_outgoing_msg_timer);
|
||||||
|
|
||||||
|
worker_loop_event_queue.dispatch(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void worker_loop_event_cb(int event)
|
||||||
|
{
|
||||||
|
if (event == LINK_UP) {
|
||||||
|
printf("cable connected\r\n\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event == LINK_DOWN) {
|
||||||
|
printf("cable disconnected\r\n\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void worker_loop_end(void)
|
||||||
|
{
|
||||||
|
worker_loop_event_queue.break_dispatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char *emac_if_get_own_addr(void)
|
||||||
|
{
|
||||||
|
return (emac_if_get_hw_addr());
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,93 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017, 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EMAC_UTIL_H
|
||||||
|
#define EMAC_UTIL_H
|
||||||
|
|
||||||
|
#define SECOND_TO_US 1000000
|
||||||
|
#define SECOND_TO_MS 1000
|
||||||
|
#define MS_TO_US 1000
|
||||||
|
|
||||||
|
extern const unsigned char eth_mac_broadcast_addr[];
|
||||||
|
|
||||||
|
// Trace flags
|
||||||
|
#define TRACE_ETH_FRAMES 0x01
|
||||||
|
#define TRACE_SUCCESS 0x02
|
||||||
|
#define TRACE_FAILURE 0x04
|
||||||
|
#define SET_TRACE_LEVEL(level) emac_if_set_trace_level(level)
|
||||||
|
|
||||||
|
// Message validation flags
|
||||||
|
#define BROADCAST 0x01
|
||||||
|
#define RESPONSE_RECEIVED 0x02
|
||||||
|
#define INVALID_LENGHT 0x04
|
||||||
|
#define INVALID_DATA 0x08
|
||||||
|
#define PRINTED 0x10
|
||||||
|
|
||||||
|
#define RESET_OUTGOING_MSG_DATA emac_if_reset_outgoing_msg()
|
||||||
|
|
||||||
|
// General error flags
|
||||||
|
#define TEST_FAILED 0x01
|
||||||
|
#define MSG_VALID_ERROR 0x02
|
||||||
|
#define OUT_OF_MSG_DATA 0x04
|
||||||
|
#define NO_FREE_MEM_BUF 0x08
|
||||||
|
#define NO_RESPONSE 0x10
|
||||||
|
|
||||||
|
#define ERROR_FLAGS emac_if_get_error_flags()
|
||||||
|
#define RESET_ERROR_FLAGS emac_if_reset_error_flags()
|
||||||
|
#define PRINT_ERROR_FLAGS emac_if_print_error_flags()
|
||||||
|
#define SET_ERROR_FLAGS(flags) emac_if_set_error_flags(flags)
|
||||||
|
|
||||||
|
#define ETH_FRAME_HEADER_LEN 28
|
||||||
|
#define ETH_FRAME_MIN_LEN 60
|
||||||
|
#define ETH_MAC_ADDR_LEN 6
|
||||||
|
|
||||||
|
int emac_if_find_outgoing_msg(int receipt_number);
|
||||||
|
void emac_if_free_outgoing_msg(int index);
|
||||||
|
int emac_if_count_outgoing_msg(void);
|
||||||
|
void emac_if_reset_outgoing_msg(void);
|
||||||
|
int emac_if_add_outgoing_msg(int length);
|
||||||
|
void emac_if_timeout_outgoing_msg(void);
|
||||||
|
void emac_if_validate_outgoing_msg(void);
|
||||||
|
void emac_if_set_outgoing_msg_receipt_num(int index, int receipt_number);
|
||||||
|
void emac_if_set_outgoing_msg_flags(int index, int flags);
|
||||||
|
|
||||||
|
void emac_if_add_echo_server_addr(unsigned char *addr);
|
||||||
|
int emac_if_count_echo_server_addr(void);
|
||||||
|
unsigned char *emac_if_get_echo_server_addr(int index);
|
||||||
|
|
||||||
|
void emac_if_set_error_flags(unsigned int error_flags_value);
|
||||||
|
unsigned int emac_if_get_error_flags(void);
|
||||||
|
void emac_if_reset_error_flags(void);
|
||||||
|
void emac_if_print_error_flags(void);
|
||||||
|
|
||||||
|
void emac_if_set_trace_level(char trace_level_value);
|
||||||
|
|
||||||
|
void emac_if_trace_to_ascii_hex_dump(const char *prefix, int len, char *data);
|
||||||
|
|
||||||
|
void emac_if_link_state_change_cb(void *data, bool up);
|
||||||
|
|
||||||
|
unsigned char *emac_if_get_own_addr(void);
|
||||||
|
|
||||||
|
extern void emac_if_link_input_cb(void *data, void *mem_chain_p);
|
||||||
|
extern void emac_if_link_state_change_cb(void *data, bool up);
|
||||||
|
|
||||||
|
void worker_loop_start(void (*test_step_cb_fnc)(void), int timeout);
|
||||||
|
void worker_loop_end(void);
|
||||||
|
|
||||||
|
void emac_if_init_main_thread(void);
|
||||||
|
|
||||||
|
#endif /* EMAC_UTIL_H */
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017, 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(MBED_CONF_APP_TEST_WIFI) || \
|
||||||
|
!defined(MBED_CONF_APP_TEST_ETHERNET) || \
|
||||||
|
!defined(MBED_CONF_APP_ECHO_SERVER) || \
|
||||||
|
!defined(MBED_CONF_APP_WIFI_SCAN) || \
|
||||||
|
!defined(MBED_CONF_APP_WIFI_SSID ) || \
|
||||||
|
!defined(MBED_CONF_APP_WIFI_SECURITY) || \
|
||||||
|
!defined(MBED_CONF_APP_WIFI_PASSWORD)
|
||||||
|
#error [NOT_SUPPORTED] Requires parameters from mbed_app.json
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !MBED_CONF_APP_TEST_WIFI && !MBED_CONF_APP_TEST_ETHERNET
|
||||||
|
#error [NOT_SUPPORTED] Either wifi or ethernet testing need to be enabled
|
||||||
|
#endif
|
||||||
|
#if MBED_CONF_APP_TEST_WIFI
|
||||||
|
#if !defined(TARGET_UBLOX_EVK_ODIN_W2) && !defined(TARGET_REALTEK_RTL8195AM)
|
||||||
|
#error [NOT_SUPPORTED] Tests are valid only for UBLOX_EVK_ODIN_W2 and REALTEK_RTL8195AM
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
#if MBED_CONF_APP_TEST_ETHERNET
|
||||||
|
#error [NOT_SUPPORTED] Ethernet testing not supported
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "greentea-client/test_env.h"
|
||||||
|
#include "unity/unity.h"
|
||||||
|
#include "utest.h"
|
||||||
|
|
||||||
|
#include "emac_tests.h"
|
||||||
|
#include "emac_util.h"
|
||||||
|
|
||||||
|
using namespace utest::v1;
|
||||||
|
|
||||||
|
// Test setup
|
||||||
|
utest::v1::status_t test_setup(const size_t number_of_cases) {
|
||||||
|
#if !MBED_CONF_APP_ECHO_SERVER
|
||||||
|
GREENTEA_SETUP(600, "default_auto");
|
||||||
|
#endif
|
||||||
|
return verbose_test_setup_handler(number_of_cases);
|
||||||
|
}
|
||||||
|
|
||||||
|
Case cases[] = {
|
||||||
|
Case("EMAC interface initialize", test_emac_initialize),
|
||||||
|
Case("EMAC interface broadcast", test_emac_broadcast),
|
||||||
|
Case("EMAC interface unicast", test_emac_unicast),
|
||||||
|
Case("EMAC interface unicast frame length", test_emac_unicast_frame_len),
|
||||||
|
Case("EMAC interface broadcast (run again)", test_emac_broadcast)
|
||||||
|
};
|
||||||
|
|
||||||
|
Specification specification(test_setup, cases);
|
||||||
|
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
return !Harness::run(specification);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
"config": {
|
||||||
|
"test-ethernet": {
|
||||||
|
"help": "Enable ethernet testing",
|
||||||
|
"value": 0
|
||||||
|
},
|
||||||
|
"test-wifi": {
|
||||||
|
"help": "Enable wifi testing",
|
||||||
|
"value": 1
|
||||||
|
},
|
||||||
|
"echo-server": {
|
||||||
|
"help": "Build test to be echo server",
|
||||||
|
"value": 0
|
||||||
|
},
|
||||||
|
"wifi-scan": {
|
||||||
|
"help": "Scan and list access points",
|
||||||
|
"value": 0
|
||||||
|
},
|
||||||
|
"wifi-ssid": {
|
||||||
|
"help": "WiFi SSID for network",
|
||||||
|
"value": "\"SSID\""
|
||||||
|
},
|
||||||
|
"wifi-security": {
|
||||||
|
"help": "WiFi Security",
|
||||||
|
"value": "NSAPI_SECURITY_WPA_WPA2"
|
||||||
|
},
|
||||||
|
"wifi-password": {
|
||||||
|
"help": "WiFi Password",
|
||||||
|
"value": "\"PASSWORD\""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -50,8 +50,10 @@ WiFiInterface *get_interface()
|
||||||
{
|
{
|
||||||
static WiFiInterface *interface = NULL;
|
static WiFiInterface *interface = NULL;
|
||||||
|
|
||||||
if (interface)
|
if (interface) {
|
||||||
delete interface;
|
interface->disconnect();
|
||||||
|
return interface;
|
||||||
|
}
|
||||||
|
|
||||||
#if MBED_CONF_APP_WIFI_DRIVER == INTERNAL
|
#if MBED_CONF_APP_WIFI_DRIVER == INTERNAL
|
||||||
interface = new DRIVER();
|
interface = new DRIVER();
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2017, 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 <cstring>
|
||||||
|
#include "mbed.h"
|
||||||
|
#include "nsapi_types.h"
|
||||||
|
|
||||||
|
nsapi_security get_security()
|
||||||
|
{
|
||||||
|
#if defined MBED_CONF_APP_WIFI_SECURE_PROTOCOL
|
||||||
|
static const char *SEC_WEP = "WEP";
|
||||||
|
static const char *SEC_WPA = "WPA";
|
||||||
|
static const char *SEC_WPA2 = "WPA2";
|
||||||
|
static const char *SEC_WPA_WPA2 = "WPA/WPA2";
|
||||||
|
|
||||||
|
if (strcmp(MBED_CONF_APP_WIFI_SECURE_PROTOCOL, SEC_WEP) == 0) {
|
||||||
|
return NSAPI_SECURITY_WEP;
|
||||||
|
}
|
||||||
|
if (strcmp(MBED_CONF_APP_WIFI_SECURE_PROTOCOL, SEC_WPA) == 0) {
|
||||||
|
return NSAPI_SECURITY_WPA;
|
||||||
|
}
|
||||||
|
if (strcmp(MBED_CONF_APP_WIFI_SECURE_PROTOCOL, SEC_WPA2) == 0) {
|
||||||
|
return NSAPI_SECURITY_WPA2;
|
||||||
|
}
|
||||||
|
if (strcmp(MBED_CONF_APP_WIFI_SECURE_PROTOCOL, SEC_WPA_WPA2) == 0) {
|
||||||
|
return NSAPI_SECURITY_WPA_WPA2;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return NSAPI_SECURITY_NONE;
|
||||||
|
}
|
|
@ -30,7 +30,8 @@
|
||||||
!defined(MBED_CONF_APP_WIFI_PASSWORD) || \
|
!defined(MBED_CONF_APP_WIFI_PASSWORD) || \
|
||||||
!defined(MBED_CONF_APP_WIFI_RX) || \
|
!defined(MBED_CONF_APP_WIFI_RX) || \
|
||||||
!defined(MBED_CONF_APP_WIFI_SECURE_SSID) || \
|
!defined(MBED_CONF_APP_WIFI_SECURE_SSID) || \
|
||||||
!defined(MBED_CONF_APP_WIFI_TX)
|
!defined(MBED_CONF_APP_WIFI_TX) || \
|
||||||
|
!defined MBED_CONF_APP_WIFI_SECURE_PROTOCOL
|
||||||
#error [NOT_SUPPORTED] Requires parameters from mbed_app.json (for secure connections)
|
#error [NOT_SUPPORTED] Requires parameters from mbed_app.json (for secure connections)
|
||||||
#endif
|
#endif
|
||||||
#endif // defined(MBED_CONF_APP_WIFI_SECURE_SSID)
|
#endif // defined(MBED_CONF_APP_WIFI_SECURE_SSID)
|
||||||
|
@ -58,6 +59,7 @@ utest::v1::status_t test_setup(const size_t number_of_cases) {
|
||||||
// Test cases
|
// Test cases
|
||||||
Case cases[] = {
|
Case cases[] = {
|
||||||
Case("WIFI-CONSTRUCTOR", wifi_constructor),
|
Case("WIFI-CONSTRUCTOR", wifi_constructor),
|
||||||
|
Case("WIFI-CONNECT-NOCREDENTIALS", wifi_connect_nocredentials),
|
||||||
Case("WIFI-SET-CREDENTIAL", wifi_set_credential),
|
Case("WIFI-SET-CREDENTIAL", wifi_set_credential),
|
||||||
Case("WIFI-SET-CHANNEL", wifi_set_channel),
|
Case("WIFI-SET-CHANNEL", wifi_set_channel),
|
||||||
#if defined(MBED_CONF_APP_WIFI_UNSECURE_SSID)
|
#if defined(MBED_CONF_APP_WIFI_UNSECURE_SSID)
|
||||||
|
@ -72,7 +74,6 @@ Case cases[] = {
|
||||||
Case("WIFI-CONNECT-PARAMS-CHANNEL", wifi_connect_params_channel),
|
Case("WIFI-CONNECT-PARAMS-CHANNEL", wifi_connect_params_channel),
|
||||||
Case("WIFI-CONNECT-PARAMS-CHANNEL-FAIL", wifi_connect_params_channel_fail),
|
Case("WIFI-CONNECT-PARAMS-CHANNEL-FAIL", wifi_connect_params_channel_fail),
|
||||||
#endif
|
#endif
|
||||||
Case("WIFI-CONNECT-NOCREDENTIALS", wifi_connect_nocredentials),
|
|
||||||
#if defined(MBED_CONF_APP_WIFI_UNSECURE_SSID)
|
#if defined(MBED_CONF_APP_WIFI_UNSECURE_SSID)
|
||||||
Case("WIFI-CONNECT", wifi_connect),
|
Case("WIFI-CONNECT", wifi_connect),
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -12,6 +12,10 @@
|
||||||
"help": "WiFi Password",
|
"help": "WiFi Password",
|
||||||
"value": "\"PASSWORD\""
|
"value": "\"PASSWORD\""
|
||||||
},
|
},
|
||||||
|
"wifi-secure-protocol": {
|
||||||
|
"help": "WiFi security protocol, valid values are WEP, WPA, WPA2, WPA/WPA2",
|
||||||
|
"value": "\"WPA/WPA2\""
|
||||||
|
},
|
||||||
"wifi-ch-secure": {
|
"wifi-ch-secure": {
|
||||||
"help": "Channel number of secure SSID",
|
"help": "Channel number of secure SSID",
|
||||||
"value": 1
|
"value": 1
|
||||||
|
|
|
@ -28,6 +28,5 @@ void wifi_connect_nocredentials(void)
|
||||||
WiFiInterface *wifi = get_interface();
|
WiFiInterface *wifi = get_interface();
|
||||||
nsapi_error_t error;
|
nsapi_error_t error;
|
||||||
error = wifi->connect();
|
error = wifi->connect();
|
||||||
wifi->disconnect();
|
TEST_ASSERT(error == NSAPI_ERROR_NO_SSID || error == NSAPI_ERROR_PARAMETER);
|
||||||
TEST_ASSERT(error == NSAPI_ERROR_PARAMETER);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ void wifi_connect_params_channel(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsapi_error_t error = wifi->connect(MBED_CONF_APP_WIFI_SECURE_SSID, MBED_CONF_APP_WIFI_PASSWORD, NSAPI_SECURITY_WPA2, MBED_CONF_APP_WIFI_CH_SECURE);
|
nsapi_error_t error = wifi->connect(MBED_CONF_APP_WIFI_SECURE_SSID, MBED_CONF_APP_WIFI_PASSWORD, get_security(), MBED_CONF_APP_WIFI_CH_SECURE);
|
||||||
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, error);
|
TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,7 +34,7 @@ void wifi_connect_params_channel_fail(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsapi_error_t error = wifi->connect(MBED_CONF_APP_WIFI_SECURE_SSID, MBED_CONF_APP_WIFI_PASSWORD, NSAPI_SECURITY_WPA2, MBED_CONF_APP_WIFI_CH_SECURE);
|
nsapi_error_t error = wifi->connect(MBED_CONF_APP_WIFI_SECURE_SSID, MBED_CONF_APP_WIFI_PASSWORD, get_security(), MBED_CONF_APP_WIFI_CH_SECURE);
|
||||||
TEST_ASSERT(error==NSAPI_ERROR_CONNECTION_TIMEOUT || error==NSAPI_ERROR_NO_CONNECTION);
|
TEST_ASSERT(error==NSAPI_ERROR_CONNECTION_TIMEOUT || error==NSAPI_ERROR_NO_CONNECTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,19 +29,7 @@ void wifi_connect_params_valid_secure(void)
|
||||||
{
|
{
|
||||||
WiFiInterface *wifi = get_interface();
|
WiFiInterface *wifi = get_interface();
|
||||||
|
|
||||||
if(wifi->connect(MBED_CONF_APP_WIFI_SECURE_SSID, MBED_CONF_APP_WIFI_PASSWORD, NSAPI_SECURITY_WPA2) == NSAPI_ERROR_OK) {
|
if(wifi->connect(MBED_CONF_APP_WIFI_SECURE_SSID, MBED_CONF_APP_WIFI_PASSWORD, get_security()) == NSAPI_ERROR_OK) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(wifi->connect(MBED_CONF_APP_WIFI_SECURE_SSID, MBED_CONF_APP_WIFI_PASSWORD, NSAPI_SECURITY_WPA_WPA2) == NSAPI_ERROR_OK) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(wifi->connect(MBED_CONF_APP_WIFI_SECURE_SSID, MBED_CONF_APP_WIFI_PASSWORD, NSAPI_SECURITY_WPA) == NSAPI_ERROR_OK) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(wifi->connect(MBED_CONF_APP_WIFI_SECURE_SSID, MBED_CONF_APP_WIFI_PASSWORD, NSAPI_SECURITY_WEP) == NSAPI_ERROR_OK) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ void wifi_connect_secure(void)
|
||||||
{
|
{
|
||||||
WiFiInterface *wifi = get_interface();
|
WiFiInterface *wifi = get_interface();
|
||||||
|
|
||||||
TEST_ASSERT_EQUAL_INT(NSAPI_ERROR_OK, wifi->set_credentials(MBED_CONF_APP_WIFI_SECURE_SSID, MBED_CONF_APP_WIFI_PASSWORD, NSAPI_SECURITY_WPA2));
|
TEST_ASSERT_EQUAL_INT(NSAPI_ERROR_OK, wifi->set_credentials(MBED_CONF_APP_WIFI_SECURE_SSID, MBED_CONF_APP_WIFI_PASSWORD, get_security()));
|
||||||
|
|
||||||
TEST_ASSERT_EQUAL_INT(NSAPI_ERROR_OK, wifi->connect());
|
TEST_ASSERT_EQUAL_INT(NSAPI_ERROR_OK, wifi->connect());
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ void wifi_connect_secure_fail(void)
|
||||||
{
|
{
|
||||||
WiFiInterface *wifi = get_interface();
|
WiFiInterface *wifi = get_interface();
|
||||||
|
|
||||||
TEST_ASSERT_EQUAL_INT(NSAPI_ERROR_OK, wifi->set_credentials(MBED_CONF_APP_WIFI_SECURE_SSID, "aaaaaaaa", NSAPI_SECURITY_WPA2));
|
TEST_ASSERT_EQUAL_INT(NSAPI_ERROR_OK, wifi->set_credentials(MBED_CONF_APP_WIFI_SECURE_SSID, "aaaaaaaa", get_security()));
|
||||||
|
|
||||||
TEST_ASSERT_EQUAL_INT(NSAPI_ERROR_AUTH_FAILURE, wifi->connect());
|
TEST_ASSERT_EQUAL_INT(NSAPI_ERROR_AUTH_FAILURE, wifi->connect());
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,20 +46,23 @@ void wifi_scan(void)
|
||||||
|
|
||||||
for (int i=0; i<size; i++) {
|
for (int i=0; i<size; i++) {
|
||||||
const char *ssid = ap[i].get_ssid();
|
const char *ssid = ap[i].get_ssid();
|
||||||
const uint8_t *bssid = ap[i].get_bssid();
|
|
||||||
nsapi_security_t security = ap[i].get_security();
|
nsapi_security_t security = ap[i].get_security();
|
||||||
int8_t rssi = ap[i].get_rssi();
|
int8_t rssi = ap[i].get_rssi();
|
||||||
uint8_t ch = ap[i].get_channel();
|
uint8_t ch = ap[i].get_channel();
|
||||||
TEST_ASSERT_INT8_WITHIN(-10, -100, rssi);
|
TEST_ASSERT_INT8_WITHIN(-10, -100, rssi);
|
||||||
if (strcmp(MBED_CONF_APP_WIFI_SECURE_SSID, ssid) == 0) {
|
if (strcmp(MBED_CONF_APP_WIFI_SECURE_SSID, ssid) == 0) {
|
||||||
secure_found = true;
|
secure_found = true;
|
||||||
TEST_ASSERT_EQUAL_INT(NSAPI_SECURITY_WPA2, security);
|
TEST_ASSERT_EQUAL_INT(get_security(), security);
|
||||||
TEST_ASSERT_EQUAL_INT(MBED_CONF_APP_WIFI_CH_SECURE, ch);
|
if (MBED_CONF_APP_WIFI_CH_SECURE) {
|
||||||
|
TEST_ASSERT_EQUAL_INT(MBED_CONF_APP_WIFI_CH_SECURE, ch);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (strcmp(MBED_CONF_APP_WIFI_UNSECURE_SSID, ssid) == 0) {
|
if (strcmp(MBED_CONF_APP_WIFI_UNSECURE_SSID, ssid) == 0) {
|
||||||
unsecure_found = true;
|
unsecure_found = true;
|
||||||
TEST_ASSERT_EQUAL_INT(NSAPI_SECURITY_NONE, security);
|
TEST_ASSERT_EQUAL_INT(NSAPI_SECURITY_NONE, security);
|
||||||
TEST_ASSERT_EQUAL_INT(MBED_CONF_APP_WIFI_CH_UNSECURE, ch);
|
if (MBED_CONF_APP_WIFI_CH_UNSECURE) {
|
||||||
|
TEST_ASSERT_EQUAL_INT(MBED_CONF_APP_WIFI_CH_UNSECURE, ch);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TEST_ASSERT_TRUE(secure_found);
|
TEST_ASSERT_TRUE(secure_found);
|
||||||
|
|
|
@ -47,17 +47,17 @@ void wifi_set_credential(void)
|
||||||
TEST_ASSERT((error == NSAPI_ERROR_OK) || (error == NSAPI_ERROR_UNSUPPORTED));
|
TEST_ASSERT((error == NSAPI_ERROR_OK) || (error == NSAPI_ERROR_UNSUPPORTED));
|
||||||
|
|
||||||
error = iface->set_credentials("OK", "12345678", NSAPI_SECURITY_WPA);
|
error = iface->set_credentials("OK", "12345678", NSAPI_SECURITY_WPA);
|
||||||
TEST_ASSERT(error == NSAPI_ERROR_OK);
|
TEST_ASSERT((error == NSAPI_ERROR_OK) || (error == NSAPI_ERROR_UNSUPPORTED));
|
||||||
|
|
||||||
error = iface->set_credentials("OK", "12345678", NSAPI_SECURITY_WPA2);
|
error = iface->set_credentials("OK", "12345678", NSAPI_SECURITY_WPA2);
|
||||||
TEST_ASSERT(error == NSAPI_ERROR_OK);
|
TEST_ASSERT((error == NSAPI_ERROR_OK) || (error == NSAPI_ERROR_UNSUPPORTED));
|
||||||
|
|
||||||
error = iface->set_credentials("OK", "12345678", NSAPI_SECURITY_WPA_WPA2);
|
error = iface->set_credentials("OK", "12345678", NSAPI_SECURITY_WPA_WPA2);
|
||||||
TEST_ASSERT(error == NSAPI_ERROR_OK);
|
TEST_ASSERT(error == NSAPI_ERROR_OK);
|
||||||
|
|
||||||
error = iface->set_credentials("OK", "kUjd0PHHeAqaDoyfcDDEOvbyiVbYMpUHDukGoR6EJZnO5iLzWsfwiM9JQqOngni", NSAPI_SECURITY_WPA2);
|
error = iface->set_credentials("OK", "kUjd0PHHeAqaDoyfcDDEOvbyiVbYMpUHDukGoR6EJZnO5iLzWsfwiM9JQqOngni", get_security());
|
||||||
TEST_ASSERT(error == NSAPI_ERROR_OK);
|
TEST_ASSERT(error == NSAPI_ERROR_OK);
|
||||||
|
|
||||||
error = iface->set_credentials("OK", "kUjd0PHHeAqaDoyfcDDEOvbyiVbYMpUHDukGoR6EJZnO5iLzWsfwiM9JQqOngni8", NSAPI_SECURITY_WPA2);
|
error = iface->set_credentials("OK", "kUjd0PHHeAqaDoyfcDDEOvbyiVbYMpUHDukGoR6EJZnO5iLzWsfwiM9JQqOngni8", get_security());
|
||||||
TEST_ASSERT(error == NSAPI_ERROR_PARAMETER);
|
TEST_ASSERT(error == NSAPI_ERROR_PARAMETER);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,11 @@
|
||||||
* app_json. */
|
* app_json. */
|
||||||
WiFiInterface *get_interface(void);
|
WiFiInterface *get_interface(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get security protocol to be used
|
||||||
|
*/
|
||||||
|
nsapi_security get_security(void);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Test cases
|
* Test cases
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -37,26 +37,29 @@
|
||||||
/* CMSIS compiler specific defines */
|
/* CMSIS compiler specific defines */
|
||||||
#ifndef __ASM
|
#ifndef __ASM
|
||||||
#define __ASM __asm
|
#define __ASM __asm
|
||||||
#endif
|
#endif
|
||||||
#ifndef __INLINE
|
#ifndef __INLINE
|
||||||
#define __INLINE __inline
|
#define __INLINE __inline
|
||||||
#endif
|
#endif
|
||||||
#ifndef __FORCEINLINE
|
#ifndef __FORCEINLINE
|
||||||
#define __FORCEINLINE __forceinline
|
#define __FORCEINLINE __forceinline
|
||||||
#endif
|
#endif
|
||||||
#ifndef __STATIC_INLINE
|
#ifndef __STATIC_INLINE
|
||||||
#define __STATIC_INLINE static __inline
|
#define __STATIC_INLINE static __inline
|
||||||
#endif
|
#endif
|
||||||
#ifndef __STATIC_FORCEINLINE
|
#ifndef __STATIC_FORCEINLINE
|
||||||
#define __STATIC_FORCEINLINE static __forceinline
|
#define __STATIC_FORCEINLINE static __forceinline
|
||||||
#endif
|
#endif
|
||||||
#ifndef __NO_RETURN
|
#ifndef __NO_RETURN
|
||||||
#define __NO_RETURN __declspec(noreturn)
|
#define __NO_RETURN __declspec(noreturn)
|
||||||
#endif
|
#endif
|
||||||
#ifndef __USED
|
#ifndef CMSIS_DEPRECATED
|
||||||
|
#define CMSIS_DEPRECATED __attribute__((deprecated))
|
||||||
|
#endif
|
||||||
|
#ifndef __USED
|
||||||
#define __USED __attribute__((used))
|
#define __USED __attribute__((used))
|
||||||
#endif
|
#endif
|
||||||
#ifndef __WEAK
|
#ifndef __WEAK
|
||||||
#define __WEAK __attribute__((weak))
|
#define __WEAK __attribute__((weak))
|
||||||
#endif
|
#endif
|
||||||
#ifndef __PACKED
|
#ifndef __PACKED
|
||||||
|
@ -79,8 +82,8 @@
|
||||||
#endif
|
#endif
|
||||||
#ifndef __ALIGNED
|
#ifndef __ALIGNED
|
||||||
#define __ALIGNED(x) __attribute__((aligned(x)))
|
#define __ALIGNED(x) __attribute__((aligned(x)))
|
||||||
#endif
|
#endif
|
||||||
#ifndef __PACKED
|
#ifndef __PACKED
|
||||||
#define __PACKED __attribute__((packed))
|
#define __PACKED __attribute__((packed))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -134,6 +137,7 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Reverse byte order (32 bit)
|
\brief Reverse byte order (32 bit)
|
||||||
|
\details Reverses the byte order in unsigned integer value. For example, 0x12345678 becomes 0x78563412.
|
||||||
\param [in] value Value to reverse
|
\param [in] value Value to reverse
|
||||||
\return Reversed value
|
\return Reversed value
|
||||||
*/
|
*/
|
||||||
|
@ -141,6 +145,7 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Reverse byte order (16 bit)
|
\brief Reverse byte order (16 bit)
|
||||||
|
\details Reverses the byte order within each halfword of a word. For example, 0x12345678 becomes 0x34127856.
|
||||||
\param [in] value Value to reverse
|
\param [in] value Value to reverse
|
||||||
\return Reversed value
|
\return Reversed value
|
||||||
*/
|
*/
|
||||||
|
@ -153,12 +158,13 @@ __attribute__((section(".rev16_text"))) __STATIC_INLINE __ASM uint32_t __REV16(u
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Reverse byte order in signed short value
|
\brief Reverse byte order (16 bit)
|
||||||
|
\details Reverses the byte order in a 16-bit value and returns the signed 16-bit result. For example, 0x0080 becomes 0x8000.
|
||||||
\param [in] value Value to reverse
|
\param [in] value Value to reverse
|
||||||
\return Reversed value
|
\return Reversed value
|
||||||
*/
|
*/
|
||||||
#ifndef __NO_EMBEDDED_ASM
|
#ifndef __NO_EMBEDDED_ASM
|
||||||
__attribute__((section(".revsh_text"))) __STATIC_INLINE __ASM int32_t __REVSH(int32_t value)
|
__attribute__((section(".revsh_text"))) __STATIC_INLINE __ASM int16_t __REVSH(int16_t value)
|
||||||
{
|
{
|
||||||
revsh r0, r0
|
revsh r0, r0
|
||||||
bx lr
|
bx lr
|
||||||
|
@ -351,14 +357,16 @@ __STATIC_INLINE void __set_CPSR(uint32_t cpsr)
|
||||||
/** \brief Get Mode
|
/** \brief Get Mode
|
||||||
\return Processor Mode
|
\return Processor Mode
|
||||||
*/
|
*/
|
||||||
__STATIC_INLINE uint32_t __get_mode(void) {
|
__STATIC_INLINE uint32_t __get_mode(void)
|
||||||
|
{
|
||||||
return (__get_CPSR() & 0x1FU);
|
return (__get_CPSR() & 0x1FU);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \brief Set Mode
|
/** \brief Set Mode
|
||||||
\param [in] mode Mode value to set
|
\param [in] mode Mode value to set
|
||||||
*/
|
*/
|
||||||
__STATIC_INLINE __ASM void __set_mode(uint32_t mode) {
|
__STATIC_INLINE __ASM void __set_mode(uint32_t mode)
|
||||||
|
{
|
||||||
MOV r1, lr
|
MOV r1, lr
|
||||||
MSR CPSR_C, r0
|
MSR CPSR_C, r0
|
||||||
BX r1
|
BX r1
|
||||||
|
@ -373,7 +381,7 @@ __STATIC_INLINE __ASM uint32_t __get_SP(void)
|
||||||
BX lr
|
BX lr
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \brief Set Stack Pointer
|
/** \brief Set Stack Pointer
|
||||||
\param [in] stack Stack Pointer value to set
|
\param [in] stack Stack Pointer value to set
|
||||||
*/
|
*/
|
||||||
__STATIC_INLINE __ASM void __set_SP(uint32_t stack)
|
__STATIC_INLINE __ASM void __set_SP(uint32_t stack)
|
||||||
|
@ -442,75 +450,32 @@ __STATIC_INLINE void __set_FPEXC(uint32_t fpexc)
|
||||||
/*
|
/*
|
||||||
* Include common core functions to access Coprocessor 15 registers
|
* Include common core functions to access Coprocessor 15 registers
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define __get_CP(cp, op1, Rt, CRn, CRm, op2) do { register uint32_t tmp __ASM("cp" # cp ":" # op1 ":c" # CRn ":c" # CRm ":" # op2); Rt = tmp; } while(0)
|
#define __get_CP(cp, op1, Rt, CRn, CRm, op2) do { register uint32_t tmp __ASM("cp" # cp ":" # op1 ":c" # CRn ":c" # CRm ":" # op2); (Rt) = tmp; } while(0)
|
||||||
#define __set_CP(cp, op1, Rt, CRn, CRm, op2) do { register uint32_t tmp __ASM("cp" # cp ":" # op1 ":c" # CRn ":c" # CRm ":" # op2); tmp = Rt; } while(0)
|
#define __set_CP(cp, op1, Rt, CRn, CRm, op2) do { register uint32_t tmp __ASM("cp" # cp ":" # op1 ":c" # CRn ":c" # CRm ":" # op2); tmp = (Rt); } while(0)
|
||||||
|
#define __get_CP64(cp, op1, Rt, CRm) \
|
||||||
|
do { \
|
||||||
|
uint32_t ltmp, htmp; \
|
||||||
|
__ASM volatile("MRRC p" # cp ", " # op1 ", ltmp, htmp, c" # CRm); \
|
||||||
|
(Rt) = ((((uint64_t)htmp) << 32U) | ((uint64_t)ltmp)); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define __set_CP64(cp, op1, Rt, CRm) \
|
||||||
|
do { \
|
||||||
|
const uint64_t tmp = (Rt); \
|
||||||
|
const uint32_t ltmp = (uint32_t)(tmp); \
|
||||||
|
const uint32_t htmp = (uint32_t)(tmp >> 32U); \
|
||||||
|
__ASM volatile("MCRR p" # cp ", " # op1 ", ltmp, htmp, c" # CRm); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
#include "cmsis_cp15.h"
|
#include "cmsis_cp15.h"
|
||||||
|
|
||||||
/** \brief Clean and Invalidate the entire data or unified cache
|
|
||||||
* \param [in] op 0 - invalidate, 1 - clean, otherwise - invalidate and clean
|
|
||||||
*/
|
|
||||||
__STATIC_INLINE __ASM void __L1C_CleanInvalidateCache(uint32_t op) {
|
|
||||||
ARM
|
|
||||||
|
|
||||||
PUSH {R4-R11}
|
|
||||||
|
|
||||||
MRC p15, 1, R6, c0, c0, 1 // Read CLIDR
|
|
||||||
ANDS R3, R6, #0x07000000 // Extract coherency level
|
|
||||||
MOV R3, R3, LSR #23 // Total cache levels << 1
|
|
||||||
BEQ Finished // If 0, no need to clean
|
|
||||||
|
|
||||||
MOV R10, #0 // R10 holds current cache level << 1
|
|
||||||
Loop1 ADD R2, R10, R10, LSR #1 // R2 holds cache "Set" position
|
|
||||||
MOV R1, R6, LSR R2 // Bottom 3 bits are the Cache-type for this level
|
|
||||||
AND R1, R1, #7 // Isolate those lower 3 bits
|
|
||||||
CMP R1, #2
|
|
||||||
BLT Skip // No cache or only instruction cache at this level
|
|
||||||
|
|
||||||
MCR p15, 2, R10, c0, c0, 0 // Write the Cache Size selection register
|
|
||||||
ISB // ISB to sync the change to the CacheSizeID reg
|
|
||||||
MRC p15, 1, R1, c0, c0, 0 // Reads current Cache Size ID register
|
|
||||||
AND R2, R1, #7 // Extract the line length field
|
|
||||||
ADD R2, R2, #4 // Add 4 for the line length offset (log2 16 bytes)
|
|
||||||
LDR R4, =0x3FF
|
|
||||||
ANDS R4, R4, R1, LSR #3 // R4 is the max number on the way size (right aligned)
|
|
||||||
CLZ R5, R4 // R5 is the bit position of the way size increment
|
|
||||||
LDR R7, =0x7FFF
|
|
||||||
ANDS R7, R7, R1, LSR #13 // R7 is the max number of the index size (right aligned)
|
|
||||||
|
|
||||||
Loop2 MOV R9, R4 // R9 working copy of the max way size (right aligned)
|
|
||||||
|
|
||||||
Loop3 ORR R11, R10, R9, LSL R5 // Factor in the Way number and cache number into R11
|
|
||||||
ORR R11, R11, R7, LSL R2 // Factor in the Set number
|
|
||||||
CMP R0, #0
|
|
||||||
BNE Dccsw
|
|
||||||
MCR p15, 0, R11, c7, c6, 2 // DCISW. Invalidate by Set/Way
|
|
||||||
B cont
|
|
||||||
Dccsw CMP R0, #1
|
|
||||||
BNE Dccisw
|
|
||||||
MCR p15, 0, R11, c7, c10, 2 // DCCSW. Clean by Set/Way
|
|
||||||
B cont
|
|
||||||
Dccisw MCR p15, 0, R11, c7, c14, 2 // DCCISW. Clean and Invalidate by Set/Way
|
|
||||||
cont SUBS R9, R9, #1 // Decrement the Way number
|
|
||||||
BGE Loop3
|
|
||||||
SUBS R7, R7, #1 // Decrement the Set number
|
|
||||||
BGE Loop2
|
|
||||||
Skip ADD R10, R10, #2 // Increment the cache number
|
|
||||||
CMP R3, R10
|
|
||||||
BGT Loop1
|
|
||||||
|
|
||||||
Finished
|
|
||||||
DSB
|
|
||||||
POP {R4-R11}
|
|
||||||
BX lr
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \brief Enable Floating Point Unit
|
/** \brief Enable Floating Point Unit
|
||||||
|
|
||||||
Critical section, called from undef handler, so systick is disabled
|
Critical section, called from undef handler, so systick is disabled
|
||||||
*/
|
*/
|
||||||
__STATIC_INLINE __ASM void __FPU_Enable(void) {
|
__STATIC_INLINE __ASM void __FPU_Enable(void)
|
||||||
|
{
|
||||||
ARM
|
ARM
|
||||||
|
|
||||||
//Permit access to VFP/NEON, registers by modifying CPACR
|
//Permit access to VFP/NEON, registers by modifying CPACR
|
||||||
|
@ -528,7 +493,7 @@ __STATIC_INLINE __ASM void __FPU_Enable(void) {
|
||||||
|
|
||||||
//Initialise VFP/NEON registers to 0
|
//Initialise VFP/NEON registers to 0
|
||||||
MOV R2,#0
|
MOV R2,#0
|
||||||
IF {TARGET_FEATURE_EXTENSION_REGISTER_COUNT} >= 16
|
|
||||||
//Initialise D16 registers to 0
|
//Initialise D16 registers to 0
|
||||||
VMOV D0, R2,R2
|
VMOV D0, R2,R2
|
||||||
VMOV D1, R2,R2
|
VMOV D1, R2,R2
|
||||||
|
@ -546,7 +511,7 @@ __STATIC_INLINE __ASM void __FPU_Enable(void) {
|
||||||
VMOV D13,R2,R2
|
VMOV D13,R2,R2
|
||||||
VMOV D14,R2,R2
|
VMOV D14,R2,R2
|
||||||
VMOV D15,R2,R2
|
VMOV D15,R2,R2
|
||||||
ENDIF
|
|
||||||
IF {TARGET_FEATURE_EXTENSION_REGISTER_COUNT} == 32
|
IF {TARGET_FEATURE_EXTENSION_REGISTER_COUNT} == 32
|
||||||
//Initialise D32 registers to 0
|
//Initialise D32 registers to 0
|
||||||
VMOV D16,R2,R2
|
VMOV D16,R2,R2
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
#ifndef __CMSIS_ARMCLANG_H
|
#ifndef __CMSIS_ARMCLANG_H
|
||||||
#define __CMSIS_ARMCLANG_H
|
#define __CMSIS_ARMCLANG_H
|
||||||
|
|
||||||
|
#pragma clang system_header /* treat file as system include file */
|
||||||
|
|
||||||
#ifndef __ARM_COMPAT_H
|
#ifndef __ARM_COMPAT_H
|
||||||
#include <arm_compat.h> /* Compatibility header for ARM Compiler 5 intrinsics */
|
#include <arm_compat.h> /* Compatibility header for ARM Compiler 5 intrinsics */
|
||||||
#endif
|
#endif
|
||||||
|
@ -32,26 +34,29 @@
|
||||||
/* CMSIS compiler specific defines */
|
/* CMSIS compiler specific defines */
|
||||||
#ifndef __ASM
|
#ifndef __ASM
|
||||||
#define __ASM __asm
|
#define __ASM __asm
|
||||||
#endif
|
#endif
|
||||||
#ifndef __INLINE
|
#ifndef __INLINE
|
||||||
#define __INLINE __inline
|
#define __INLINE __inline
|
||||||
#endif
|
#endif
|
||||||
#ifndef __FORCEINLINE
|
#ifndef __FORCEINLINE
|
||||||
#define __FORCEINLINE __attribute__((always_inline))
|
#define __FORCEINLINE __attribute__((always_inline))
|
||||||
#endif
|
#endif
|
||||||
#ifndef __STATIC_INLINE
|
#ifndef __STATIC_INLINE
|
||||||
#define __STATIC_INLINE static __inline
|
#define __STATIC_INLINE static __inline
|
||||||
#endif
|
#endif
|
||||||
#ifndef __STATIC_FORCEINLINE
|
#ifndef __STATIC_FORCEINLINE
|
||||||
#define __STATIC_FORCEINLINE __attribute__((always_inline)) static __inline
|
#define __STATIC_FORCEINLINE __attribute__((always_inline)) static __inline
|
||||||
#endif
|
#endif
|
||||||
#ifndef __NO_RETURN
|
#ifndef __NO_RETURN
|
||||||
#define __NO_RETURN __declspec(noreturn)
|
#define __NO_RETURN __attribute__((__noreturn__))
|
||||||
#endif
|
#endif
|
||||||
#ifndef __USED
|
#ifndef CMSIS_DEPRECATED
|
||||||
|
#define CMSIS_DEPRECATED __attribute__((deprecated))
|
||||||
|
#endif
|
||||||
|
#ifndef __USED
|
||||||
#define __USED __attribute__((used))
|
#define __USED __attribute__((used))
|
||||||
#endif
|
#endif
|
||||||
#ifndef __WEAK
|
#ifndef __WEAK
|
||||||
#define __WEAK __attribute__((weak))
|
#define __WEAK __attribute__((weak))
|
||||||
#endif
|
#endif
|
||||||
#ifndef __PACKED
|
#ifndef __PACKED
|
||||||
|
@ -93,8 +98,8 @@
|
||||||
#endif
|
#endif
|
||||||
#ifndef __ALIGNED
|
#ifndef __ALIGNED
|
||||||
#define __ALIGNED(x) __attribute__((aligned(x)))
|
#define __ALIGNED(x) __attribute__((aligned(x)))
|
||||||
#endif
|
#endif
|
||||||
#ifndef __PACKED
|
#ifndef __PACKED
|
||||||
#define __PACKED __attribute__((packed))
|
#define __PACKED __attribute__((packed))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -148,38 +153,29 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Reverse byte order (32 bit)
|
\brief Reverse byte order (32 bit)
|
||||||
|
\details Reverses the byte order in unsigned integer value. For example, 0x12345678 becomes 0x78563412.
|
||||||
\param [in] value Value to reverse
|
\param [in] value Value to reverse
|
||||||
\return Reversed value
|
\return Reversed value
|
||||||
*/
|
*/
|
||||||
#define __REV __builtin_bswap32
|
#define __REV(value) __builtin_bswap32(value)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Reverse byte order (16 bit)
|
\brief Reverse byte order (16 bit)
|
||||||
|
\details Reverses the byte order within each halfword of a word. For example, 0x12345678 becomes 0x34127856.
|
||||||
\param [in] value Value to reverse
|
\param [in] value Value to reverse
|
||||||
\return Reversed value
|
\return Reversed value
|
||||||
*/
|
*/
|
||||||
#ifndef __NO_EMBEDDED_ASM
|
#define __REV16(value) __ROR(__REV(value), 16)
|
||||||
__attribute__((section(".rev16_text"))) __STATIC_INLINE uint32_t __REV16(uint32_t value)
|
|
||||||
{
|
|
||||||
uint32_t result;
|
|
||||||
__ASM volatile("rev16 %0, %1" : "=r" (result) : "r" (value));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Reverse byte order in signed short value
|
\brief Reverse byte order (16 bit)
|
||||||
|
\details Reverses the byte order in a 16-bit value and returns the signed 16-bit result. For example, 0x0080 becomes 0x8000.
|
||||||
\param [in] value Value to reverse
|
\param [in] value Value to reverse
|
||||||
\return Reversed value
|
\return Reversed value
|
||||||
*/
|
*/
|
||||||
#ifndef __NO_EMBEDDED_ASM
|
#define __REVSH(value) (int16_t)__builtin_bswap16(value)
|
||||||
__attribute__((section(".revsh_text"))) __STATIC_INLINE int32_t __REVSH(int32_t value)
|
|
||||||
{
|
|
||||||
int32_t result;
|
|
||||||
__ASM volatile("revsh %0, %1" : "=r" (result) : "r" (value));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Rotate Right in unsigned value (32 bit)
|
\brief Rotate Right in unsigned value (32 bit)
|
||||||
|
@ -188,31 +184,37 @@ __attribute__((section(".revsh_text"))) __STATIC_INLINE int32_t __REVSH(int32_t
|
||||||
\param [in] op2 Number of Bits to rotate
|
\param [in] op2 Number of Bits to rotate
|
||||||
\return Rotated value
|
\return Rotated value
|
||||||
*/
|
*/
|
||||||
__attribute__((always_inline)) __STATIC_INLINE uint32_t __ROR(uint32_t op1, uint32_t op2)
|
__STATIC_FORCEINLINE uint32_t __ROR(uint32_t op1, uint32_t op2)
|
||||||
{
|
{
|
||||||
|
op2 %= 32U;
|
||||||
|
if (op2 == 0U)
|
||||||
|
{
|
||||||
|
return op1;
|
||||||
|
}
|
||||||
return (op1 >> op2) | (op1 << (32U - op2));
|
return (op1 >> op2) | (op1 << (32U - op2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Breakpoint
|
\brief Breakpoint
|
||||||
\param [in] value is ignored by the processor.
|
\param [in] value is ignored by the processor.
|
||||||
If required, a debugger can use it to store additional information about the breakpoint.
|
If required, a debugger can use it to store additional information about the breakpoint.
|
||||||
*/
|
*/
|
||||||
#define __BKPT(value) __ASM volatile ("bkpt "#value)
|
#define __BKPT(value) __ASM volatile ("bkpt "#value)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Reverse bit order of value
|
\brief Reverse bit order of value
|
||||||
\param [in] value Value to reverse
|
\param [in] value Value to reverse
|
||||||
\return Reversed value
|
\return Reversed value
|
||||||
*/
|
*/
|
||||||
#define __RBIT __builtin_arm_rbit
|
#define __RBIT __builtin_arm_rbit
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Count leading zeros
|
\brief Count leading zeros
|
||||||
\param [in] value Value to count the leading zeros
|
\param [in] value Value to count the leading zeros
|
||||||
\return number of leading zeros in value
|
\return number of leading zeros in value
|
||||||
*/
|
*/
|
||||||
#define __CLZ __builtin_clz
|
#define __CLZ (uint8_t)__builtin_clz
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief LDR Exclusive (8 bit)
|
\brief LDR Exclusive (8 bit)
|
||||||
|
@ -313,7 +315,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __ROR(uint32_t op1, uint
|
||||||
/** \brief Get CPSR Register
|
/** \brief Get CPSR Register
|
||||||
\return CPSR Register value
|
\return CPSR Register value
|
||||||
*/
|
*/
|
||||||
__attribute__((always_inline)) __STATIC_INLINE uint32_t __get_CPSR(void)
|
__STATIC_FORCEINLINE uint32_t __get_CPSR(void)
|
||||||
{
|
{
|
||||||
uint32_t result;
|
uint32_t result;
|
||||||
__ASM volatile("MRS %0, cpsr" : "=r" (result) );
|
__ASM volatile("MRS %0, cpsr" : "=r" (result) );
|
||||||
|
@ -323,7 +325,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __get_CPSR(void)
|
||||||
/** \brief Set CPSR Register
|
/** \brief Set CPSR Register
|
||||||
\param [in] cpsr CPSR value to set
|
\param [in] cpsr CPSR value to set
|
||||||
*/
|
*/
|
||||||
__attribute__((always_inline)) __STATIC_INLINE void __set_CPSR(uint32_t cpsr)
|
__STATIC_FORCEINLINE void __set_CPSR(uint32_t cpsr)
|
||||||
{
|
{
|
||||||
__ASM volatile ("MSR cpsr, %0" : : "r" (cpsr) : "memory");
|
__ASM volatile ("MSR cpsr, %0" : : "r" (cpsr) : "memory");
|
||||||
}
|
}
|
||||||
|
@ -331,7 +333,7 @@ __ASM volatile ("MSR cpsr, %0" : : "r" (cpsr) : "memory");
|
||||||
/** \brief Get Mode
|
/** \brief Get Mode
|
||||||
\return Processor Mode
|
\return Processor Mode
|
||||||
*/
|
*/
|
||||||
__attribute__((always_inline)) __STATIC_INLINE uint32_t __get_mode(void)
|
__STATIC_FORCEINLINE uint32_t __get_mode(void)
|
||||||
{
|
{
|
||||||
return (__get_CPSR() & 0x1FU);
|
return (__get_CPSR() & 0x1FU);
|
||||||
}
|
}
|
||||||
|
@ -339,7 +341,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __get_mode(void)
|
||||||
/** \brief Set Mode
|
/** \brief Set Mode
|
||||||
\param [in] mode Mode value to set
|
\param [in] mode Mode value to set
|
||||||
*/
|
*/
|
||||||
__attribute__((always_inline)) __STATIC_INLINE void __set_mode(uint32_t mode)
|
__STATIC_FORCEINLINE void __set_mode(uint32_t mode)
|
||||||
{
|
{
|
||||||
__ASM volatile("MSR cpsr_c, %0" : : "r" (mode) : "memory");
|
__ASM volatile("MSR cpsr_c, %0" : : "r" (mode) : "memory");
|
||||||
}
|
}
|
||||||
|
@ -347,7 +349,7 @@ __attribute__((always_inline)) __STATIC_INLINE void __set_mode(uint32_t mode)
|
||||||
/** \brief Get Stack Pointer
|
/** \brief Get Stack Pointer
|
||||||
\return Stack Pointer value
|
\return Stack Pointer value
|
||||||
*/
|
*/
|
||||||
__attribute__((always_inline)) __STATIC_INLINE uint32_t __get_SP()
|
__STATIC_FORCEINLINE uint32_t __get_SP()
|
||||||
{
|
{
|
||||||
uint32_t result;
|
uint32_t result;
|
||||||
__ASM volatile("MOV %0, sp" : "=r" (result) : : "memory");
|
__ASM volatile("MOV %0, sp" : "=r" (result) : : "memory");
|
||||||
|
@ -357,7 +359,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __get_SP()
|
||||||
/** \brief Set Stack Pointer
|
/** \brief Set Stack Pointer
|
||||||
\param [in] stack Stack Pointer value to set
|
\param [in] stack Stack Pointer value to set
|
||||||
*/
|
*/
|
||||||
__attribute__((always_inline)) __STATIC_INLINE void __set_SP(uint32_t stack)
|
__STATIC_FORCEINLINE void __set_SP(uint32_t stack)
|
||||||
{
|
{
|
||||||
__ASM volatile("MOV sp, %0" : : "r" (stack) : "memory");
|
__ASM volatile("MOV sp, %0" : : "r" (stack) : "memory");
|
||||||
}
|
}
|
||||||
|
@ -365,7 +367,7 @@ __attribute__((always_inline)) __STATIC_INLINE void __set_SP(uint32_t stack)
|
||||||
/** \brief Get USR/SYS Stack Pointer
|
/** \brief Get USR/SYS Stack Pointer
|
||||||
\return USR/SYS Stack Pointer value
|
\return USR/SYS Stack Pointer value
|
||||||
*/
|
*/
|
||||||
__attribute__((always_inline)) __STATIC_INLINE uint32_t __get_SP_usr()
|
__STATIC_FORCEINLINE uint32_t __get_SP_usr()
|
||||||
{
|
{
|
||||||
uint32_t cpsr;
|
uint32_t cpsr;
|
||||||
uint32_t result;
|
uint32_t result;
|
||||||
|
@ -382,7 +384,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __get_SP_usr()
|
||||||
/** \brief Set USR/SYS Stack Pointer
|
/** \brief Set USR/SYS Stack Pointer
|
||||||
\param [in] topOfProcStack USR/SYS Stack Pointer value to set
|
\param [in] topOfProcStack USR/SYS Stack Pointer value to set
|
||||||
*/
|
*/
|
||||||
__attribute__((always_inline)) __STATIC_INLINE void __set_SP_usr(uint32_t topOfProcStack)
|
__STATIC_FORCEINLINE void __set_SP_usr(uint32_t topOfProcStack)
|
||||||
{
|
{
|
||||||
uint32_t cpsr;
|
uint32_t cpsr;
|
||||||
__ASM volatile(
|
__ASM volatile(
|
||||||
|
@ -397,7 +399,7 @@ __attribute__((always_inline)) __STATIC_INLINE void __set_SP_usr(uint32_t topOfP
|
||||||
/** \brief Get FPEXC
|
/** \brief Get FPEXC
|
||||||
\return Floating Point Exception Control register value
|
\return Floating Point Exception Control register value
|
||||||
*/
|
*/
|
||||||
__attribute__((always_inline)) __STATIC_INLINE uint32_t __get_FPEXC(void)
|
__STATIC_FORCEINLINE uint32_t __get_FPEXC(void)
|
||||||
{
|
{
|
||||||
#if (__FPU_PRESENT == 1)
|
#if (__FPU_PRESENT == 1)
|
||||||
uint32_t result;
|
uint32_t result;
|
||||||
|
@ -411,7 +413,7 @@ __attribute__((always_inline)) __STATIC_INLINE uint32_t __get_FPEXC(void)
|
||||||
/** \brief Set FPEXC
|
/** \brief Set FPEXC
|
||||||
\param [in] fpexc Floating Point Exception Control value to set
|
\param [in] fpexc Floating Point Exception Control value to set
|
||||||
*/
|
*/
|
||||||
__attribute__((always_inline)) __STATIC_INLINE void __set_FPEXC(uint32_t fpexc)
|
__STATIC_FORCEINLINE void __set_FPEXC(uint32_t fpexc)
|
||||||
{
|
{
|
||||||
#if (__FPU_PRESENT == 1)
|
#if (__FPU_PRESENT == 1)
|
||||||
__ASM volatile ("VMSR fpexc, %0" : : "r" (fpexc) : "memory");
|
__ASM volatile ("VMSR fpexc, %0" : : "r" (fpexc) : "memory");
|
||||||
|
@ -424,69 +426,11 @@ __attribute__((always_inline)) __STATIC_INLINE void __set_FPEXC(uint32_t fpexc)
|
||||||
|
|
||||||
#define __get_CP(cp, op1, Rt, CRn, CRm, op2) __ASM volatile("MRC p" # cp ", " # op1 ", %0, c" # CRn ", c" # CRm ", " # op2 : "=r" (Rt) : : "memory" )
|
#define __get_CP(cp, op1, Rt, CRn, CRm, op2) __ASM volatile("MRC p" # cp ", " # op1 ", %0, c" # CRn ", c" # CRm ", " # op2 : "=r" (Rt) : : "memory" )
|
||||||
#define __set_CP(cp, op1, Rt, CRn, CRm, op2) __ASM volatile("MCR p" # cp ", " # op1 ", %0, c" # CRn ", c" # CRm ", " # op2 : : "r" (Rt) : "memory" )
|
#define __set_CP(cp, op1, Rt, CRn, CRm, op2) __ASM volatile("MCR p" # cp ", " # op1 ", %0, c" # CRn ", c" # CRm ", " # op2 : : "r" (Rt) : "memory" )
|
||||||
|
#define __get_CP64(cp, op1, Rt, CRm) __ASM volatile("MRRC p" # cp ", " # op1 ", %Q0, %R0, c" # CRm : "=r" (Rt) : : "memory" )
|
||||||
|
#define __set_CP64(cp, op1, Rt, CRm) __ASM volatile("MCRR p" # cp ", " # op1 ", %Q0, %R0, c" # CRm : : "r" (Rt) : "memory" )
|
||||||
|
|
||||||
#include "cmsis_cp15.h"
|
#include "cmsis_cp15.h"
|
||||||
|
|
||||||
|
|
||||||
/** \brief Clean and Invalidate the entire data or unified cache
|
|
||||||
|
|
||||||
Generic mechanism for cleaning/invalidating the entire data or unified cache to the point of coherency
|
|
||||||
*/
|
|
||||||
__STATIC_INLINE void __L1C_CleanInvalidateCache(uint32_t op)
|
|
||||||
{
|
|
||||||
__ASM volatile(
|
|
||||||
" PUSH {R4-R11} \n"
|
|
||||||
|
|
||||||
" MRC p15, 1, R6, c0, c0, 1 \n" // Read CLIDR
|
|
||||||
" ANDS R3, R6, #0x07000000 \n" // Extract coherency level
|
|
||||||
" MOV R3, R3, LSR #23 \n" // Total cache levels << 1
|
|
||||||
" BEQ Finished \n" // If 0, no need to clean
|
|
||||||
|
|
||||||
" MOV R10, #0 \n" // R10 holds current cache level << 1
|
|
||||||
"Loop1: ADD R2, R10, R10, LSR #1 \n" // R2 holds cache "Set" position
|
|
||||||
" MOV R1, R6, LSR R2 \n" // Bottom 3 bits are the Cache-type for this level
|
|
||||||
" AND R1, R1, #7 \n" // Isolate those lower 3 bits
|
|
||||||
" CMP R1, #2 \n"
|
|
||||||
" BLT Skip \n" // No cache or only instruction cache at this level
|
|
||||||
|
|
||||||
" MCR p15, 2, R10, c0, c0, 0 \n" // Write the Cache Size selection register
|
|
||||||
" ISB \n" // ISB to sync the change to the CacheSizeID reg
|
|
||||||
" MRC p15, 1, R1, c0, c0, 0 \n" // Reads current Cache Size ID register
|
|
||||||
" AND R2, R1, #7 \n" // Extract the line length field
|
|
||||||
" ADD R2, R2, #4 \n" // Add 4 for the line length offset (log2 16 bytes)
|
|
||||||
" LDR R4, =0x3FF \n"
|
|
||||||
" ANDS R4, R4, R1, LSR #3 \n" // R4 is the max number on the way size (right aligned)
|
|
||||||
" CLZ R5, R4 \n" // R5 is the bit position of the way size increment
|
|
||||||
" LDR R7, =0x7FFF \n"
|
|
||||||
" ANDS R7, R7, R1, LSR #13 \n" // R7 is the max number of the index size (right aligned)
|
|
||||||
|
|
||||||
"Loop2: MOV R9, R4 \n" // R9 working copy of the max way size (right aligned)
|
|
||||||
|
|
||||||
"Loop3: ORR R11, R10, R9, LSL R5 \n" // Factor in the Way number and cache number into R11
|
|
||||||
" ORR R11, R11, R7, LSL R2 \n" // Factor in the Set number
|
|
||||||
" CMP R0, #0 \n"
|
|
||||||
" BNE Dccsw \n"
|
|
||||||
" MCR p15, 0, R11, c7, c6, 2 \n" // DCISW. Invalidate by Set/Way
|
|
||||||
" B cont \n"
|
|
||||||
"Dccsw: CMP R0, #1 \n"
|
|
||||||
" BNE Dccisw \n"
|
|
||||||
" MCR p15, 0, R11, c7, c10, 2 \n" // DCCSW. Clean by Set/Way
|
|
||||||
" B cont \n"
|
|
||||||
"Dccisw: MCR p15, 0, R11, c7, c14, 2 \n" // DCCISW. Clean and Invalidate by Set/Way
|
|
||||||
"cont: SUBS R9, R9, #1 \n" // Decrement the Way number
|
|
||||||
" BGE Loop3 \n"
|
|
||||||
" SUBS R7, R7, #1 \n" // Decrement the Set number
|
|
||||||
" BGE Loop2 \n"
|
|
||||||
"Skip: ADD R10, R10, #2 \n" // Increment the cache number
|
|
||||||
" CMP R3, R10 \n"
|
|
||||||
" BGT Loop1 \n"
|
|
||||||
|
|
||||||
"Finished: \n"
|
|
||||||
" DSB \n"
|
|
||||||
" POP {R4-R11} "
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \brief Enable Floating Point Unit
|
/** \brief Enable Floating Point Unit
|
||||||
|
|
||||||
Critical section, called from undef handler, so systick is disabled
|
Critical section, called from undef handler, so systick is disabled
|
||||||
|
@ -494,24 +438,23 @@ __STATIC_INLINE void __L1C_CleanInvalidateCache(uint32_t op)
|
||||||
__STATIC_INLINE void __FPU_Enable(void)
|
__STATIC_INLINE void __FPU_Enable(void)
|
||||||
{
|
{
|
||||||
__ASM volatile(
|
__ASM volatile(
|
||||||
//Permit access to VFP/NEON, registers by modifying CPACR
|
//Permit access to VFP/NEON, registers by modifying CPACR
|
||||||
" MRC p15,0,R1,c1,c0,2 \n"
|
" MRC p15,0,R1,c1,c0,2 \n"
|
||||||
" ORR R1,R1,#0x00F00000 \n"
|
" ORR R1,R1,#0x00F00000 \n"
|
||||||
" MCR p15,0,R1,c1,c0,2 \n"
|
" MCR p15,0,R1,c1,c0,2 \n"
|
||||||
|
|
||||||
//Ensure that subsequent instructions occur in the context of VFP/NEON access permitted
|
//Ensure that subsequent instructions occur in the context of VFP/NEON access permitted
|
||||||
" ISB \n"
|
" ISB \n"
|
||||||
|
|
||||||
//Enable VFP/NEON
|
//Enable VFP/NEON
|
||||||
" VMRS R1,FPEXC \n"
|
" VMRS R1,FPEXC \n"
|
||||||
" ORR R1,R1,#0x40000000 \n"
|
" ORR R1,R1,#0x40000000 \n"
|
||||||
" VMSR FPEXC,R1 \n"
|
" VMSR FPEXC,R1 \n"
|
||||||
|
|
||||||
//Initialise VFP/NEON registers to 0
|
//Initialise VFP/NEON registers to 0
|
||||||
" MOV R2,#0 \n"
|
" MOV R2,#0 \n"
|
||||||
|
|
||||||
#if TARGET_FEATURE_EXTENSION_REGISTER_COUNT >= 16
|
//Initialise D16 registers to 0
|
||||||
//Initialise D16 registers to 0
|
|
||||||
" VMOV D0, R2,R2 \n"
|
" VMOV D0, R2,R2 \n"
|
||||||
" VMOV D1, R2,R2 \n"
|
" VMOV D1, R2,R2 \n"
|
||||||
" VMOV D2, R2,R2 \n"
|
" VMOV D2, R2,R2 \n"
|
||||||
|
@ -528,10 +471,9 @@ __STATIC_INLINE void __FPU_Enable(void)
|
||||||
" VMOV D13,R2,R2 \n"
|
" VMOV D13,R2,R2 \n"
|
||||||
" VMOV D14,R2,R2 \n"
|
" VMOV D14,R2,R2 \n"
|
||||||
" VMOV D15,R2,R2 \n"
|
" VMOV D15,R2,R2 \n"
|
||||||
#endif
|
|
||||||
|
|
||||||
#if TARGET_FEATURE_EXTENSION_REGISTER_COUNT == 32
|
#if __ARM_NEON == 1
|
||||||
//Initialise D32 registers to 0
|
//Initialise D32 registers to 0
|
||||||
" VMOV D16,R2,R2 \n"
|
" VMOV D16,R2,R2 \n"
|
||||||
" VMOV D17,R2,R2 \n"
|
" VMOV D17,R2,R2 \n"
|
||||||
" VMOV D18,R2,R2 \n"
|
" VMOV D18,R2,R2 \n"
|
||||||
|
@ -548,9 +490,9 @@ __STATIC_INLINE void __FPU_Enable(void)
|
||||||
" VMOV D29,R2,R2 \n"
|
" VMOV D29,R2,R2 \n"
|
||||||
" VMOV D30,R2,R2 \n"
|
" VMOV D30,R2,R2 \n"
|
||||||
" VMOV D31,R2,R2 \n"
|
" VMOV D31,R2,R2 \n"
|
||||||
".endif \n"
|
|
||||||
#endif
|
#endif
|
||||||
//Initialise FPSCR to a known state
|
|
||||||
|
//Initialise FPSCR to a known state
|
||||||
" VMRS R2,FPSCR \n"
|
" VMRS R2,FPSCR \n"
|
||||||
" LDR R3,=0x00086060 \n" //Mask off all bits that do not have to be preserved. Non-preserved bits can/should be zero.
|
" LDR R3,=0x00086060 \n" //Mask off all bits that do not have to be preserved. Non-preserved bits can/should be zero.
|
||||||
" AND R2,R2,R3 \n"
|
" AND R2,R2,R3 \n"
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
/**************************************************************************//**
|
/**************************************************************************//**
|
||||||
* @file cmsis_compiler.h
|
* @file cmsis_compiler.h
|
||||||
* @brief CMSIS compiler specific macros, functions, instructions
|
* @brief CMSIS compiler specific macros, functions, instructions
|
||||||
* @version V1.00
|
* @version V1.0.1
|
||||||
* @date 22. Feb 2017
|
* @date 01. December 2017
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2009-2017 ARM Limited. All rights reserved.
|
* Copyright (c) 2009-2017 ARM Limited. All rights reserved.
|
||||||
|
@ -54,7 +54,7 @@
|
||||||
#elif defined ( __ICCARM__ )
|
#elif defined ( __ICCARM__ )
|
||||||
#include "cmsis_iccarm.h"
|
#include "cmsis_iccarm.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TI ARM Compiler
|
* TI ARM Compiler
|
||||||
*/
|
*/
|
||||||
|
@ -70,9 +70,18 @@
|
||||||
#ifndef __STATIC_INLINE
|
#ifndef __STATIC_INLINE
|
||||||
#define __STATIC_INLINE static inline
|
#define __STATIC_INLINE static inline
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef __STATIC_INLINE
|
||||||
|
#define __STATIC_INLINE static inline
|
||||||
|
#endif
|
||||||
|
#ifndef __STATIC_FORCEINLINE
|
||||||
|
#define __STATIC_FORCEINLINE __STATIC_INLINE
|
||||||
|
#endif
|
||||||
#ifndef __NO_RETURN
|
#ifndef __NO_RETURN
|
||||||
#define __NO_RETURN __attribute__((noreturn))
|
#define __NO_RETURN __attribute__((noreturn))
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef CMSIS_DEPRECATED
|
||||||
|
#define CMSIS_DEPRECATED __attribute__((deprecated))
|
||||||
|
#endif
|
||||||
#ifndef __USED
|
#ifndef __USED
|
||||||
#define __USED __attribute__((used))
|
#define __USED __attribute__((used))
|
||||||
#endif
|
#endif
|
||||||
|
@ -110,9 +119,15 @@
|
||||||
#ifndef __STATIC_INLINE
|
#ifndef __STATIC_INLINE
|
||||||
#define __STATIC_INLINE static inline
|
#define __STATIC_INLINE static inline
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef __STATIC_FORCEINLINE
|
||||||
|
#define __STATIC_FORCEINLINE __STATIC_INLINE
|
||||||
|
#endif
|
||||||
#ifndef __NO_RETURN
|
#ifndef __NO_RETURN
|
||||||
#define __NO_RETURN __attribute__((noreturn))
|
#define __NO_RETURN __attribute__((noreturn))
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef CMSIS_DEPRECATED
|
||||||
|
#define CMSIS_DEPRECATED __attribute__((deprecated))
|
||||||
|
#endif
|
||||||
#ifndef __USED
|
#ifndef __USED
|
||||||
#define __USED __attribute__((used))
|
#define __USED __attribute__((used))
|
||||||
#endif
|
#endif
|
||||||
|
@ -146,6 +161,9 @@
|
||||||
#ifndef __STATIC_INLINE
|
#ifndef __STATIC_INLINE
|
||||||
#define __STATIC_INLINE static inline
|
#define __STATIC_INLINE static inline
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef __STATIC_FORCEINLINE
|
||||||
|
#define __STATIC_FORCEINLINE __STATIC_INLINE
|
||||||
|
#endif
|
||||||
#ifndef __NO_RETURN
|
#ifndef __NO_RETURN
|
||||||
// NO RETURN is automatically detected hence no warning here
|
// NO RETURN is automatically detected hence no warning here
|
||||||
#define __NO_RETURN
|
#define __NO_RETURN
|
||||||
|
@ -154,6 +172,10 @@
|
||||||
#warning No compiler specific solution for __USED. __USED is ignored.
|
#warning No compiler specific solution for __USED. __USED is ignored.
|
||||||
#define __USED
|
#define __USED
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef CMSIS_DEPRECATED
|
||||||
|
#warning No compiler specific solution for CMSIS_DEPRECATED. CMSIS_DEPRECATED is ignored.
|
||||||
|
#define CMSIS_DEPRECATED
|
||||||
|
#endif
|
||||||
#ifndef __WEAK
|
#ifndef __WEAK
|
||||||
#define __WEAK __weak
|
#define __WEAK __weak
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -22,6 +22,12 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#if defined ( __ICCARM__ )
|
||||||
|
#pragma system_include /* treat file as system include file for MISRA check */
|
||||||
|
#elif defined (__clang__)
|
||||||
|
#pragma clang system_header /* treat file as system include file */
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef __CMSIS_CP15_H
|
#ifndef __CMSIS_CP15_H
|
||||||
#define __CMSIS_CP15_H
|
#define __CMSIS_CP15_H
|
||||||
|
|
||||||
|
@ -31,7 +37,6 @@
|
||||||
__STATIC_FORCEINLINE uint32_t __get_ACTLR(void)
|
__STATIC_FORCEINLINE uint32_t __get_ACTLR(void)
|
||||||
{
|
{
|
||||||
uint32_t result;
|
uint32_t result;
|
||||||
// __ASM volatile("MRC p15, 0, %0, c1, c0, 1" : "=r" (result) : : "memory" );
|
|
||||||
__get_CP(15, 0, result, 1, 0, 1);
|
__get_CP(15, 0, result, 1, 0, 1);
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
@ -41,7 +46,6 @@ __STATIC_FORCEINLINE uint32_t __get_ACTLR(void)
|
||||||
*/
|
*/
|
||||||
__STATIC_FORCEINLINE void __set_ACTLR(uint32_t actlr)
|
__STATIC_FORCEINLINE void __set_ACTLR(uint32_t actlr)
|
||||||
{
|
{
|
||||||
// __ASM volatile ("MCR p15, 0, %0, c1, c0, 1" : : "r" (actlr) : "memory");
|
|
||||||
__set_CP(15, 0, actlr, 1, 0, 1);
|
__set_CP(15, 0, actlr, 1, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -51,7 +55,6 @@ __STATIC_FORCEINLINE void __set_ACTLR(uint32_t actlr)
|
||||||
__STATIC_FORCEINLINE uint32_t __get_CPACR(void)
|
__STATIC_FORCEINLINE uint32_t __get_CPACR(void)
|
||||||
{
|
{
|
||||||
uint32_t result;
|
uint32_t result;
|
||||||
// __ASM volatile("MRC p15, 0, %0, c1, c0, 2" : "=r"(result) : : "memory");
|
|
||||||
__get_CP(15, 0, result, 1, 0, 2);
|
__get_CP(15, 0, result, 1, 0, 2);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -61,7 +64,6 @@ __STATIC_FORCEINLINE uint32_t __get_CPACR(void)
|
||||||
*/
|
*/
|
||||||
__STATIC_FORCEINLINE void __set_CPACR(uint32_t cpacr)
|
__STATIC_FORCEINLINE void __set_CPACR(uint32_t cpacr)
|
||||||
{
|
{
|
||||||
// __ASM volatile("MCR p15, 0, %0, c1, c0, 2" : : "r"(cpacr) : "memory");
|
|
||||||
__set_CP(15, 0, cpacr, 1, 0, 2);
|
__set_CP(15, 0, cpacr, 1, 0, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +73,6 @@ __STATIC_FORCEINLINE void __set_CPACR(uint32_t cpacr)
|
||||||
__STATIC_FORCEINLINE uint32_t __get_DFSR(void)
|
__STATIC_FORCEINLINE uint32_t __get_DFSR(void)
|
||||||
{
|
{
|
||||||
uint32_t result;
|
uint32_t result;
|
||||||
// __ASM volatile("MRC p15, 0, %0, c5, c0, 0" : "=r"(result) : : "memory");
|
|
||||||
__get_CP(15, 0, result, 5, 0, 0);
|
__get_CP(15, 0, result, 5, 0, 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -81,7 +82,6 @@ __STATIC_FORCEINLINE uint32_t __get_DFSR(void)
|
||||||
*/
|
*/
|
||||||
__STATIC_FORCEINLINE void __set_DFSR(uint32_t dfsr)
|
__STATIC_FORCEINLINE void __set_DFSR(uint32_t dfsr)
|
||||||
{
|
{
|
||||||
// __ASM volatile("MCR p15, 0, %0, c5, c0, 0" : : "r"(dfsr) : "memory");
|
|
||||||
__set_CP(15, 0, dfsr, 5, 0, 0);
|
__set_CP(15, 0, dfsr, 5, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,7 +91,6 @@ __STATIC_FORCEINLINE void __set_DFSR(uint32_t dfsr)
|
||||||
__STATIC_FORCEINLINE uint32_t __get_IFSR(void)
|
__STATIC_FORCEINLINE uint32_t __get_IFSR(void)
|
||||||
{
|
{
|
||||||
uint32_t result;
|
uint32_t result;
|
||||||
// __ASM volatile("MRC p15, 0, %0, c5, c0, 1" : "=r"(result) : : "memory");
|
|
||||||
__get_CP(15, 0, result, 5, 0, 1);
|
__get_CP(15, 0, result, 5, 0, 1);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -101,7 +100,6 @@ __STATIC_FORCEINLINE uint32_t __get_IFSR(void)
|
||||||
*/
|
*/
|
||||||
__STATIC_FORCEINLINE void __set_IFSR(uint32_t ifsr)
|
__STATIC_FORCEINLINE void __set_IFSR(uint32_t ifsr)
|
||||||
{
|
{
|
||||||
// __ASM volatile("MCR p15, 0, %0, c5, c0, 1" : : "r"(ifsr) : "memory");
|
|
||||||
__set_CP(15, 0, ifsr, 5, 0, 1);
|
__set_CP(15, 0, ifsr, 5, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +109,6 @@ __STATIC_FORCEINLINE void __set_IFSR(uint32_t ifsr)
|
||||||
__STATIC_FORCEINLINE uint32_t __get_ISR(void)
|
__STATIC_FORCEINLINE uint32_t __get_ISR(void)
|
||||||
{
|
{
|
||||||
uint32_t result;
|
uint32_t result;
|
||||||
// __ASM volatile("MRC p15, 0, %0, c12, c1, 0" : "=r"(result) : : "memory");
|
|
||||||
__get_CP(15, 0, result, 12, 1, 0);
|
__get_CP(15, 0, result, 12, 1, 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -122,7 +119,6 @@ __STATIC_FORCEINLINE uint32_t __get_ISR(void)
|
||||||
__STATIC_FORCEINLINE uint32_t __get_CBAR(void)
|
__STATIC_FORCEINLINE uint32_t __get_CBAR(void)
|
||||||
{
|
{
|
||||||
uint32_t result;
|
uint32_t result;
|
||||||
// __ASM volatile("MRC p15, 4, %0, c15, c0, 0" : "=r"(result) : : "memory");
|
|
||||||
__get_CP(15, 4, result, 15, 0, 0);
|
__get_CP(15, 4, result, 15, 0, 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -136,7 +132,6 @@ __STATIC_FORCEINLINE uint32_t __get_CBAR(void)
|
||||||
__STATIC_FORCEINLINE uint32_t __get_TTBR0(void)
|
__STATIC_FORCEINLINE uint32_t __get_TTBR0(void)
|
||||||
{
|
{
|
||||||
uint32_t result;
|
uint32_t result;
|
||||||
// __ASM volatile("MRC p15, 0, %0, c2, c0, 0" : "=r"(result) : : "memory");
|
|
||||||
__get_CP(15, 0, result, 2, 0, 0);
|
__get_CP(15, 0, result, 2, 0, 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -149,7 +144,6 @@ __STATIC_FORCEINLINE uint32_t __get_TTBR0(void)
|
||||||
*/
|
*/
|
||||||
__STATIC_FORCEINLINE void __set_TTBR0(uint32_t ttbr0)
|
__STATIC_FORCEINLINE void __set_TTBR0(uint32_t ttbr0)
|
||||||
{
|
{
|
||||||
// __ASM volatile("MCR p15, 0, %0, c2, c0, 0" : : "r"(ttbr0) : "memory");
|
|
||||||
__set_CP(15, 0, ttbr0, 2, 0, 0);
|
__set_CP(15, 0, ttbr0, 2, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,7 +156,6 @@ __STATIC_FORCEINLINE void __set_TTBR0(uint32_t ttbr0)
|
||||||
__STATIC_FORCEINLINE uint32_t __get_DACR(void)
|
__STATIC_FORCEINLINE uint32_t __get_DACR(void)
|
||||||
{
|
{
|
||||||
uint32_t result;
|
uint32_t result;
|
||||||
// __ASM volatile("MRC p15, 0, %0, c3, c0, 0" : "=r"(result) : : "memory");
|
|
||||||
__get_CP(15, 0, result, 3, 0, 0);
|
__get_CP(15, 0, result, 3, 0, 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -175,7 +168,6 @@ __STATIC_FORCEINLINE uint32_t __get_DACR(void)
|
||||||
*/
|
*/
|
||||||
__STATIC_FORCEINLINE void __set_DACR(uint32_t dacr)
|
__STATIC_FORCEINLINE void __set_DACR(uint32_t dacr)
|
||||||
{
|
{
|
||||||
// __ASM volatile("MCR p15, 0, %0, c3, c0, 0" : : "r"(dacr) : "memory");
|
|
||||||
__set_CP(15, 0, dacr, 3, 0, 0);
|
__set_CP(15, 0, dacr, 3, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,7 +179,6 @@ __STATIC_FORCEINLINE void __set_DACR(uint32_t dacr)
|
||||||
*/
|
*/
|
||||||
__STATIC_FORCEINLINE void __set_SCTLR(uint32_t sctlr)
|
__STATIC_FORCEINLINE void __set_SCTLR(uint32_t sctlr)
|
||||||
{
|
{
|
||||||
// __ASM volatile("MCR p15, 0, %0, c1, c0, 0" : : "r"(sctlr) : "memory");
|
|
||||||
__set_CP(15, 0, sctlr, 1, 0, 0);
|
__set_CP(15, 0, sctlr, 1, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,7 +188,6 @@ __STATIC_FORCEINLINE void __set_SCTLR(uint32_t sctlr)
|
||||||
__STATIC_FORCEINLINE uint32_t __get_SCTLR(void)
|
__STATIC_FORCEINLINE uint32_t __get_SCTLR(void)
|
||||||
{
|
{
|
||||||
uint32_t result;
|
uint32_t result;
|
||||||
// __ASM volatile("MRC p15, 0, %0, c1, c0, 0" : "=r"(result) : : "memory");
|
|
||||||
__get_CP(15, 0, result, 1, 0, 0);
|
__get_CP(15, 0, result, 1, 0, 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -207,7 +197,6 @@ __STATIC_FORCEINLINE uint32_t __get_SCTLR(void)
|
||||||
*/
|
*/
|
||||||
__STATIC_FORCEINLINE void __set_ACTRL(uint32_t actrl)
|
__STATIC_FORCEINLINE void __set_ACTRL(uint32_t actrl)
|
||||||
{
|
{
|
||||||
// __ASM volatile("MCR p15, 0, %0, c1, c0, 1" : : "r"(actrl) : "memory");
|
|
||||||
__set_CP(15, 0, actrl, 1, 0, 1);
|
__set_CP(15, 0, actrl, 1, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,7 +206,6 @@ __STATIC_FORCEINLINE void __set_ACTRL(uint32_t actrl)
|
||||||
__STATIC_FORCEINLINE uint32_t __get_ACTRL(void)
|
__STATIC_FORCEINLINE uint32_t __get_ACTRL(void)
|
||||||
{
|
{
|
||||||
uint32_t result;
|
uint32_t result;
|
||||||
// __ASM volatile("MRC p15, 0, %0, c1, c0, 1" : "=r"(result) : : "memory");
|
|
||||||
__get_CP(15, 0, result, 1, 0, 1);
|
__get_CP(15, 0, result, 1, 0, 1);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -231,7 +219,6 @@ __STATIC_FORCEINLINE uint32_t __get_ACTRL(void)
|
||||||
__STATIC_FORCEINLINE uint32_t __get_MPIDR(void)
|
__STATIC_FORCEINLINE uint32_t __get_MPIDR(void)
|
||||||
{
|
{
|
||||||
uint32_t result;
|
uint32_t result;
|
||||||
// __ASM volatile("MRC p15, 0, %0, c0, c0, 5" : "=r"(result) : : "memory");
|
|
||||||
__get_CP(15, 0, result, 0, 0, 5);
|
__get_CP(15, 0, result, 0, 0, 5);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -245,7 +232,6 @@ __STATIC_FORCEINLINE uint32_t __get_MPIDR(void)
|
||||||
__STATIC_FORCEINLINE uint32_t __get_VBAR(void)
|
__STATIC_FORCEINLINE uint32_t __get_VBAR(void)
|
||||||
{
|
{
|
||||||
uint32_t result;
|
uint32_t result;
|
||||||
// __ASM volatile("MRC p15, 0, %0, c12, c0, 0" : "=r"(result) : : "memory");
|
|
||||||
__get_CP(15, 0, result, 12, 0, 0);
|
__get_CP(15, 0, result, 12, 0, 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -258,7 +244,6 @@ __STATIC_FORCEINLINE uint32_t __get_VBAR(void)
|
||||||
*/
|
*/
|
||||||
__STATIC_FORCEINLINE void __set_VBAR(uint32_t vbar)
|
__STATIC_FORCEINLINE void __set_VBAR(uint32_t vbar)
|
||||||
{
|
{
|
||||||
// __ASM volatile("MCR p15, 0, %0, c12, c0, 1" : : "r"(vbar) : "memory");
|
|
||||||
__set_CP(15, 0, vbar, 12, 0, 1);
|
__set_CP(15, 0, vbar, 12, 0, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,7 +259,6 @@ __STATIC_FORCEINLINE void __set_VBAR(uint32_t vbar)
|
||||||
*/
|
*/
|
||||||
__STATIC_FORCEINLINE void __set_CNTFRQ(uint32_t value)
|
__STATIC_FORCEINLINE void __set_CNTFRQ(uint32_t value)
|
||||||
{
|
{
|
||||||
// __ASM volatile("MCR p15, 0, %0, c14, c0, 0" : : "r"(value) : "memory");
|
|
||||||
__set_CP(15, 0, value, 14, 0, 0);
|
__set_CP(15, 0, value, 14, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,7 +271,6 @@ __STATIC_FORCEINLINE void __set_CNTFRQ(uint32_t value)
|
||||||
__STATIC_FORCEINLINE uint32_t __get_CNTFRQ(void)
|
__STATIC_FORCEINLINE uint32_t __get_CNTFRQ(void)
|
||||||
{
|
{
|
||||||
uint32_t result;
|
uint32_t result;
|
||||||
// __ASM volatile("MRC p15, 0, %0, c14, c0, 0" : "=r"(result) : : "memory");
|
|
||||||
__get_CP(15, 0, result, 14, 0 , 0);
|
__get_CP(15, 0, result, 14, 0 , 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -300,7 +283,6 @@ __STATIC_FORCEINLINE uint32_t __get_CNTFRQ(void)
|
||||||
*/
|
*/
|
||||||
__STATIC_FORCEINLINE void __set_CNTP_TVAL(uint32_t value)
|
__STATIC_FORCEINLINE void __set_CNTP_TVAL(uint32_t value)
|
||||||
{
|
{
|
||||||
// __ASM volatile("MCR p15, 0, %0, c14, c2, 0" : : "r"(value) : "memory");
|
|
||||||
__set_CP(15, 0, value, 14, 2, 0);
|
__set_CP(15, 0, value, 14, 2, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -313,11 +295,47 @@ __STATIC_FORCEINLINE void __set_CNTP_TVAL(uint32_t value)
|
||||||
__STATIC_FORCEINLINE uint32_t __get_CNTP_TVAL(void)
|
__STATIC_FORCEINLINE uint32_t __get_CNTP_TVAL(void)
|
||||||
{
|
{
|
||||||
uint32_t result;
|
uint32_t result;
|
||||||
// __ASM volatile("MRC p15, 0, %0, c14, c2, 0" : "=r"(result) : : "memory");
|
|
||||||
__get_CP(15, 0, result, 14, 2, 0);
|
__get_CP(15, 0, result, 14, 2, 0);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** \brief Get CNTPCT
|
||||||
|
|
||||||
|
This function returns the value of the 64 bits PL1 Physical Count Register (CNTPCT).
|
||||||
|
|
||||||
|
\return CNTPCT Register value
|
||||||
|
*/
|
||||||
|
__STATIC_FORCEINLINE uint64_t __get_CNTPCT(void)
|
||||||
|
{
|
||||||
|
uint64_t result;
|
||||||
|
__get_CP64(15, 0, result, 14);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Set CNTP_CVAL
|
||||||
|
|
||||||
|
This function assigns the given value to 64bits PL1 Physical Timer CompareValue Register (CNTP_CVAL).
|
||||||
|
|
||||||
|
\param [in] value CNTP_CVAL Register value to set
|
||||||
|
*/
|
||||||
|
__STATIC_FORCEINLINE void __set_CNTP_CVAL(uint64_t value)
|
||||||
|
{
|
||||||
|
__set_CP64(15, 2, value, 14);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Get CNTP_CVAL
|
||||||
|
|
||||||
|
This function returns the value of the 64 bits PL1 Physical Timer CompareValue Register (CNTP_CVAL).
|
||||||
|
|
||||||
|
\return CNTP_CVAL Register value
|
||||||
|
*/
|
||||||
|
__STATIC_FORCEINLINE uint64_t __get_CNTP_CVAL(void)
|
||||||
|
{
|
||||||
|
uint64_t result;
|
||||||
|
__get_CP64(15, 2, result, 14);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/** \brief Set CNTP_CTL
|
/** \brief Set CNTP_CTL
|
||||||
|
|
||||||
This function assigns the given value to PL1 Physical Timer Control Register (CNTP_CTL).
|
This function assigns the given value to PL1 Physical Timer Control Register (CNTP_CTL).
|
||||||
|
@ -326,7 +344,6 @@ __STATIC_FORCEINLINE uint32_t __get_CNTP_TVAL(void)
|
||||||
*/
|
*/
|
||||||
__STATIC_FORCEINLINE void __set_CNTP_CTL(uint32_t value)
|
__STATIC_FORCEINLINE void __set_CNTP_CTL(uint32_t value)
|
||||||
{
|
{
|
||||||
// __ASM volatile("MCR p15, 0, %0, c14, c2, 1" : : "r"(value) : "memory");
|
|
||||||
__set_CP(15, 0, value, 14, 2, 1);
|
__set_CP(15, 0, value, 14, 2, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,7 +353,6 @@ __STATIC_FORCEINLINE void __set_CNTP_CTL(uint32_t value)
|
||||||
__STATIC_FORCEINLINE uint32_t __get_CNTP_CTL(void)
|
__STATIC_FORCEINLINE uint32_t __get_CNTP_CTL(void)
|
||||||
{
|
{
|
||||||
uint32_t result;
|
uint32_t result;
|
||||||
// __ASM volatile("MRC p15, 0, %0, c14, c2, 1" : "=r"(result) : : "memory");
|
|
||||||
__get_CP(15, 0, result, 14, 2, 1);
|
__get_CP(15, 0, result, 14, 2, 1);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -349,7 +365,6 @@ __STATIC_FORCEINLINE uint32_t __get_CNTP_CTL(void)
|
||||||
*/
|
*/
|
||||||
__STATIC_FORCEINLINE void __set_TLBIALL(uint32_t value)
|
__STATIC_FORCEINLINE void __set_TLBIALL(uint32_t value)
|
||||||
{
|
{
|
||||||
// __ASM volatile("MCR p15, 0, %0, c8, c7, 0" : : "r"(value) : "memory");
|
|
||||||
__set_CP(15, 0, value, 8, 7, 0);
|
__set_CP(15, 0, value, 8, 7, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -359,7 +374,6 @@ __STATIC_FORCEINLINE void __set_TLBIALL(uint32_t value)
|
||||||
*/
|
*/
|
||||||
__STATIC_FORCEINLINE void __set_BPIALL(uint32_t value)
|
__STATIC_FORCEINLINE void __set_BPIALL(uint32_t value)
|
||||||
{
|
{
|
||||||
// __ASM volatile("MCR p15, 0, %0, c7, c5, 6" : : "r"(value) : "memory");
|
|
||||||
__set_CP(15, 0, value, 7, 5, 6);
|
__set_CP(15, 0, value, 7, 5, 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,7 +383,6 @@ __STATIC_FORCEINLINE void __set_BPIALL(uint32_t value)
|
||||||
*/
|
*/
|
||||||
__STATIC_FORCEINLINE void __set_ICIALLU(uint32_t value)
|
__STATIC_FORCEINLINE void __set_ICIALLU(uint32_t value)
|
||||||
{
|
{
|
||||||
// __ASM volatile("MCR p15, 0, %0, c7, c5, 0" : : "r"(value) : "memory");
|
|
||||||
__set_CP(15, 0, value, 7, 5, 0);
|
__set_CP(15, 0, value, 7, 5, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -379,7 +392,6 @@ __STATIC_FORCEINLINE void __set_ICIALLU(uint32_t value)
|
||||||
*/
|
*/
|
||||||
__STATIC_FORCEINLINE void __set_DCCMVAC(uint32_t value)
|
__STATIC_FORCEINLINE void __set_DCCMVAC(uint32_t value)
|
||||||
{
|
{
|
||||||
// __ASM volatile("MCR p15, 0, %0, c7, c10, 1" : : "r"(value) : "memory");
|
|
||||||
__set_CP(15, 0, value, 7, 10, 1);
|
__set_CP(15, 0, value, 7, 10, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -389,7 +401,6 @@ __STATIC_FORCEINLINE void __set_DCCMVAC(uint32_t value)
|
||||||
*/
|
*/
|
||||||
__STATIC_FORCEINLINE void __set_DCIMVAC(uint32_t value)
|
__STATIC_FORCEINLINE void __set_DCIMVAC(uint32_t value)
|
||||||
{
|
{
|
||||||
// __ASM volatile("MCR p15, 0, %0, c7, c6, 1" : : "r"(value) : "memory");
|
|
||||||
__set_CP(15, 0, value, 7, 6, 1);
|
__set_CP(15, 0, value, 7, 6, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -399,7 +410,6 @@ __STATIC_FORCEINLINE void __set_DCIMVAC(uint32_t value)
|
||||||
*/
|
*/
|
||||||
__STATIC_FORCEINLINE void __set_DCCIMVAC(uint32_t value)
|
__STATIC_FORCEINLINE void __set_DCCIMVAC(uint32_t value)
|
||||||
{
|
{
|
||||||
// __ASM volatile("MCR p15, 0, %0, c7, c14, 1" : : "r"(value) : "memory");
|
|
||||||
__set_CP(15, 0, value, 7, 14, 1);
|
__set_CP(15, 0, value, 7, 14, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -434,4 +444,28 @@ __STATIC_FORCEINLINE uint32_t __get_CLIDR(void)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** \brief Set DCISW
|
||||||
|
*/
|
||||||
|
__STATIC_FORCEINLINE void __set_DCISW(uint32_t value)
|
||||||
|
{
|
||||||
|
// __ASM volatile("MCR p15, 0, %0, c7, c6, 2" : : "r"(value) : "memory")
|
||||||
|
__set_CP(15, 0, value, 7, 6, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Set DCCSW
|
||||||
|
*/
|
||||||
|
__STATIC_FORCEINLINE void __set_DCCSW(uint32_t value)
|
||||||
|
{
|
||||||
|
// __ASM volatile("MCR p15, 0, %0, c7, c10, 2" : : "r"(value) : "memory")
|
||||||
|
__set_CP(15, 0, value, 7, 10, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Set DCCISW
|
||||||
|
*/
|
||||||
|
__STATIC_FORCEINLINE void __set_DCCISW(uint32_t value)
|
||||||
|
{
|
||||||
|
// __ASM volatile("MCR p15, 0, %0, c7, c14, 2" : : "r"(value) : "memory")
|
||||||
|
__set_CP(15, 0, value, 7, 14, 2);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -43,17 +43,20 @@
|
||||||
#ifndef __INLINE
|
#ifndef __INLINE
|
||||||
#define __INLINE inline
|
#define __INLINE inline
|
||||||
#endif
|
#endif
|
||||||
#ifndef __FORCEINLINE
|
#ifndef __FORCEINLINE
|
||||||
#define __FORCEINLINE __attribute__((always_inline))
|
#define __FORCEINLINE __attribute__((always_inline))
|
||||||
#endif
|
#endif
|
||||||
#ifndef __STATIC_INLINE
|
#ifndef __STATIC_INLINE
|
||||||
#define __STATIC_INLINE static inline
|
#define __STATIC_INLINE static inline
|
||||||
#endif
|
#endif
|
||||||
#ifndef __STATIC_FORCEINLINE
|
#ifndef __STATIC_FORCEINLINE
|
||||||
#define __STATIC_FORCEINLINE __attribute__((always_inline)) static inline
|
#define __STATIC_FORCEINLINE __attribute__((always_inline)) static inline
|
||||||
#endif
|
#endif
|
||||||
#ifndef __NO_RETURN
|
#ifndef __NO_RETURN
|
||||||
#define __NO_RETURN __attribute__((noreturn))
|
#define __NO_RETURN __attribute__((__noreturn__))
|
||||||
|
#endif
|
||||||
|
#ifndef CMSIS_DEPRECATED
|
||||||
|
#define CMSIS_DEPRECATED __attribute__((deprecated))
|
||||||
#endif
|
#endif
|
||||||
#ifndef __USED
|
#ifndef __USED
|
||||||
#define __USED __attribute__((used))
|
#define __USED __attribute__((used))
|
||||||
|
@ -157,7 +160,7 @@ __STATIC_FORCEINLINE void __DMB(void)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Reverse byte order (32 bit)
|
\brief Reverse byte order (32 bit)
|
||||||
\details Reverses the byte order in integer value.
|
\details Reverses the byte order in unsigned integer value. For example, 0x12345678 becomes 0x78563412.
|
||||||
\param [in] value Value to reverse
|
\param [in] value Value to reverse
|
||||||
\return Reversed value
|
\return Reversed value
|
||||||
*/
|
*/
|
||||||
|
@ -169,12 +172,13 @@ __STATIC_FORCEINLINE uint32_t __REV(uint32_t value)
|
||||||
uint32_t result;
|
uint32_t result;
|
||||||
|
|
||||||
__ASM volatile ("rev %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) );
|
__ASM volatile ("rev %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) );
|
||||||
return(result);
|
return result;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Reverse byte order (16 bit)
|
\brief Reverse byte order (16 bit)
|
||||||
|
\details Reverses the byte order within each halfword of a word. For example, 0x12345678 becomes 0x34127856.
|
||||||
\param [in] value Value to reverse
|
\param [in] value Value to reverse
|
||||||
\return Reversed value
|
\return Reversed value
|
||||||
*/
|
*/
|
||||||
|
@ -188,20 +192,20 @@ __attribute__((section(".rev16_text"))) __STATIC_INLINE uint32_t __REV16(uint32_
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Reverse byte order in signed short value
|
\brief Reverse byte order (16 bit)
|
||||||
\details Reverses the byte order in a signed short value with sign extension to integer.
|
\details Reverses the byte order in a 16-bit value and returns the signed 16-bit result. For example, 0x0080 becomes 0x8000.
|
||||||
\param [in] value Value to reverse
|
\param [in] value Value to reverse
|
||||||
\return Reversed value
|
\return Reversed value
|
||||||
*/
|
*/
|
||||||
__STATIC_FORCEINLINE int32_t __REVSH(int32_t value)
|
__STATIC_FORCEINLINE int16_t __REVSH(int16_t value)
|
||||||
{
|
{
|
||||||
#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)
|
#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)
|
||||||
return (short)__builtin_bswap16(value);
|
return (int16_t)__builtin_bswap16(value);
|
||||||
#else
|
#else
|
||||||
int32_t result;
|
int16_t result;
|
||||||
|
|
||||||
__ASM volatile ("revsh %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) );
|
__ASM volatile ("revsh %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) );
|
||||||
return(result);
|
return result;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,9 +218,14 @@ __STATIC_FORCEINLINE int32_t __REVSH(int32_t value)
|
||||||
*/
|
*/
|
||||||
__STATIC_FORCEINLINE uint32_t __ROR(uint32_t op1, uint32_t op2)
|
__STATIC_FORCEINLINE uint32_t __ROR(uint32_t op1, uint32_t op2)
|
||||||
{
|
{
|
||||||
|
op2 %= 32U;
|
||||||
|
if (op2 == 0U) {
|
||||||
|
return op1;
|
||||||
|
}
|
||||||
return (op1 >> op2) | (op1 << (32U - op2));
|
return (op1 >> op2) | (op1 << (32U - op2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Breakpoint
|
\brief Breakpoint
|
||||||
\param [in] value is ignored by the processor.
|
\param [in] value is ignored by the processor.
|
||||||
|
@ -239,7 +248,7 @@ __STATIC_FORCEINLINE uint32_t __RBIT(uint32_t value)
|
||||||
(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) )
|
(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) )
|
||||||
__ASM volatile ("rbit %0, %1" : "=r" (result) : "r" (value) );
|
__ASM volatile ("rbit %0, %1" : "=r" (result) : "r" (value) );
|
||||||
#else
|
#else
|
||||||
int32_t s = (4 /*sizeof(v)*/ * 8) - 1; /* extra shift needed at end */
|
int32_t s = (4U /*sizeof(v)*/ * 8U) - 1U; /* extra shift needed at end */
|
||||||
|
|
||||||
result = value; /* r will be reversed bits of v; first get LSB of v */
|
result = value; /* r will be reversed bits of v; first get LSB of v */
|
||||||
for (value >>= 1U; value; value >>= 1U)
|
for (value >>= 1U; value; value >>= 1U)
|
||||||
|
@ -250,7 +259,7 @@ __STATIC_FORCEINLINE uint32_t __RBIT(uint32_t value)
|
||||||
}
|
}
|
||||||
result <<= s; /* shift when v's highest bits are zero */
|
result <<= s; /* shift when v's highest bits are zero */
|
||||||
#endif
|
#endif
|
||||||
return(result);
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -258,7 +267,7 @@ __STATIC_FORCEINLINE uint32_t __RBIT(uint32_t value)
|
||||||
\param [in] value Value to count the leading zeros
|
\param [in] value Value to count the leading zeros
|
||||||
\return number of leading zeros in value
|
\return number of leading zeros in value
|
||||||
*/
|
*/
|
||||||
#define __CLZ __builtin_clz
|
#define __CLZ (uint8_t)__builtin_clz
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief LDR Exclusive (8 bit)
|
\brief LDR Exclusive (8 bit)
|
||||||
|
@ -496,14 +505,16 @@ __ASM volatile ("MSR cpsr, %0" : : "r" (cpsr) : "memory");
|
||||||
/** \brief Get Mode
|
/** \brief Get Mode
|
||||||
\return Processor Mode
|
\return Processor Mode
|
||||||
*/
|
*/
|
||||||
__STATIC_FORCEINLINE uint32_t __get_mode(void) {
|
__STATIC_FORCEINLINE uint32_t __get_mode(void)
|
||||||
|
{
|
||||||
return (__get_CPSR() & 0x1FU);
|
return (__get_CPSR() & 0x1FU);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \brief Set Mode
|
/** \brief Set Mode
|
||||||
\param [in] mode Mode value to set
|
\param [in] mode Mode value to set
|
||||||
*/
|
*/
|
||||||
__STATIC_FORCEINLINE void __set_mode(uint32_t mode) {
|
__STATIC_FORCEINLINE void __set_mode(uint32_t mode)
|
||||||
|
{
|
||||||
__ASM volatile("MSR cpsr_c, %0" : : "r" (mode) : "memory");
|
__ASM volatile("MSR cpsr_c, %0" : : "r" (mode) : "memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -585,108 +596,35 @@ __STATIC_FORCEINLINE void __set_FPEXC(uint32_t fpexc)
|
||||||
|
|
||||||
#define __get_CP(cp, op1, Rt, CRn, CRm, op2) __ASM volatile("MRC p" # cp ", " # op1 ", %0, c" # CRn ", c" # CRm ", " # op2 : "=r" (Rt) : : "memory" )
|
#define __get_CP(cp, op1, Rt, CRn, CRm, op2) __ASM volatile("MRC p" # cp ", " # op1 ", %0, c" # CRn ", c" # CRm ", " # op2 : "=r" (Rt) : : "memory" )
|
||||||
#define __set_CP(cp, op1, Rt, CRn, CRm, op2) __ASM volatile("MCR p" # cp ", " # op1 ", %0, c" # CRn ", c" # CRm ", " # op2 : : "r" (Rt) : "memory" )
|
#define __set_CP(cp, op1, Rt, CRn, CRm, op2) __ASM volatile("MCR p" # cp ", " # op1 ", %0, c" # CRn ", c" # CRm ", " # op2 : : "r" (Rt) : "memory" )
|
||||||
|
#define __get_CP64(cp, op1, Rt, CRm) __ASM volatile("MRRC p" # cp ", " # op1 ", %Q0, %R0, c" # CRm : "=r" (Rt) : : "memory" )
|
||||||
|
#define __set_CP64(cp, op1, Rt, CRm) __ASM volatile("MCRR p" # cp ", " # op1 ", %Q0, %R0, c" # CRm : : "r" (Rt) : "memory" )
|
||||||
|
|
||||||
#include "cmsis_cp15.h"
|
#include "cmsis_cp15.h"
|
||||||
|
|
||||||
__STATIC_FORCEINLINE int32_t log2_up(uint32_t n)
|
|
||||||
{
|
|
||||||
int32_t log = -1;
|
|
||||||
uint32_t t = n;
|
|
||||||
while(t)
|
|
||||||
{
|
|
||||||
log++; t >>=1;
|
|
||||||
}
|
|
||||||
/* if n not power of 2 -> round up*/
|
|
||||||
if ( n & (n - 1) ) log++;
|
|
||||||
return log;
|
|
||||||
}
|
|
||||||
|
|
||||||
__STATIC_INLINE void __L1C_MaintainDCacheSetWay(uint32_t level, uint32_t maint)
|
|
||||||
{
|
|
||||||
register volatile uint32_t Dummy;
|
|
||||||
register volatile uint32_t ccsidr;
|
|
||||||
uint32_t num_sets;
|
|
||||||
uint32_t num_ways;
|
|
||||||
uint32_t shift_way;
|
|
||||||
uint32_t log2_linesize;
|
|
||||||
uint32_t log2_num_ways;
|
|
||||||
|
|
||||||
Dummy = level << 1;
|
|
||||||
/* set csselr, select ccsidr register */
|
|
||||||
__set_CCSIDR(Dummy);
|
|
||||||
/* get current ccsidr register */
|
|
||||||
ccsidr = __get_CCSIDR();
|
|
||||||
num_sets = ((ccsidr & 0x0FFFE000) >> 13) + 1;
|
|
||||||
num_ways = ((ccsidr & 0x00001FF8) >> 3) + 1;
|
|
||||||
log2_linesize = (ccsidr & 0x00000007) + 2 + 2;
|
|
||||||
log2_num_ways = log2_up(num_ways);
|
|
||||||
shift_way = 32 - log2_num_ways;
|
|
||||||
for(int way = num_ways-1; way >= 0; way--) {
|
|
||||||
for(int set = num_sets-1; set >= 0; set--) {
|
|
||||||
Dummy = (level << 1) | (set << log2_linesize) | (way << shift_way);
|
|
||||||
switch (maint)
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
__ASM volatile("MCR p15, 0, %0, c7, c6, 2" : : "r"(Dummy) : "memory"); // DCISW. Invalidate by Set/Way
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
__ASM volatile("MCR p15, 0, %0, c7, c10, 2" : : "r"(Dummy) : "memory"); // DCCSW. Clean by Set/Way
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
__ASM volatile("MCR p15, 0, %0, c7, c14, 2" : : "r"(Dummy) : "memory"); // DCCISW. Clean and Invalidate by Set/Way
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
__DMB();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \brief Clean and Invalidate the entire data or unified cache
|
|
||||||
|
|
||||||
Generic mechanism for cleaning/invalidating the entire data or unified cache to the point of coherency
|
|
||||||
*/
|
|
||||||
__STATIC_INLINE void __L1C_CleanInvalidateCache(uint32_t op) {
|
|
||||||
register volatile uint32_t clidr;
|
|
||||||
uint32_t cache_type;
|
|
||||||
clidr = __get_CLIDR();
|
|
||||||
for(uint32_t i = 0; i<7; i++)
|
|
||||||
{
|
|
||||||
cache_type = (clidr >> i*3) & 0x7UL;
|
|
||||||
if ((cache_type >= 2) && (cache_type <= 4))
|
|
||||||
{
|
|
||||||
__L1C_MaintainDCacheSetWay(i, op);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \brief Enable Floating Point Unit
|
/** \brief Enable Floating Point Unit
|
||||||
|
|
||||||
Critical section, called from undef handler, so systick is disabled
|
Critical section, called from undef handler, so systick is disabled
|
||||||
*/
|
*/
|
||||||
__STATIC_INLINE void __FPU_Enable(void) {
|
__STATIC_INLINE void __FPU_Enable(void)
|
||||||
|
{
|
||||||
__ASM volatile(
|
__ASM volatile(
|
||||||
//Permit access to VFP/NEON, registers by modifying CPACR
|
//Permit access to VFP/NEON, registers by modifying CPACR
|
||||||
" MRC p15,0,R1,c1,c0,2 \n"
|
" MRC p15,0,R1,c1,c0,2 \n"
|
||||||
" ORR R1,R1,#0x00F00000 \n"
|
" ORR R1,R1,#0x00F00000 \n"
|
||||||
" MCR p15,0,R1,c1,c0,2 \n"
|
" MCR p15,0,R1,c1,c0,2 \n"
|
||||||
|
|
||||||
//Ensure that subsequent instructions occur in the context of VFP/NEON access permitted
|
//Ensure that subsequent instructions occur in the context of VFP/NEON access permitted
|
||||||
" ISB \n"
|
" ISB \n"
|
||||||
|
|
||||||
//Enable VFP/NEON
|
//Enable VFP/NEON
|
||||||
" VMRS R1,FPEXC \n"
|
" VMRS R1,FPEXC \n"
|
||||||
" ORR R1,R1,#0x40000000 \n"
|
" ORR R1,R1,#0x40000000 \n"
|
||||||
" VMSR FPEXC,R1 \n"
|
" VMSR FPEXC,R1 \n"
|
||||||
|
|
||||||
//Initialise VFP/NEON registers to 0
|
//Initialise VFP/NEON registers to 0
|
||||||
" MOV R2,#0 \n"
|
" MOV R2,#0 \n"
|
||||||
|
|
||||||
#if TARGET_FEATURE_EXTENSION_REGISTER_COUNT >= 16
|
//Initialise D16 registers to 0
|
||||||
//Initialise D16 registers to 0
|
|
||||||
" VMOV D0, R2,R2 \n"
|
" VMOV D0, R2,R2 \n"
|
||||||
" VMOV D1, R2,R2 \n"
|
" VMOV D1, R2,R2 \n"
|
||||||
" VMOV D2, R2,R2 \n"
|
" VMOV D2, R2,R2 \n"
|
||||||
|
@ -703,10 +641,9 @@ __STATIC_INLINE void __FPU_Enable(void) {
|
||||||
" VMOV D13,R2,R2 \n"
|
" VMOV D13,R2,R2 \n"
|
||||||
" VMOV D14,R2,R2 \n"
|
" VMOV D14,R2,R2 \n"
|
||||||
" VMOV D15,R2,R2 \n"
|
" VMOV D15,R2,R2 \n"
|
||||||
#endif
|
|
||||||
|
|
||||||
#if TARGET_FEATURE_EXTENSION_REGISTER_COUNT == 32
|
#if __ARM_NEON == 1
|
||||||
//Initialise D32 registers to 0
|
//Initialise D32 registers to 0
|
||||||
" VMOV D16,R2,R2 \n"
|
" VMOV D16,R2,R2 \n"
|
||||||
" VMOV D17,R2,R2 \n"
|
" VMOV D17,R2,R2 \n"
|
||||||
" VMOV D18,R2,R2 \n"
|
" VMOV D18,R2,R2 \n"
|
||||||
|
@ -724,7 +661,8 @@ __STATIC_INLINE void __FPU_Enable(void) {
|
||||||
" VMOV D30,R2,R2 \n"
|
" VMOV D30,R2,R2 \n"
|
||||||
" VMOV D31,R2,R2 \n"
|
" VMOV D31,R2,R2 \n"
|
||||||
#endif
|
#endif
|
||||||
//Initialise FPSCR to a known state
|
|
||||||
|
//Initialise FPSCR to a known state
|
||||||
" VMRS R2,FPSCR \n"
|
" VMRS R2,FPSCR \n"
|
||||||
" LDR R3,=0x00086060 \n" //Mask off all bits that do not have to be preserved. Non-preserved bits can/should be zero.
|
" LDR R3,=0x00086060 \n" //Mask off all bits that do not have to be preserved. Non-preserved bits can/should be zero.
|
||||||
" AND R2,R2,R3 \n"
|
" AND R2,R2,R3 \n"
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
/**************************************************************************//**
|
/**************************************************************************//**
|
||||||
* @file cmsis_iccarm.h
|
* @file cmsis_iccarm.h
|
||||||
* @brief CMSIS compiler ICCARM (IAR compiler) header file
|
* @brief CMSIS compiler ICCARM (IAR compiler) header file
|
||||||
* @version V5.0.3
|
* @version V5.0.4
|
||||||
* @date 29. August 2017
|
* @date 01. December 2017
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
@ -74,7 +74,11 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef __NO_RETURN
|
#ifndef __NO_RETURN
|
||||||
#define __NO_RETURN _Pragma("object_attribute=__noreturn")
|
#if __ICCARM_V8
|
||||||
|
#define __NO_RETURN __attribute__((__noreturn__))
|
||||||
|
#else
|
||||||
|
#define __NO_RETURN _Pragma("object_attribute=__noreturn")
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef __PACKED
|
#ifndef __PACKED
|
||||||
|
@ -105,25 +109,30 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef __RESTRICT
|
#ifndef __RESTRICT
|
||||||
#define __RESTRICT restrict
|
#define __RESTRICT restrict
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifndef __STATIC_INLINE
|
#ifndef __STATIC_INLINE
|
||||||
#define __STATIC_INLINE static inline
|
#define __STATIC_INLINE static inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __FORCEINLINE
|
||||||
|
#define __FORCEINLINE _Pragma("inline=forced")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef __STATIC_FORCEINLINE
|
#ifndef __STATIC_FORCEINLINE
|
||||||
#define __STATIC_FORCEINLINE _Pragma("inline=forced") static inline
|
#define __STATIC_FORCEINLINE __FORCEINLINE __STATIC_INLINE
|
||||||
#endif
|
#endif
|
||||||
#ifndef __FORCEINLINE
|
|
||||||
#define __FORCEINLINE _Pragma("inline=forced")
|
#ifndef CMSIS_DEPRECATED
|
||||||
|
#define CMSIS_DEPRECATED __attribute__((deprecated))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef __UNALIGNED_UINT16_READ
|
#ifndef __UNALIGNED_UINT16_READ
|
||||||
#pragma language=save
|
#pragma language=save
|
||||||
#pragma language=extended
|
#pragma language=extended
|
||||||
__IAR_FT uint16_t __iar_uint16_read(void const *ptr) {
|
__IAR_FT uint16_t __iar_uint16_read(void const *ptr)
|
||||||
|
{
|
||||||
return *(__packed uint16_t*)(ptr);
|
return *(__packed uint16_t*)(ptr);
|
||||||
}
|
}
|
||||||
#pragma language=restore
|
#pragma language=restore
|
||||||
|
@ -134,7 +143,8 @@
|
||||||
#ifndef __UNALIGNED_UINT16_WRITE
|
#ifndef __UNALIGNED_UINT16_WRITE
|
||||||
#pragma language=save
|
#pragma language=save
|
||||||
#pragma language=extended
|
#pragma language=extended
|
||||||
__IAR_FT void __iar_uint16_write(void const *ptr, uint16_t val) {
|
__IAR_FT void __iar_uint16_write(void const *ptr, uint16_t val)
|
||||||
|
{
|
||||||
*(__packed uint16_t*)(ptr) = val;;
|
*(__packed uint16_t*)(ptr) = val;;
|
||||||
}
|
}
|
||||||
#pragma language=restore
|
#pragma language=restore
|
||||||
|
@ -144,7 +154,8 @@
|
||||||
#ifndef __UNALIGNED_UINT32_READ
|
#ifndef __UNALIGNED_UINT32_READ
|
||||||
#pragma language=save
|
#pragma language=save
|
||||||
#pragma language=extended
|
#pragma language=extended
|
||||||
__IAR_FT uint32_t __iar_uint32_read(void const *ptr) {
|
__IAR_FT uint32_t __iar_uint32_read(void const *ptr)
|
||||||
|
{
|
||||||
return *(__packed uint32_t*)(ptr);
|
return *(__packed uint32_t*)(ptr);
|
||||||
}
|
}
|
||||||
#pragma language=restore
|
#pragma language=restore
|
||||||
|
@ -154,7 +165,8 @@
|
||||||
#ifndef __UNALIGNED_UINT32_WRITE
|
#ifndef __UNALIGNED_UINT32_WRITE
|
||||||
#pragma language=save
|
#pragma language=save
|
||||||
#pragma language=extended
|
#pragma language=extended
|
||||||
__IAR_FT void __iar_uint32_write(void const *ptr, uint32_t val) {
|
__IAR_FT void __iar_uint32_write(void const *ptr, uint32_t val)
|
||||||
|
{
|
||||||
*(__packed uint32_t*)(ptr) = val;;
|
*(__packed uint32_t*)(ptr) = val;;
|
||||||
}
|
}
|
||||||
#pragma language=restore
|
#pragma language=restore
|
||||||
|
@ -212,12 +224,12 @@
|
||||||
|
|
||||||
#include "iccarm_builtin.h"
|
#include "iccarm_builtin.h"
|
||||||
|
|
||||||
#define __enable_irq __iar_builtin_enable_interrupt
|
#define __enable_irq __iar_builtin_enable_interrupt
|
||||||
#define __disable_irq __iar_builtin_disable_interrupt
|
#define __disable_irq __iar_builtin_disable_interrupt
|
||||||
#define __enable_fault_irq __iar_builtin_enable_fiq
|
#define __enable_fault_irq __iar_builtin_enable_fiq
|
||||||
#define __disable_fault_irq __iar_builtin_disable_fiq
|
#define __disable_fault_irq __iar_builtin_disable_fiq
|
||||||
#define __arm_rsr __iar_builtin_rsr
|
#define __arm_rsr __iar_builtin_rsr
|
||||||
#define __arm_wsr __iar_builtin_wsr
|
#define __arm_wsr __iar_builtin_wsr
|
||||||
|
|
||||||
#if __FPU_PRESENT
|
#if __FPU_PRESENT
|
||||||
#define __get_FPSCR() (__arm_rsr("FPSCR"))
|
#define __get_FPSCR() (__arm_rsr("FPSCR"))
|
||||||
|
@ -234,28 +246,31 @@
|
||||||
#define __set_mode(VALUE) (__arm_wsr("CPSR_c", (VALUE)))
|
#define __set_mode(VALUE) (__arm_wsr("CPSR_c", (VALUE)))
|
||||||
|
|
||||||
|
|
||||||
#define __get_FPEXC() (__arm_rsr("FPEXC"))
|
#define __get_FPEXC() (__arm_rsr("FPEXC"))
|
||||||
#define __set_FPEXC(VALUE) (__arm_wsr("FPEXC", VALUE))
|
#define __set_FPEXC(VALUE) (__arm_wsr("FPEXC", VALUE))
|
||||||
|
|
||||||
#define __get_CP(cp, op1, RT, CRn, CRm, op2) \
|
#define __get_CP(cp, op1, RT, CRn, CRm, op2) \
|
||||||
(RT = __arm_rsr("p" # cp ":" # op1 ":c" # CRn ":c" # CRm ":" # op2))
|
((RT) = __arm_rsr("p" # cp ":" # op1 ":c" # CRn ":c" # CRm ":" # op2))
|
||||||
|
|
||||||
#define __set_CP(cp, op1, RT, CRn, CRm, op2) \
|
#define __set_CP(cp, op1, RT, CRn, CRm, op2) \
|
||||||
(__arm_wsr("p" # cp ":" # op1 ":c" # CRn ":c" # CRm ":" # op2, RT))
|
(__arm_wsr("p" # cp ":" # op1 ":c" # CRn ":c" # CRm ":" # op2, (RT)))
|
||||||
|
|
||||||
|
#define __get_CP64(cp, op1, Rt, CRm) \
|
||||||
|
__ASM volatile("MRRC p" # cp ", " # op1 ", %Q0, %R0, c" # CRm : "=r" (Rt) : : "memory" )
|
||||||
|
|
||||||
|
#define __set_CP64(cp, op1, Rt, CRm) \
|
||||||
|
__ASM volatile("MCRR p" # cp ", " # op1 ", %Q0, %R0, c" # CRm : : "r" (Rt) : "memory" )
|
||||||
|
|
||||||
#include "cmsis_cp15.h"
|
#include "cmsis_cp15.h"
|
||||||
|
|
||||||
#define __NOP __iar_builtin_no_operation
|
#define __NOP __iar_builtin_no_operation
|
||||||
|
|
||||||
__IAR_FT uint8_t __CLZ(uint32_t val) {
|
#define __CLZ __iar_builtin_CLZ
|
||||||
return __iar_builtin_CLZ(val);
|
#define __CLREX __iar_builtin_CLREX
|
||||||
}
|
|
||||||
|
|
||||||
#define __CLREX __iar_builtin_CLREX
|
#define __DMB __iar_builtin_DMB
|
||||||
|
#define __DSB __iar_builtin_DSB
|
||||||
#define __DMB __iar_builtin_DMB
|
#define __ISB __iar_builtin_ISB
|
||||||
#define __DSB __iar_builtin_DSB
|
|
||||||
#define __ISB __iar_builtin_ISB
|
|
||||||
|
|
||||||
#define __LDREXB __iar_builtin_LDREXB
|
#define __LDREXB __iar_builtin_LDREXB
|
||||||
#define __LDREXH __iar_builtin_LDREXH
|
#define __LDREXH __iar_builtin_LDREXH
|
||||||
|
@ -265,8 +280,9 @@
|
||||||
#define __REV __iar_builtin_REV
|
#define __REV __iar_builtin_REV
|
||||||
#define __REV16 __iar_builtin_REV16
|
#define __REV16 __iar_builtin_REV16
|
||||||
|
|
||||||
__IAR_FT int32_t __REVSH(int32_t val) {
|
__IAR_FT int16_t __REVSH(int16_t val)
|
||||||
return __iar_builtin_REVSH((int16_t)val);
|
{
|
||||||
|
return (int16_t) __iar_builtin_REVSH(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define __ROR __iar_builtin_ROR
|
#define __ROR __iar_builtin_ROR
|
||||||
|
@ -354,6 +370,10 @@
|
||||||
#define __get_FPSCR __cmsis_iar_get_FPSR_not_active
|
#define __get_FPSCR __cmsis_iar_get_FPSR_not_active
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef __INTRINSICS_INCLUDED
|
||||||
|
#error intrinsics.h is already included previously!
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <intrinsics.h>
|
#include <intrinsics.h>
|
||||||
|
|
||||||
#if !__FPU_PRESENT
|
#if !__FPU_PRESENT
|
||||||
|
@ -363,36 +383,40 @@
|
||||||
#pragma diag_suppress=Pe940
|
#pragma diag_suppress=Pe940
|
||||||
#pragma diag_suppress=Pe177
|
#pragma diag_suppress=Pe177
|
||||||
|
|
||||||
#define __enable_irq __enable_interrupt
|
#define __enable_irq __enable_interrupt
|
||||||
#define __disable_irq __disable_interrupt
|
#define __disable_irq __disable_interrupt
|
||||||
#define __enable_fault_irq __enable_fiq
|
#define __enable_fault_irq __enable_fiq
|
||||||
#define __disable_fault_irq __disable_fiq
|
#define __disable_fault_irq __disable_fiq
|
||||||
#define __NOP __no_operation
|
#define __NOP __no_operation
|
||||||
|
|
||||||
#define __get_xPSR __get_PSR
|
#define __get_xPSR __get_PSR
|
||||||
|
|
||||||
__IAR_FT void __set_mode(uint32_t mode)
|
__IAR_FT void __set_mode(uint32_t mode)
|
||||||
{
|
{
|
||||||
__ASM volatile("MSR cpsr_c, %0" : : "r" (mode) : "memory");
|
__ASM volatile("MSR cpsr_c, %0" : : "r" (mode) : "memory");
|
||||||
}
|
}
|
||||||
|
|
||||||
__IAR_FT uint32_t __LDREXW(uint32_t volatile *ptr) {
|
__IAR_FT uint32_t __LDREXW(uint32_t volatile *ptr)
|
||||||
|
{
|
||||||
return __LDREX((unsigned long *)ptr);
|
return __LDREX((unsigned long *)ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
__IAR_FT uint32_t __STREXW(uint32_t value, uint32_t volatile *ptr) {
|
__IAR_FT uint32_t __STREXW(uint32_t value, uint32_t volatile *ptr)
|
||||||
|
{
|
||||||
return __STREX(value, (unsigned long *)ptr);
|
return __STREX(value, (unsigned long *)ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
__IAR_FT uint32_t __RRX(uint32_t value) {
|
__IAR_FT uint32_t __RRX(uint32_t value)
|
||||||
|
{
|
||||||
uint32_t result;
|
uint32_t result;
|
||||||
__ASM("RRX %0, %1" : "=r"(result) : "r" (value) : "cc");
|
__ASM("RRX %0, %1" : "=r"(result) : "r" (value) : "cc");
|
||||||
return(result);
|
return(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
__IAR_FT uint32_t __ROR(uint32_t op1, uint32_t op2) {
|
__IAR_FT uint32_t __ROR(uint32_t op1, uint32_t op2)
|
||||||
|
{
|
||||||
return (op1 >> op2) | (op1 << ((sizeof(op1)*8)-op2));
|
return (op1 >> op2) | (op1 << ((sizeof(op1)*8)-op2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -418,7 +442,11 @@
|
||||||
#define __get_CP(cp, op1, Rt, CRn, CRm, op2) \
|
#define __get_CP(cp, op1, Rt, CRn, CRm, op2) \
|
||||||
__ASM volatile("MRC p" # cp ", " # op1 ", %0, c" # CRn ", c" # CRm ", " # op2 : "=r" (Rt) : : "memory" )
|
__ASM volatile("MRC p" # cp ", " # op1 ", %0, c" # CRn ", c" # CRm ", " # op2 : "=r" (Rt) : : "memory" )
|
||||||
#define __set_CP(cp, op1, Rt, CRn, CRm, op2) \
|
#define __set_CP(cp, op1, Rt, CRn, CRm, op2) \
|
||||||
__ASM volatile("MCR p" # cp ", " # op1 ", %0, c" # CRn ", c" # CRm ", " # op2 : : "r" (Rt) : "memory" )
|
__ASM volatile("MCR p" # cp ", " # op1 ", %0, c" # CRn ", c" # CRm ", " # op2 : : "r" (Rt) : "memory" )
|
||||||
|
#define __get_CP64(cp, op1, Rt, CRm) \
|
||||||
|
__ASM volatile("MRRC p" # cp ", " # op1 ", %Q0, %R0, c" # CRm : "=r" (Rt) : : "memory" )
|
||||||
|
#define __set_CP64(cp, op1, Rt, CRm) \
|
||||||
|
__ASM volatile("MCRR p" # cp ", " # op1 ", %Q0, %R0, c" # CRm : : "r" (Rt) : "memory" )
|
||||||
|
|
||||||
#include "cmsis_cp15.h"
|
#include "cmsis_cp15.h"
|
||||||
|
|
||||||
|
@ -455,86 +483,27 @@ __IAR_FT void __set_SP_usr(uint32_t topOfProcStack)
|
||||||
|
|
||||||
#define __get_mode() (__get_CPSR() & 0x1FU)
|
#define __get_mode() (__get_CPSR() & 0x1FU)
|
||||||
|
|
||||||
|
|
||||||
__STATIC_INLINE
|
|
||||||
void __L1C_CleanInvalidateCache(uint32_t op)
|
|
||||||
{
|
|
||||||
__ASM volatile(
|
|
||||||
" PUSH {R4-R11} \n"
|
|
||||||
|
|
||||||
" MRC p15, 1, R6, c0, c0, 1 \n" // Read CLIDR
|
|
||||||
" ANDS R3, R6, #0x07000000 \n" // Extract coherency level
|
|
||||||
" MOV R3, R3, LSR #23 \n" // Total cache levels << 1
|
|
||||||
" BEQ Finished \n" // If 0, no need to clean
|
|
||||||
|
|
||||||
" MOV R10, #0 \n" // R10 holds current cache level << 1
|
|
||||||
"Loop1: ADD R2, R10, R10, LSR #1 \n" // R2 holds cache "Set" position
|
|
||||||
" MOV R1, R6, LSR R2 \n" // Bottom 3 bits are the Cache-type for this level
|
|
||||||
" AND R1, R1, #7 \n" // Isolate those lower 3 bits
|
|
||||||
" CMP R1, #2 \n"
|
|
||||||
" BLT Skip \n" // No cache or only instruction cache at this level
|
|
||||||
|
|
||||||
" MCR p15, 2, R10, c0, c0, 0 \n" // Write the Cache Size selection register
|
|
||||||
" ISB \n" // ISB to sync the change to the CacheSizeID reg
|
|
||||||
" MRC p15, 1, R1, c0, c0, 0 \n" // Reads current Cache Size ID register
|
|
||||||
" AND R2, R1, #7 \n" // Extract the line length field
|
|
||||||
" ADD R2, R2, #4 \n" // Add 4 for the line length offset (log2 16 bytes)
|
|
||||||
" MOVW R4, #0x3FF \n"
|
|
||||||
" ANDS R4, R4, R1, LSR #3 \n" // R4 is the max number on the way size (right aligned)
|
|
||||||
" CLZ R5, R4 \n" // R5 is the bit position of the way size increment
|
|
||||||
" MOVW R7, #0x7FFF \n"
|
|
||||||
" ANDS R7, R7, R1, LSR #13 \n" // R7 is the max number of the index size (right aligned)
|
|
||||||
|
|
||||||
"Loop2: MOV R9, R4 \n" // R9 working copy of the max way size (right aligned)
|
|
||||||
|
|
||||||
"Loop3: ORR R11, R10, R9, LSL R5 \n" // Factor in the Way number and cache number into R11
|
|
||||||
" ORR R11, R11, R7, LSL R2 \n" // Factor in the Set number
|
|
||||||
" CMP R0, #0 \n"
|
|
||||||
" BNE Dccsw \n"
|
|
||||||
" MCR p15, 0, R11, c7, c6, 2 \n" // DCISW. Invalidate by Set/Way
|
|
||||||
" B cont \n"
|
|
||||||
"Dccsw: CMP R0, #1 \n"
|
|
||||||
" BNE Dccisw \n"
|
|
||||||
" MCR p15, 0, R11, c7, c10, 2 \n" // DCCSW. Clean by Set/Way
|
|
||||||
" B cont \n"
|
|
||||||
"Dccisw: MCR p15, 0, R11, c7, c14, 2 \n" // DCCISW. Clean and Invalidate by Set/Way
|
|
||||||
"cont: SUBS R9, R9, #1 \n" // Decrement the Way number
|
|
||||||
" BGE Loop3 \n"
|
|
||||||
" SUBS R7, R7, #1 \n" // Decrement the Set number
|
|
||||||
" BGE Loop2 \n"
|
|
||||||
"Skip: ADD R10, R10, #2 \n" // Increment the cache number
|
|
||||||
" CMP R3, R10 \n"
|
|
||||||
" BGT Loop1 \n"
|
|
||||||
|
|
||||||
"Finished: \n"
|
|
||||||
" DSB \n"
|
|
||||||
" POP {R4-R11} "
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
__STATIC_INLINE
|
__STATIC_INLINE
|
||||||
void __FPU_Enable(void)
|
void __FPU_Enable(void)
|
||||||
{
|
{
|
||||||
__ASM volatile(
|
__ASM volatile(
|
||||||
//Permit access to VFP/NEON, registers by modifying CPACR
|
//Permit access to VFP/NEON, registers by modifying CPACR
|
||||||
" MRC p15,0,R1,c1,c0,2 \n"
|
" MRC p15,0,R1,c1,c0,2 \n"
|
||||||
" ORR R1,R1,#0x00F00000 \n"
|
" ORR R1,R1,#0x00F00000 \n"
|
||||||
" MCR p15,0,R1,c1,c0,2 \n"
|
" MCR p15,0,R1,c1,c0,2 \n"
|
||||||
|
|
||||||
//Ensure that subsequent instructions occur in the context of VFP/NEON access permitted
|
//Ensure that subsequent instructions occur in the context of VFP/NEON access permitted
|
||||||
" ISB \n"
|
" ISB \n"
|
||||||
|
|
||||||
//Enable VFP/NEON
|
//Enable VFP/NEON
|
||||||
" VMRS R1,FPEXC \n"
|
" VMRS R1,FPEXC \n"
|
||||||
" ORR R1,R1,#0x40000000 \n"
|
" ORR R1,R1,#0x40000000 \n"
|
||||||
" VMSR FPEXC,R1 \n"
|
" VMSR FPEXC,R1 \n"
|
||||||
|
|
||||||
//Initialise VFP/NEON registers to 0
|
//Initialise VFP/NEON registers to 0
|
||||||
" MOV R2,#0 \n"
|
" MOV R2,#0 \n"
|
||||||
|
|
||||||
#if TARGET_FEATURE_EXTENSION_REGISTER_COUNT >= 16
|
//Initialise D16 registers to 0
|
||||||
//Initialise D16 registers to 0
|
|
||||||
" VMOV D0, R2,R2 \n"
|
" VMOV D0, R2,R2 \n"
|
||||||
" VMOV D1, R2,R2 \n"
|
" VMOV D1, R2,R2 \n"
|
||||||
" VMOV D2, R2,R2 \n"
|
" VMOV D2, R2,R2 \n"
|
||||||
|
@ -551,10 +520,9 @@ void __FPU_Enable(void)
|
||||||
" VMOV D13,R2,R2 \n"
|
" VMOV D13,R2,R2 \n"
|
||||||
" VMOV D14,R2,R2 \n"
|
" VMOV D14,R2,R2 \n"
|
||||||
" VMOV D15,R2,R2 \n"
|
" VMOV D15,R2,R2 \n"
|
||||||
#endif
|
|
||||||
|
|
||||||
#if TARGET_FEATURE_EXTENSION_REGISTER_COUNT == 32
|
#ifdef __ARM_ADVANCED_SIMD__
|
||||||
//Initialise D32 registers to 0
|
//Initialise D32 registers to 0
|
||||||
" VMOV D16,R2,R2 \n"
|
" VMOV D16,R2,R2 \n"
|
||||||
" VMOV D17,R2,R2 \n"
|
" VMOV D17,R2,R2 \n"
|
||||||
" VMOV D18,R2,R2 \n"
|
" VMOV D18,R2,R2 \n"
|
||||||
|
@ -571,12 +539,12 @@ void __FPU_Enable(void)
|
||||||
" VMOV D29,R2,R2 \n"
|
" VMOV D29,R2,R2 \n"
|
||||||
" VMOV D30,R2,R2 \n"
|
" VMOV D30,R2,R2 \n"
|
||||||
" VMOV D31,R2,R2 \n"
|
" VMOV D31,R2,R2 \n"
|
||||||
".endif \n"
|
|
||||||
#endif
|
#endif
|
||||||
//Initialise FPSCR to a known state
|
|
||||||
|
//Initialise FPSCR to a known state
|
||||||
" VMRS R2,FPSCR \n"
|
" VMRS R2,FPSCR \n"
|
||||||
" MOV32 R3,#0x00086060 \n" //Mask off all bits that do not have to be preserved. Non-preserved bits can/should be zero.
|
" MOV32 R3,#0x00086060 \n" //Mask off all bits that do not have to be preserved. Non-preserved bits can/should be zero.
|
||||||
" AND R2,R2,R3 \n"
|
" AND R2,R2,R3 \n"
|
||||||
" VMSR FPSCR,R2 \n");
|
" VMSR FPSCR,R2 \n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,8 +22,10 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#if defined ( __ICCARM__ )
|
#if defined ( __ICCARM__ )
|
||||||
#pragma system_include /* treat file as system include file for MISRA check */
|
#pragma system_include /* treat file as system include file for MISRA check */
|
||||||
|
#elif defined (__clang__)
|
||||||
|
#pragma clang system_header /* treat file as system include file */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -40,7 +42,7 @@
|
||||||
|
|
||||||
/* CMSIS CA definitions */
|
/* CMSIS CA definitions */
|
||||||
#define __CA_CMSIS_VERSION_MAIN (1U) /*!< \brief [31:16] CMSIS-Core(A) main version */
|
#define __CA_CMSIS_VERSION_MAIN (1U) /*!< \brief [31:16] CMSIS-Core(A) main version */
|
||||||
#define __CA_CMSIS_VERSION_SUB (0U) /*!< \brief [15:0] CMSIS-Core(A) sub version */
|
#define __CA_CMSIS_VERSION_SUB (1U) /*!< \brief [15:0] CMSIS-Core(A) sub version */
|
||||||
#define __CA_CMSIS_VERSION ((__CA_CMSIS_VERSION_MAIN << 16U) | \
|
#define __CA_CMSIS_VERSION ((__CA_CMSIS_VERSION_MAIN << 16U) | \
|
||||||
__CA_CMSIS_VERSION_SUB ) /*!< \brief CMSIS-Core(A) version number */
|
__CA_CMSIS_VERSION_SUB ) /*!< \brief CMSIS-Core(A) version number */
|
||||||
|
|
||||||
|
@ -505,9 +507,9 @@ typedef union
|
||||||
uint32_t CP9:2; /*!< \brief bit:18..19 Access rights for coprocessor 9 */
|
uint32_t CP9:2; /*!< \brief bit:18..19 Access rights for coprocessor 9 */
|
||||||
uint32_t CP10:2; /*!< \brief bit:20..21 Access rights for coprocessor 10 */
|
uint32_t CP10:2; /*!< \brief bit:20..21 Access rights for coprocessor 10 */
|
||||||
uint32_t CP11:2; /*!< \brief bit:22..23 Access rights for coprocessor 11 */
|
uint32_t CP11:2; /*!< \brief bit:22..23 Access rights for coprocessor 11 */
|
||||||
uint32_t CP12:2; /*!< \brief bit:24..25 Access rights for coprocessor 11 */
|
uint32_t CP12:2; /*!< \brief bit:24..25 Access rights for coprocessor 11 */
|
||||||
uint32_t CP13:2; /*!< \brief bit:26..27 Access rights for coprocessor 11 */
|
uint32_t CP13:2; /*!< \brief bit:26..27 Access rights for coprocessor 11 */
|
||||||
uint32_t TRCDIS:1; /*!< \brief bit: 28 Disable CP14 access to trace registers */
|
uint32_t TRCDIS:1; /*!< \brief bit: 28 Disable CP14 access to trace registers */
|
||||||
RESERVED(0:1, uint32_t)
|
RESERVED(0:1, uint32_t)
|
||||||
uint32_t D32DIS:1; /*!< \brief bit: 30 Disable use of registers D16-D31 of the VFP register file */
|
uint32_t D32DIS:1; /*!< \brief bit: 30 Disable use of registers D16-D31 of the VFP register file */
|
||||||
uint32_t ASEDIS:1; /*!< \brief bit: 31 Disable Advanced SIMD Functionality */
|
uint32_t ASEDIS:1; /*!< \brief bit: 31 Disable Advanced SIMD Functionality */
|
||||||
|
@ -539,7 +541,7 @@ typedef union
|
||||||
uint32_t FS0:4; /*!< \brief bit: 0.. 3 Fault Status bits bit 0-3 */
|
uint32_t FS0:4; /*!< \brief bit: 0.. 3 Fault Status bits bit 0-3 */
|
||||||
uint32_t Domain:4; /*!< \brief bit: 4.. 7 Fault on which domain */
|
uint32_t Domain:4; /*!< \brief bit: 4.. 7 Fault on which domain */
|
||||||
RESERVED(0:1, uint32_t)
|
RESERVED(0:1, uint32_t)
|
||||||
uint32_t LPAE:1; /*!< \brief bit: 9 Large Physical Address Extension */
|
uint32_t LPAE:1; /*!< \brief bit: 9 Large Physical Address Extension */
|
||||||
uint32_t FS1:1; /*!< \brief bit: 10 Fault Status bits bit 4 */
|
uint32_t FS1:1; /*!< \brief bit: 10 Fault Status bits bit 4 */
|
||||||
uint32_t WnR:1; /*!< \brief bit: 11 Write not Read bit */
|
uint32_t WnR:1; /*!< \brief bit: 11 Write not Read bit */
|
||||||
uint32_t ExT:1; /*!< \brief bit: 12 External abort type */
|
uint32_t ExT:1; /*!< \brief bit: 12 External abort type */
|
||||||
|
@ -550,7 +552,7 @@ typedef union
|
||||||
{
|
{
|
||||||
uint32_t STATUS:5; /*!< \brief bit: 0.. 5 Fault Status bits */
|
uint32_t STATUS:5; /*!< \brief bit: 0.. 5 Fault Status bits */
|
||||||
RESERVED(0:3, uint32_t)
|
RESERVED(0:3, uint32_t)
|
||||||
uint32_t LPAE:1; /*!< \brief bit: 9 Large Physical Address Extension */
|
uint32_t LPAE:1; /*!< \brief bit: 9 Large Physical Address Extension */
|
||||||
RESERVED(1:1, uint32_t)
|
RESERVED(1:1, uint32_t)
|
||||||
uint32_t WnR:1; /*!< \brief bit: 11 Write not Read bit */
|
uint32_t WnR:1; /*!< \brief bit: 11 Write not Read bit */
|
||||||
uint32_t ExT:1; /*!< \brief bit: 12 External abort type */
|
uint32_t ExT:1; /*!< \brief bit: 12 External abort type */
|
||||||
|
@ -846,35 +848,35 @@ typedef struct
|
||||||
|
|
||||||
/** \brief Enable Caches by setting I and C bits in SCTLR register.
|
/** \brief Enable Caches by setting I and C bits in SCTLR register.
|
||||||
*/
|
*/
|
||||||
__STATIC_INLINE void L1C_EnableCaches(void) {
|
__STATIC_FORCEINLINE void L1C_EnableCaches(void) {
|
||||||
__set_SCTLR( __get_SCTLR() | (1U << SCTLR_I_Pos) | (1U << SCTLR_C_Pos));
|
__set_SCTLR( __get_SCTLR() | SCTLR_I_Msk | SCTLR_C_Msk);
|
||||||
__ISB();
|
__ISB();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \brief Disable Caches by clearing I and C bits in SCTLR register.
|
/** \brief Disable Caches by clearing I and C bits in SCTLR register.
|
||||||
*/
|
*/
|
||||||
__STATIC_INLINE void L1C_DisableCaches(void) {
|
__STATIC_FORCEINLINE void L1C_DisableCaches(void) {
|
||||||
__set_SCTLR( __get_SCTLR() & ~(1U << SCTLR_I_Pos) & ~(1U << SCTLR_C_Pos));
|
__set_SCTLR( __get_SCTLR() & (~SCTLR_I_Msk) & (~SCTLR_C_Msk));
|
||||||
__ISB();
|
__ISB();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \brief Enable Branch Prediction by setting Z bit in SCTLR register.
|
/** \brief Enable Branch Prediction by setting Z bit in SCTLR register.
|
||||||
*/
|
*/
|
||||||
__STATIC_INLINE void L1C_EnableBTAC(void) {
|
__STATIC_FORCEINLINE void L1C_EnableBTAC(void) {
|
||||||
__set_SCTLR( __get_SCTLR() | (1U << SCTLR_Z_Pos));
|
__set_SCTLR( __get_SCTLR() | SCTLR_Z_Msk);
|
||||||
__ISB();
|
__ISB();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \brief Disable Branch Prediction by clearing Z bit in SCTLR register.
|
/** \brief Disable Branch Prediction by clearing Z bit in SCTLR register.
|
||||||
*/
|
*/
|
||||||
__STATIC_INLINE void L1C_DisableBTAC(void) {
|
__STATIC_FORCEINLINE void L1C_DisableBTAC(void) {
|
||||||
__set_SCTLR( __get_SCTLR() & ~(1U << SCTLR_Z_Pos));
|
__set_SCTLR( __get_SCTLR() & (~SCTLR_Z_Msk));
|
||||||
__ISB();
|
__ISB();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \brief Invalidate entire branch predictor array
|
/** \brief Invalidate entire branch predictor array
|
||||||
*/
|
*/
|
||||||
__STATIC_INLINE void L1C_InvalidateBTAC(void) {
|
__STATIC_FORCEINLINE void L1C_InvalidateBTAC(void) {
|
||||||
__set_BPIALL(0);
|
__set_BPIALL(0);
|
||||||
__DSB(); //ensure completion of the invalidation
|
__DSB(); //ensure completion of the invalidation
|
||||||
__ISB(); //ensure instruction fetch path sees new state
|
__ISB(); //ensure instruction fetch path sees new state
|
||||||
|
@ -882,7 +884,7 @@ __STATIC_INLINE void L1C_InvalidateBTAC(void) {
|
||||||
|
|
||||||
/** \brief Invalidate the whole instruction cache
|
/** \brief Invalidate the whole instruction cache
|
||||||
*/
|
*/
|
||||||
__STATIC_INLINE void L1C_InvalidateICacheAll(void) {
|
__STATIC_FORCEINLINE void L1C_InvalidateICacheAll(void) {
|
||||||
__set_ICIALLU(0);
|
__set_ICIALLU(0);
|
||||||
__DSB(); //ensure completion of the invalidation
|
__DSB(); //ensure completion of the invalidation
|
||||||
__ISB(); //ensure instruction fetch path sees new I cache state
|
__ISB(); //ensure instruction fetch path sees new I cache state
|
||||||
|
@ -891,7 +893,7 @@ __STATIC_INLINE void L1C_InvalidateICacheAll(void) {
|
||||||
/** \brief Clean data cache line by address.
|
/** \brief Clean data cache line by address.
|
||||||
* \param [in] va Pointer to data to clear the cache for.
|
* \param [in] va Pointer to data to clear the cache for.
|
||||||
*/
|
*/
|
||||||
__STATIC_INLINE void L1C_CleanDCacheMVA(void *va) {
|
__STATIC_FORCEINLINE void L1C_CleanDCacheMVA(void *va) {
|
||||||
__set_DCCMVAC((uint32_t)va);
|
__set_DCCMVAC((uint32_t)va);
|
||||||
__DMB(); //ensure the ordering of data cache maintenance operations and their effects
|
__DMB(); //ensure the ordering of data cache maintenance operations and their effects
|
||||||
}
|
}
|
||||||
|
@ -899,7 +901,7 @@ __STATIC_INLINE void L1C_CleanDCacheMVA(void *va) {
|
||||||
/** \brief Invalidate data cache line by address.
|
/** \brief Invalidate data cache line by address.
|
||||||
* \param [in] va Pointer to data to invalidate the cache for.
|
* \param [in] va Pointer to data to invalidate the cache for.
|
||||||
*/
|
*/
|
||||||
__STATIC_INLINE void L1C_InvalidateDCacheMVA(void *va) {
|
__STATIC_FORCEINLINE void L1C_InvalidateDCacheMVA(void *va) {
|
||||||
__set_DCIMVAC((uint32_t)va);
|
__set_DCIMVAC((uint32_t)va);
|
||||||
__DMB(); //ensure the ordering of data cache maintenance operations and their effects
|
__DMB(); //ensure the ordering of data cache maintenance operations and their effects
|
||||||
}
|
}
|
||||||
|
@ -907,38 +909,130 @@ __STATIC_INLINE void L1C_InvalidateDCacheMVA(void *va) {
|
||||||
/** \brief Clean and Invalidate data cache by address.
|
/** \brief Clean and Invalidate data cache by address.
|
||||||
* \param [in] va Pointer to data to invalidate the cache for.
|
* \param [in] va Pointer to data to invalidate the cache for.
|
||||||
*/
|
*/
|
||||||
__STATIC_INLINE void L1C_CleanInvalidateDCacheMVA(void *va) {
|
__STATIC_FORCEINLINE void L1C_CleanInvalidateDCacheMVA(void *va) {
|
||||||
__set_DCCIMVAC((uint32_t)va);
|
__set_DCCIMVAC((uint32_t)va);
|
||||||
__DMB(); //ensure the ordering of data cache maintenance operations and their effects
|
__DMB(); //ensure the ordering of data cache maintenance operations and their effects
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \brief Clean and Invalidate the entire data or unified cache
|
/** \brief Calculate log2 rounded up
|
||||||
* \param [in] op 0 - invalidate, 1 - clean, otherwise - invalidate and clean
|
* - log(0) => 0
|
||||||
* \see __L1C_CleanInvalidateCache
|
* - log(1) => 0
|
||||||
|
* - log(2) => 1
|
||||||
|
* - log(3) => 2
|
||||||
|
* - log(4) => 2
|
||||||
|
* - log(5) => 3
|
||||||
|
* : :
|
||||||
|
* - log(16) => 4
|
||||||
|
* - log(32) => 5
|
||||||
|
* : :
|
||||||
|
* \param [in] n input value parameter
|
||||||
|
* \return log2(n)
|
||||||
*/
|
*/
|
||||||
__STATIC_INLINE void L1C_CleanInvalidateCache(uint32_t op) {
|
__STATIC_FORCEINLINE uint8_t __log2_up(uint32_t n)
|
||||||
__L1C_CleanInvalidateCache(op);
|
{
|
||||||
|
if (n < 2U) {
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
uint8_t log = 0U;
|
||||||
|
uint32_t t = n;
|
||||||
|
while(t > 1U)
|
||||||
|
{
|
||||||
|
log++;
|
||||||
|
t >>= 1U;
|
||||||
|
}
|
||||||
|
if (n & 1U) { log++; }
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Apply cache maintenance to given cache level.
|
||||||
|
* \param [in] level cache level to be maintained
|
||||||
|
* \param [in] maint 0 - invalidate, 1 - clean, otherwise - invalidate and clean
|
||||||
|
*/
|
||||||
|
__STATIC_FORCEINLINE void __L1C_MaintainDCacheSetWay(uint32_t level, uint32_t maint)
|
||||||
|
{
|
||||||
|
register volatile uint32_t Dummy;
|
||||||
|
register volatile uint32_t ccsidr;
|
||||||
|
uint32_t num_sets;
|
||||||
|
uint32_t num_ways;
|
||||||
|
uint32_t shift_way;
|
||||||
|
uint32_t log2_linesize;
|
||||||
|
int32_t log2_num_ways;
|
||||||
|
|
||||||
|
Dummy = level << 1U;
|
||||||
|
/* set csselr, select ccsidr register */
|
||||||
|
__set_CCSIDR(Dummy);
|
||||||
|
/* get current ccsidr register */
|
||||||
|
ccsidr = __get_CCSIDR();
|
||||||
|
num_sets = ((ccsidr & 0x0FFFE000U) >> 13U) + 1U;
|
||||||
|
num_ways = ((ccsidr & 0x00001FF8U) >> 3U) + 1U;
|
||||||
|
log2_linesize = (ccsidr & 0x00000007U) + 2U + 2U;
|
||||||
|
log2_num_ways = __log2_up(num_ways);
|
||||||
|
if ((log2_num_ways < 0) || (log2_num_ways > 32)) {
|
||||||
|
return; // FATAL ERROR
|
||||||
|
}
|
||||||
|
shift_way = 32U - (uint32_t)log2_num_ways;
|
||||||
|
for(int32_t way = num_ways-1; way >= 0; way--)
|
||||||
|
{
|
||||||
|
for(int32_t set = num_sets-1; set >= 0; set--)
|
||||||
|
{
|
||||||
|
Dummy = (level << 1U) | (((uint32_t)set) << log2_linesize) | (((uint32_t)way) << shift_way);
|
||||||
|
switch (maint)
|
||||||
|
{
|
||||||
|
case 0U: __set_DCISW(Dummy); break;
|
||||||
|
case 1U: __set_DCCSW(Dummy); break;
|
||||||
|
default: __set_DCCISW(Dummy); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
__DMB();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Clean and Invalidate the entire data or unified cache
|
||||||
|
* Generic mechanism for cleaning/invalidating the entire data or unified cache to the point of coherency
|
||||||
|
* \param [in] op 0 - invalidate, 1 - clean, otherwise - invalidate and clean
|
||||||
|
*/
|
||||||
|
__STATIC_FORCEINLINE void L1C_CleanInvalidateCache(uint32_t op) {
|
||||||
|
register volatile uint32_t clidr;
|
||||||
|
uint32_t cache_type;
|
||||||
|
clidr = __get_CLIDR();
|
||||||
|
for(uint32_t i = 0U; i<7U; i++)
|
||||||
|
{
|
||||||
|
cache_type = (clidr >> i*3U) & 0x7UL;
|
||||||
|
if ((cache_type >= 2U) && (cache_type <= 4U))
|
||||||
|
{
|
||||||
|
__L1C_MaintainDCacheSetWay(i, op);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Clean and Invalidate the entire data or unified cache
|
||||||
|
* Generic mechanism for cleaning/invalidating the entire data or unified cache to the point of coherency
|
||||||
|
* \param [in] op 0 - invalidate, 1 - clean, otherwise - invalidate and clean
|
||||||
|
* \deprecated Use generic L1C_CleanInvalidateCache instead.
|
||||||
|
*/
|
||||||
|
CMSIS_DEPRECATED
|
||||||
|
__STATIC_FORCEINLINE void __L1C_CleanInvalidateCache(uint32_t op) {
|
||||||
|
L1C_CleanInvalidateCache(op);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \brief Invalidate the whole data cache.
|
/** \brief Invalidate the whole data cache.
|
||||||
*/
|
*/
|
||||||
__STATIC_INLINE void L1C_InvalidateDCacheAll(void) {
|
__STATIC_FORCEINLINE void L1C_InvalidateDCacheAll(void) {
|
||||||
L1C_CleanInvalidateCache(0);
|
L1C_CleanInvalidateCache(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \brief Clean the whole data cache.
|
/** \brief Clean the whole data cache.
|
||||||
*/
|
*/
|
||||||
__STATIC_INLINE void L1C_CleanDCacheAll(void) {
|
__STATIC_FORCEINLINE void L1C_CleanDCacheAll(void) {
|
||||||
L1C_CleanInvalidateCache(1);
|
L1C_CleanInvalidateCache(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \brief Clean and invalidate the whole data cache.
|
/** \brief Clean and invalidate the whole data cache.
|
||||||
*/
|
*/
|
||||||
__STATIC_INLINE void L1C_CleanInvalidateDCacheAll(void) {
|
__STATIC_FORCEINLINE void L1C_CleanInvalidateDCacheAll(void) {
|
||||||
L1C_CleanInvalidateCache(2);
|
L1C_CleanInvalidateCache(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* ########################## L2 Cache functions ################################# */
|
/* ########################## L2 Cache functions ################################# */
|
||||||
#if (__L2C_PRESENT == 1U) || defined(DOXYGEN)
|
#if (__L2C_PRESENT == 1U) || defined(DOXYGEN)
|
||||||
/** \brief Cache Sync operation by writing CACHE_SYNC register.
|
/** \brief Cache Sync operation by writing CACHE_SYNC register.
|
||||||
|
@ -1354,8 +1448,8 @@ __STATIC_INLINE uint32_t GIC_GetGroup(IRQn_Type IRQn)
|
||||||
*/
|
*/
|
||||||
__STATIC_INLINE void GIC_DistInit(void)
|
__STATIC_INLINE void GIC_DistInit(void)
|
||||||
{
|
{
|
||||||
IRQn_Type i;
|
uint32_t i;
|
||||||
uint32_t num_irq = 0;
|
uint32_t num_irq = 0U;
|
||||||
uint32_t priority_field;
|
uint32_t priority_field;
|
||||||
|
|
||||||
//A reset sets all bits in the IGROUPRs corresponding to the SPIs to 0,
|
//A reset sets all bits in the IGROUPRs corresponding to the SPIs to 0,
|
||||||
|
@ -1364,26 +1458,24 @@ __STATIC_INLINE void GIC_DistInit(void)
|
||||||
//Disable interrupt forwarding
|
//Disable interrupt forwarding
|
||||||
GIC_DisableDistributor();
|
GIC_DisableDistributor();
|
||||||
//Get the maximum number of interrupts that the GIC supports
|
//Get the maximum number of interrupts that the GIC supports
|
||||||
num_irq = 32 * ((GIC_DistributorInfo() & 0x1f) + 1);
|
num_irq = 32U * ((GIC_DistributorInfo() & 0x1FU) + 1U);
|
||||||
|
|
||||||
/* Priority level is implementation defined.
|
/* Priority level is implementation defined.
|
||||||
To determine the number of priority bits implemented write 0xFF to an IPRIORITYR
|
To determine the number of priority bits implemented write 0xFF to an IPRIORITYR
|
||||||
priority field and read back the value stored.*/
|
priority field and read back the value stored.*/
|
||||||
GIC_SetPriority((IRQn_Type)0, 0xff);
|
GIC_SetPriority((IRQn_Type)0U, 0xFFU);
|
||||||
priority_field = GIC_GetPriority((IRQn_Type)0);
|
priority_field = GIC_GetPriority((IRQn_Type)0U);
|
||||||
|
|
||||||
for (i = (IRQn_Type)32; i < num_irq; i++)
|
for (i = 32U; i < num_irq; i++)
|
||||||
{
|
{
|
||||||
//Disable the SPI interrupt
|
//Disable the SPI interrupt
|
||||||
GIC_DisableIRQ(i);
|
GIC_DisableIRQ((IRQn_Type)i);
|
||||||
if (i > 15) {
|
//Set level-sensitive (and N-N model)
|
||||||
//Set level-sensitive (and N-N model)
|
GIC_SetConfiguration((IRQn_Type)i, 0U);
|
||||||
GIC_SetConfiguration(i, 0);
|
|
||||||
}
|
|
||||||
//Set priority
|
//Set priority
|
||||||
GIC_SetPriority(i, priority_field/2);
|
GIC_SetPriority((IRQn_Type)i, priority_field/2U);
|
||||||
//Set target list to CPU0
|
//Set target list to CPU0
|
||||||
GIC_SetTarget(i, 1);
|
GIC_SetTarget((IRQn_Type)i, 1U);
|
||||||
}
|
}
|
||||||
//Enable distributor
|
//Enable distributor
|
||||||
GIC_EnableDistributor();
|
GIC_EnableDistributor();
|
||||||
|
@ -1393,7 +1485,7 @@ __STATIC_INLINE void GIC_DistInit(void)
|
||||||
*/
|
*/
|
||||||
__STATIC_INLINE void GIC_CPUInterfaceInit(void)
|
__STATIC_INLINE void GIC_CPUInterfaceInit(void)
|
||||||
{
|
{
|
||||||
IRQn_Type i;
|
uint32_t i;
|
||||||
uint32_t priority_field;
|
uint32_t priority_field;
|
||||||
|
|
||||||
//A reset sets all bits in the IGROUPRs corresponding to the SPIs to 0,
|
//A reset sets all bits in the IGROUPRs corresponding to the SPIs to 0,
|
||||||
|
@ -1405,27 +1497,27 @@ __STATIC_INLINE void GIC_CPUInterfaceInit(void)
|
||||||
/* Priority level is implementation defined.
|
/* Priority level is implementation defined.
|
||||||
To determine the number of priority bits implemented write 0xFF to an IPRIORITYR
|
To determine the number of priority bits implemented write 0xFF to an IPRIORITYR
|
||||||
priority field and read back the value stored.*/
|
priority field and read back the value stored.*/
|
||||||
GIC_SetPriority((IRQn_Type)0, 0xff);
|
GIC_SetPriority((IRQn_Type)0U, 0xFFU);
|
||||||
priority_field = GIC_GetPriority((IRQn_Type)0);
|
priority_field = GIC_GetPriority((IRQn_Type)0U);
|
||||||
|
|
||||||
//SGI and PPI
|
//SGI and PPI
|
||||||
for (i = (IRQn_Type)0; i < 32; i++)
|
for (i = 0U; i < 32U; i++)
|
||||||
{
|
{
|
||||||
if(i > 15) {
|
if(i > 15U) {
|
||||||
//Set level-sensitive (and N-N model) for PPI
|
//Set level-sensitive (and N-N model) for PPI
|
||||||
GIC_SetConfiguration(i, 0U);
|
GIC_SetConfiguration((IRQn_Type)i, 0U);
|
||||||
}
|
}
|
||||||
//Disable SGI and PPI interrupts
|
//Disable SGI and PPI interrupts
|
||||||
GIC_DisableIRQ(i);
|
GIC_DisableIRQ((IRQn_Type)i);
|
||||||
//Set priority
|
//Set priority
|
||||||
GIC_SetPriority(i, priority_field/2);
|
GIC_SetPriority((IRQn_Type)i, priority_field/2U);
|
||||||
}
|
}
|
||||||
//Enable interface
|
//Enable interface
|
||||||
GIC_EnableInterface();
|
GIC_EnableInterface();
|
||||||
//Set binary point to 0
|
//Set binary point to 0
|
||||||
GIC_SetBinaryPoint(0);
|
GIC_SetBinaryPoint(0U);
|
||||||
//Set priority mask
|
//Set priority mask
|
||||||
GIC_SetInterfacePriorityMask(0xff);
|
GIC_SetInterfacePriorityMask(0xFFU);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \brief Initialize and enable the GIC
|
/** \brief Initialize and enable the GIC
|
||||||
|
@ -1477,11 +1569,36 @@ __STATIC_INLINE void PL1_SetLoadValue(uint32_t value)
|
||||||
/** \brief Get the current counter value.
|
/** \brief Get the current counter value.
|
||||||
* \return Current counter value.
|
* \return Current counter value.
|
||||||
*/
|
*/
|
||||||
__STATIC_INLINE uint32_t PL1_GetCurrentValue()
|
__STATIC_INLINE uint32_t PL1_GetCurrentValue(void)
|
||||||
{
|
{
|
||||||
return(__get_CNTP_TVAL());
|
return(__get_CNTP_TVAL());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** \brief Get the current physical counter value.
|
||||||
|
* \return Current physical counter value.
|
||||||
|
*/
|
||||||
|
__STATIC_INLINE uint64_t PL1_GetCurrentPhysicalValue(void)
|
||||||
|
{
|
||||||
|
return(__get_CNTPCT());
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Set the physical compare value.
|
||||||
|
* \param [in] value New physical timer compare value.
|
||||||
|
*/
|
||||||
|
__STATIC_INLINE void PL1_SetPhysicalCompareValue(uint64_t value)
|
||||||
|
{
|
||||||
|
__set_CNTP_CVAL(value);
|
||||||
|
__ISB();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Get the physical compare value.
|
||||||
|
* \return Physical compare value.
|
||||||
|
*/
|
||||||
|
__STATIC_INLINE uint64_t PL1_GetPhysicalCompareValue(void)
|
||||||
|
{
|
||||||
|
return(__get_CNTP_CVAL());
|
||||||
|
}
|
||||||
|
|
||||||
/** \brief Configure the timer by setting the control value.
|
/** \brief Configure the timer by setting the control value.
|
||||||
* \param [in] value New timer control value.
|
* \param [in] value New timer control value.
|
||||||
*/
|
*/
|
||||||
|
@ -1494,7 +1611,7 @@ __STATIC_INLINE void PL1_SetControl(uint32_t value)
|
||||||
/** \brief Get the control value.
|
/** \brief Get the control value.
|
||||||
* \return Control value.
|
* \return Control value.
|
||||||
*/
|
*/
|
||||||
__STATIC_INLINE uint32_t PL1_GetControl()
|
__STATIC_INLINE uint32_t PL1_GetControl(void)
|
||||||
{
|
{
|
||||||
return(__get_CNTP_CTL());
|
return(__get_CNTP_CTL());
|
||||||
}
|
}
|
||||||
|
@ -1763,6 +1880,21 @@ typedef struct RegionStruct {
|
||||||
region.sh_t = NON_SHARED; \
|
region.sh_t = NON_SHARED; \
|
||||||
MMU_GetSectionDescriptor(&descriptor_l1, region);
|
MMU_GetSectionDescriptor(&descriptor_l1, region);
|
||||||
|
|
||||||
|
//Sect_Normal_NC. Outer & inner non-cacheable, non-shareable, executable, rw, domain 0
|
||||||
|
#define section_normal_nc(descriptor_l1, region) region.rg_t = SECTION; \
|
||||||
|
region.domain = 0x0; \
|
||||||
|
region.e_t = ECC_DISABLED; \
|
||||||
|
region.g_t = GLOBAL; \
|
||||||
|
region.inner_norm_t = NON_CACHEABLE; \
|
||||||
|
region.outer_norm_t = NON_CACHEABLE; \
|
||||||
|
region.mem_t = NORMAL; \
|
||||||
|
region.sec_t = SECURE; \
|
||||||
|
region.xn_t = EXECUTE; \
|
||||||
|
region.priv_t = RW; \
|
||||||
|
region.user_t = RW; \
|
||||||
|
region.sh_t = NON_SHARED; \
|
||||||
|
MMU_GetSectionDescriptor(&descriptor_l1, region);
|
||||||
|
|
||||||
//Sect_Normal_Cod. Outer & inner wb/wa, non-shareable, executable, ro, domain 0
|
//Sect_Normal_Cod. Outer & inner wb/wa, non-shareable, executable, ro, domain 0
|
||||||
#define section_normal_cod(descriptor_l1, region) region.rg_t = SECTION; \
|
#define section_normal_cod(descriptor_l1, region) region.rg_t = SECTION; \
|
||||||
region.domain = 0x0; \
|
region.domain = 0x0; \
|
||||||
|
|
|
@ -28,9 +28,10 @@ SingletonPtr<PlatformMutex> I2C::_mutex;
|
||||||
|
|
||||||
I2C::I2C(PinName sda, PinName scl) :
|
I2C::I2C(PinName sda, PinName scl) :
|
||||||
#if DEVICE_I2C_ASYNCH
|
#if DEVICE_I2C_ASYNCH
|
||||||
_irq(this), _usage(DMA_USAGE_NEVER),
|
_irq(this), _usage(DMA_USAGE_NEVER), _deep_sleep_locked(false),
|
||||||
#endif
|
#endif
|
||||||
_i2c(), _hz(100000) {
|
_i2c(), _hz(100000)
|
||||||
|
{
|
||||||
// No lock needed in the constructor
|
// No lock needed in the constructor
|
||||||
|
|
||||||
// The init function also set the frequency to 100000
|
// The init function also set the frequency to 100000
|
||||||
|
@ -133,7 +134,7 @@ int I2C::transfer(int address, const char *tx_buffer, int tx_length, char *rx_bu
|
||||||
unlock();
|
unlock();
|
||||||
return -1; // transaction ongoing
|
return -1; // transaction ongoing
|
||||||
}
|
}
|
||||||
sleep_manager_lock_deep_sleep();
|
lock_deep_sleep();
|
||||||
aquire();
|
aquire();
|
||||||
|
|
||||||
_callback = callback;
|
_callback = callback;
|
||||||
|
@ -148,7 +149,7 @@ void I2C::abort_transfer(void)
|
||||||
{
|
{
|
||||||
lock();
|
lock();
|
||||||
i2c_abort_asynch(&_i2c);
|
i2c_abort_asynch(&_i2c);
|
||||||
sleep_manager_unlock_deep_sleep();
|
unlock_deep_sleep();
|
||||||
unlock();
|
unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,11 +160,26 @@ void I2C::irq_handler_asynch(void)
|
||||||
_callback.call(event);
|
_callback.call(event);
|
||||||
}
|
}
|
||||||
if (event) {
|
if (event) {
|
||||||
sleep_manager_unlock_deep_sleep();
|
unlock_deep_sleep();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void I2C::lock_deep_sleep()
|
||||||
|
{
|
||||||
|
if (_deep_sleep_locked == false) {
|
||||||
|
sleep_manager_lock_deep_sleep();
|
||||||
|
_deep_sleep_locked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void I2C::unlock_deep_sleep()
|
||||||
|
{
|
||||||
|
if (_deep_sleep_locked == true) {
|
||||||
|
sleep_manager_unlock_deep_sleep();
|
||||||
|
_deep_sleep_locked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -176,11 +176,19 @@ public:
|
||||||
/** Abort the on-going I2C transfer
|
/** Abort the on-going I2C transfer
|
||||||
*/
|
*/
|
||||||
void abort_transfer();
|
void abort_transfer();
|
||||||
protected:
|
|
||||||
|
protected:
|
||||||
|
/** Lock deep sleep only if it is not yet locked */
|
||||||
|
void lock_deep_sleep();
|
||||||
|
|
||||||
|
/** Unlock deep sleep only if it has been locked */
|
||||||
|
void unlock_deep_sleep();
|
||||||
|
|
||||||
void irq_handler_asynch(void);
|
void irq_handler_asynch(void);
|
||||||
event_callback_t _callback;
|
event_callback_t _callback;
|
||||||
CThunk<I2C> _irq;
|
CThunk<I2C> _irq;
|
||||||
DMAUsage _usage;
|
DMAUsage _usage;
|
||||||
|
bool _deep_sleep_locked;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -33,6 +33,7 @@ SPI::SPI(PinName mosi, PinName miso, PinName sclk, PinName ssel) :
|
||||||
#if DEVICE_SPI_ASYNCH
|
#if DEVICE_SPI_ASYNCH
|
||||||
_irq(this),
|
_irq(this),
|
||||||
_usage(DMA_USAGE_NEVER),
|
_usage(DMA_USAGE_NEVER),
|
||||||
|
_deep_sleep_locked(false),
|
||||||
#endif
|
#endif
|
||||||
_bits(8),
|
_bits(8),
|
||||||
_mode(0),
|
_mode(0),
|
||||||
|
@ -140,7 +141,7 @@ int SPI::transfer(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_
|
||||||
void SPI::abort_transfer()
|
void SPI::abort_transfer()
|
||||||
{
|
{
|
||||||
spi_abort_asynch(&_spi);
|
spi_abort_asynch(&_spi);
|
||||||
sleep_manager_unlock_deep_sleep();
|
unlock_deep_sleep();
|
||||||
#if TRANSACTION_QUEUE_SIZE_SPI
|
#if TRANSACTION_QUEUE_SIZE_SPI
|
||||||
dequeue_transaction();
|
dequeue_transaction();
|
||||||
#endif
|
#endif
|
||||||
|
@ -200,13 +201,29 @@ int SPI::queue_transfer(const void *tx_buffer, int tx_length, void *rx_buffer, i
|
||||||
|
|
||||||
void SPI::start_transfer(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_length, unsigned char bit_width, const event_callback_t& callback, int event)
|
void SPI::start_transfer(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_length, unsigned char bit_width, const event_callback_t& callback, int event)
|
||||||
{
|
{
|
||||||
sleep_manager_lock_deep_sleep();
|
lock_deep_sleep();
|
||||||
_acquire();
|
_acquire();
|
||||||
_callback = callback;
|
_callback = callback;
|
||||||
_irq.callback(&SPI::irq_handler_asynch);
|
_irq.callback(&SPI::irq_handler_asynch);
|
||||||
spi_master_transfer(&_spi, tx_buffer, tx_length, rx_buffer, rx_length, bit_width, _irq.entry(), event , _usage);
|
spi_master_transfer(&_spi, tx_buffer, tx_length, rx_buffer, rx_length, bit_width, _irq.entry(), event , _usage);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SPI::lock_deep_sleep()
|
||||||
|
{
|
||||||
|
if (_deep_sleep_locked == false) {
|
||||||
|
sleep_manager_lock_deep_sleep();
|
||||||
|
_deep_sleep_locked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SPI::unlock_deep_sleep()
|
||||||
|
{
|
||||||
|
if (_deep_sleep_locked == true) {
|
||||||
|
sleep_manager_unlock_deep_sleep();
|
||||||
|
_deep_sleep_locked = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if TRANSACTION_QUEUE_SIZE_SPI
|
#if TRANSACTION_QUEUE_SIZE_SPI
|
||||||
|
|
||||||
void SPI::start_transaction(transaction_t *data)
|
void SPI::start_transaction(transaction_t *data)
|
||||||
|
@ -230,7 +247,7 @@ void SPI::irq_handler_asynch(void)
|
||||||
{
|
{
|
||||||
int event = spi_irq_handler_asynch(&_spi);
|
int event = spi_irq_handler_asynch(&_spi);
|
||||||
if (_callback && (event & SPI_EVENT_ALL)) {
|
if (_callback && (event & SPI_EVENT_ALL)) {
|
||||||
sleep_manager_unlock_deep_sleep();
|
unlock_deep_sleep();
|
||||||
_callback.call(event & SPI_EVENT_ALL);
|
_callback.call(event & SPI_EVENT_ALL);
|
||||||
}
|
}
|
||||||
#if TRANSACTION_QUEUE_SIZE_SPI
|
#if TRANSACTION_QUEUE_SIZE_SPI
|
||||||
|
|
|
@ -246,6 +246,14 @@ protected:
|
||||||
*/
|
*/
|
||||||
void start_transfer(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_length, unsigned char bit_width, const event_callback_t& callback, int event);
|
void start_transfer(const void *tx_buffer, int tx_length, void *rx_buffer, int rx_length, unsigned char bit_width, const event_callback_t& callback, int event);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/** Lock deep sleep only if it is not yet locked */
|
||||||
|
void lock_deep_sleep();
|
||||||
|
|
||||||
|
/** Unlock deep sleep in case it is locked */
|
||||||
|
void unlock_deep_sleep();
|
||||||
|
|
||||||
|
|
||||||
#if TRANSACTION_QUEUE_SIZE_SPI
|
#if TRANSACTION_QUEUE_SIZE_SPI
|
||||||
|
|
||||||
/** Start a new transaction
|
/** Start a new transaction
|
||||||
|
@ -274,6 +282,7 @@ protected:
|
||||||
CThunk<SPI> _irq;
|
CThunk<SPI> _irq;
|
||||||
event_callback_t _callback;
|
event_callback_t _callback;
|
||||||
DMAUsage _usage;
|
DMAUsage _usage;
|
||||||
|
bool _deep_sleep_locked;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void aquire(void);
|
void aquire(void);
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* Copyright (c) 2017 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(DEVICE_ITM)
|
||||||
|
|
||||||
|
#include "hal/itm_api.h"
|
||||||
|
#include "platform/FileHandle.h"
|
||||||
|
|
||||||
|
class SerialWireOutput : public FileHandle {
|
||||||
|
public:
|
||||||
|
SerialWireOutput(void)
|
||||||
|
{
|
||||||
|
/* Initialize ITM using internal init function. */
|
||||||
|
mbed_itm_init();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ssize_t write(const void *buffer, size_t size)
|
||||||
|
{
|
||||||
|
const unsigned char *buf = static_cast<const unsigned char *>(buffer);
|
||||||
|
|
||||||
|
/* Send buffer one character at a time over the ITM SWO port */
|
||||||
|
for (size_t i = 0; i < size; i++) {
|
||||||
|
mbed_itm_send(ITM_PORT_SWO, buf[i]);
|
||||||
|
}
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ssize_t read(void *buffer, size_t size)
|
||||||
|
{
|
||||||
|
/* Reading is not supported by this file handle */
|
||||||
|
return -EBADF;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual off_t seek(off_t offset, int whence = SEEK_SET)
|
||||||
|
{
|
||||||
|
/* Seeking is not support by this file handler */
|
||||||
|
return -ESPIPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual off_t size()
|
||||||
|
{
|
||||||
|
/* Size is not defined for this file handle */
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int isatty()
|
||||||
|
{
|
||||||
|
/* File handle is used for terminal output */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int close()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -49,7 +49,7 @@ extern "C" {
|
||||||
// Platform includes
|
// Platform includes
|
||||||
#if defined(EQUEUE_PLATFORM_POSIX)
|
#if defined(EQUEUE_PLATFORM_POSIX)
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#elif defined(EQUEUE_PLATFORM_MBED)
|
#elif defined(EQUEUE_PLATFORM_MBED) && defined(MBED_CONF_RTOS_PRESENT)
|
||||||
#include "cmsis_os2.h"
|
#include "cmsis_os2.h"
|
||||||
#include "mbed_rtos_storage.h"
|
#include "mbed_rtos_storage.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -45,6 +45,11 @@ namespace mbed {
|
||||||
* for the event loop to work without an RTOS, or an RTOS system can can save
|
* for the event loop to work without an RTOS, or an RTOS system can can save
|
||||||
* memory by reusing the main stack.
|
* memory by reusing the main stack.
|
||||||
*
|
*
|
||||||
|
* @note
|
||||||
|
* mbed_event_queue is not itself IRQ safe. To use the mbed_event_queue in
|
||||||
|
* interrupt context, you must first call `mbed_event_queue()` in threaded
|
||||||
|
* context and store the pointer for later use.
|
||||||
|
*
|
||||||
* @return pointer to event queue
|
* @return pointer to event queue
|
||||||
*/
|
*/
|
||||||
events::EventQueue *mbed_event_queue();
|
events::EventQueue *mbed_event_queue();
|
||||||
|
@ -67,6 +72,12 @@ events::EventQueue *mbed_event_queue();
|
||||||
* or less, but could occasionally be significantly higher if many events are
|
* or less, but could occasionally be significantly higher if many events are
|
||||||
* queued.
|
* queued.
|
||||||
*
|
*
|
||||||
|
* @note
|
||||||
|
* mbed_highprio_event_queue is not itself IRQ safe. To use the
|
||||||
|
* mbed_highprio_event_queue in interrupt context, you must first call
|
||||||
|
* `mbed_event_queue()` in threaded context and store the pointer for
|
||||||
|
* later use.
|
||||||
|
*
|
||||||
* @return pointer to high-priority event queue
|
* @return pointer to high-priority event queue
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#ifndef MBED_UUID_H__
|
#ifndef MBED_UUID_H__
|
||||||
#define MBED_UUID_H__
|
#define MBED_UUID_H__
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
|
@ -26,27 +26,12 @@
|
||||||
namespace ble {
|
namespace ble {
|
||||||
namespace generic {
|
namespace generic {
|
||||||
|
|
||||||
// forward declarations
|
|
||||||
struct procedure_control_block_t;
|
|
||||||
struct discovery_control_block_t;
|
|
||||||
struct read_control_block_t;
|
|
||||||
struct write_control_block_t;
|
|
||||||
struct descriptor_discovery_control_block_t;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic implementation of the GattClient.
|
* Generic implementation of the GattClient.
|
||||||
* It requires a pal::GattClient injected at construction site.
|
* It requires a pal::GattClient injected at construction site.
|
||||||
* @attention: Not part of the public interface of BLE API.
|
* @attention: Not part of the public interface of BLE API.
|
||||||
*/
|
*/
|
||||||
class GenericGattClient : public GattClient {
|
class GenericGattClient : public GattClient {
|
||||||
|
|
||||||
// give access to control block classes
|
|
||||||
friend struct procedure_control_block_t;
|
|
||||||
friend struct discovery_control_block_t;
|
|
||||||
friend struct read_control_block_t;
|
|
||||||
friend struct write_control_block_t;
|
|
||||||
friend struct descriptor_discovery_control_block_t;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Create a GenericGattClient from a pal::GattClient
|
* Create a GenericGattClient from a pal::GattClient
|
||||||
|
@ -130,10 +115,16 @@ public:
|
||||||
virtual ble_error_t reset(void);
|
virtual ble_error_t reset(void);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
procedure_control_block_t* get_control_block(Gap::Handle_t connection);
|
struct ProcedureControlBlock;
|
||||||
const procedure_control_block_t* get_control_block(Gap::Handle_t connection) const;
|
struct DiscoveryControlBlock;
|
||||||
void insert_control_block(procedure_control_block_t* cb) const;
|
struct ReadControlBlock;
|
||||||
void remove_control_block(procedure_control_block_t* cb) const;
|
struct WriteControlBlock;
|
||||||
|
struct DescriptorDiscoveryControlBlock;
|
||||||
|
|
||||||
|
ProcedureControlBlock* get_control_block(Gap::Handle_t connection);
|
||||||
|
const ProcedureControlBlock* get_control_block(Gap::Handle_t connection) const;
|
||||||
|
void insert_control_block(ProcedureControlBlock* cb) const;
|
||||||
|
void remove_control_block(ProcedureControlBlock* cb) const;
|
||||||
|
|
||||||
void on_termination(Gap::Handle_t connection_handle);
|
void on_termination(Gap::Handle_t connection_handle);
|
||||||
void on_server_message_received(connection_handle_t, const pal::AttServerMessage&);
|
void on_server_message_received(connection_handle_t, const pal::AttServerMessage&);
|
||||||
|
@ -145,7 +136,8 @@ private:
|
||||||
|
|
||||||
pal::GattClient* const _pal_client;
|
pal::GattClient* const _pal_client;
|
||||||
ServiceDiscovery::TerminationCallback_t _termination_callback;
|
ServiceDiscovery::TerminationCallback_t _termination_callback;
|
||||||
mutable procedure_control_block_t* control_blocks;
|
mutable ProcedureControlBlock* control_blocks;
|
||||||
|
bool _is_reseting;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -410,8 +410,6 @@ struct initiator_policy_t : SafeEnum<initiator_policy_t, uint8_t> {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hold advertising data.
|
* Hold advertising data.
|
||||||
*/
|
*/
|
||||||
|
@ -473,7 +471,7 @@ struct advertising_data_t {
|
||||||
/**
|
/**
|
||||||
* Return (fixed) size of advertising data.
|
* Return (fixed) size of advertising data.
|
||||||
*/
|
*/
|
||||||
static uint8_t size() {
|
uint8_t size() const {
|
||||||
return sizeof(value);
|
return sizeof(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#include <new>
|
#include <new>
|
||||||
#include "EventQueue.h"
|
#include "EventQueue.h"
|
||||||
#include "ble/BLEInstanceBase.h"
|
#include "ble/BLEInstanceBase.h"
|
||||||
#include "BLE/ble.h"
|
#include "ble/BLE.h"
|
||||||
|
|
||||||
namespace ble {
|
namespace ble {
|
||||||
namespace pal {
|
namespace pal {
|
||||||
|
|
|
@ -376,7 +376,6 @@ GenericGap::GenericGap(
|
||||||
_pal_gap(pal_gap),
|
_pal_gap(pal_gap),
|
||||||
_gap_service(generic_access_service),
|
_gap_service(generic_access_service),
|
||||||
_address_type(BLEProtocol::AddressType::PUBLIC),
|
_address_type(BLEProtocol::AddressType::PUBLIC),
|
||||||
_address(),
|
|
||||||
_initiator_policy_mode(pal::initiator_policy_t::NO_FILTER),
|
_initiator_policy_mode(pal::initiator_policy_t::NO_FILTER),
|
||||||
_scanning_filter_policy(pal::scanning_filter_policy_t::NO_FILTER),
|
_scanning_filter_policy(pal::scanning_filter_policy_t::NO_FILTER),
|
||||||
_advertising_filter_policy(pal::advertising_filter_policy_t::NO_FILTER),
|
_advertising_filter_policy(pal::advertising_filter_policy_t::NO_FILTER),
|
||||||
|
@ -440,7 +439,14 @@ ble_error_t GenericGap::getAddress(
|
||||||
BLEProtocol::AddressBytes_t address
|
BLEProtocol::AddressBytes_t address
|
||||||
) {
|
) {
|
||||||
*type = _address_type;
|
*type = _address_type;
|
||||||
memcpy(address, _address.data(), _address.size());
|
pal::address_t address_value;
|
||||||
|
if (_address_type == BLEProtocol::AddressType::PUBLIC) {
|
||||||
|
address_value = _pal_gap.get_device_address();
|
||||||
|
} else {
|
||||||
|
address_value = _pal_gap.get_random_address();
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(address, address_value.data(), address_value.size());
|
||||||
return BLE_ERROR_NONE;
|
return BLE_ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1040,6 +1046,12 @@ void GenericGap::on_connection_complete(const pal::GapConnectionCompleteEvent& e
|
||||||
e.connection_latency,
|
e.connection_latency,
|
||||||
e.supervision_timeout
|
e.supervision_timeout
|
||||||
};
|
};
|
||||||
|
pal::address_t address;
|
||||||
|
if (_address_type == BLEProtocol::AddressType::PUBLIC) {
|
||||||
|
address = _pal_gap.get_device_address();
|
||||||
|
} else {
|
||||||
|
address = _pal_gap.get_random_address();
|
||||||
|
}
|
||||||
|
|
||||||
processConnectionEvent(
|
processConnectionEvent(
|
||||||
e.connection_handle,
|
e.connection_handle,
|
||||||
|
@ -1047,7 +1059,7 @@ void GenericGap::on_connection_complete(const pal::GapConnectionCompleteEvent& e
|
||||||
(BLEProtocol::AddressType_t) e.peer_address_type.value(),
|
(BLEProtocol::AddressType_t) e.peer_address_type.value(),
|
||||||
e.peer_address.data(),
|
e.peer_address.data(),
|
||||||
_address_type,
|
_address_type,
|
||||||
_address.data(),
|
address.data(),
|
||||||
&connection_params
|
&connection_params
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -55,14 +55,14 @@ enum procedure_type_t {
|
||||||
/*
|
/*
|
||||||
* Base class for a procedure control block
|
* Base class for a procedure control block
|
||||||
*/
|
*/
|
||||||
struct procedure_control_block_t {
|
struct GenericGattClient::ProcedureControlBlock {
|
||||||
/*
|
/*
|
||||||
* Base constructor for procedure control block.
|
* Base constructor for procedure control block.
|
||||||
*/
|
*/
|
||||||
procedure_control_block_t(procedure_type_t type, Gap::Handle_t handle) :
|
ProcedureControlBlock(procedure_type_t type, Gap::Handle_t handle) :
|
||||||
type(type), connection_handle(handle), next(NULL) { }
|
type(type), connection_handle(handle), next(NULL) { }
|
||||||
|
|
||||||
virtual ~procedure_control_block_t() { }
|
virtual ~ProcedureControlBlock() { }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Entry point of the control block stack machine.
|
* Entry point of the control block stack machine.
|
||||||
|
@ -74,23 +74,28 @@ struct procedure_control_block_t {
|
||||||
*/
|
*/
|
||||||
virtual void handle_timeout_error(GenericGattClient* client) = 0;
|
virtual void handle_timeout_error(GenericGattClient* client) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function called when the procedure is aborted
|
||||||
|
*/
|
||||||
|
virtual void abort(GenericGattClient *client) = 0;
|
||||||
|
|
||||||
procedure_type_t type;
|
procedure_type_t type;
|
||||||
Gap::Handle_t connection_handle;
|
Gap::Handle_t connection_handle;
|
||||||
procedure_control_block_t* next;
|
ProcedureControlBlock* next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Procedure control block for the discovery process.
|
* Procedure control block for the discovery process.
|
||||||
*/
|
*/
|
||||||
struct discovery_control_block_t : public procedure_control_block_t {
|
struct GenericGattClient::DiscoveryControlBlock : public ProcedureControlBlock {
|
||||||
discovery_control_block_t(
|
DiscoveryControlBlock(
|
||||||
Gap::Handle_t handle,
|
Gap::Handle_t handle,
|
||||||
ServiceDiscovery::ServiceCallback_t service_callback,
|
ServiceDiscovery::ServiceCallback_t service_callback,
|
||||||
ServiceDiscovery::CharacteristicCallback_t characteristic_callback,
|
ServiceDiscovery::CharacteristicCallback_t characteristic_callback,
|
||||||
UUID matching_service_uuid,
|
UUID matching_service_uuid,
|
||||||
UUID matching_characteristic_uuid
|
UUID matching_characteristic_uuid
|
||||||
) : procedure_control_block_t(COMPLETE_DISCOVERY_PROCEDURE, handle),
|
) : ProcedureControlBlock(COMPLETE_DISCOVERY_PROCEDURE, handle),
|
||||||
service_callback(service_callback),
|
service_callback(service_callback),
|
||||||
characteristic_callback(characteristic_callback),
|
characteristic_callback(characteristic_callback),
|
||||||
matching_service_uuid(matching_service_uuid),
|
matching_service_uuid(matching_service_uuid),
|
||||||
|
@ -99,7 +104,7 @@ struct discovery_control_block_t : public procedure_control_block_t {
|
||||||
done(false) {
|
done(false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~discovery_control_block_t() {
|
virtual ~DiscoveryControlBlock() {
|
||||||
while(services_discovered) {
|
while(services_discovered) {
|
||||||
service_t* tmp = services_discovered->next;
|
service_t* tmp = services_discovered->next;
|
||||||
delete services_discovered;
|
delete services_discovered;
|
||||||
|
@ -111,6 +116,10 @@ struct discovery_control_block_t : public procedure_control_block_t {
|
||||||
terminate(client);
|
terminate(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void abort(GenericGattClient *client) {
|
||||||
|
terminate(client);
|
||||||
|
}
|
||||||
|
|
||||||
virtual void handle(GenericGattClient* client, const AttServerMessage& message) {
|
virtual void handle(GenericGattClient* client, const AttServerMessage& message) {
|
||||||
// if end of discovery has been requested, ends it immediately
|
// if end of discovery has been requested, ends it immediately
|
||||||
if (done) {
|
if (done) {
|
||||||
|
@ -409,15 +418,15 @@ struct discovery_control_block_t : public procedure_control_block_t {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct read_control_block_t : public procedure_control_block_t {
|
struct GenericGattClient::ReadControlBlock : public ProcedureControlBlock {
|
||||||
read_control_block_t(
|
ReadControlBlock(
|
||||||
Gap::Handle_t connection_handle, uint16_t attribute_handle, uint16_t offset
|
Gap::Handle_t connection_handle, uint16_t attribute_handle, uint16_t offset
|
||||||
) : procedure_control_block_t(READ_PROCEDURE, connection_handle),
|
) : ProcedureControlBlock(READ_PROCEDURE, connection_handle),
|
||||||
attribute_handle(attribute_handle),
|
attribute_handle(attribute_handle),
|
||||||
offset(offset), current_offset(offset), data(NULL) {
|
offset(offset), current_offset(offset), data(NULL) {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~read_control_block_t() {
|
virtual ~ReadControlBlock() {
|
||||||
if (data != NULL) {
|
if (data != NULL) {
|
||||||
free(data);
|
free(data);
|
||||||
}
|
}
|
||||||
|
@ -436,6 +445,19 @@ struct read_control_block_t : public procedure_control_block_t {
|
||||||
terminate(client, response);
|
terminate(client, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void abort(GenericGattClient *client) {
|
||||||
|
GattReadCallbackParams response = {
|
||||||
|
connection_handle,
|
||||||
|
attribute_handle,
|
||||||
|
offset,
|
||||||
|
0, // size of 0
|
||||||
|
NULL, // no data
|
||||||
|
BLE_ERROR_INVALID_STATE,
|
||||||
|
|
||||||
|
};
|
||||||
|
terminate(client, response);
|
||||||
|
}
|
||||||
|
|
||||||
void terminate(GenericGattClient* client, const GattReadCallbackParams& response) {
|
void terminate(GenericGattClient* client, const GattReadCallbackParams& response) {
|
||||||
client->remove_control_block(this);
|
client->remove_control_block(this);
|
||||||
client->processReadResponse(&response);
|
client->processReadResponse(&response);
|
||||||
|
@ -593,16 +615,16 @@ struct read_control_block_t : public procedure_control_block_t {
|
||||||
/*
|
/*
|
||||||
* Control block for the write process
|
* Control block for the write process
|
||||||
*/
|
*/
|
||||||
struct write_control_block_t : public procedure_control_block_t {
|
struct GenericGattClient::WriteControlBlock : public ProcedureControlBlock {
|
||||||
write_control_block_t(
|
WriteControlBlock(
|
||||||
Gap::Handle_t connection_handle, uint16_t attribute_handle,
|
Gap::Handle_t connection_handle, uint16_t attribute_handle,
|
||||||
uint8_t* data, uint16_t len
|
uint8_t* data, uint16_t len
|
||||||
) : procedure_control_block_t(WRITE_PROCEDURE, connection_handle),
|
) : ProcedureControlBlock(WRITE_PROCEDURE, connection_handle),
|
||||||
attribute_handle(attribute_handle), len(len), offset(0), data(data),
|
attribute_handle(attribute_handle), len(len), offset(0), data(data),
|
||||||
prepare_success(false), status(BLE_ERROR_UNSPECIFIED), error_code(0xFF) {
|
prepare_success(false), status(BLE_ERROR_UNSPECIFIED), error_code(0xFF) {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~write_control_block_t() {
|
virtual ~WriteControlBlock() {
|
||||||
free(data);
|
free(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -617,6 +639,17 @@ struct write_control_block_t : public procedure_control_block_t {
|
||||||
terminate(client, response);
|
terminate(client, response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void abort(GenericGattClient *client) {
|
||||||
|
GattWriteCallbackParams response = {
|
||||||
|
connection_handle,
|
||||||
|
attribute_handle,
|
||||||
|
GattWriteCallbackParams::OP_WRITE_REQ,
|
||||||
|
BLE_ERROR_INVALID_STATE,
|
||||||
|
0x00
|
||||||
|
};
|
||||||
|
terminate(client, response);
|
||||||
|
}
|
||||||
|
|
||||||
void terminate(GenericGattClient* client, const GattWriteCallbackParams& response) {
|
void terminate(GenericGattClient* client, const GattWriteCallbackParams& response) {
|
||||||
client->remove_control_block(this);
|
client->remove_control_block(this);
|
||||||
client->processWriteResponse(&response);
|
client->processWriteResponse(&response);
|
||||||
|
@ -785,12 +818,12 @@ struct write_control_block_t : public procedure_control_block_t {
|
||||||
/*
|
/*
|
||||||
* Control block for the descriptor discovery process
|
* Control block for the descriptor discovery process
|
||||||
*/
|
*/
|
||||||
struct descriptor_discovery_control_block_t : public procedure_control_block_t {
|
struct GenericGattClient::DescriptorDiscoveryControlBlock : public ProcedureControlBlock {
|
||||||
descriptor_discovery_control_block_t(
|
DescriptorDiscoveryControlBlock(
|
||||||
const DiscoveredCharacteristic& characteristic,
|
const DiscoveredCharacteristic& characteristic,
|
||||||
const CharacteristicDescriptorDiscovery::DiscoveryCallback_t& discoveryCallback,
|
const CharacteristicDescriptorDiscovery::DiscoveryCallback_t& discoveryCallback,
|
||||||
const CharacteristicDescriptorDiscovery::TerminationCallback_t& terminationCallback
|
const CharacteristicDescriptorDiscovery::TerminationCallback_t& terminationCallback
|
||||||
) : procedure_control_block_t(DESCRIPTOR_DISCOVERY_PROCEDURE, characteristic.getConnectionHandle()),
|
) : ProcedureControlBlock(DESCRIPTOR_DISCOVERY_PROCEDURE, characteristic.getConnectionHandle()),
|
||||||
characteristic(characteristic),
|
characteristic(characteristic),
|
||||||
discovery_cb(discoveryCallback),
|
discovery_cb(discoveryCallback),
|
||||||
termination_cb(terminationCallback),
|
termination_cb(terminationCallback),
|
||||||
|
@ -798,7 +831,7 @@ struct descriptor_discovery_control_block_t : public procedure_control_block_t {
|
||||||
done(false) {
|
done(false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~descriptor_discovery_control_block_t() { }
|
virtual ~DescriptorDiscoveryControlBlock() { }
|
||||||
|
|
||||||
ble_error_t start(GenericGattClient* client) {
|
ble_error_t start(GenericGattClient* client) {
|
||||||
return client->_pal_client->discover_characteristics_descriptors(
|
return client->_pal_client->discover_characteristics_descriptors(
|
||||||
|
@ -814,6 +847,10 @@ struct descriptor_discovery_control_block_t : public procedure_control_block_t {
|
||||||
terminate(client, BLE_ERROR_UNSPECIFIED);
|
terminate(client, BLE_ERROR_UNSPECIFIED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual void abort(GenericGattClient *client) {
|
||||||
|
terminate(client, BLE_ERROR_INVALID_STATE);
|
||||||
|
}
|
||||||
|
|
||||||
virtual void handle(GenericGattClient* client, const AttServerMessage& message) {
|
virtual void handle(GenericGattClient* client, const AttServerMessage& message) {
|
||||||
if (done) {
|
if (done) {
|
||||||
terminate(client, BLE_ERROR_NONE);
|
terminate(client, BLE_ERROR_NONE);
|
||||||
|
@ -892,7 +929,8 @@ struct descriptor_discovery_control_block_t : public procedure_control_block_t {
|
||||||
GenericGattClient::GenericGattClient(pal::GattClient* pal_client) :
|
GenericGattClient::GenericGattClient(pal::GattClient* pal_client) :
|
||||||
_pal_client(pal_client),
|
_pal_client(pal_client),
|
||||||
_termination_callback(),
|
_termination_callback(),
|
||||||
control_blocks(NULL) {
|
control_blocks(NULL),
|
||||||
|
_is_reseting(false) {
|
||||||
_pal_client->when_server_message_received(
|
_pal_client->when_server_message_received(
|
||||||
mbed::callback(this, &GenericGattClient::on_server_message_received)
|
mbed::callback(this, &GenericGattClient::on_server_message_received)
|
||||||
);
|
);
|
||||||
|
@ -909,7 +947,7 @@ ble_error_t GenericGattClient::launchServiceDiscovery(
|
||||||
const UUID& matching_characteristic_uuid
|
const UUID& matching_characteristic_uuid
|
||||||
) {
|
) {
|
||||||
// verify that there is no other procedures going on this connection
|
// verify that there is no other procedures going on this connection
|
||||||
if (get_control_block(connection_handle)) {
|
if (_is_reseting || get_control_block(connection_handle)) {
|
||||||
return BLE_ERROR_INVALID_STATE;
|
return BLE_ERROR_INVALID_STATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -919,7 +957,7 @@ ble_error_t GenericGattClient::launchServiceDiscovery(
|
||||||
return BLE_ERROR_NONE;
|
return BLE_ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
discovery_control_block_t* discovery_pcb = new(std::nothrow) discovery_control_block_t(
|
DiscoveryControlBlock* discovery_pcb = new(std::nothrow) DiscoveryControlBlock(
|
||||||
connection_handle,
|
connection_handle,
|
||||||
service_callback,
|
service_callback,
|
||||||
characteristic_callback,
|
characteristic_callback,
|
||||||
|
@ -959,7 +997,7 @@ ble_error_t GenericGattClient::launchServiceDiscovery(
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GenericGattClient::isServiceDiscoveryActive() const {
|
bool GenericGattClient::isServiceDiscoveryActive() const {
|
||||||
procedure_control_block_t* pcb = control_blocks;
|
ProcedureControlBlock* pcb = control_blocks;
|
||||||
|
|
||||||
while (pcb) {
|
while (pcb) {
|
||||||
if (pcb->type == COMPLETE_DISCOVERY_PROCEDURE) {
|
if (pcb->type == COMPLETE_DISCOVERY_PROCEDURE) {
|
||||||
|
@ -973,10 +1011,10 @@ bool GenericGattClient::isServiceDiscoveryActive() const {
|
||||||
|
|
||||||
void GenericGattClient::terminateServiceDiscovery()
|
void GenericGattClient::terminateServiceDiscovery()
|
||||||
{
|
{
|
||||||
procedure_control_block_t* pcb = control_blocks;
|
ProcedureControlBlock* pcb = control_blocks;
|
||||||
while (pcb) {
|
while (pcb) {
|
||||||
if (pcb->type == COMPLETE_DISCOVERY_PROCEDURE) {
|
if (pcb->type == COMPLETE_DISCOVERY_PROCEDURE) {
|
||||||
static_cast<discovery_control_block_t*>(pcb)->done = true;
|
static_cast<DiscoveryControlBlock*>(pcb)->done = true;
|
||||||
}
|
}
|
||||||
pcb = pcb->next;
|
pcb = pcb->next;
|
||||||
}
|
}
|
||||||
|
@ -988,11 +1026,11 @@ ble_error_t GenericGattClient::read(
|
||||||
uint16_t offset) const
|
uint16_t offset) const
|
||||||
{
|
{
|
||||||
// verify that there is no other procedures going on this connection
|
// verify that there is no other procedures going on this connection
|
||||||
if (get_control_block(connection_handle)) {
|
if (_is_reseting || get_control_block(connection_handle)) {
|
||||||
return BLE_ERROR_INVALID_STATE;
|
return BLE_ERROR_INVALID_STATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
read_control_block_t* read_pcb = new(std::nothrow) read_control_block_t(
|
ReadControlBlock* read_pcb = new(std::nothrow) ReadControlBlock(
|
||||||
connection_handle,
|
connection_handle,
|
||||||
attribute_handle,
|
attribute_handle,
|
||||||
offset
|
offset
|
||||||
|
@ -1032,7 +1070,7 @@ ble_error_t GenericGattClient::write(
|
||||||
const uint8_t* value
|
const uint8_t* value
|
||||||
) const {
|
) const {
|
||||||
// verify that there is no other procedures going on this connection
|
// verify that there is no other procedures going on this connection
|
||||||
if (get_control_block(connection_handle)) {
|
if (_is_reseting || get_control_block(connection_handle)) {
|
||||||
return BLE_ERROR_INVALID_STATE;
|
return BLE_ERROR_INVALID_STATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1058,7 +1096,7 @@ ble_error_t GenericGattClient::write(
|
||||||
memcpy(data, value, length);
|
memcpy(data, value, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
write_control_block_t* write_pcb = new(std::nothrow) write_control_block_t(
|
WriteControlBlock* write_pcb = new(std::nothrow) WriteControlBlock(
|
||||||
connection_handle,
|
connection_handle,
|
||||||
attribute_handle,
|
attribute_handle,
|
||||||
data,
|
data,
|
||||||
|
@ -1111,7 +1149,7 @@ ble_error_t GenericGattClient::discoverCharacteristicDescriptors(
|
||||||
const CharacteristicDescriptorDiscovery::TerminationCallback_t& terminationCallback
|
const CharacteristicDescriptorDiscovery::TerminationCallback_t& terminationCallback
|
||||||
) {
|
) {
|
||||||
// verify that there is no other procedures going on this connection
|
// verify that there is no other procedures going on this connection
|
||||||
if (get_control_block(characteristic.getConnectionHandle())) {
|
if (_is_reseting || get_control_block(characteristic.getConnectionHandle())) {
|
||||||
return BLE_ERROR_INVALID_STATE;
|
return BLE_ERROR_INVALID_STATE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1126,8 +1164,8 @@ ble_error_t GenericGattClient::discoverCharacteristicDescriptors(
|
||||||
return BLE_ERROR_NONE;
|
return BLE_ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
descriptor_discovery_control_block_t* discovery_pcb =
|
DescriptorDiscoveryControlBlock* discovery_pcb =
|
||||||
new(std::nothrow) descriptor_discovery_control_block_t(
|
new(std::nothrow) DescriptorDiscoveryControlBlock(
|
||||||
characteristic,
|
characteristic,
|
||||||
discoveryCallback,
|
discoveryCallback,
|
||||||
terminationCallback
|
terminationCallback
|
||||||
|
@ -1152,11 +1190,11 @@ ble_error_t GenericGattClient::discoverCharacteristicDescriptors(
|
||||||
bool GenericGattClient::isCharacteristicDescriptorDiscoveryActive(
|
bool GenericGattClient::isCharacteristicDescriptorDiscoveryActive(
|
||||||
const DiscoveredCharacteristic& characteristic
|
const DiscoveredCharacteristic& characteristic
|
||||||
) const {
|
) const {
|
||||||
procedure_control_block_t* pcb = control_blocks;
|
ProcedureControlBlock* pcb = control_blocks;
|
||||||
|
|
||||||
while (pcb) {
|
while (pcb) {
|
||||||
if (pcb->type == DESCRIPTOR_DISCOVERY_PROCEDURE &&
|
if (pcb->type == DESCRIPTOR_DISCOVERY_PROCEDURE &&
|
||||||
static_cast<descriptor_discovery_control_block_t*>(pcb)->characteristic == characteristic) {
|
static_cast<DescriptorDiscoveryControlBlock*>(pcb)->characteristic == characteristic) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
pcb = pcb->next;
|
pcb = pcb->next;
|
||||||
|
@ -1168,12 +1206,12 @@ bool GenericGattClient::isCharacteristicDescriptorDiscoveryActive(
|
||||||
void GenericGattClient::terminateCharacteristicDescriptorDiscovery(
|
void GenericGattClient::terminateCharacteristicDescriptorDiscovery(
|
||||||
const DiscoveredCharacteristic& characteristic
|
const DiscoveredCharacteristic& characteristic
|
||||||
) {
|
) {
|
||||||
procedure_control_block_t* pcb = control_blocks;
|
ProcedureControlBlock* pcb = control_blocks;
|
||||||
|
|
||||||
while (pcb) {
|
while (pcb) {
|
||||||
if (pcb->type == DESCRIPTOR_DISCOVERY_PROCEDURE) {
|
if (pcb->type == DESCRIPTOR_DISCOVERY_PROCEDURE) {
|
||||||
descriptor_discovery_control_block_t* dpcb =
|
DescriptorDiscoveryControlBlock* dpcb =
|
||||||
static_cast<descriptor_discovery_control_block_t*>(pcb);
|
static_cast<DescriptorDiscoveryControlBlock*>(pcb);
|
||||||
if (dpcb->characteristic == characteristic) {
|
if (dpcb->characteristic == characteristic) {
|
||||||
dpcb->done = true;
|
dpcb->done = true;
|
||||||
return;
|
return;
|
||||||
|
@ -1186,7 +1224,17 @@ void GenericGattClient::terminateCharacteristicDescriptorDiscovery(
|
||||||
}
|
}
|
||||||
|
|
||||||
ble_error_t GenericGattClient::reset(void) {
|
ble_error_t GenericGattClient::reset(void) {
|
||||||
return BLE_ERROR_NOT_IMPLEMENTED;
|
|
||||||
|
// _is_reseting prevent executions of new procedure while the instance resets.
|
||||||
|
// otherwise new procedures can be launched from callbacks generated by the
|
||||||
|
// reset.
|
||||||
|
_is_reseting = true;
|
||||||
|
while (control_blocks) {
|
||||||
|
control_blocks->abort(this);
|
||||||
|
}
|
||||||
|
_is_reseting = false;
|
||||||
|
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenericGattClient::on_termination(Gap::Handle_t connection_handle) {
|
void GenericGattClient::on_termination(Gap::Handle_t connection_handle) {
|
||||||
|
@ -1230,7 +1278,7 @@ void GenericGattClient::on_server_response(
|
||||||
connection_handle_t connection,
|
connection_handle_t connection,
|
||||||
const AttServerMessage& message
|
const AttServerMessage& message
|
||||||
) {
|
) {
|
||||||
procedure_control_block_t* pcb = get_control_block(connection);
|
ProcedureControlBlock* pcb = get_control_block(connection);
|
||||||
if (pcb == NULL) {
|
if (pcb == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1270,7 +1318,7 @@ void GenericGattClient::on_server_event(connection_handle_t connection, const At
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenericGattClient::on_transaction_timeout(connection_handle_t connection) {
|
void GenericGattClient::on_transaction_timeout(connection_handle_t connection) {
|
||||||
procedure_control_block_t* pcb = get_control_block(connection);
|
ProcedureControlBlock* pcb = get_control_block(connection);
|
||||||
if (pcb == NULL) {
|
if (pcb == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1278,36 +1326,36 @@ void GenericGattClient::on_transaction_timeout(connection_handle_t connection) {
|
||||||
pcb->handle_timeout_error(this);
|
pcb->handle_timeout_error(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
procedure_control_block_t* GenericGattClient::get_control_block(Gap::Handle_t connection) {
|
GenericGattClient::ProcedureControlBlock* GenericGattClient::get_control_block(Gap::Handle_t connection) {
|
||||||
procedure_control_block_t* it = control_blocks;
|
ProcedureControlBlock* it = control_blocks;
|
||||||
while (it && it->connection_handle != connection) {
|
while (it && it->connection_handle != connection) {
|
||||||
it = it->next;
|
it = it->next;
|
||||||
}
|
}
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
const procedure_control_block_t* GenericGattClient::get_control_block(Gap::Handle_t connection) const {
|
const GenericGattClient::ProcedureControlBlock* GenericGattClient::get_control_block(Gap::Handle_t connection) const {
|
||||||
procedure_control_block_t* it = control_blocks;
|
ProcedureControlBlock* it = control_blocks;
|
||||||
while (it && it->connection_handle != connection) {
|
while (it && it->connection_handle != connection) {
|
||||||
it = it->next;
|
it = it->next;
|
||||||
}
|
}
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenericGattClient::insert_control_block(procedure_control_block_t* cb) const {
|
void GenericGattClient::insert_control_block(ProcedureControlBlock* cb) const {
|
||||||
if (control_blocks == NULL) {
|
if (control_blocks == NULL) {
|
||||||
control_blocks = cb;
|
control_blocks = cb;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
procedure_control_block_t* current = control_blocks;
|
ProcedureControlBlock* current = control_blocks;
|
||||||
while (current->next) {
|
while (current->next) {
|
||||||
current = current->next;
|
current = current->next;
|
||||||
}
|
}
|
||||||
current->next = cb;
|
current->next = cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenericGattClient::remove_control_block(procedure_control_block_t* cb) const {
|
void GenericGattClient::remove_control_block(ProcedureControlBlock* cb) const {
|
||||||
if (control_blocks == NULL) {
|
if (control_blocks == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1317,7 +1365,7 @@ void GenericGattClient::remove_control_block(procedure_control_block_t* cb) cons
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
procedure_control_block_t* current = control_blocks;
|
ProcedureControlBlock* current = control_blocks;
|
||||||
while (current->next && current->next != cb) {
|
while (current->next && current->next != cb) {
|
||||||
current = current->next;
|
current = current->next;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,12 +22,15 @@
|
||||||
#include "ble/BLEInstanceBase.h"
|
#include "ble/BLEInstanceBase.h"
|
||||||
|
|
||||||
#include "CordioHCIDriver.h"
|
#include "CordioHCIDriver.h"
|
||||||
#include "CordioGap.h"
|
|
||||||
#include "CordioGattServer.h"
|
#include "CordioGattServer.h"
|
||||||
#include "CordioSecurityManager.h"
|
#include "CordioSecurityManager.h"
|
||||||
#include "CordioPalAttClient.h"
|
#include "CordioPalAttClient.h"
|
||||||
#include "ble/pal/AttClientToGattClientAdapter.h"
|
#include "ble/pal/AttClientToGattClientAdapter.h"
|
||||||
#include "ble/generic/GenericGattClient.h"
|
#include "ble/generic/GenericGattClient.h"
|
||||||
|
#include "CordioPalGap.h"
|
||||||
|
#include "CordioPalGenericAccessService.h"
|
||||||
|
#include "ble/generic/GenericGap.h"
|
||||||
|
#include "ble/pal/SimpleEventQueue.h"
|
||||||
|
|
||||||
namespace ble {
|
namespace ble {
|
||||||
namespace vendor {
|
namespace vendor {
|
||||||
|
@ -81,12 +84,12 @@ public:
|
||||||
/**
|
/**
|
||||||
* @see BLEInstanceBase::getGap
|
* @see BLEInstanceBase::getGap
|
||||||
*/
|
*/
|
||||||
virtual Gap& getGap();
|
virtual ::Gap& getGap();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see BLEInstanceBase::getGap
|
* @see BLEInstanceBase::getGap
|
||||||
*/
|
*/
|
||||||
virtual const Gap& getGap() const;
|
virtual const ::Gap& getGap() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see BLEInstanceBase::getGattServer
|
* @see BLEInstanceBase::getGattServer
|
||||||
|
@ -143,6 +146,7 @@ private:
|
||||||
} initialization_status;
|
} initialization_status;
|
||||||
|
|
||||||
::BLE::InstanceID_t instanceID;
|
::BLE::InstanceID_t instanceID;
|
||||||
|
mutable pal::SimpleEventQueue _event_queue;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace cordio
|
} // namespace cordio
|
||||||
|
|
|
@ -1,262 +0,0 @@
|
||||||
/* mbed Microcontroller Library
|
|
||||||
* Copyright (c) 2017-2017 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 CORDIO_GAP_H_
|
|
||||||
#define CORDIO_GAP_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "ble/blecommon.h"
|
|
||||||
#include "ble/GapAdvertisingParams.h"
|
|
||||||
#include "ble/GapAdvertisingData.h"
|
|
||||||
#include "ble/Gap.h"
|
|
||||||
#include "ble/GapScanningParams.h"
|
|
||||||
#include "dm_api.h"
|
|
||||||
#include "att_api.h"
|
|
||||||
|
|
||||||
namespace ble {
|
|
||||||
namespace vendor {
|
|
||||||
namespace cordio {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap
|
|
||||||
*/
|
|
||||||
class Gap : public ::Gap
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Return the Gap singleton implementing ::Gap for the Cordio stac.
|
|
||||||
*/
|
|
||||||
static Gap &getInstance();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function shall be called once the stack has been initialized
|
|
||||||
*/
|
|
||||||
void initialize();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::setAddress
|
|
||||||
*/
|
|
||||||
virtual ble_error_t setAddress(AddressType_t type, const Address_t address);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::getAddress
|
|
||||||
*/
|
|
||||||
virtual ble_error_t getAddress(AddressType_t *typeP, Address_t address);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::setAdvertisingData
|
|
||||||
*/
|
|
||||||
virtual ble_error_t setAdvertisingData(
|
|
||||||
const GapAdvertisingData&, const GapAdvertisingData&
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::connect
|
|
||||||
*/
|
|
||||||
virtual ble_error_t connect(
|
|
||||||
const BLEProtocol::AddressBytes_t peerAddr,
|
|
||||||
BLEProtocol::AddressType_t peerAddrType,
|
|
||||||
const ConnectionParams_t* connectionParams,
|
|
||||||
const GapScanningParams* scanParams
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::getMinAdvertisingInterval
|
|
||||||
*/
|
|
||||||
virtual uint16_t getMinAdvertisingInterval() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::getMinNonConnectableAdvertisingInterval
|
|
||||||
*/
|
|
||||||
virtual uint16_t getMinNonConnectableAdvertisingInterval() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::getMaxAdvertisingInterval
|
|
||||||
*/
|
|
||||||
virtual uint16_t getMaxAdvertisingInterval() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::startAdvertising
|
|
||||||
*/
|
|
||||||
virtual ble_error_t startAdvertising(const GapAdvertisingParams &);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::stopAdvertising
|
|
||||||
*/
|
|
||||||
virtual ble_error_t stopAdvertising();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::disconnect
|
|
||||||
*/
|
|
||||||
virtual ble_error_t disconnect(
|
|
||||||
Handle_t connectionHandle,
|
|
||||||
DisconnectionReason_t reason
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::disconnect
|
|
||||||
*/
|
|
||||||
virtual ble_error_t disconnect(DisconnectionReason_t reason);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::setDeviceName
|
|
||||||
*/
|
|
||||||
virtual ble_error_t setDeviceName(const uint8_t *deviceName);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::getDeviceName
|
|
||||||
*/
|
|
||||||
virtual ble_error_t getDeviceName(uint8_t *deviceName, unsigned *lengthP);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::setAppearance
|
|
||||||
*/
|
|
||||||
virtual ble_error_t setAppearance(GapAdvertisingData::Appearance appearance);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::getAppearance
|
|
||||||
*/
|
|
||||||
virtual ble_error_t getAppearance(GapAdvertisingData::Appearance *appearanceP);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::setTxPower
|
|
||||||
*/
|
|
||||||
virtual ble_error_t setTxPower(int8_t txPower);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::getPermittedTxPowerValues
|
|
||||||
*/
|
|
||||||
virtual void getPermittedTxPowerValues(
|
|
||||||
const int8_t **valueArrayPP, size_t *countP
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the internal connection handle
|
|
||||||
*/
|
|
||||||
void setConnectionHandle(uint16_t m_connectionHandle);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the current connection handle
|
|
||||||
*/
|
|
||||||
uint16_t getConnectionHandle();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::getPreferredConnectionParams
|
|
||||||
*/
|
|
||||||
virtual ble_error_t getPreferredConnectionParams(ConnectionParams_t *params);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::setPreferredConnectionParams
|
|
||||||
*/
|
|
||||||
virtual ble_error_t setPreferredConnectionParams(
|
|
||||||
const ConnectionParams_t *params
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::updateConnectionParams
|
|
||||||
*/
|
|
||||||
virtual ble_error_t updateConnectionParams(
|
|
||||||
Handle_t handle, const ConnectionParams_t *params
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::startRadioScan
|
|
||||||
*/
|
|
||||||
virtual ble_error_t startRadioScan(const GapScanningParams &scanningParams);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::stopScan
|
|
||||||
*/
|
|
||||||
virtual ble_error_t stopScan();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when advertising is stopped.
|
|
||||||
*/
|
|
||||||
void advertisingStopped();
|
|
||||||
|
|
||||||
// Whitelist management
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::getMaxWhitelistSize
|
|
||||||
*/
|
|
||||||
virtual uint8_t getMaxWhitelistSize(void) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::getWhitelist
|
|
||||||
*/
|
|
||||||
virtual ble_error_t getWhitelist(Whitelist_t &whitelist) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::setWhitelist
|
|
||||||
*/
|
|
||||||
virtual ble_error_t setWhitelist(const Whitelist_t &whitelist);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::setAdvertisingPolicyMode
|
|
||||||
*/
|
|
||||||
virtual ble_error_t setAdvertisingPolicyMode(AdvertisingPolicyMode_t mode);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::getAdvertisingPolicyMode
|
|
||||||
*/
|
|
||||||
virtual AdvertisingPolicyMode_t getAdvertisingPolicyMode(void) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::setScanningPolicyMode
|
|
||||||
*/
|
|
||||||
virtual ble_error_t setScanningPolicyMode(ScanningPolicyMode_t mode);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::getScanningPolicyMode
|
|
||||||
*/
|
|
||||||
virtual ScanningPolicyMode_t getScanningPolicyMode(void) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::setInitiatorPolicyMode
|
|
||||||
*/
|
|
||||||
virtual ble_error_t setInitiatorPolicyMode(InitiatorPolicyMode_t mode);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::getInitiatorPolicyMode
|
|
||||||
*/
|
|
||||||
virtual InitiatorPolicyMode_t getInitiatorPolicyMode(void) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @see ::Gap::reset
|
|
||||||
*/
|
|
||||||
virtual ble_error_t reset(void);
|
|
||||||
|
|
||||||
private:
|
|
||||||
Gap();
|
|
||||||
|
|
||||||
Gap(Gap const &);
|
|
||||||
void operator=(Gap const &);
|
|
||||||
|
|
||||||
uint16_t m_connectionHandle;
|
|
||||||
addr_type_t m_type;
|
|
||||||
Address_t m_addr;
|
|
||||||
|
|
||||||
AdvertisingPolicyMode_t advertising_policy_mode;
|
|
||||||
ScanningPolicyMode_t scanning_policy_mode;
|
|
||||||
InitiatorPolicyMode_t initiator_policy_mode;
|
|
||||||
Whitelist_t whitelist;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace cordio
|
|
||||||
} // namespace vendor
|
|
||||||
} // namespace ble
|
|
||||||
|
|
||||||
#endif /* CORDIO_GAP_H_ */
|
|
|
@ -0,0 +1,477 @@
|
||||||
|
#ifndef CORDIO_PAL_GAP_
|
||||||
|
#define CORDIO_PAL_GAP_
|
||||||
|
|
||||||
|
#include "ble/pal/PalGap.h"
|
||||||
|
#include "dm_api.h"
|
||||||
|
|
||||||
|
namespace ble {
|
||||||
|
namespace pal {
|
||||||
|
namespace vendor {
|
||||||
|
namespace cordio {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of ble::pal::Gap for the Cordio stack.
|
||||||
|
*/
|
||||||
|
class Gap : public ::ble::pal::Gap {
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ble_error_t initialize() {
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ble_error_t terminate() {
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual address_t get_device_address() {
|
||||||
|
return address_t(HciGetBdAddr(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual address_t get_random_address() {
|
||||||
|
return device_random_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ble_error_t set_random_address(const address_t& address) {
|
||||||
|
device_random_address = address;
|
||||||
|
DmDevSetRandAddr(const_cast<uint8_t*>(address.data()));
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ble_error_t set_advertising_parameters(
|
||||||
|
uint16_t advertising_interval_min,
|
||||||
|
uint16_t advertising_interval_max,
|
||||||
|
advertising_type_t advertising_type,
|
||||||
|
own_address_type_t own_address_type,
|
||||||
|
advertising_peer_address_type_t peer_address_type,
|
||||||
|
const address_t& peer_address,
|
||||||
|
advertising_channel_map_t advertising_channel_map,
|
||||||
|
advertising_filter_policy_t advertising_filter_policy
|
||||||
|
) {
|
||||||
|
DmAdvSetInterval(
|
||||||
|
DM_ADV_HANDLE_DEFAULT,
|
||||||
|
advertising_interval_min,
|
||||||
|
advertising_interval_max
|
||||||
|
);
|
||||||
|
|
||||||
|
DmAdvSetAddrType(own_address_type.value());
|
||||||
|
|
||||||
|
DmAdvSetChannelMap(
|
||||||
|
DM_ADV_HANDLE_DEFAULT,
|
||||||
|
advertising_channel_map.value()
|
||||||
|
);
|
||||||
|
|
||||||
|
DmDevSetFilterPolicy(
|
||||||
|
DM_FILT_POLICY_MODE_ADV,
|
||||||
|
advertising_filter_policy.value()
|
||||||
|
);
|
||||||
|
|
||||||
|
DmAdvConfig(
|
||||||
|
DM_ADV_HANDLE_DEFAULT,
|
||||||
|
advertising_type.value(),
|
||||||
|
peer_address_type.value(),
|
||||||
|
const_cast<uint8_t*>(peer_address.data())
|
||||||
|
);
|
||||||
|
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ble_error_t set_advertising_data(
|
||||||
|
uint8_t advertising_data_length,
|
||||||
|
const advertising_data_t& advertising_data
|
||||||
|
) {
|
||||||
|
DmAdvSetData(
|
||||||
|
DM_ADV_HANDLE_DEFAULT,
|
||||||
|
HCI_ADV_DATA_OP_COMP_FRAG,
|
||||||
|
DM_DATA_LOC_ADV,
|
||||||
|
advertising_data_length,
|
||||||
|
const_cast<uint8_t*>(advertising_data.data())
|
||||||
|
);
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ble_error_t set_scan_response_data(
|
||||||
|
uint8_t scan_response_data_length,
|
||||||
|
const advertising_data_t& scan_response_data
|
||||||
|
) {
|
||||||
|
DmAdvSetData(
|
||||||
|
DM_ADV_HANDLE_DEFAULT,
|
||||||
|
HCI_ADV_DATA_OP_COMP_FRAG,
|
||||||
|
DM_DATA_LOC_SCAN,
|
||||||
|
scan_response_data_length,
|
||||||
|
const_cast<uint8_t*>(scan_response_data.data())
|
||||||
|
);
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ble_error_t advertising_enable(bool enable) {
|
||||||
|
if (enable) {
|
||||||
|
uint8_t adv_handles[] = { DM_ADV_HANDLE_DEFAULT };
|
||||||
|
uint16_t adv_durations[] = { /* infinite */ 0 };
|
||||||
|
uint8_t max_ea_events[] = { 0 };
|
||||||
|
DmAdvStart(1, adv_handles, adv_durations, max_ea_events);
|
||||||
|
} else {
|
||||||
|
uint8_t adv_handles[] = { DM_ADV_HANDLE_DEFAULT };
|
||||||
|
DmAdvStop(1, adv_handles);
|
||||||
|
}
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ble_error_t set_scan_parameters(
|
||||||
|
bool active_scanning,
|
||||||
|
uint16_t scan_interval,
|
||||||
|
uint16_t scan_window,
|
||||||
|
own_address_type_t own_address_type,
|
||||||
|
scanning_filter_policy_t filter_policy
|
||||||
|
) {
|
||||||
|
use_active_scanning = active_scanning;
|
||||||
|
DmScanSetInterval(HCI_INIT_PHY_LE_1M_BIT, &scan_interval, &scan_window);
|
||||||
|
DmScanSetAddrType(own_address_type.value());
|
||||||
|
DmDevSetFilterPolicy(
|
||||||
|
DM_FILT_POLICY_MODE_SCAN,
|
||||||
|
filter_policy.value()
|
||||||
|
);
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ble_error_t scan_enable(
|
||||||
|
bool enable,
|
||||||
|
bool filter_duplicates
|
||||||
|
) {
|
||||||
|
if (enable) {
|
||||||
|
uint8_t scanType = use_active_scanning ? DM_SCAN_TYPE_ACTIVE : DM_SCAN_TYPE_PASSIVE;
|
||||||
|
DmScanStart(
|
||||||
|
HCI_SCAN_PHY_LE_1M_BIT,
|
||||||
|
DM_DISC_MODE_NONE,
|
||||||
|
&scanType,
|
||||||
|
filter_duplicates,
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
DmScanStop();
|
||||||
|
}
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ble_error_t create_connection(
|
||||||
|
uint16_t scan_interval,
|
||||||
|
uint16_t scan_window,
|
||||||
|
initiator_policy_t initiator_policy,
|
||||||
|
connection_peer_address_type_t peer_address_type,
|
||||||
|
const address_t& peer_address,
|
||||||
|
own_address_type_t own_address_type,
|
||||||
|
uint16_t connection_interval_min,
|
||||||
|
uint16_t connection_interval_max,
|
||||||
|
uint16_t connection_latency,
|
||||||
|
uint16_t supervision_timeout,
|
||||||
|
uint16_t minimum_connection_event_length,
|
||||||
|
uint16_t maximum_connection_event_length
|
||||||
|
) {
|
||||||
|
DmConnSetScanInterval(scan_interval, scan_window);
|
||||||
|
DmDevSetFilterPolicy(DM_FILT_POLICY_MODE_INIT, initiator_policy.value());
|
||||||
|
DmConnSetAddrType(own_address_type.value());
|
||||||
|
|
||||||
|
hciConnSpec_t conn_spec = {
|
||||||
|
connection_interval_min,
|
||||||
|
connection_interval_max,
|
||||||
|
connection_latency,
|
||||||
|
supervision_timeout,
|
||||||
|
minimum_connection_event_length,
|
||||||
|
maximum_connection_event_length
|
||||||
|
};
|
||||||
|
DmConnSetConnSpec(&conn_spec);
|
||||||
|
|
||||||
|
dmConnId_t connection_id = DmConnOpen(
|
||||||
|
DM_CLIENT_ID_APP,
|
||||||
|
HCI_INIT_PHY_LE_1M_BIT,
|
||||||
|
peer_address_type.value(),
|
||||||
|
const_cast<uint8_t*>(peer_address.data())
|
||||||
|
);
|
||||||
|
|
||||||
|
if (connection_id == DM_CONN_ID_NONE) {
|
||||||
|
return BLE_ERROR_INTERNAL_STACK_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ble_error_t cancel_connection_creation() {
|
||||||
|
DmConnClose(
|
||||||
|
DM_CLIENT_ID_APP,
|
||||||
|
/* connection handle - invalid */ DM_CONN_ID_NONE,
|
||||||
|
/* reason - invalid (use success) */ 0x00
|
||||||
|
);
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual uint8_t read_white_list_capacity() {
|
||||||
|
return HciGetWhiteListSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ble_error_t clear_whitelist() {
|
||||||
|
DmDevWhiteListClear();
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ble_error_t add_device_to_whitelist(
|
||||||
|
whitelist_address_type_t address_type,
|
||||||
|
address_t address
|
||||||
|
) {
|
||||||
|
DmDevWhiteListAdd(
|
||||||
|
address_type.value(),
|
||||||
|
const_cast<uint8_t*>(address.data())
|
||||||
|
);
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ble_error_t remove_device_from_whitelist(
|
||||||
|
whitelist_address_type_t address_type,
|
||||||
|
address_t address
|
||||||
|
) {
|
||||||
|
DmDevWhiteListRemove(
|
||||||
|
address_type.value(),
|
||||||
|
const_cast<uint8_t*>(address.data())
|
||||||
|
);
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ble_error_t connection_parameters_update(
|
||||||
|
connection_handle_t connection,
|
||||||
|
uint16_t connection_interval_min,
|
||||||
|
uint16_t connection_interval_max,
|
||||||
|
uint16_t connection_latency,
|
||||||
|
uint16_t supervision_timeout,
|
||||||
|
uint16_t minimum_connection_event_length,
|
||||||
|
uint16_t maximum_connection_event_length
|
||||||
|
) {
|
||||||
|
if (DmConnCheckIdle(connection) != 0) {
|
||||||
|
return BLE_ERROR_INVALID_STATE;
|
||||||
|
}
|
||||||
|
|
||||||
|
hciConnSpec_t connection_spec = {
|
||||||
|
connection_interval_min,
|
||||||
|
connection_interval_max,
|
||||||
|
connection_latency,
|
||||||
|
supervision_timeout,
|
||||||
|
minimum_connection_event_length,
|
||||||
|
maximum_connection_event_length
|
||||||
|
};
|
||||||
|
DmConnUpdate(
|
||||||
|
connection,
|
||||||
|
&connection_spec
|
||||||
|
);
|
||||||
|
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ble_error_t accept_connection_parameter_request(
|
||||||
|
connection_handle_t connection_handle,
|
||||||
|
uint16_t interval_min,
|
||||||
|
uint16_t interval_max,
|
||||||
|
uint16_t latency,
|
||||||
|
uint16_t supervision_timeout,
|
||||||
|
uint16_t minimum_connection_event_length,
|
||||||
|
uint16_t maximum_connection_event_length
|
||||||
|
) {
|
||||||
|
hciConnSpec_t connection_spec = {
|
||||||
|
interval_min,
|
||||||
|
interval_max,
|
||||||
|
latency,
|
||||||
|
supervision_timeout,
|
||||||
|
minimum_connection_event_length,
|
||||||
|
maximum_connection_event_length
|
||||||
|
};
|
||||||
|
DmRemoteConnParamReqReply(connection_handle, &connection_spec);
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ble_error_t reject_connection_parameter_request(
|
||||||
|
connection_handle_t connection_handle,
|
||||||
|
hci_error_code_t rejection_reason
|
||||||
|
) {
|
||||||
|
DmRemoteConnParamReqNegReply(
|
||||||
|
connection_handle,
|
||||||
|
rejection_reason.value()
|
||||||
|
);
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ble_error_t disconnect(
|
||||||
|
connection_handle_t connection,
|
||||||
|
disconnection_reason_t disconnection_reason
|
||||||
|
) {
|
||||||
|
DmConnClose(
|
||||||
|
DM_CLIENT_ID_APP,
|
||||||
|
connection,
|
||||||
|
disconnection_reason.value()
|
||||||
|
);
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// singleton of the ARM Cordio client
|
||||||
|
static Gap& get_gap() {
|
||||||
|
static Gap _gap;
|
||||||
|
return _gap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef bool (*event_handler_t)(const wsfMsgHdr_t* msg);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Callback which handle wsfMsgHdr_t and forward them to emit_gap_event.
|
||||||
|
*/
|
||||||
|
static void gap_handler(const wsfMsgHdr_t* msg) {
|
||||||
|
if (msg == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// all handlers are stored in a static array
|
||||||
|
static const event_handler_t handlers[] = {
|
||||||
|
&event_handler<ConnectionCompleteMessageConverter>,
|
||||||
|
&event_handler<GapAdvertisingReportMessageConverter>,
|
||||||
|
&event_handler<DisconnectionMessageConverter>,
|
||||||
|
&event_handler<ConnectionUpdateMessageConverter>,
|
||||||
|
&event_handler<RemoteConnectionParameterRequestMessageConverter>
|
||||||
|
};
|
||||||
|
|
||||||
|
// event->hdr.param: connection handle
|
||||||
|
|
||||||
|
// traverse all handlers and execute them with the event in input.
|
||||||
|
// exit if an handler has handled the event.
|
||||||
|
for(size_t i = 0; i < (sizeof(handlers)/sizeof(handlers[0])); ++i) {
|
||||||
|
if (handlers[i](msg)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* T shall define a can_convert and convert function and a type
|
||||||
|
*/
|
||||||
|
template<typename T>
|
||||||
|
static bool event_handler(const wsfMsgHdr_t* msg) {
|
||||||
|
if (T::can_convert(msg)) {
|
||||||
|
get_gap().emit_gap_event(T::convert((const typename T::type*)msg));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Traits defining can_convert for events.
|
||||||
|
*/
|
||||||
|
template<uint8_t EventID>
|
||||||
|
struct MessageConverter {
|
||||||
|
static bool can_convert(const wsfMsgHdr_t* msg) {
|
||||||
|
if (msg->event == EventID) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ConnectionCompleteMessageConverter : public MessageConverter<DM_CONN_OPEN_IND> {
|
||||||
|
typedef hciLeConnCmplEvt_t type;
|
||||||
|
|
||||||
|
static GapConnectionCompleteEvent convert(const hciLeConnCmplEvt_t* conn_evt) {
|
||||||
|
return GapConnectionCompleteEvent(
|
||||||
|
conn_evt->status,
|
||||||
|
// note the usage of the stack handle, not the HCI handle
|
||||||
|
conn_evt->hdr.param,
|
||||||
|
(connection_role_t::type) conn_evt->role,
|
||||||
|
(advertising_peer_address_type_t::type) conn_evt->addrType,
|
||||||
|
conn_evt->peerAddr,
|
||||||
|
conn_evt->connInterval,
|
||||||
|
conn_evt->connLatency,
|
||||||
|
conn_evt->supTimeout
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct GapAdvertisingReportMessageConverter : public MessageConverter<DM_SCAN_REPORT_IND> {
|
||||||
|
typedef hciLeAdvReportEvt_t type;
|
||||||
|
|
||||||
|
struct CordioGapAdvertisingReportEvent : public GapAdvertisingReportEvent {
|
||||||
|
CordioGapAdvertisingReportEvent(const advertising_t& advertising) :
|
||||||
|
GapAdvertisingReportEvent(), advertising(advertising) {
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ~CordioGapAdvertisingReportEvent() { }
|
||||||
|
|
||||||
|
virtual uint8_t size() const {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual advertising_t operator[](uint8_t i) const {
|
||||||
|
return advertising;
|
||||||
|
}
|
||||||
|
|
||||||
|
advertising_t advertising;
|
||||||
|
};
|
||||||
|
|
||||||
|
static CordioGapAdvertisingReportEvent convert(const hciLeAdvReportEvt_t *scan_report) {
|
||||||
|
GapAdvertisingReportEvent::advertising_t advertising = {
|
||||||
|
(received_advertising_type_t::type) scan_report->eventType,
|
||||||
|
(connection_peer_address_type_t::type) scan_report->addrType,
|
||||||
|
scan_report->addr,
|
||||||
|
make_const_ArrayView(scan_report->pData, scan_report->len),
|
||||||
|
scan_report->rssi
|
||||||
|
};
|
||||||
|
return CordioGapAdvertisingReportEvent(advertising);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DisconnectionMessageConverter : public MessageConverter<DM_CONN_CLOSE_IND> {
|
||||||
|
typedef hciDisconnectCmplEvt_t type;
|
||||||
|
|
||||||
|
static GapDisconnectionCompleteEvent convert(const hciDisconnectCmplEvt_t* disc_evt) {
|
||||||
|
return GapDisconnectionCompleteEvent(
|
||||||
|
disc_evt->status,
|
||||||
|
// note the usage of the stack handle, not the HCI handle
|
||||||
|
disc_evt->hdr.param,
|
||||||
|
disc_evt->reason
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ConnectionUpdateMessageConverter : public MessageConverter<DM_CONN_UPDATE_IND> {
|
||||||
|
typedef hciLeConnUpdateCmplEvt_t type;
|
||||||
|
|
||||||
|
static GapConnectionUpdateEvent convert(const hciLeConnUpdateCmplEvt_t* evt) {
|
||||||
|
return GapConnectionUpdateEvent(
|
||||||
|
evt->status,
|
||||||
|
evt->hdr.param,
|
||||||
|
evt->connInterval,
|
||||||
|
evt->connLatency,
|
||||||
|
evt->supTimeout
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RemoteConnectionParameterRequestMessageConverter : public MessageConverter<DM_REM_CONN_PARAM_REQ_IND> {
|
||||||
|
typedef hciLeRemConnParamReqEvt_t type;
|
||||||
|
|
||||||
|
static GapRemoteConnectionParameterRequestEvent convert(const hciLeRemConnParamReqEvt_t* evt) {
|
||||||
|
return GapRemoteConnectionParameterRequestEvent(
|
||||||
|
evt->hdr.param,
|
||||||
|
evt->intervalMin,
|
||||||
|
evt->intervalMax,
|
||||||
|
evt->latency,
|
||||||
|
evt->timeout
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
address_t device_random_address;
|
||||||
|
bool use_active_scanning;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // cordio
|
||||||
|
} // vendor
|
||||||
|
} // pal
|
||||||
|
} // ble
|
||||||
|
|
||||||
|
#endif /* CORDIO_PAL_GAP_ */
|
|
@ -0,0 +1,88 @@
|
||||||
|
#ifndef CORDIO_PAL_GENERIC_ACCESS_SERVICE_
|
||||||
|
#define CORDIO_PAL_GENERIC_ACCESS_SERVICE_
|
||||||
|
|
||||||
|
#include "ble/pal/GenericAccessService.h"
|
||||||
|
#include "CordioGattServer.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace ble {
|
||||||
|
namespace pal {
|
||||||
|
namespace vendor {
|
||||||
|
namespace cordio {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of ble::pal::GenericAccessService for the Cordio stack.
|
||||||
|
*/
|
||||||
|
class GenericAccessService : public ::ble::pal::GenericAccessService {
|
||||||
|
public:
|
||||||
|
GenericAccessService() { }
|
||||||
|
|
||||||
|
virtual ~GenericAccessService() { }
|
||||||
|
|
||||||
|
virtual ble_error_t get_device_name_length(uint8_t& length) {
|
||||||
|
const uint8_t* name = NULL;
|
||||||
|
uint16_t actual_length = 0;
|
||||||
|
|
||||||
|
gatt_server().getDeviceName(name, actual_length);
|
||||||
|
length = actual_length;
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ble_error_t get_device_name(ArrayView<uint8_t>& array) {
|
||||||
|
const uint8_t* name = NULL;
|
||||||
|
uint16_t length = 0;
|
||||||
|
|
||||||
|
gatt_server().getDeviceName(name, length);
|
||||||
|
|
||||||
|
if (length > array.size()) {
|
||||||
|
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(array.data(), name, length);
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ble_error_t set_device_name(const uint8_t* device_name) {
|
||||||
|
return gatt_server().setDeviceName(device_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ble_error_t get_appearance(
|
||||||
|
GapAdvertisingData::Appearance& appearance
|
||||||
|
) {
|
||||||
|
appearance = gatt_server().getAppearance();
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ble_error_t set_appearance(
|
||||||
|
GapAdvertisingData::Appearance appearance
|
||||||
|
) {
|
||||||
|
gatt_server().setAppearance(appearance);
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ble_error_t get_peripheral_prefered_connection_parameters(
|
||||||
|
::Gap::ConnectionParams_t& parameters
|
||||||
|
) {
|
||||||
|
parameters = gatt_server().getPreferredConnectionParams();
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ble_error_t set_peripheral_prefered_connection_parameters(
|
||||||
|
const ::Gap::ConnectionParams_t& parameters
|
||||||
|
) {
|
||||||
|
gatt_server().setPreferredConnectionParams(parameters);
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
ble::vendor::cordio::GattServer& gatt_server() {
|
||||||
|
return ble::vendor::cordio::GattServer::getInstance();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // cordio
|
||||||
|
} // vendor
|
||||||
|
} // pal
|
||||||
|
} // ble
|
||||||
|
|
||||||
|
#endif /* CORDIO_PAL_GENERIC_ACCESS_SERVICE_ */
|
|
@ -40,9 +40,6 @@
|
||||||
/*! WSF handler ID */
|
/*! WSF handler ID */
|
||||||
wsfHandlerId_t stack_handler_id;
|
wsfHandlerId_t stack_handler_id;
|
||||||
|
|
||||||
/* Store the Event signaling state */
|
|
||||||
bool isEventsSignaled = false;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Weak definition of ble_cordio_get_hci_driver.
|
* Weak definition of ble_cordio_get_hci_driver.
|
||||||
* A runtime error is generated if the user does not define any
|
* A runtime error is generated if the user does not define any
|
||||||
|
@ -79,10 +76,7 @@ extern "C" void hci_mbed_os_handle_reset_sequence(uint8_t* msg)
|
||||||
*/
|
*/
|
||||||
extern "C" void wsf_mbed_ble_signal_event(void)
|
extern "C" void wsf_mbed_ble_signal_event(void)
|
||||||
{
|
{
|
||||||
if(isEventsSignaled == false) {
|
ble::vendor::cordio::BLE::deviceInstance().signalEventsToProcess(::BLE::DEFAULT_INSTANCE);
|
||||||
isEventsSignaled = true;
|
|
||||||
ble::vendor::cordio::BLE::deviceInstance().signalEventsToProcess(::BLE::DEFAULT_INSTANCE);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -100,7 +94,8 @@ namespace cordio {
|
||||||
|
|
||||||
BLE::BLE(CordioHCIDriver& hci_driver) :
|
BLE::BLE(CordioHCIDriver& hci_driver) :
|
||||||
initialization_status(NOT_INITIALIZED),
|
initialization_status(NOT_INITIALIZED),
|
||||||
instanceID(::BLE::DEFAULT_INSTANCE)
|
instanceID(::BLE::DEFAULT_INSTANCE),
|
||||||
|
_event_queue()
|
||||||
{
|
{
|
||||||
_hci_driver = &hci_driver;
|
_hci_driver = &hci_driver;
|
||||||
stack_setup();
|
stack_setup();
|
||||||
|
@ -123,9 +118,9 @@ ble_error_t BLE::init(
|
||||||
::BLE::InstanceID_t instanceID,
|
::BLE::InstanceID_t instanceID,
|
||||||
FunctionPointerWithContext< ::BLE::InitializationCompleteCallbackContext *> initCallback)
|
FunctionPointerWithContext< ::BLE::InitializationCompleteCallbackContext *> initCallback)
|
||||||
{
|
{
|
||||||
|
|
||||||
switch (initialization_status) {
|
switch (initialization_status) {
|
||||||
case NOT_INITIALIZED:
|
case NOT_INITIALIZED:
|
||||||
|
_event_queue.initialize(this, instanceID);
|
||||||
_init_callback = initCallback;
|
_init_callback = initCallback;
|
||||||
start_stack_reset();
|
start_stack_reset();
|
||||||
return BLE_ERROR_NONE;
|
return BLE_ERROR_NONE;
|
||||||
|
@ -158,6 +153,7 @@ ble_error_t BLE::shutdown()
|
||||||
getGattServer().reset();
|
getGattServer().reset();
|
||||||
getGattClient().reset();
|
getGattClient().reset();
|
||||||
getGap().reset();
|
getGap().reset();
|
||||||
|
_event_queue.clear();
|
||||||
|
|
||||||
return BLE_ERROR_NONE;
|
return BLE_ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
@ -168,15 +164,25 @@ const char* BLE::getVersion()
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|
||||||
Gap& BLE::getGap()
|
::Gap& BLE::getGap()
|
||||||
{
|
{
|
||||||
return cordio::Gap::getInstance();
|
typedef ::Gap& return_type;
|
||||||
|
const BLE* self = this;
|
||||||
|
return const_cast<return_type>(self->getGap());
|
||||||
}
|
}
|
||||||
|
|
||||||
const Gap& BLE::getGap() const
|
const ::Gap& BLE::getGap() const
|
||||||
{
|
{
|
||||||
return cordio::Gap::getInstance();
|
static pal::vendor::cordio::Gap& cordio_pal_gap =
|
||||||
}
|
pal::vendor::cordio::Gap::get_gap();
|
||||||
|
static pal::vendor::cordio::GenericAccessService cordio_gap_service;
|
||||||
|
static ble::generic::GenericGap gap(
|
||||||
|
_event_queue,
|
||||||
|
cordio_pal_gap,
|
||||||
|
cordio_gap_service
|
||||||
|
);
|
||||||
|
return gap;
|
||||||
|
};
|
||||||
|
|
||||||
GattServer& BLE::getGattServer()
|
GattServer& BLE::getGattServer()
|
||||||
{
|
{
|
||||||
|
@ -227,11 +233,8 @@ void BLE::waitForEvent()
|
||||||
|
|
||||||
void BLE::processEvents()
|
void BLE::processEvents()
|
||||||
{
|
{
|
||||||
if (isEventsSignaled) {
|
callDispatcher();
|
||||||
isEventsSignaled = false;
|
}
|
||||||
callDispatcher();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void BLE::stack_handler(wsfEventMask_t event, wsfMsgHdr_t* msg)
|
void BLE::stack_handler(wsfEventMask_t event, wsfMsgHdr_t* msg)
|
||||||
{
|
{
|
||||||
|
@ -250,66 +253,12 @@ void BLE::processEvents()
|
||||||
BLE_ERROR_NONE
|
BLE_ERROR_NONE
|
||||||
};
|
};
|
||||||
deviceInstance().getGattServer().initialize();
|
deviceInstance().getGattServer().initialize();
|
||||||
deviceInstance().getGap().initialize();
|
|
||||||
deviceInstance().initialization_status = INITIALIZED;
|
deviceInstance().initialization_status = INITIALIZED;
|
||||||
_init_callback.call(&context);
|
_init_callback.call(&context);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case DM_ADV_START_IND:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DM_ADV_STOP_IND:
|
|
||||||
Gap::getInstance().advertisingStopped();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DM_SCAN_REPORT_IND: {
|
|
||||||
hciLeAdvReportEvt_t *scan_report = (hciLeAdvReportEvt_t*) msg;
|
|
||||||
Gap::getInstance().processAdvertisementReport(
|
|
||||||
scan_report->addr,
|
|
||||||
scan_report->rssi,
|
|
||||||
(scan_report->eventType == DM_RPT_SCAN_RESPONSE) ? true : false,
|
|
||||||
(GapAdvertisingParams::AdvertisingType_t) scan_report->eventType,
|
|
||||||
scan_report->len,
|
|
||||||
scan_report->pData
|
|
||||||
);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case DM_CONN_OPEN_IND: {
|
|
||||||
hciLeConnCmplEvt_t* conn_evt = (hciLeConnCmplEvt_t*) msg;
|
|
||||||
dmConnId_t connection_id = conn_evt->hdr.param;
|
|
||||||
Gap::getInstance().setConnectionHandle(connection_id);
|
|
||||||
Gap::AddressType_t own_addr_type;
|
|
||||||
Gap::Address_t own_addr;
|
|
||||||
Gap::getInstance().getAddress(&own_addr_type, own_addr);
|
|
||||||
|
|
||||||
Gap::ConnectionParams_t params = {
|
|
||||||
conn_evt->connInterval,
|
|
||||||
conn_evt->connInterval,
|
|
||||||
conn_evt->connLatency,
|
|
||||||
conn_evt->supTimeout
|
|
||||||
};
|
|
||||||
|
|
||||||
Gap::getInstance().processConnectionEvent(
|
|
||||||
connection_id,
|
|
||||||
(conn_evt->role == DM_ROLE_MASTER) ? Gap::CENTRAL : Gap::PERIPHERAL,
|
|
||||||
(Gap::AddressType_t) conn_evt->addrType,
|
|
||||||
conn_evt->peerAddr,
|
|
||||||
own_addr_type,
|
|
||||||
own_addr,
|
|
||||||
¶ms
|
|
||||||
);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case DM_CONN_CLOSE_IND: {
|
|
||||||
dmEvt_t *disconnect_evt = (dmEvt_t*) msg;
|
|
||||||
Gap::getInstance().setConnectionHandle(DM_CONN_ID_NONE);
|
|
||||||
Gap::getInstance().processDisconnectionEvent(
|
|
||||||
disconnect_evt->hdr.param,
|
|
||||||
(Gap::DisconnectionReason_t) disconnect_evt->connClose.reason
|
|
||||||
);
|
|
||||||
} break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
ble::pal::vendor::cordio::Gap::gap_handler(msg);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -425,6 +374,10 @@ void BLE::start_stack_reset()
|
||||||
|
|
||||||
void BLE::callDispatcher()
|
void BLE::callDispatcher()
|
||||||
{
|
{
|
||||||
|
// process the external event queue
|
||||||
|
_event_queue.process();
|
||||||
|
|
||||||
|
// follow by stack events
|
||||||
static uint32_t lastTimeUs = us_ticker_read();
|
static uint32_t lastTimeUs = us_ticker_read();
|
||||||
uint32_t currTimeUs, deltaTimeMs;
|
uint32_t currTimeUs, deltaTimeMs;
|
||||||
|
|
||||||
|
|
|
@ -1,543 +0,0 @@
|
||||||
/* mbed Microcontroller Library
|
|
||||||
* Copyright (c) 2017-2017 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 <algorithm>
|
|
||||||
|
|
||||||
#include "CordioGap.h"
|
|
||||||
#include "mbed.h"
|
|
||||||
#include "dm_api.h"
|
|
||||||
#include "CordioGattServer.h"
|
|
||||||
#include "hci_core.h"
|
|
||||||
|
|
||||||
/**< Minimum Advertising interval in 625 us units, i.e. 20 ms. */
|
|
||||||
#define BLE_GAP_ADV_INTERVAL_MIN 0x0020
|
|
||||||
|
|
||||||
/**< Minimum Advertising interval in 625 us units for non connectable mode, i.e. 100 ms. */
|
|
||||||
#define BLE_GAP_ADV_NONCON_INTERVAL_MIN 0x00A0
|
|
||||||
|
|
||||||
/**< Maximum Advertising interval in 625 us units, i.e. 10.24 s. */
|
|
||||||
#define BLE_GAP_ADV_INTERVAL_MAX 0x4000
|
|
||||||
|
|
||||||
namespace ble {
|
|
||||||
namespace vendor {
|
|
||||||
namespace cordio {
|
|
||||||
|
|
||||||
Gap &Gap::getInstance()
|
|
||||||
{
|
|
||||||
static Gap m_instance;
|
|
||||||
return m_instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Gap::initialize()
|
|
||||||
{
|
|
||||||
uint8_t whitelist_size = HciGetWhiteListSize();
|
|
||||||
|
|
||||||
if (whitelist_size == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
whitelist.addresses = new(std::nothrow) BLEProtocol::Address_t[whitelist_size];
|
|
||||||
if (whitelist.addresses == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
whitelist.size = 0;
|
|
||||||
whitelist.capacity = hciCoreCb.whiteListSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
ble_error_t Gap::setAddress(AddressType_t type, const Address_t address)
|
|
||||||
{
|
|
||||||
switch (type) {
|
|
||||||
case BLEProtocol::AddressType::PUBLIC:
|
|
||||||
// TODO: use vendor specific commands from the driver
|
|
||||||
return BLE_ERROR_OPERATION_NOT_PERMITTED;
|
|
||||||
|
|
||||||
// See bluetooth 5, Vol 6 part, part B, 1.3.2
|
|
||||||
case BLEProtocol::AddressType::RANDOM_STATIC:
|
|
||||||
if ((address[5] >> 6) != 3) {
|
|
||||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_type = type;
|
|
||||||
BdaCpy(m_addr, address);
|
|
||||||
DmDevSetRandAddr(m_addr);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// should not be here, generation is supposed to be handled by the controller.
|
|
||||||
case BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE:
|
|
||||||
case BLEProtocol::AddressType::RANDOM_PRIVATE_NON_RESOLVABLE:
|
|
||||||
m_type = type;
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
DmAdvSetAddrType(m_type);
|
|
||||||
DmConnSetAddrType(m_type);
|
|
||||||
DmScanSetAddrType(m_type);
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ble_error_t Gap::getAddress(AddressType_t *typeP, Address_t address)
|
|
||||||
{
|
|
||||||
*typeP = m_type;
|
|
||||||
|
|
||||||
if(m_type == BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE ||
|
|
||||||
m_type == BLEProtocol::AddressType::RANDOM_PRIVATE_RESOLVABLE) {
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
BdaCpy(address, m_addr);
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ble_error_t Gap::setAdvertisingData(const GapAdvertisingData &advData, const GapAdvertisingData &scanResponse)
|
|
||||||
{
|
|
||||||
/* Make sure we don't exceed the advertising payload length */
|
|
||||||
if (advData.getPayloadLen() > GAP_ADVERTISING_DATA_MAX_PAYLOAD) {
|
|
||||||
return BLE_ERROR_BUFFER_OVERFLOW;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Make sure we have a payload! */
|
|
||||||
if (advData.getPayloadLen() == 0) {
|
|
||||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* set advertising and scan response data for discoverable mode */
|
|
||||||
DmAdvSetData(DM_ADV_HANDLE_DEFAULT, HCI_ADV_DATA_OP_COMP_FRAG, DM_DATA_LOC_ADV, advData.getPayloadLen(), (uint8_t*)advData.getPayload());
|
|
||||||
DmAdvSetData(DM_ADV_HANDLE_DEFAULT, HCI_ADV_DATA_OP_COMP_FRAG, DM_DATA_LOC_SCAN, scanResponse.getPayloadLen(), (uint8_t*)scanResponse.getPayload());
|
|
||||||
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ble_error_t Gap::connect(
|
|
||||||
const BLEProtocol::AddressBytes_t peerAddr,
|
|
||||||
BLEProtocol::AddressType_t peerAddrType,
|
|
||||||
const ConnectionParams_t* connectionParams,
|
|
||||||
const GapScanningParams* scanParams
|
|
||||||
) {
|
|
||||||
// prepare the scan interval
|
|
||||||
if (scanParams != NULL) {
|
|
||||||
DmConnSetScanInterval(scanParams->getInterval(), scanParams->getWindow());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (connectionParams != NULL) {
|
|
||||||
hciConnSpec_t conn_spec = {
|
|
||||||
/* connIntervalMin */ connectionParams->minConnectionInterval,
|
|
||||||
/* connIntervalMax */ connectionParams->maxConnectionInterval,
|
|
||||||
/* connLatency */ connectionParams->slaveLatency,
|
|
||||||
/* supTimeout */ connectionParams->connectionSupervisionTimeout,
|
|
||||||
/* minCeLen */ DM_GAP_CONN_EST_MIN_CE_LEN,
|
|
||||||
/* maxCeLen */ DM_GAP_CONN_EST_MAX_CE_LEN
|
|
||||||
};
|
|
||||||
DmConnSetConnSpec(&conn_spec);
|
|
||||||
}
|
|
||||||
|
|
||||||
DmScanStop();
|
|
||||||
dmConnId_t connection_id = DmConnOpen(
|
|
||||||
DM_CLIENT_ID_APP,
|
|
||||||
HCI_INIT_PHY_LE_1M_BIT,
|
|
||||||
peerAddrType,
|
|
||||||
(uint8_t*) peerAddr
|
|
||||||
);
|
|
||||||
|
|
||||||
if (connection_id == DM_CONN_ID_NONE) {
|
|
||||||
return BLE_ERROR_INTERNAL_STACK_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t Gap::getMinAdvertisingInterval() const
|
|
||||||
{
|
|
||||||
return BLE_GAP_ADV_INTERVAL_MIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t Gap::getMinNonConnectableAdvertisingInterval() const
|
|
||||||
{
|
|
||||||
return BLE_GAP_ADV_NONCON_INTERVAL_MIN;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t Gap::getMaxAdvertisingInterval() const
|
|
||||||
{
|
|
||||||
return BLE_GAP_ADV_INTERVAL_MAX;
|
|
||||||
}
|
|
||||||
|
|
||||||
ble_error_t Gap::startAdvertising(const GapAdvertisingParams ¶ms)
|
|
||||||
{
|
|
||||||
/* Make sure we support the advertising type */
|
|
||||||
if (params.getAdvertisingType() == GapAdvertisingParams::ADV_CONNECTABLE_DIRECTED) {
|
|
||||||
/* ToDo: This requires a proper security implementation, etc. */
|
|
||||||
return BLE_ERROR_NOT_IMPLEMENTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check interval range */
|
|
||||||
if (params.getAdvertisingType() == GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED) {
|
|
||||||
/* Min delay is slightly longer for unconnectable devices */
|
|
||||||
if ((params.getIntervalInADVUnits() < GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MIN_NONCON) ||
|
|
||||||
(params.getIntervalInADVUnits() > GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MAX)) {
|
|
||||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ((params.getIntervalInADVUnits() < GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MIN) ||
|
|
||||||
(params.getIntervalInADVUnits() > GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MAX)) {
|
|
||||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check timeout is zero for Connectable Directed */
|
|
||||||
if ((params.getAdvertisingType() == GapAdvertisingParams::ADV_CONNECTABLE_DIRECTED) && (params.getTimeout() != 0)) {
|
|
||||||
/* Timeout must be 0 with this type, although we'll never get here */
|
|
||||||
/* since this isn't implemented yet anyway */
|
|
||||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check timeout for other advertising types */
|
|
||||||
if ((params.getAdvertisingType() != GapAdvertisingParams::ADV_CONNECTABLE_DIRECTED) &&
|
|
||||||
(params.getTimeout() > GapAdvertisingParams::GAP_ADV_PARAMS_TIMEOUT_MAX)) {
|
|
||||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t adv_interval_min = params.getIntervalInADVUnits();
|
|
||||||
if (adv_interval_min == GapAdvertisingParams::GAP_ADV_PARAMS_INTERVAL_MAX) {
|
|
||||||
--adv_interval_min;
|
|
||||||
}
|
|
||||||
uint16_t adv_interval_max = adv_interval_min + 1;
|
|
||||||
|
|
||||||
DmAdvSetInterval(DM_ADV_HANDLE_DEFAULT, adv_interval_min, adv_interval_max);
|
|
||||||
|
|
||||||
/* Peer Addr Type 0 = Public */
|
|
||||||
uint8_t peerAddrType = 0;
|
|
||||||
uint8_t peerAddr[6] = { 0 };
|
|
||||||
DmAdvConfig(DM_ADV_HANDLE_DEFAULT, params.getAdvertisingType(), peerAddrType, peerAddr);
|
|
||||||
|
|
||||||
uint8_t adv_handles[] = { DM_ADV_HANDLE_DEFAULT };
|
|
||||||
uint16_t adv_durations[] = { (uint16_t) (params.getTimeout() * 1000) };
|
|
||||||
uint8_t max_ea_events[] = { 0 };
|
|
||||||
DmAdvStart(1, adv_handles, adv_durations, max_ea_events);
|
|
||||||
|
|
||||||
state.advertising = 1;
|
|
||||||
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ble_error_t Gap::stopAdvertising(void)
|
|
||||||
{
|
|
||||||
uint8_t adv_handles[] = { DM_ADV_HANDLE_DEFAULT };
|
|
||||||
DmAdvStop(1, adv_handles);
|
|
||||||
|
|
||||||
state.advertising = 0;
|
|
||||||
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ble_error_t Gap::disconnect(Handle_t connectionHandle, DisconnectionReason_t reason)
|
|
||||||
{
|
|
||||||
DmConnClose(DM_CLIENT_ID_APP, connectionHandle, reason);
|
|
||||||
|
|
||||||
state.advertising = 0;
|
|
||||||
state.connected = 0;
|
|
||||||
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ble_error_t Gap::disconnect(DisconnectionReason_t reason)
|
|
||||||
{
|
|
||||||
DmConnClose(DM_CLIENT_ID_APP, m_connectionHandle, reason);
|
|
||||||
|
|
||||||
state.advertising = 0;
|
|
||||||
state.connected = 0;
|
|
||||||
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ble_error_t Gap::setDeviceName(const uint8_t *deviceName)
|
|
||||||
{
|
|
||||||
return GattServer::getInstance().setDeviceName(deviceName);
|
|
||||||
}
|
|
||||||
|
|
||||||
ble_error_t Gap::getDeviceName(uint8_t *deviceName, unsigned *lengthP)
|
|
||||||
{
|
|
||||||
const uint8_t* name = NULL;
|
|
||||||
uint16_t length = 0;
|
|
||||||
|
|
||||||
GattServer::getInstance().getDeviceName(name, length);
|
|
||||||
|
|
||||||
if (deviceName != NULL) {
|
|
||||||
memcpy(deviceName, name, std::min((uint16_t) *lengthP, length));
|
|
||||||
}
|
|
||||||
|
|
||||||
*lengthP = length;
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ble_error_t Gap::setAppearance(GapAdvertisingData::Appearance appearance)
|
|
||||||
{
|
|
||||||
GattServer::getInstance().setAppearance(appearance);
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ble_error_t Gap::getAppearance(GapAdvertisingData::Appearance *appearanceP)
|
|
||||||
{
|
|
||||||
*appearanceP = GattServer::getInstance().getAppearance();
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ble_error_t Gap::setTxPower(int8_t txPower)
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
HciVsSetTxPower(txPower);
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
#else
|
|
||||||
return BLE_ERROR_NOT_IMPLEMENTED;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void Gap::getPermittedTxPowerValues(const int8_t **valueArrayPP, size_t *countP)
|
|
||||||
{
|
|
||||||
*valueArrayPP = NULL;
|
|
||||||
*countP = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Gap::setConnectionHandle(uint16_t connectionHandle)
|
|
||||||
{
|
|
||||||
m_connectionHandle = connectionHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t Gap::getConnectionHandle(void)
|
|
||||||
{
|
|
||||||
return m_connectionHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
ble_error_t Gap::getPreferredConnectionParams(ConnectionParams_t *params)
|
|
||||||
{
|
|
||||||
*params = GattServer::getInstance().getPreferredConnectionParams();
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ble_error_t Gap::setPreferredConnectionParams(const ConnectionParams_t *params)
|
|
||||||
{
|
|
||||||
// ensure that parameters are correct
|
|
||||||
// see BLUETOOTH SPECIFICATION Version 4.2 [Vol 3, Part C]
|
|
||||||
// section 12.3 PERIPHERAL PREFERRED CONNECTION PARAMETERS CHARACTERISTIC
|
|
||||||
if (((0x0006 > params->minConnectionInterval) || (params->minConnectionInterval > 0x0C80)) &&
|
|
||||||
params->minConnectionInterval != 0xFFFF) {
|
|
||||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (((params->minConnectionInterval > params->maxConnectionInterval) || (params->maxConnectionInterval > 0x0C80)) &&
|
|
||||||
params->maxConnectionInterval != 0xFFFF) {
|
|
||||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (params->slaveLatency > 0x01F3) {
|
|
||||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (((0x000A > params->connectionSupervisionTimeout) || (params->connectionSupervisionTimeout > 0x0C80)) &&
|
|
||||||
params->connectionSupervisionTimeout != 0xFFFF) {
|
|
||||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
GattServer::getInstance().setPreferredConnectionParams(*params);
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ble_error_t Gap::updateConnectionParams(Handle_t handle, const ConnectionParams_t *newParams)
|
|
||||||
{
|
|
||||||
if (DmConnCheckIdle(handle) != 0) {
|
|
||||||
return BLE_STACK_BUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
hciConnSpec_t connSpec;
|
|
||||||
connSpec.connIntervalMin = newParams->minConnectionInterval;
|
|
||||||
connSpec.connIntervalMax = newParams->maxConnectionInterval;
|
|
||||||
connSpec.connLatency = newParams->slaveLatency;
|
|
||||||
connSpec.supTimeout = newParams->connectionSupervisionTimeout;
|
|
||||||
DmConnUpdate(handle, &connSpec);
|
|
||||||
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ble_error_t Gap::startRadioScan(const GapScanningParams &scanningParams)
|
|
||||||
{
|
|
||||||
// not needed to start scanning if the whitelist is empty and the scanning
|
|
||||||
// policy filter all the advertising packets
|
|
||||||
if ((whitelist.size == 0) && (scanning_policy_mode == Gap::SCAN_POLICY_FILTER_ALL_ADV)) {
|
|
||||||
return BLE_ERROR_INVALID_STATE;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t scan_intervals[] = { scanningParams.getInterval() };
|
|
||||||
uint16_t scan_windows[] = { scanningParams.getWindow() };
|
|
||||||
|
|
||||||
DmScanSetInterval(HCI_SCAN_PHY_LE_1M_BIT, scan_intervals, scan_windows);
|
|
||||||
|
|
||||||
uint8_t scanType = scanningParams.getActiveScanning() ? DM_SCAN_TYPE_ACTIVE : DM_SCAN_TYPE_PASSIVE;
|
|
||||||
uint32_t duration = (uint32_t)scanningParams.getTimeout() * 1000;
|
|
||||||
if (duration > 0xFFFF) {
|
|
||||||
// saturate to 16-bits
|
|
||||||
duration = 0xFFFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
DmScanStart(HCI_SCAN_PHY_LE_1M_BIT, DM_DISC_MODE_NONE, &scanType, TRUE, duration, 0);
|
|
||||||
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ble_error_t Gap::stopScan(void)
|
|
||||||
{
|
|
||||||
DmScanStop();
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Gap::advertisingStopped(void)
|
|
||||||
{
|
|
||||||
/* If advertising stopped due to a call to stopAdvertising(), state.advertising will
|
|
||||||
* be '0.' Otherwise, advertising must have stopped due to a timeout
|
|
||||||
*/
|
|
||||||
if (state.advertising) {
|
|
||||||
processTimeoutEvent(Gap::TIMEOUT_SRC_ADVERTISING);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t Gap::getMaxWhitelistSize(void) const
|
|
||||||
{
|
|
||||||
return whitelist.capacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
ble_error_t Gap::getWhitelist(Whitelist_t &other) const
|
|
||||||
{
|
|
||||||
// i is a shorthand for other.size
|
|
||||||
uint8_t& i = other.size;
|
|
||||||
|
|
||||||
for (i = 0; (i < whitelist.capacity) && (i < other.capacity); ++i) {
|
|
||||||
other.addresses[i] = whitelist.addresses[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ble_error_t Gap::setWhitelist(const Whitelist_t& other)
|
|
||||||
{
|
|
||||||
if (other.capacity > whitelist.capacity) {
|
|
||||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// note : can be improved by sending the diff instead of the full list
|
|
||||||
|
|
||||||
DmDevWhiteListClear();
|
|
||||||
|
|
||||||
// alias i to whitelist.size
|
|
||||||
uint8_t& i = whitelist.size;
|
|
||||||
|
|
||||||
for (i = 0; (i < other.capacity) && (i < whitelist.capacity); ++i) {
|
|
||||||
whitelist.addresses[i] = other.addresses[i];
|
|
||||||
DmDevWhiteListAdd(
|
|
||||||
(whitelist.addresses[i].type > 1) ? 0xFF : whitelist.addresses[i].type,
|
|
||||||
whitelist.addresses[i].address
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
ble_error_t Gap::setAdvertisingPolicyMode(AdvertisingPolicyMode_t mode)
|
|
||||||
{
|
|
||||||
bool_t result = DmDevSetFilterPolicy(
|
|
||||||
DM_FILT_POLICY_MODE_ADV,
|
|
||||||
mode
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result == false) {
|
|
||||||
return BLE_ERROR_INVALID_STATE;
|
|
||||||
}
|
|
||||||
|
|
||||||
advertising_policy_mode = mode;
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
Gap::AdvertisingPolicyMode_t Gap::getAdvertisingPolicyMode(void) const
|
|
||||||
{
|
|
||||||
return advertising_policy_mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
ble_error_t Gap::setScanningPolicyMode(ScanningPolicyMode_t mode)
|
|
||||||
{
|
|
||||||
bool_t result = DmDevSetFilterPolicy(
|
|
||||||
DM_FILT_POLICY_MODE_SCAN,
|
|
||||||
mode
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result == false) {
|
|
||||||
return BLE_ERROR_INVALID_STATE;
|
|
||||||
}
|
|
||||||
|
|
||||||
scanning_policy_mode = mode;
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Gap::ScanningPolicyMode_t Gap::getScanningPolicyMode(void) const
|
|
||||||
{
|
|
||||||
return scanning_policy_mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
ble_error_t Gap::setInitiatorPolicyMode(InitiatorPolicyMode_t mode)
|
|
||||||
{
|
|
||||||
bool_t result = DmDevSetFilterPolicy(
|
|
||||||
DM_FILT_POLICY_MODE_INIT,
|
|
||||||
mode
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result == false) {
|
|
||||||
return BLE_ERROR_INVALID_STATE;
|
|
||||||
}
|
|
||||||
|
|
||||||
initiator_policy_mode = mode;
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
Gap::InitiatorPolicyMode_t Gap::getInitiatorPolicyMode(void) const
|
|
||||||
{
|
|
||||||
return initiator_policy_mode;
|
|
||||||
}
|
|
||||||
|
|
||||||
ble_error_t Gap::reset(void)
|
|
||||||
{
|
|
||||||
this->::Gap::reset();
|
|
||||||
delete[] whitelist.addresses;
|
|
||||||
whitelist.addresses = NULL;
|
|
||||||
whitelist.size = 0;
|
|
||||||
whitelist.capacity = 0;
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
Gap::Gap() :
|
|
||||||
::Gap(),
|
|
||||||
m_connectionHandle(DM_CONN_ID_NONE),
|
|
||||||
m_type(BLEProtocol::AddressType::RANDOM_STATIC),
|
|
||||||
m_addr(),
|
|
||||||
advertising_policy_mode(ADV_POLICY_IGNORE_WHITELIST),
|
|
||||||
scanning_policy_mode(SCAN_POLICY_IGNORE_WHITELIST),
|
|
||||||
initiator_policy_mode(INIT_POLICY_IGNORE_WHITELIST),
|
|
||||||
whitelist()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace cordio
|
|
||||||
} // namespace vendor
|
|
||||||
} // namespace ble
|
|
|
@ -16,7 +16,6 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "CordioGattServer.h"
|
#include "CordioGattServer.h"
|
||||||
#include "CordioGap.h"
|
|
||||||
#include "mbed.h"
|
#include "mbed.h"
|
||||||
#include "wsf_types.h"
|
#include "wsf_types.h"
|
||||||
#include "att_api.h"
|
#include "att_api.h"
|
||||||
|
@ -286,33 +285,63 @@ ble_error_t GattServer::read(Gap::Handle_t connectionHandle, GattAttribute::Hand
|
||||||
|
|
||||||
ble_error_t GattServer::write(GattAttribute::Handle_t attributeHandle, const uint8_t buffer[], uint16_t len, bool localOnly)
|
ble_error_t GattServer::write(GattAttribute::Handle_t attributeHandle, const uint8_t buffer[], uint16_t len, bool localOnly)
|
||||||
{
|
{
|
||||||
uint16_t connectionHandle = Gap::getInstance().getConnectionHandle();
|
// Check to see if this is a CCCD, if it is the case update the value for all
|
||||||
|
// connections
|
||||||
|
uint8_t idx;
|
||||||
|
for (idx = 0; idx < cccCnt; idx++) {
|
||||||
|
if (attributeHandle == cccSet[idx].handle) {
|
||||||
|
for (uint16_t conn_id = 0, conn_found = 0; (conn_found < DM_CONN_MAX) && (conn_id < 0x100); ++conn_id) {
|
||||||
|
if (DmConnInUse(conn_id) == true) {
|
||||||
|
++conn_found;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
AttsCccSet(conn_id, idx, *((uint16_t*)buffer));
|
||||||
|
}
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// write the value to the attribute handle
|
||||||
if (AttsSetAttr(attributeHandle, len, (uint8_t*)buffer) != ATT_SUCCESS) {
|
if (AttsSetAttr(attributeHandle, len, (uint8_t*)buffer) != ATT_SUCCESS) {
|
||||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!localOnly) {
|
// return if the update does not have to be propagated to peers
|
||||||
if (connectionHandle != DM_CONN_ID_NONE) {
|
if (localOnly) {
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
// Check to see if this characteristic has a CCCD attribute
|
// Check to see if this characteristic has a CCCD attribute
|
||||||
uint8_t idx;
|
for (idx = 0; idx < cccCnt; idx++) {
|
||||||
for (idx = 0; idx < cccCnt; idx++) {
|
if (attributeHandle == cccHandles[idx]) {
|
||||||
if (attributeHandle == cccHandles[idx]) {
|
break;
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// exit if the characteristic has no CCCD attribute
|
||||||
|
if (idx >= cccCnt) {
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This characteristic has a CCCD attribute. Handle notifications and indications.
|
||||||
|
// for all connections
|
||||||
|
|
||||||
|
for (uint16_t conn_id = 0, conn_found = 0; (conn_found < DM_CONN_MAX) && (conn_id < 0x100); ++conn_id) {
|
||||||
|
if (DmConnInUse(conn_id) == true) {
|
||||||
|
++conn_found;
|
||||||
|
} else {
|
||||||
|
uint16_t cccEnabled = AttsCccEnabled(conn_id, idx);
|
||||||
|
if (cccEnabled & ATT_CLIENT_CFG_NOTIFY) {
|
||||||
|
AttsHandleValueNtf(conn_id, attributeHandle, len, (uint8_t*)buffer);
|
||||||
}
|
}
|
||||||
if (idx < cccCnt) {
|
if (cccEnabled & ATT_CLIENT_CFG_INDICATE) {
|
||||||
// This characteristic has a CCCD attribute. Handle notifications and indications.
|
AttsHandleValueInd(conn_id, attributeHandle, len, (uint8_t*)buffer);
|
||||||
uint16_t cccEnabled = AttsCccEnabled(connectionHandle, idx);
|
|
||||||
if (cccEnabled & ATT_CLIENT_CFG_NOTIFY) {
|
|
||||||
AttsHandleValueNtf(connectionHandle, attributeHandle, len, (uint8_t*)buffer);
|
|
||||||
}
|
|
||||||
if (cccEnabled & ATT_CLIENT_CFG_INDICATE) {
|
|
||||||
AttsHandleValueInd(connectionHandle, attributeHandle, len, (uint8_t*)buffer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AttsCccSet(conn_id, idx, *((uint16_t*)buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
return BLE_ERROR_NONE;
|
return BLE_ERROR_NONE;
|
||||||
|
@ -332,26 +361,59 @@ ble_error_t GattServer::write(Gap::Handle_t connectionHandle, GattAttribute::Han
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is not a CCCD. Use the non-connection specific update method.
|
// write the value to the attribute handle
|
||||||
return write(attributeHandle, buffer, len, localOnly);
|
if (AttsSetAttr(attributeHandle, len, (uint8_t*)buffer) != ATT_SUCCESS) {
|
||||||
|
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return if the update does not have to be propagated to peers
|
||||||
|
if (localOnly) {
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check to see if this characteristic has a CCCD attribute
|
||||||
|
for (idx = 0; idx < cccCnt; idx++) {
|
||||||
|
if (attributeHandle == cccHandles[idx]) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// exit if the characteristic has no CCCD attribute
|
||||||
|
if (idx >= cccCnt) {
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This characteristic has a CCCD attribute. Handle notifications and indications.
|
||||||
|
uint16_t cccEnabled = AttsCccEnabled(connectionHandle, idx);
|
||||||
|
if (cccEnabled & ATT_CLIENT_CFG_NOTIFY) {
|
||||||
|
AttsHandleValueNtf(connectionHandle, attributeHandle, len, (uint8_t*)buffer);
|
||||||
|
}
|
||||||
|
if (cccEnabled & ATT_CLIENT_CFG_INDICATE) {
|
||||||
|
AttsHandleValueInd(connectionHandle, attributeHandle, len, (uint8_t*)buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ble_error_t GattServer::areUpdatesEnabled(const GattCharacteristic &characteristic, bool *enabledP)
|
ble_error_t GattServer::areUpdatesEnabled(const GattCharacteristic &characteristic, bool *enabledP)
|
||||||
{
|
{
|
||||||
uint16_t connectionHandle = Gap::getInstance().getConnectionHandle();
|
for (size_t idx = 0; idx < cccCnt; idx++) {
|
||||||
|
if (characteristic.getValueHandle() == cccHandles[idx]) {
|
||||||
if (connectionHandle != DM_CONN_ID_NONE) {
|
for (uint16_t conn_id = 0, conn_found = 0; (conn_found < DM_CONN_MAX) && (conn_id < 0x100); ++conn_id) {
|
||||||
uint8_t idx;
|
if (DmConnInUse(conn_id) == true) {
|
||||||
for (idx = 0; idx < cccCnt; idx++) {
|
++conn_found;
|
||||||
if (characteristic.getValueHandle() == cccHandles[idx]) {
|
|
||||||
uint16_t cccValue = AttsCccGet(connectionHandle, idx);
|
|
||||||
if (cccValue & ATT_CLIENT_CFG_NOTIFY) {
|
|
||||||
*enabledP = true;
|
|
||||||
} else {
|
} else {
|
||||||
*enabledP = false;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t cccValue = AttsCccGet(conn_id, idx);
|
||||||
|
if ((cccValue & ATT_CLIENT_CFG_NOTIFY) || (cccValue & ATT_CLIENT_CFG_INDICATE)) {
|
||||||
|
*enabledP = true;
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
}
|
}
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
}
|
}
|
||||||
|
*enabledP = false;
|
||||||
|
return BLE_ERROR_NONE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,7 +427,7 @@ ble_error_t GattServer::areUpdatesEnabled(Gap::Handle_t connectionHandle, const
|
||||||
for (idx = 0; idx < cccCnt; idx++) {
|
for (idx = 0; idx < cccCnt; idx++) {
|
||||||
if (characteristic.getValueHandle() == cccHandles[idx]) {
|
if (characteristic.getValueHandle() == cccHandles[idx]) {
|
||||||
uint16_t cccValue = AttsCccGet(connectionHandle, idx);
|
uint16_t cccValue = AttsCccGet(connectionHandle, idx);
|
||||||
if (cccValue & ATT_CLIENT_CFG_NOTIFY) {
|
if (cccValue & ATT_CLIENT_CFG_NOTIFY || (cccValue & ATT_CLIENT_CFG_INDICATE)) {
|
||||||
*enabledP = true;
|
*enabledP = true;
|
||||||
} else {
|
} else {
|
||||||
*enabledP = false;
|
*enabledP = false;
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2015-2017, 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 "cmsis.h"
|
||||||
|
#include "nrf_error.h"
|
||||||
|
#include "nrf_sdm.h"
|
||||||
|
#include "nrf_soc.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
static union {
|
||||||
|
uint32_t _PRIMASK_state;
|
||||||
|
uint8_t _sd_state;
|
||||||
|
} _state = {0};
|
||||||
|
|
||||||
|
static bool _use_softdevice_routine = false;
|
||||||
|
static bool _state_saved = false;
|
||||||
|
|
||||||
|
void hal_critical_section_enter(void)
|
||||||
|
{
|
||||||
|
// Fetch the current state of interrupts
|
||||||
|
uint32_t primask = __get_PRIMASK();
|
||||||
|
uint8_t temp_state = 0;
|
||||||
|
|
||||||
|
// If interrupts are enabled, try to use the soft device
|
||||||
|
uint8_t sd_enabled;
|
||||||
|
if ((primask == 0) &&
|
||||||
|
(sd_softdevice_is_enabled(&sd_enabled) == NRF_SUCCESS) &&
|
||||||
|
(sd_enabled == 1)) {
|
||||||
|
// If the softdevice can be used, use it.
|
||||||
|
sd_nvic_critical_region_enter(&temp_state);
|
||||||
|
_use_softdevice_routine = true;
|
||||||
|
|
||||||
|
if (_state_saved == false) {
|
||||||
|
_state._sd_state = temp_state;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If interrupts are enabled, disable them.
|
||||||
|
if (primask == 0) {
|
||||||
|
__disable_irq();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store PRIMASK state, it will be restored when exiting critical
|
||||||
|
// section.
|
||||||
|
_use_softdevice_routine = false;
|
||||||
|
|
||||||
|
if (_state_saved == false) {
|
||||||
|
_state._PRIMASK_state = primask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_state_saved = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hal_critical_section_exit(void)
|
||||||
|
{
|
||||||
|
_state_saved = false;
|
||||||
|
|
||||||
|
// Restore the state as it was prior to entering the critical section.
|
||||||
|
if (_use_softdevice_routine) {
|
||||||
|
sd_nvic_critical_region_exit(_state._sd_state)
|
||||||
|
} else {
|
||||||
|
__set_PRIMASK(_state._PRIMASK_state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hal_in_critical_section(void)
|
||||||
|
{
|
||||||
|
return (_state_saved == true);
|
||||||
|
}
|
|
@ -1,80 +0,0 @@
|
||||||
/*
|
|
||||||
* 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"
|
|
||||||
|
|
||||||
static union {
|
|
||||||
uint32_t _PRIMASK_state;
|
|
||||||
uint8_t _sd_state;
|
|
||||||
} _state = { 0 } ;
|
|
||||||
static volatile uint32_t _entry_count = 0;
|
|
||||||
static bool _use_softdevice_routine = false;
|
|
||||||
|
|
||||||
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
|
|
||||||
uint32_t primask = __get_PRIMASK();
|
|
||||||
|
|
||||||
// if interrupts are enabled, try to use the soft device
|
|
||||||
uint8_t sd_enabled;
|
|
||||||
if ((primask == 0) && (sd_softdevice_is_enabled(&sd_enabled) == NRF_SUCCESS) && sd_enabled == 1) {
|
|
||||||
// if the soft device can be use, use it
|
|
||||||
sd_nvic_critical_region_enter(&_state._sd_state);
|
|
||||||
_use_softdevice_routine = true;
|
|
||||||
} else {
|
|
||||||
// if interrupts where enabled, disable them
|
|
||||||
if(primask == 0) {
|
|
||||||
__disable_irq();
|
|
||||||
}
|
|
||||||
|
|
||||||
// store the PRIMASK state, it will be restored at the end of the critical section
|
|
||||||
_state._PRIMASK_state = primask;
|
|
||||||
_use_softdevice_routine = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
if (_use_softdevice_routine) {
|
|
||||||
sd_nvic_critical_region_exit(_state._sd_state);
|
|
||||||
} else {
|
|
||||||
__set_PRIMASK(_state._PRIMASK_state);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -51,11 +51,9 @@ extern "C" {
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "nrf_ble_hci.h"
|
#include "nrf_ble_hci.h"
|
||||||
#include "btle_discovery.h"
|
|
||||||
|
|
||||||
#include "nRF5xGattClient.h"
|
#include "nRF5XPalGattClient.h"
|
||||||
#include "nRF5xServiceDiscovery.h"
|
|
||||||
#include "nRF5xCharacteristicDescriptorDiscoverer.h"
|
|
||||||
|
|
||||||
|
|
||||||
bool isEventsSignaled = false;
|
bool isEventsSignaled = false;
|
||||||
|
@ -67,23 +65,6 @@ extern "C" void SD_EVT_IRQHandler(void); // export the softdevice event handler
|
||||||
|
|
||||||
static void btle_handler(ble_evt_t *p_ble_evt);
|
static void btle_handler(ble_evt_t *p_ble_evt);
|
||||||
|
|
||||||
#if 0
|
|
||||||
#define CENTRAL_LINK_COUNT (YOTTA_CFG_NORDIC_BLE_CENTRAL_LINKS) /**<number of central links used by the application. When changing this number remember to adjust the RAM settings */
|
|
||||||
/** If value for YOTTA_CFG_NORDIC_BLE_PERIPHERAL_LINKS was used, ram settings are adjusted by the yotta target module. */
|
|
||||||
#define PERIPHERAL_LINK_COUNT (YOTTA_CFG_NORDIC_BLE_PERIPHERAL_LINKS) /**<number of peripheral links used by the application. When changing this number remember to adjust the RAM settings*/
|
|
||||||
/** If value for YOTTA_CFG_NORDIC_BLE_CENTRAL_LINKS was used, ram settings are adjusted by the yotta target module. */
|
|
||||||
#define GATTS_ATTR_TAB_SIZE (YOTTA_CFG_NORDIC_BLE_GATTS_ATTR_TAB_SIZE) /**< GATTS attribite table size. */
|
|
||||||
/** If value for YOTTA_CFG_NORDIC_BLE_GATTS_ATTR_TAB_SIZE was used, ram settings are adjusted by the yotta target module. */
|
|
||||||
#else
|
|
||||||
#define CENTRAL_LINK_COUNT 3 /**<number of central links used by the application. When changing this number remember to adjust the RAM settings */
|
|
||||||
/** If value for YOTTA_CFG_NORDIC_BLE_PERIPHERAL_LINKS was used, ram settings are adjusted by the yotta target module. */
|
|
||||||
#define PERIPHERAL_LINK_COUNT 1 /**<number of peripheral links used by the application. When changing this number remember to adjust the RAM settings*/
|
|
||||||
/** If value for YOTTA_CFG_NORDIC_BLE_CENTRAL_LINKS was used, ram settings are adjusted by the yotta target module. */
|
|
||||||
#define GATTS_ATTR_TAB_SIZE 0x600 /**< GATTS attribite table size. */
|
|
||||||
/** If value for YOTTA_CFG_NORDIC_BLE_GATTS_ATTR_TAB_SIZE was used, ram settings are adjusted by the yotta target module. */
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void sys_evt_dispatch(uint32_t sys_evt)
|
static void sys_evt_dispatch(uint32_t sys_evt)
|
||||||
{
|
{
|
||||||
#if (IS_LEGACY_DEVICE_MANAGER_ENABLED)
|
#if (IS_LEGACY_DEVICE_MANAGER_ENABLED)
|
||||||
|
@ -121,7 +102,7 @@ error_t btle_init(void)
|
||||||
|
|
||||||
// register softdevice handler vector
|
// register softdevice handler vector
|
||||||
NVIC_SetVector(SD_EVT_IRQn, (uint32_t) SD_EVT_IRQHandler);
|
NVIC_SetVector(SD_EVT_IRQn, (uint32_t) SD_EVT_IRQHandler);
|
||||||
|
|
||||||
// Configure the LF clock according to values provided by btle_clock.h.
|
// Configure the LF clock according to values provided by btle_clock.h.
|
||||||
// It is input from the chain of the yotta configuration system.
|
// It is input from the chain of the yotta configuration system.
|
||||||
clockConfiguration.source = LFCLK_CONF_SOURCE;
|
clockConfiguration.source = LFCLK_CONF_SOURCE;
|
||||||
|
@ -189,6 +170,8 @@ error_t btle_init(void)
|
||||||
|
|
||||||
static void btle_handler(ble_evt_t *p_ble_evt)
|
static void btle_handler(ble_evt_t *p_ble_evt)
|
||||||
{
|
{
|
||||||
|
using ble::pal::vendor::nordic::nRF5XGattClient;
|
||||||
|
|
||||||
/* Library service handlers */
|
/* Library service handlers */
|
||||||
#if SDK_CONN_PARAMS_MODULE_ENABLE
|
#if SDK_CONN_PARAMS_MODULE_ENABLE
|
||||||
ble_conn_params_on_ble_evt(p_ble_evt);
|
ble_conn_params_on_ble_evt(p_ble_evt);
|
||||||
|
@ -206,7 +189,7 @@ static void btle_handler(ble_evt_t *p_ble_evt)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110)
|
#if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110)
|
||||||
bleGattcEventHandler(p_ble_evt);
|
nRF5XGattClient::handle_events(p_ble_evt);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
nRF5xn &ble = nRF5xn::Instance(BLE::DEFAULT_INSTANCE);
|
nRF5xn &ble = nRF5xn::Instance(BLE::DEFAULT_INSTANCE);
|
||||||
|
@ -229,7 +212,7 @@ static void btle_handler(ble_evt_t *p_ble_evt)
|
||||||
const ble_gap_addr_t *peer = &p_ble_evt->evt.gap_evt.params.connected.peer_addr;
|
const ble_gap_addr_t *peer = &p_ble_evt->evt.gap_evt.params.connected.peer_addr;
|
||||||
#if (NRF_SD_BLE_API_VERSION <= 2)
|
#if (NRF_SD_BLE_API_VERSION <= 2)
|
||||||
const ble_gap_addr_t *own = &p_ble_evt->evt.gap_evt.params.connected.own_addr;
|
const ble_gap_addr_t *own = &p_ble_evt->evt.gap_evt.params.connected.own_addr;
|
||||||
|
|
||||||
gap.processConnectionEvent(handle,
|
gap.processConnectionEvent(handle,
|
||||||
role,
|
role,
|
||||||
static_cast<BLEProtocol::AddressType_t>(peer->addr_type), peer->addr,
|
static_cast<BLEProtocol::AddressType_t>(peer->addr_type), peer->addr,
|
||||||
|
@ -275,9 +258,7 @@ static void btle_handler(ble_evt_t *p_ble_evt)
|
||||||
|
|
||||||
#if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110)
|
#if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110)
|
||||||
// Close all pending discoveries for this connection
|
// Close all pending discoveries for this connection
|
||||||
nRF5xGattClient& gattClient = ble.getGattClient();
|
nRF5XGattClient::handle_connection_termination(handle);
|
||||||
gattClient.characteristicDescriptorDiscoverer().terminate(handle, BLE_ERROR_INVALID_STATE);
|
|
||||||
gattClient.discovery().terminate(handle);
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
gap.processDisconnectionEvent(handle, reason);
|
gap.processDisconnectionEvent(handle, reason);
|
||||||
|
|
|
@ -26,6 +26,13 @@ extern "C" {
|
||||||
#include "ble_srv_common.h"
|
#include "ble_srv_common.h"
|
||||||
#include "headers/nrf_ble.h"
|
#include "headers/nrf_ble.h"
|
||||||
|
|
||||||
|
#define CENTRAL_LINK_COUNT 3 /**<number of central links used by the application. When changing this number remember to adjust the RAM settings */
|
||||||
|
/** If value for YOTTA_CFG_NORDIC_BLE_PERIPHERAL_LINKS was used, ram settings are adjusted by the yotta target module. */
|
||||||
|
#define PERIPHERAL_LINK_COUNT 1 /**<number of peripheral links used by the application. When changing this number remember to adjust the RAM settings*/
|
||||||
|
/** If value for YOTTA_CFG_NORDIC_BLE_CENTRAL_LINKS was used, ram settings are adjusted by the yotta target module. */
|
||||||
|
#define GATTS_ATTR_TAB_SIZE 0x600 /**< GATTS attribite table size. */
|
||||||
|
/** If value for YOTTA_CFG_NORDIC_BLE_GATTS_ATTR_TAB_SIZE was used, ram settings are adjusted by the yotta target module. */
|
||||||
|
|
||||||
error_t btle_init(void);
|
error_t btle_init(void);
|
||||||
|
|
||||||
// flag indicating if events have been signaled or not
|
// flag indicating if events have been signaled or not
|
||||||
|
|
|
@ -1,147 +0,0 @@
|
||||||
/* 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 "nRF5xServiceDiscovery.h"
|
|
||||||
#include "nRF5xCharacteristicDescriptorDiscoverer.h"
|
|
||||||
#include "nRF5xGattClient.h"
|
|
||||||
#include "nRF5xn.h"
|
|
||||||
|
|
||||||
#if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110)
|
|
||||||
void bleGattcEventHandler(const ble_evt_t *p_ble_evt)
|
|
||||||
{
|
|
||||||
nRF5xn &ble = nRF5xn::Instance(BLE::DEFAULT_INSTANCE);
|
|
||||||
nRF5xGattClient &gattClient = (nRF5xGattClient &) ble.getGattClient();
|
|
||||||
nRF5xServiceDiscovery &sdSingleton = gattClient.discovery();
|
|
||||||
nRF5xCharacteristicDescriptorDiscoverer &characteristicDescriptorDiscoverer =
|
|
||||||
gattClient.characteristicDescriptorDiscoverer();
|
|
||||||
|
|
||||||
switch (p_ble_evt->header.evt_id) {
|
|
||||||
case BLE_GATTC_EVT_PRIM_SRVC_DISC_RSP:
|
|
||||||
switch (p_ble_evt->evt.gattc_evt.gatt_status) {
|
|
||||||
case BLE_GATT_STATUS_SUCCESS:
|
|
||||||
sdSingleton.setupDiscoveredServices(&p_ble_evt->evt.gattc_evt.params.prim_srvc_disc_rsp);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_FOUND:
|
|
||||||
default:
|
|
||||||
sdSingleton.terminate();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BLE_GATTC_EVT_CHAR_DISC_RSP:
|
|
||||||
switch (p_ble_evt->evt.gattc_evt.gatt_status) {
|
|
||||||
case BLE_GATT_STATUS_SUCCESS:
|
|
||||||
sdSingleton.setupDiscoveredCharacteristics(&p_ble_evt->evt.gattc_evt.params.char_disc_rsp);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_FOUND:
|
|
||||||
default:
|
|
||||||
sdSingleton.terminateCharacteristicDiscovery(BLE_ERROR_NONE);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BLE_GATTC_EVT_CHAR_VAL_BY_UUID_READ_RSP:
|
|
||||||
if (sdSingleton.isActive()) {
|
|
||||||
sdSingleton.processDiscoverUUIDResponse(&p_ble_evt->evt.gattc_evt);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BLE_GATTC_EVT_READ_RSP: {
|
|
||||||
GattReadCallbackParams response = {
|
|
||||||
/* .connHandle = */ p_ble_evt->evt.gattc_evt.conn_handle,
|
|
||||||
/* .handle = */ p_ble_evt->evt.gattc_evt.params.read_rsp.handle,
|
|
||||||
/* .offset = */ p_ble_evt->evt.gattc_evt.params.read_rsp.offset,
|
|
||||||
/* .len = */ p_ble_evt->evt.gattc_evt.params.read_rsp.len,
|
|
||||||
/* .data = */ p_ble_evt->evt.gattc_evt.params.read_rsp.data,
|
|
||||||
};
|
|
||||||
gattClient.processReadResponse(&response);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BLE_GATTC_EVT_WRITE_RSP: {
|
|
||||||
GattWriteCallbackParams response = {
|
|
||||||
/* .connHandle = */ p_ble_evt->evt.gattc_evt.conn_handle,
|
|
||||||
/* .handle = */ p_ble_evt->evt.gattc_evt.params.write_rsp.handle,
|
|
||||||
/* .writeOp = */ (GattWriteCallbackParams::WriteOp_t)(p_ble_evt->evt.gattc_evt.params.write_rsp.write_op),
|
|
||||||
/* .offset = */ p_ble_evt->evt.gattc_evt.params.write_rsp.offset,
|
|
||||||
/* .len = */ p_ble_evt->evt.gattc_evt.params.write_rsp.len,
|
|
||||||
/* .data = */ p_ble_evt->evt.gattc_evt.params.write_rsp.data,
|
|
||||||
};
|
|
||||||
gattClient.processWriteResponse(&response);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BLE_GATTC_EVT_HVX: {
|
|
||||||
GattHVXCallbackParams params = {
|
|
||||||
/* connHandle = */ p_ble_evt->evt.gattc_evt.conn_handle,
|
|
||||||
/* handle = */ p_ble_evt->evt.gattc_evt.params.hvx.handle,
|
|
||||||
/* type = */ static_cast<HVXType_t>(p_ble_evt->evt.gattc_evt.params.hvx.type),
|
|
||||||
/* len = */ p_ble_evt->evt.gattc_evt.params.hvx.len,
|
|
||||||
/* data = */ p_ble_evt->evt.gattc_evt.params.hvx.data
|
|
||||||
};
|
|
||||||
|
|
||||||
gattClient.processHVXEvent(¶ms);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BLE_GATTC_EVT_DESC_DISC_RSP: {
|
|
||||||
uint16_t conn_handle = p_ble_evt->evt.gattc_evt.conn_handle;
|
|
||||||
uint16_t status = p_ble_evt->evt.gattc_evt.gatt_status;
|
|
||||||
const ble_gattc_evt_desc_disc_rsp_t& discovered_descriptors = p_ble_evt->evt.gattc_evt.params.desc_disc_rsp;
|
|
||||||
|
|
||||||
switch(status) {
|
|
||||||
case BLE_GATT_STATUS_SUCCESS:
|
|
||||||
characteristicDescriptorDiscoverer.process(
|
|
||||||
conn_handle,
|
|
||||||
discovered_descriptors
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
case BLE_GATT_STATUS_ATTERR_ATTRIBUTE_NOT_FOUND:
|
|
||||||
// end of discovery
|
|
||||||
characteristicDescriptorDiscoverer.terminate(conn_handle, BLE_ERROR_NONE);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
characteristicDescriptorDiscoverer.terminate(conn_handle, BLE_ERROR_UNSPECIFIED);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} break;
|
|
||||||
|
|
||||||
case BLE_GATTC_EVT_ATTR_INFO_DISC_RSP : {
|
|
||||||
uint16_t conn_handle = p_ble_evt->evt.gattc_evt.conn_handle;
|
|
||||||
uint16_t status = p_ble_evt->evt.gattc_evt.gatt_status;
|
|
||||||
const ble_gattc_evt_attr_info_disc_rsp_t& infos = p_ble_evt->evt.gattc_evt.params.attr_info_disc_rsp;
|
|
||||||
|
|
||||||
switch(status) {
|
|
||||||
case BLE_GATT_STATUS_SUCCESS:
|
|
||||||
characteristicDescriptorDiscoverer.processAttributeInformation(
|
|
||||||
conn_handle,
|
|
||||||
infos
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
characteristicDescriptorDiscoverer.terminate(conn_handle, BLE_ERROR_UNSPECIFIED);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
|
|
||||||
sdSingleton.progressCharacteristicDiscovery();
|
|
||||||
sdSingleton.progressServiceDiscovery();
|
|
||||||
}
|
|
||||||
#endif
|
|
|
@ -210,6 +210,8 @@ error_t custom_add_in_characteristic(uint16_t service_handle,
|
||||||
bool has_variable_len,
|
bool has_variable_len,
|
||||||
const uint8_t *userDescriptionDescriptorValuePtr,
|
const uint8_t *userDescriptionDescriptorValuePtr,
|
||||||
uint16_t userDescriptionDescriptorValueLen,
|
uint16_t userDescriptionDescriptorValueLen,
|
||||||
|
const uint8_t *presentationFormatDescriptorValuePtr,
|
||||||
|
uint16_t presentationFormatDescriptorValueLen,
|
||||||
bool readAuthorization,
|
bool readAuthorization,
|
||||||
bool writeAuthorization,
|
bool writeAuthorization,
|
||||||
ble_gatts_char_handles_t *p_char_handle)
|
ble_gatts_char_handles_t *p_char_handle)
|
||||||
|
@ -238,6 +240,11 @@ error_t custom_add_in_characteristic(uint16_t service_handle,
|
||||||
char_md.char_user_desc_max_size = userDescriptionDescriptorValueLen;
|
char_md.char_user_desc_max_size = userDescriptionDescriptorValueLen;
|
||||||
char_md.char_user_desc_size = userDescriptionDescriptorValueLen;
|
char_md.char_user_desc_size = userDescriptionDescriptorValueLen;
|
||||||
}
|
}
|
||||||
|
if ((presentationFormatDescriptorValueLen > 0) && (presentationFormatDescriptorValuePtr != NULL)) {
|
||||||
|
ASSERT_TRUE( sizeof(ble_gatts_char_pf_t) == sizeof(GattCharacteristic::PresentationFormat_t), ERROR_INVALID_PARAM );
|
||||||
|
ASSERT_TRUE( presentationFormatDescriptorValueLen == sizeof(GattCharacteristic::PresentationFormat_t), ERROR_INVALID_PARAM );
|
||||||
|
char_md.p_char_pf = const_cast<ble_gatts_char_pf_t *>(reinterpret_cast<const ble_gatts_char_pf_t *>(presentationFormatDescriptorValuePtr));
|
||||||
|
}
|
||||||
|
|
||||||
/* Attribute declaration */
|
/* Attribute declaration */
|
||||||
ble_gatts_attr_md_t attr_md = {0};
|
ble_gatts_attr_md_t attr_md = {0};
|
||||||
|
|
|
@ -52,6 +52,8 @@ error_t custom_add_in_characteristic(uint16_t service_handle,
|
||||||
bool has_variable_len,
|
bool has_variable_len,
|
||||||
const uint8_t *userDescriptionDescriptorValuePtr,
|
const uint8_t *userDescriptionDescriptorValuePtr,
|
||||||
uint16_t userDescriptionDescriptorValueLen,
|
uint16_t userDescriptionDescriptorValueLen,
|
||||||
|
const uint8_t *presentationFormatDescriptorValuePtr,
|
||||||
|
uint16_t presentationFormatDescriptorValueLen,
|
||||||
bool readAuthorization,
|
bool readAuthorization,
|
||||||
bool writeAuthorization,
|
bool writeAuthorization,
|
||||||
ble_gatts_char_handles_t *p_char_handle);
|
ble_gatts_char_handles_t *p_char_handle);
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,257 @@
|
||||||
|
/* mbed Microcontroller Library
|
||||||
|
* Copyright (c) 2017-2017 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 BLE_NORDIC_PAL_GATT_CLIENT_H_
|
||||||
|
#define BLE_NORDIC_PAL_GATT_CLIENT_H_
|
||||||
|
|
||||||
|
#include "ble/pal/PalGattClient.h"
|
||||||
|
#include "ble/blecommon.h"
|
||||||
|
#include "ble/UUID.h"
|
||||||
|
|
||||||
|
#include "nrf_ble_gatt.h"
|
||||||
|
#include "nrf_ble.h"
|
||||||
|
#include "nrf_ble_types.h"
|
||||||
|
#include "btle.h"
|
||||||
|
|
||||||
|
namespace ble {
|
||||||
|
namespace pal {
|
||||||
|
namespace vendor {
|
||||||
|
namespace nordic {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Implementation of pal::GattClient for the Nordic stack.
|
||||||
|
*/
|
||||||
|
class nRF5XGattClient : public ble::pal::GattClient {
|
||||||
|
|
||||||
|
public:
|
||||||
|
nRF5XGattClient();
|
||||||
|
|
||||||
|
virtual ~nRF5XGattClient();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* see pal::GattClient::initialize .
|
||||||
|
*/
|
||||||
|
virtual ble_error_t initialize();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* see pal::GattClient::terminate .
|
||||||
|
*/
|
||||||
|
virtual ble_error_t terminate();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* see pal::GattClient::exchange_mtu .
|
||||||
|
*/
|
||||||
|
virtual ble_error_t exchange_mtu(connection_handle_t connection);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* see pal::GattClient::get_mtu_size .
|
||||||
|
*/
|
||||||
|
virtual ble_error_t get_mtu_size(
|
||||||
|
connection_handle_t connection_handle, uint16_t& mtu_size
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* see pal::GattClient::discover_primary_service .
|
||||||
|
*/
|
||||||
|
virtual ble_error_t discover_primary_service(
|
||||||
|
connection_handle_t connection,
|
||||||
|
attribute_handle_t discovery_range_begining
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* see pal::GattClient::discover_primary_service_by_service_uuid .
|
||||||
|
*/
|
||||||
|
virtual ble_error_t discover_primary_service_by_service_uuid(
|
||||||
|
connection_handle_t connection_handle,
|
||||||
|
attribute_handle_t discovery_range_beginning,
|
||||||
|
const UUID& uuid
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* see pal::GattClient::find_included_service .
|
||||||
|
*/
|
||||||
|
virtual ble_error_t find_included_service(
|
||||||
|
connection_handle_t connection_handle,
|
||||||
|
attribute_handle_range_t service_range
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* see pal::GattClient::discover_characteristics_of_a_service .
|
||||||
|
*/
|
||||||
|
virtual ble_error_t discover_characteristics_of_a_service(
|
||||||
|
connection_handle_t connection_handle,
|
||||||
|
attribute_handle_range_t discovery_range
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* see pal::GattClient::discover_characteristics_descriptors .
|
||||||
|
*/
|
||||||
|
virtual ble_error_t discover_characteristics_descriptors(
|
||||||
|
connection_handle_t connection_handle,
|
||||||
|
attribute_handle_range_t descriptors_discovery_range
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* see pal::GattClient::read_attribute_value .
|
||||||
|
*/
|
||||||
|
virtual ble_error_t read_attribute_value(
|
||||||
|
connection_handle_t connection_handle,
|
||||||
|
attribute_handle_t attribute_handle
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* see pal::GattClient::read_using_characteristic_uuid .
|
||||||
|
*/
|
||||||
|
virtual ble_error_t read_using_characteristic_uuid(
|
||||||
|
connection_handle_t connection_handle,
|
||||||
|
attribute_handle_range_t read_range,
|
||||||
|
const UUID& uuid
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* see pal::GattClient::read_attribute_blob .
|
||||||
|
*/
|
||||||
|
virtual ble_error_t read_attribute_blob(
|
||||||
|
connection_handle_t connection,
|
||||||
|
attribute_handle_t attribute_handle,
|
||||||
|
uint16_t offset
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* see pal::GattClient::read_multiple_characteristic_values .
|
||||||
|
*/
|
||||||
|
virtual ble_error_t read_multiple_characteristic_values(
|
||||||
|
connection_handle_t connection,
|
||||||
|
const ArrayView<const attribute_handle_t>& characteristic_handles
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* see pal::GattClient::write_without_response .
|
||||||
|
*/
|
||||||
|
virtual ble_error_t write_without_response(
|
||||||
|
connection_handle_t connection_handle,
|
||||||
|
attribute_handle_t characteristic_value_handle,
|
||||||
|
const ArrayView<const uint8_t>& value
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* see pal::GattClient::signed_write_without_response .
|
||||||
|
*/
|
||||||
|
virtual ble_error_t signed_write_without_response(
|
||||||
|
connection_handle_t connection_handle,
|
||||||
|
attribute_handle_t characteristic_value_handle,
|
||||||
|
const ArrayView<const uint8_t>& value
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* see pal::GattClient::write_attribute .
|
||||||
|
*/
|
||||||
|
virtual ble_error_t write_attribute(
|
||||||
|
connection_handle_t connection_handle,
|
||||||
|
attribute_handle_t attribute_handle,
|
||||||
|
const ArrayView<const uint8_t>& value
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* see pal::GattClient::queue_prepare_write .
|
||||||
|
*/
|
||||||
|
virtual ble_error_t queue_prepare_write(
|
||||||
|
connection_handle_t connection_handle,
|
||||||
|
attribute_handle_t characteristic_value_handle,
|
||||||
|
const ArrayView<const uint8_t>& value,
|
||||||
|
uint16_t offset
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* see pal::GattClient::execute_write_queue .
|
||||||
|
*/
|
||||||
|
virtual ble_error_t execute_write_queue(
|
||||||
|
connection_handle_t connection_handle,
|
||||||
|
bool execute
|
||||||
|
);
|
||||||
|
|
||||||
|
// singleton of the ARM Cordio client
|
||||||
|
static nRF5XGattClient& get_client();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function call from btle.cpp
|
||||||
|
*
|
||||||
|
* Do not call directly.
|
||||||
|
*/
|
||||||
|
static void handle_events(const ble_evt_t *p_ble_evt);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by btle.cpp when a disconnection happens.
|
||||||
|
*/
|
||||||
|
static void handle_connection_termination(connection_handle_t connection);
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct GattProcedure;
|
||||||
|
struct RegularGattProcedure;
|
||||||
|
struct DiscoverPrimaryServiceProcedure;
|
||||||
|
struct DiscoverPrimaryServiceByUUIDProcedure;
|
||||||
|
struct FindIncludedServicesProcedure;
|
||||||
|
struct DiscoverCharacteristicsProcedure;
|
||||||
|
struct DiscoverDescriptorsProcedure;
|
||||||
|
struct ReadAttributeProcedure;
|
||||||
|
struct ReadUsingCharacteristicUUIDProcedure;
|
||||||
|
struct ReadAttributeBlobProcedure;
|
||||||
|
struct ReadMultipleCharacteristicsProcedure;
|
||||||
|
struct WriteAttributeProcedure;
|
||||||
|
struct QueuePrepareWriteProcedure;
|
||||||
|
struct ExecuteWriteQueueProcedure;
|
||||||
|
|
||||||
|
template<typename ProcType, typename A0>
|
||||||
|
ble_error_t launch_procedure(connection_handle_t connection, const A0& a0);
|
||||||
|
|
||||||
|
template<typename ProcType, typename A0, typename A1>
|
||||||
|
ble_error_t launch_procedure(
|
||||||
|
connection_handle_t connection, const A0& a0, const A1& a1
|
||||||
|
);
|
||||||
|
|
||||||
|
template<typename ProcType, typename A0, typename A1, typename A2>
|
||||||
|
ble_error_t launch_procedure(
|
||||||
|
connection_handle_t connection,
|
||||||
|
const A0& a0, const A1& a1, const A2& a2
|
||||||
|
);
|
||||||
|
|
||||||
|
template<typename ProcType, typename A0, typename A1, typename A2, typename A3>
|
||||||
|
ble_error_t launch_procedure(
|
||||||
|
connection_handle_t connection,
|
||||||
|
const A0& a0, const A1& a1, const A2& a2, const A3& a3
|
||||||
|
);
|
||||||
|
|
||||||
|
GattProcedure* get_procedure(connection_handle_t) const;
|
||||||
|
bool register_procedure(GattProcedure*);
|
||||||
|
bool remove_procedure(GattProcedure*);
|
||||||
|
|
||||||
|
void handle_procedure_event(const ble_evt_t &evt);
|
||||||
|
void handle_hvx_event(const ble_evt_t &evt);
|
||||||
|
void handle_timeout_event(const ble_evt_t &evt);
|
||||||
|
|
||||||
|
static const size_t max_procedures_count =
|
||||||
|
CENTRAL_LINK_COUNT + PERIPHERAL_LINK_COUNT;
|
||||||
|
|
||||||
|
// Note: Ideally we would have used an array of variant here
|
||||||
|
GattProcedure* _procedures[max_procedures_count];
|
||||||
|
};
|
||||||
|
|
||||||
|
} // nordic
|
||||||
|
} // vendor
|
||||||
|
} // pal
|
||||||
|
} // ble
|
||||||
|
|
||||||
|
#endif /* BLE_NORDIC_PAL_GATT_CLIENT_H_ */
|
|
@ -1,325 +0,0 @@
|
||||||
/* mbed Microcontroller Library
|
|
||||||
* Copyright (c) 2006-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 "nRF5xCharacteristicDescriptorDiscoverer.h"
|
|
||||||
#include "headers/nrf_ble_err.h"
|
|
||||||
#include "ble/DiscoveredCharacteristicDescriptor.h"
|
|
||||||
|
|
||||||
nRF5xCharacteristicDescriptorDiscoverer::nRF5xCharacteristicDescriptorDiscoverer() :
|
|
||||||
discoveryRunning() {
|
|
||||||
// nothing to do
|
|
||||||
}
|
|
||||||
|
|
||||||
nRF5xCharacteristicDescriptorDiscoverer::~nRF5xCharacteristicDescriptorDiscoverer() {
|
|
||||||
// nothing to do
|
|
||||||
}
|
|
||||||
|
|
||||||
ble_error_t nRF5xCharacteristicDescriptorDiscoverer::launch(
|
|
||||||
const DiscoveredCharacteristic& characteristic,
|
|
||||||
const CharacteristicDescriptorDiscovery::DiscoveryCallback_t& discoveryCallback,
|
|
||||||
const CharacteristicDescriptorDiscovery::TerminationCallback_t& terminationCallback
|
|
||||||
) {
|
|
||||||
Gap::Handle_t connHandle = characteristic.getConnectionHandle();
|
|
||||||
// it is ok to deduce that the start handle for descriptors is after
|
|
||||||
// the characteristic declaration and the characteristic value declaration
|
|
||||||
// see BLUETOOTH SPECIFICATION Version 4.2 [Vol 3, Part G] (3.3)
|
|
||||||
Gap::Handle_t descriptorStartHandle = characteristic.getDeclHandle() + 2;
|
|
||||||
Gap::Handle_t descriptorEndHandle = characteristic.getLastHandle();
|
|
||||||
|
|
||||||
// check if there is any descriptor to discover
|
|
||||||
if (descriptorEndHandle < descriptorStartHandle) {
|
|
||||||
CharacteristicDescriptorDiscovery::TerminationCallbackParams_t termParams = {
|
|
||||||
characteristic,
|
|
||||||
BLE_ERROR_NONE
|
|
||||||
};
|
|
||||||
terminationCallback.call(&termParams);
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if we can run this discovery
|
|
||||||
if (isConnectionInUse(connHandle)) {
|
|
||||||
return BLE_STACK_BUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get a new discovery slot, if none are available, just return
|
|
||||||
Discovery* discovery = getAvailableDiscoverySlot();
|
|
||||||
if(discovery == NULL) {
|
|
||||||
return BLE_STACK_BUSY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// try to launch the discovery
|
|
||||||
ble_error_t err = gattc_descriptors_discover(connHandle, descriptorStartHandle, descriptorEndHandle);
|
|
||||||
if(!err) {
|
|
||||||
// commit the new discovery to its slot
|
|
||||||
*discovery = Discovery(characteristic, discoveryCallback, terminationCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool nRF5xCharacteristicDescriptorDiscoverer::isActive(const DiscoveredCharacteristic& characteristic) const {
|
|
||||||
for(size_t i = 0; i < MAXIMUM_CONCURRENT_CONNECTIONS_COUNT; ++i) {
|
|
||||||
if(discoveryRunning[i].getCharacteristic() == characteristic) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void nRF5xCharacteristicDescriptorDiscoverer::requestTerminate(const DiscoveredCharacteristic& characteristic) {
|
|
||||||
Discovery* discovery = findRunningDiscovery(characteristic);
|
|
||||||
if(discovery) {
|
|
||||||
// call terminate anyway
|
|
||||||
terminate(discovery, BLE_ERROR_NONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void nRF5xCharacteristicDescriptorDiscoverer::process(uint16_t connectionHandle, const ble_gattc_evt_desc_disc_rsp_t& descriptors) {
|
|
||||||
Discovery* discovery = findRunningDiscovery(connectionHandle);
|
|
||||||
// the discovery has been removed
|
|
||||||
if(!discovery) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint16_t i = 0; i < descriptors.count; ++i) {
|
|
||||||
const ble_gattc_desc_t& desc = descriptors.descs[i];
|
|
||||||
const ble_uuid_t& uuid = desc.uuid;
|
|
||||||
|
|
||||||
if (uuid.type == BLE_UUID_TYPE_BLE) {
|
|
||||||
discovery->process(
|
|
||||||
desc.handle, UUID(uuid.uuid)
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// discover attribute infos of the descriptor
|
|
||||||
ble_error_t err = gattc_attr_info_discover(connectionHandle, desc.handle, desc.handle);
|
|
||||||
if (err) {
|
|
||||||
terminate(discovery, err);
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// prepare the next discovery request (if needed)
|
|
||||||
uint16_t startHandle = descriptors.descs[descriptors.count - 1].handle + 1;
|
|
||||||
uint16_t endHandle = discovery->getCharacteristic().getLastHandle();
|
|
||||||
|
|
||||||
if(startHandle > endHandle) {
|
|
||||||
terminate(discovery, BLE_ERROR_NONE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ble_error_t err = gattc_descriptors_discover(connectionHandle, startHandle, endHandle);
|
|
||||||
if(err) {
|
|
||||||
terminate(discovery, err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void nRF5xCharacteristicDescriptorDiscoverer::processAttributeInformation(
|
|
||||||
uint16_t connectionHandle, const ble_gattc_evt_attr_info_disc_rsp_t& infos) {
|
|
||||||
Discovery* discovery = findRunningDiscovery(connectionHandle);
|
|
||||||
// the discovery has been removed
|
|
||||||
if(!discovery) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if (NRF_SD_BLE_API_VERSION <= 2)
|
|
||||||
// for all UUIDS found, process the discovery
|
|
||||||
for (uint16_t i = 0; i < infos.count; ++i) {
|
|
||||||
bool use_16bits_uuids = infos.format == BLE_GATTC_ATTR_INFO_FORMAT_16BIT;
|
|
||||||
const ble_gattc_attr_info_t& attr_info = infos.attr_info[i];
|
|
||||||
UUID uuid = use_16bits_uuids ? UUID(attr_info.info.uuid16.uuid) : UUID(attr_info.info.uuid128.uuid128, UUID::LSB);
|
|
||||||
discovery->process(attr_info.handle, uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
// prepare the next round of descriptors discovery
|
|
||||||
uint16_t startHandle = infos.attr_info[infos.count - 1].handle + 1;
|
|
||||||
#else
|
|
||||||
uint16_t startHandle;
|
|
||||||
// for all UUIDS found, process the discovery
|
|
||||||
if (infos.format == BLE_GATTC_ATTR_INFO_FORMAT_16BIT) {
|
|
||||||
for (uint16_t i = 0; i < infos.count; ++i) {
|
|
||||||
UUID uuid = UUID(infos.info.attr_info16[i].uuid.uuid);
|
|
||||||
discovery->process(infos.info.attr_info16[i].handle, uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
// prepare the next round of descriptors discovery
|
|
||||||
startHandle = infos.info.attr_info16[infos.count - 1].handle + 1;
|
|
||||||
} else {
|
|
||||||
for (uint16_t i = 0; i < infos.count; ++i) {
|
|
||||||
UUID uuid = UUID(infos.info.attr_info128[i].uuid.uuid128, UUID::LSB);
|
|
||||||
discovery->process(infos.info.attr_info128[i].handle, uuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
// prepare the next round of descriptors discovery
|
|
||||||
startHandle = infos.info.attr_info128[infos.count - 1].handle + 1;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
uint16_t endHandle = discovery->getCharacteristic().getLastHandle();
|
|
||||||
|
|
||||||
if(startHandle > endHandle) {
|
|
||||||
terminate(discovery, BLE_ERROR_NONE);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ble_error_t err = gattc_descriptors_discover(connectionHandle, startHandle, endHandle);
|
|
||||||
if(err) {
|
|
||||||
terminate(discovery, err);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void nRF5xCharacteristicDescriptorDiscoverer::terminate(uint16_t handle, ble_error_t err) {
|
|
||||||
Discovery* discovery = findRunningDiscovery(handle);
|
|
||||||
// the discovery has already been terminated
|
|
||||||
if(!discovery) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
terminate(discovery, err);
|
|
||||||
}
|
|
||||||
|
|
||||||
void nRF5xCharacteristicDescriptorDiscoverer::terminate(Discovery* discovery, ble_error_t err) {
|
|
||||||
// temporary copy, user code can try to launch a new discovery in the onTerminate
|
|
||||||
// callback. So, this discovery should not appear in such case.
|
|
||||||
Discovery tmp = *discovery;
|
|
||||||
*discovery = Discovery();
|
|
||||||
tmp.terminate(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
nRF5xCharacteristicDescriptorDiscoverer::Discovery*
|
|
||||||
nRF5xCharacteristicDescriptorDiscoverer::findRunningDiscovery(const DiscoveredCharacteristic& characteristic) {
|
|
||||||
for(size_t i = 0; i < MAXIMUM_CONCURRENT_CONNECTIONS_COUNT; ++i) {
|
|
||||||
if((discoveryRunning[i].getCharacteristic() == characteristic) &&
|
|
||||||
(discoveryRunning[i].isEmpty() == false)) {
|
|
||||||
return &discoveryRunning[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
nRF5xCharacteristicDescriptorDiscoverer::Discovery*
|
|
||||||
nRF5xCharacteristicDescriptorDiscoverer::findRunningDiscovery(uint16_t handle) {
|
|
||||||
for(size_t i = 0; i < MAXIMUM_CONCURRENT_CONNECTIONS_COUNT; ++i) {
|
|
||||||
if((discoveryRunning[i].getCharacteristic().getConnectionHandle() == handle) &&
|
|
||||||
(discoveryRunning[i].isEmpty() == false)) {
|
|
||||||
return &discoveryRunning[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
nRF5xCharacteristicDescriptorDiscoverer::Discovery*
|
|
||||||
nRF5xCharacteristicDescriptorDiscoverer::getAvailableDiscoverySlot() {
|
|
||||||
for(size_t i = 0; i < MAXIMUM_CONCURRENT_CONNECTIONS_COUNT; ++i) {
|
|
||||||
if(discoveryRunning[i].isEmpty()) {
|
|
||||||
return &discoveryRunning[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool nRF5xCharacteristicDescriptorDiscoverer::isConnectionInUse(uint16_t connHandle) {
|
|
||||||
return findRunningDiscovery(connHandle) != NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
ble_error_t nRF5xCharacteristicDescriptorDiscoverer::gattc_descriptors_discover(
|
|
||||||
uint16_t connection_handle, uint16_t start_handle, uint16_t end_handle) {
|
|
||||||
|
|
||||||
ble_gattc_handle_range_t discoveryRange = {
|
|
||||||
start_handle,
|
|
||||||
end_handle
|
|
||||||
};
|
|
||||||
uint32_t err = sd_ble_gattc_descriptors_discover(connection_handle, &discoveryRange);
|
|
||||||
|
|
||||||
switch(err) {
|
|
||||||
case NRF_SUCCESS:
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
case BLE_ERROR_INVALID_CONN_HANDLE:
|
|
||||||
return BLE_ERROR_INVALID_PARAM;
|
|
||||||
case NRF_ERROR_INVALID_ADDR:
|
|
||||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
|
||||||
case NRF_ERROR_BUSY:
|
|
||||||
return BLE_STACK_BUSY;
|
|
||||||
default:
|
|
||||||
return BLE_ERROR_UNSPECIFIED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ble_error_t nRF5xCharacteristicDescriptorDiscoverer::gattc_attr_info_discover(
|
|
||||||
uint16_t connection_handle, uint16_t start_handle, uint16_t end_handle) {
|
|
||||||
ble_gattc_handle_range_t handle_range = { start_handle, end_handle };
|
|
||||||
uint32_t err = sd_ble_gattc_attr_info_discover(connection_handle, &handle_range);
|
|
||||||
|
|
||||||
switch(err) {
|
|
||||||
case NRF_SUCCESS:
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
case BLE_ERROR_INVALID_CONN_HANDLE:
|
|
||||||
return BLE_ERROR_INVALID_PARAM;
|
|
||||||
case NRF_ERROR_INVALID_ADDR:
|
|
||||||
return BLE_ERROR_PARAM_OUT_OF_RANGE;
|
|
||||||
case NRF_ERROR_BUSY:
|
|
||||||
return BLE_STACK_BUSY;
|
|
||||||
case NRF_ERROR_INVALID_STATE:
|
|
||||||
return BLE_ERROR_INVALID_STATE;
|
|
||||||
default:
|
|
||||||
return BLE_ERROR_UNSPECIFIED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// implementation of nRF5xCharacteristicDescriptorDiscoverer::Discovery
|
|
||||||
|
|
||||||
nRF5xCharacteristicDescriptorDiscoverer::Discovery::Discovery() :
|
|
||||||
characteristic(), onDiscovery(), onTerminate() {
|
|
||||||
}
|
|
||||||
|
|
||||||
nRF5xCharacteristicDescriptorDiscoverer::Discovery::Discovery(
|
|
||||||
const DiscoveredCharacteristic& c, const DiscoveryCallback_t& dCb, const TerminationCallback_t& tCb) :
|
|
||||||
characteristic(c), onDiscovery(dCb), onTerminate(tCb) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void nRF5xCharacteristicDescriptorDiscoverer::Discovery::process(
|
|
||||||
GattAttribute::Handle_t handle, const UUID& uuid) {
|
|
||||||
CharacteristicDescriptorDiscovery::DiscoveryCallbackParams_t params = {
|
|
||||||
characteristic,
|
|
||||||
DiscoveredCharacteristicDescriptor(
|
|
||||||
characteristic.getGattClient(),
|
|
||||||
characteristic.getConnectionHandle(),
|
|
||||||
handle,
|
|
||||||
uuid
|
|
||||||
)
|
|
||||||
};
|
|
||||||
onDiscovery.call(¶ms);
|
|
||||||
}
|
|
||||||
|
|
||||||
void nRF5xCharacteristicDescriptorDiscoverer::Discovery::terminate(ble_error_t err) {
|
|
||||||
CharacteristicDescriptorDiscovery::TerminationCallbackParams_t params = {
|
|
||||||
characteristic,
|
|
||||||
err
|
|
||||||
};
|
|
||||||
|
|
||||||
onTerminate.call(¶ms);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool nRF5xCharacteristicDescriptorDiscoverer::Discovery::isEmpty() const {
|
|
||||||
return *this == Discovery();
|
|
||||||
}
|
|
||||||
|
|
||||||
const DiscoveredCharacteristic& nRF5xCharacteristicDescriptorDiscoverer::Discovery::getCharacteristic() const {
|
|
||||||
return characteristic;
|
|
||||||
}
|
|
|
@ -1,227 +0,0 @@
|
||||||
/* mbed Microcontroller Library
|
|
||||||
* Copyright (c) 2006-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 __NRF_CHARACTERISTIC_DESCRIPTOR_DISCOVERY_H__
|
|
||||||
#define __NRF_CHARACTERISTIC_DESCRIPTOR_DISCOVERY_H__
|
|
||||||
|
|
||||||
#include "ble/Gap.h"
|
|
||||||
#include "ble/DiscoveredCharacteristic.h"
|
|
||||||
#include "ble/CharacteristicDescriptorDiscovery.h"
|
|
||||||
#include "ble/GattClient.h"
|
|
||||||
#include "headers/nrf_ble_gattc.h"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Manage the discovery of Characteristic descriptors
|
|
||||||
* @details is a bridge between BLE API and Nordic stack regarding Characteristic
|
|
||||||
* Descriptor discovery. The BLE API can launch, monitor and ask for termination
|
|
||||||
* of a discovery. The Nordic stack will provide new descriptors and indicate when
|
|
||||||
* the discovery is done.
|
|
||||||
*/
|
|
||||||
class nRF5xCharacteristicDescriptorDiscoverer
|
|
||||||
{
|
|
||||||
typedef CharacteristicDescriptorDiscovery::DiscoveryCallback_t DiscoveryCallback_t;
|
|
||||||
typedef CharacteristicDescriptorDiscovery::TerminationCallback_t TerminationCallback_t;
|
|
||||||
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* @brief Construct a new characteristic descriptor discoverer.
|
|
||||||
*/
|
|
||||||
nRF5xCharacteristicDescriptorDiscoverer();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Destroy a characteristic descriptor discoverer.
|
|
||||||
*/
|
|
||||||
~nRF5xCharacteristicDescriptorDiscoverer();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Launch a new characteristic descriptor discovery for a given DiscoveredCharacteristic.
|
|
||||||
* @param characteristic The characteristic owning the descriptors to discover.
|
|
||||||
* @param discoveryCallback The callback called when a descriptor is discovered.
|
|
||||||
* @param terminationCallback The callback called when the discovery process end.
|
|
||||||
* @return BLE_ERROR_NONE if characteristic descriptor discovery is launched successfully;
|
|
||||||
* else an appropriate error.
|
|
||||||
* @note: this will be called by BLE API side.
|
|
||||||
*/
|
|
||||||
ble_error_t launch(
|
|
||||||
const DiscoveredCharacteristic& characteristic,
|
|
||||||
const DiscoveryCallback_t& discoveryCallback,
|
|
||||||
const TerminationCallback_t& terminationCallback
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief indicate if a characteristic descriptor discovery is active for a
|
|
||||||
* given DiscoveredCharacteristic.
|
|
||||||
* @param characteristic The characteristic for whom the descriptor might be
|
|
||||||
* currently discovered.
|
|
||||||
* @return true if descriptors of characteristic are discovered, false otherwise.
|
|
||||||
* @note: this will be called by BLE API side.
|
|
||||||
*/
|
|
||||||
bool isActive(const DiscoveredCharacteristic& characteristic) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief request the termination of characteristic descriptor discovery
|
|
||||||
* for a give DiscoveredCharacteristic
|
|
||||||
* @param characteristic The characteristic for whom the descriptor discovery
|
|
||||||
* should be stopped.
|
|
||||||
* @note: this will be called by BLE API side.
|
|
||||||
*/
|
|
||||||
void requestTerminate(const DiscoveredCharacteristic& characteristic);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief process descriptors discovered from the Nordic stack.
|
|
||||||
* @param connectionHandle The connection handle upon which descriptors has been
|
|
||||||
* discovered.
|
|
||||||
* @param descriptors Discovered descriptors.
|
|
||||||
* @note This will be called by the Nordic stack.
|
|
||||||
*/
|
|
||||||
void process(uint16_t connectionHandle, const ble_gattc_evt_desc_disc_rsp_t& descriptors);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Called by the Nordic stack when the discovery is over.
|
|
||||||
* @param The connection handle upon which the discovery process is done.
|
|
||||||
* @param err An error if the termination is due to an error.
|
|
||||||
*/
|
|
||||||
void terminate(uint16_t connectionHandle, ble_error_t err);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief process attribute informations from the Nordic stack.
|
|
||||||
* @param connectionHandle The connection handle upon which
|
|
||||||
* attribute informations has been fetch.
|
|
||||||
* @param infos Informations around attribute, in that case the
|
|
||||||
* 128bit UUID of a descriptor.
|
|
||||||
* @note This will be called by the Nordic stack.
|
|
||||||
*/
|
|
||||||
void processAttributeInformation(uint16_t handle, const ble_gattc_evt_attr_info_disc_rsp_t& infos);
|
|
||||||
|
|
||||||
private:
|
|
||||||
// protection against copy construction and assignment
|
|
||||||
nRF5xCharacteristicDescriptorDiscoverer(const nRF5xCharacteristicDescriptorDiscoverer&);
|
|
||||||
nRF5xCharacteristicDescriptorDiscoverer& operator=(const nRF5xCharacteristicDescriptorDiscoverer&);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Discovery process, it store the DiscoveredCharacteristic, the
|
|
||||||
* discovery callback and the termination callback.
|
|
||||||
*/
|
|
||||||
class Discovery {
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* @brief Construct an empty discovery, such can be considerate as a not running discovery.
|
|
||||||
* @note #isEmpty function will return true
|
|
||||||
*/
|
|
||||||
Discovery();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Construct a valid discovery process.
|
|
||||||
*
|
|
||||||
* @param c the characteristic from whom descriptors will be discovered.
|
|
||||||
* @param dCb The discovery callback called each time a descriptor is discovered.
|
|
||||||
* @param tCb The termination callback called when the discovery terminate.
|
|
||||||
*
|
|
||||||
* @note #isEmpty function will return false
|
|
||||||
*/
|
|
||||||
Discovery(const DiscoveredCharacteristic& c, const DiscoveryCallback_t& dCb, const TerminationCallback_t& tCb);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Process the discovery of a descriptor.
|
|
||||||
*
|
|
||||||
* @param handle The attribute handle of the descriptor found
|
|
||||||
* @param uuid The UUID of the descriptor found.
|
|
||||||
*/
|
|
||||||
void process(GattAttribute::Handle_t handle, const UUID& uuid);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Terminate the discovery process.
|
|
||||||
*
|
|
||||||
* @param err Error associate with the termination
|
|
||||||
* @note after this call #isEmpty function will return true.
|
|
||||||
*/
|
|
||||||
void terminate(ble_error_t err);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief check if the discovery process is empty or not. Empty discovery are
|
|
||||||
* not running.
|
|
||||||
*
|
|
||||||
* @detail Discovery are empty after:
|
|
||||||
* - a default construction
|
|
||||||
* - a copy construction form a default constructed
|
|
||||||
* - an assignment from a default constructed Discovery
|
|
||||||
* @return true if the Discovery is empty and false otherwise.
|
|
||||||
*/
|
|
||||||
bool isEmpty() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief return the characteristic from whom descriptors are discovered.
|
|
||||||
* @return the characteristic from whom descriptors are discovered.
|
|
||||||
*/
|
|
||||||
const DiscoveredCharacteristic& getCharacteristic() const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief equal to operator, test if two discovery process are equal
|
|
||||||
*
|
|
||||||
* @param lhs left hand side of the expression
|
|
||||||
* @param rhs right hand side of the expression
|
|
||||||
* @return true if lhs == rhs
|
|
||||||
*/
|
|
||||||
friend bool operator==(const Discovery& lhs, const Discovery& rhs) {
|
|
||||||
return lhs.characteristic == rhs.characteristic &&
|
|
||||||
lhs.onDiscovery == rhs.onDiscovery &&
|
|
||||||
lhs.onTerminate == rhs.onTerminate;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief not equal to operator, test if two discovery process are not equal
|
|
||||||
*
|
|
||||||
* @param lhs left hand side of the expression
|
|
||||||
* @param rhs right hand side of the expression
|
|
||||||
* @return true if lhs != rhs
|
|
||||||
*/
|
|
||||||
friend bool operator!=(const Discovery& lhs, const Discovery& rhs) {
|
|
||||||
return !(lhs == rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
DiscoveredCharacteristic characteristic;
|
|
||||||
DiscoveryCallback_t onDiscovery;
|
|
||||||
TerminationCallback_t onTerminate;
|
|
||||||
};
|
|
||||||
|
|
||||||
// find a running discovery process
|
|
||||||
Discovery* findRunningDiscovery(const DiscoveredCharacteristic& characteristic);
|
|
||||||
Discovery* findRunningDiscovery(uint16_t handle);
|
|
||||||
|
|
||||||
// Called to terminate a discovery is over.
|
|
||||||
void terminate(Discovery* discovery, ble_error_t err);
|
|
||||||
|
|
||||||
// get one slot for a discovery process
|
|
||||||
Discovery* getAvailableDiscoverySlot();
|
|
||||||
|
|
||||||
// indicate if a connection is already running a discovery
|
|
||||||
bool isConnectionInUse(uint16_t connHandle);
|
|
||||||
|
|
||||||
// low level start of a discovery
|
|
||||||
static ble_error_t gattc_descriptors_discover(uint16_t connection_handle, uint16_t start_handle, uint16_t end_handle);
|
|
||||||
|
|
||||||
// discovery of 128bits UUIDS
|
|
||||||
static ble_error_t gattc_attr_info_discover(uint16_t connection_handle, uint16_t start_handle, uint16_t end_handle);
|
|
||||||
|
|
||||||
// count of concurrent connections which can run a descriptor discovery process
|
|
||||||
static const size_t MAXIMUM_CONCURRENT_CONNECTIONS_COUNT = 3;
|
|
||||||
|
|
||||||
// array of running discoveries
|
|
||||||
Discovery discoveryRunning[MAXIMUM_CONCURRENT_CONNECTIONS_COUNT];
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /*__NRF_CHARACTERISTIC_DESCRIPTOR_DISCOVERY_H__*/
|
|
|
@ -1,63 +0,0 @@
|
||||||
/* 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 "nRF5xDiscoveredCharacteristic.h"
|
|
||||||
#include "nRF5xGattClient.h"
|
|
||||||
#include "headers/nrf_ble_gatt.h"
|
|
||||||
|
|
||||||
void
|
|
||||||
nRF5xDiscoveredCharacteristic::setup(nRF5xGattClient *gattcIn,
|
|
||||||
Gap::Handle_t connectionHandleIn,
|
|
||||||
ble_gatt_char_props_t propsIn,
|
|
||||||
GattAttribute::Handle_t declHandleIn,
|
|
||||||
GattAttribute::Handle_t valueHandleIn)
|
|
||||||
{
|
|
||||||
gattc = gattcIn;
|
|
||||||
connHandle = connectionHandleIn;
|
|
||||||
declHandle = declHandleIn;
|
|
||||||
valueHandle = valueHandleIn;
|
|
||||||
|
|
||||||
props._broadcast = propsIn.broadcast;
|
|
||||||
props._read = propsIn.read;
|
|
||||||
props._writeWoResp = propsIn.write_wo_resp;
|
|
||||||
props._write = propsIn.write;
|
|
||||||
props._notify = propsIn.notify;
|
|
||||||
props._indicate = propsIn.indicate;
|
|
||||||
props._authSignedWrite = propsIn.auth_signed_wr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nRF5xDiscoveredCharacteristic::setup(nRF5xGattClient *gattcIn,
|
|
||||||
Gap::Handle_t connectionHandleIn,
|
|
||||||
UUID::ShortUUIDBytes_t uuidIn,
|
|
||||||
ble_gatt_char_props_t propsIn,
|
|
||||||
GattAttribute::Handle_t declHandleIn,
|
|
||||||
GattAttribute::Handle_t valueHandleIn)
|
|
||||||
{
|
|
||||||
gattc = gattcIn;
|
|
||||||
connHandle = connectionHandleIn;
|
|
||||||
uuid = uuidIn;
|
|
||||||
declHandle = declHandleIn;
|
|
||||||
valueHandle = valueHandleIn;
|
|
||||||
|
|
||||||
props._broadcast = propsIn.broadcast;
|
|
||||||
props._read = propsIn.read;
|
|
||||||
props._writeWoResp = propsIn.write_wo_resp;
|
|
||||||
props._write = propsIn.write;
|
|
||||||
props._notify = propsIn.notify;
|
|
||||||
props._indicate = propsIn.indicate;
|
|
||||||
props._authSignedWrite = propsIn.auth_signed_wr;
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
/* 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 __NRF_DISCOVERED_CHARACTERISTIC_H__
|
|
||||||
#define __NRF_DISCOVERED_CHARACTERISTIC_H__
|
|
||||||
|
|
||||||
#include "ble/DiscoveredCharacteristic.h"
|
|
||||||
#include "headers/nrf_ble_gatt.h"
|
|
||||||
|
|
||||||
class nRF5xGattClient; /* forward declaration */
|
|
||||||
|
|
||||||
class nRF5xDiscoveredCharacteristic : public DiscoveredCharacteristic {
|
|
||||||
public:
|
|
||||||
void setup(nRF5xGattClient *gattcIn,
|
|
||||||
Gap::Handle_t connectionHandleIn,
|
|
||||||
ble_gatt_char_props_t propsIn,
|
|
||||||
GattAttribute::Handle_t declHandleIn,
|
|
||||||
GattAttribute::Handle_t valueHandleIn);
|
|
||||||
|
|
||||||
void setup(nRF5xGattClient *gattcIn,
|
|
||||||
Gap::Handle_t connectionHandleIn,
|
|
||||||
UUID::ShortUUIDBytes_t uuidIn,
|
|
||||||
ble_gatt_char_props_t propsIn,
|
|
||||||
GattAttribute::Handle_t declHandleIn,
|
|
||||||
GattAttribute::Handle_t valueHandleIn);
|
|
||||||
|
|
||||||
void setLastHandle(GattAttribute::Handle_t last) {
|
|
||||||
lastHandle = last;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* __NRF_DISCOVERED_CHARACTERISTIC_H__ */
|
|
|
@ -1,50 +0,0 @@
|
||||||
/* 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 "nRF5xGattClient.h"
|
|
||||||
|
|
||||||
#if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110)
|
|
||||||
ble_error_t
|
|
||||||
nRF5xGattClient::launchServiceDiscovery(Gap::Handle_t connectionHandle,
|
|
||||||
ServiceDiscovery::ServiceCallback_t sc,
|
|
||||||
ServiceDiscovery::CharacteristicCallback_t cc,
|
|
||||||
const UUID &matchingServiceUUIDIn,
|
|
||||||
const UUID &matchingCharacteristicUUIDIn)
|
|
||||||
{
|
|
||||||
return _discovery.launch(connectionHandle, sc, cc, matchingServiceUUIDIn, matchingCharacteristicUUIDIn);
|
|
||||||
}
|
|
||||||
|
|
||||||
ble_error_t nRF5xGattClient::discoverCharacteristicDescriptors(
|
|
||||||
const DiscoveredCharacteristic& characteristic,
|
|
||||||
const CharacteristicDescriptorDiscovery::DiscoveryCallback_t& discoveryCallback,
|
|
||||||
const CharacteristicDescriptorDiscovery::TerminationCallback_t& terminationCallback)
|
|
||||||
{
|
|
||||||
return _characteristicDescriptorDiscoverer.launch(
|
|
||||||
characteristic,
|
|
||||||
discoveryCallback,
|
|
||||||
terminationCallback
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool nRF5xGattClient::isCharacteristicDescriptorsDiscoveryActive(const DiscoveredCharacteristic& characteristic) const {
|
|
||||||
return _characteristicDescriptorDiscoverer.isActive(characteristic);
|
|
||||||
}
|
|
||||||
|
|
||||||
void nRF5xGattClient::terminateCharacteristicDescriptorsDiscovery(const DiscoveredCharacteristic& characteristic) {
|
|
||||||
return _characteristicDescriptorDiscoverer.requestTerminate(characteristic);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,218 +0,0 @@
|
||||||
/* 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 __NRF51822_GATT_CLIENT_H__
|
|
||||||
#define __NRF51822_GATT_CLIENT_H__
|
|
||||||
|
|
||||||
#include "ble/GattClient.h"
|
|
||||||
#include "nRF5xServiceDiscovery.h"
|
|
||||||
#include "nRF5xCharacteristicDescriptorDiscoverer.h"
|
|
||||||
|
|
||||||
class nRF5xGattClient : public GattClient
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* When using S110, all Gatt client features will return
|
|
||||||
* BLE_ERROR_NOT_IMPLEMENTED
|
|
||||||
*/
|
|
||||||
#if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Launch service discovery. Once launched, service discovery will remain
|
|
||||||
* active with callbacks being issued back into the application for matching
|
|
||||||
* services/characteristics. isActive() can be used to determine status; and
|
|
||||||
* a termination callback (if setup) will be invoked at the end. Service
|
|
||||||
* discovery can be terminated prematurely if needed using terminate().
|
|
||||||
*
|
|
||||||
* @param connectionHandle
|
|
||||||
* Handle for the connection with the peer.
|
|
||||||
* @param sc
|
|
||||||
* This is the application callback for matching service. Taken as
|
|
||||||
* NULL by default. Note: service discovery may still be active
|
|
||||||
* when this callback is issued; calling asynchronous BLE-stack
|
|
||||||
* APIs from within this application callback might cause the
|
|
||||||
* stack to abort service discovery. If this becomes an issue, it
|
|
||||||
* may be better to make local copy of the discoveredService and
|
|
||||||
* wait for service discovery to terminate before operating on the
|
|
||||||
* service.
|
|
||||||
* @param cc
|
|
||||||
* This is the application callback for matching characteristic.
|
|
||||||
* Taken as NULL by default. Note: service discovery may still be
|
|
||||||
* active when this callback is issued; calling asynchronous
|
|
||||||
* BLE-stack APIs from within this application callback might cause
|
|
||||||
* the stack to abort service discovery. If this becomes an issue,
|
|
||||||
* it may be better to make local copy of the discoveredCharacteristic
|
|
||||||
* and wait for service discovery to terminate before operating on the
|
|
||||||
* characteristic.
|
|
||||||
* @param matchingServiceUUID
|
|
||||||
* UUID based filter for specifying a service in which the application is
|
|
||||||
* interested. By default it is set as the wildcard UUID_UNKNOWN,
|
|
||||||
* in which case it matches all services. If characteristic-UUID
|
|
||||||
* filter (below) is set to the wildcard value, then a service
|
|
||||||
* callback will be invoked for the matching service (or for every
|
|
||||||
* service if the service filter is a wildcard).
|
|
||||||
* @param matchingCharacteristicUUIDIn
|
|
||||||
* UUID based filter for specifying characteristic in which the application
|
|
||||||
* is interested. By default it is set as the wildcard UUID_UKNOWN
|
|
||||||
* to match against any characteristic. If both service-UUID
|
|
||||||
* filter and characteristic-UUID filter are used with non- wildcard
|
|
||||||
* values, then only a single characteristic callback is
|
|
||||||
* invoked for the matching characteristic.
|
|
||||||
*
|
|
||||||
* @Note Using wildcard values for both service-UUID and characteristic-
|
|
||||||
* UUID will result in complete service discovery--callbacks being
|
|
||||||
* called for every service and characteristic.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* BLE_ERROR_NONE if service discovery is launched successfully; else an appropriate error.
|
|
||||||
*/
|
|
||||||
virtual ble_error_t launchServiceDiscovery(Gap::Handle_t connectionHandle,
|
|
||||||
ServiceDiscovery::ServiceCallback_t sc = NULL,
|
|
||||||
ServiceDiscovery::CharacteristicCallback_t cc = NULL,
|
|
||||||
const UUID &matchingServiceUUID = UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN),
|
|
||||||
const UUID &matchingCharacteristicUUIDIn = UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN));
|
|
||||||
|
|
||||||
virtual void onServiceDiscoveryTermination(ServiceDiscovery::TerminationCallback_t callback) {
|
|
||||||
_discovery.onTermination(callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Is service-discovery currently active?
|
|
||||||
*/
|
|
||||||
virtual bool isServiceDiscoveryActive(void) const {
|
|
||||||
return _discovery.isActive();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Terminate an ongoing service-discovery. This should result in an
|
|
||||||
* invocation of the TerminationCallback if service-discovery is active.
|
|
||||||
*/
|
|
||||||
virtual void terminateServiceDiscovery(void) {
|
|
||||||
_discovery.terminate();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Implementation of GattClient::discoverCharacteristicDescriptors
|
|
||||||
* @see GattClient::discoverCharacteristicDescriptors
|
|
||||||
*/
|
|
||||||
virtual ble_error_t discoverCharacteristicDescriptors(
|
|
||||||
const DiscoveredCharacteristic& characteristic,
|
|
||||||
const CharacteristicDescriptorDiscovery::DiscoveryCallback_t& discoveryCallback,
|
|
||||||
const CharacteristicDescriptorDiscovery::TerminationCallback_t& terminationCallback
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Implementation of GattClient::isCharacteristicDiscoveryActive
|
|
||||||
* @see GattClient::isCharacteristicDiscoveryActive
|
|
||||||
*/
|
|
||||||
virtual bool isCharacteristicDescriptorsDiscoveryActive(const DiscoveredCharacteristic& characteristic) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Implementation of GattClient::terminateCharacteristicDiscovery
|
|
||||||
* @see GattClient::terminateCharacteristicDiscovery
|
|
||||||
*/
|
|
||||||
virtual void terminateCharacteristicDescriptorsDiscovery(const DiscoveredCharacteristic& characteristic);
|
|
||||||
|
|
||||||
virtual ble_error_t read(Gap::Handle_t connHandle, GattAttribute::Handle_t attributeHandle, uint16_t offset) const {
|
|
||||||
uint32_t rc = sd_ble_gattc_read(connHandle, attributeHandle, offset);
|
|
||||||
if (rc == NRF_SUCCESS) {
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
}
|
|
||||||
switch (rc) {
|
|
||||||
case NRF_ERROR_BUSY:
|
|
||||||
return BLE_STACK_BUSY;
|
|
||||||
case BLE_ERROR_INVALID_CONN_HANDLE:
|
|
||||||
case NRF_ERROR_INVALID_STATE:
|
|
||||||
case NRF_ERROR_INVALID_ADDR:
|
|
||||||
default:
|
|
||||||
return BLE_ERROR_INVALID_STATE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ble_error_t write(GattClient::WriteOp_t cmd, Gap::Handle_t connHandle, GattAttribute::Handle_t attributeHandle, size_t length, const uint8_t *value) const {
|
|
||||||
ble_gattc_write_params_t writeParams;
|
|
||||||
writeParams.write_op = cmd;
|
|
||||||
writeParams.flags = 0; /* this is inconsequential */
|
|
||||||
writeParams.handle = attributeHandle;
|
|
||||||
writeParams.offset = 0;
|
|
||||||
writeParams.len = length;
|
|
||||||
writeParams.p_value = const_cast<uint8_t *>(value);
|
|
||||||
|
|
||||||
uint32_t rc = sd_ble_gattc_write(connHandle, &writeParams);
|
|
||||||
if (rc == NRF_SUCCESS) {
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
}
|
|
||||||
switch (rc) {
|
|
||||||
case NRF_ERROR_BUSY:
|
|
||||||
return BLE_STACK_BUSY;
|
|
||||||
case BLE_ERROR_NO_TX_PACKETS:
|
|
||||||
return BLE_ERROR_NO_MEM;
|
|
||||||
case BLE_ERROR_INVALID_CONN_HANDLE:
|
|
||||||
case NRF_ERROR_INVALID_STATE:
|
|
||||||
case NRF_ERROR_INVALID_ADDR:
|
|
||||||
default:
|
|
||||||
return BLE_ERROR_INVALID_STATE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Clear nRF5xGattClient's state.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* BLE_ERROR_NONE if successful.
|
|
||||||
*/
|
|
||||||
virtual ble_error_t reset(void) {
|
|
||||||
/* Clear all state that is from the parent, including private members */
|
|
||||||
if (GattClient::reset() != BLE_ERROR_NONE) {
|
|
||||||
return BLE_ERROR_INVALID_STATE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clear derived class members */
|
|
||||||
_discovery.reset();
|
|
||||||
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
/*
|
|
||||||
* Allow instantiation from nRF5xn when required.
|
|
||||||
*/
|
|
||||||
friend class nRF5xn;
|
|
||||||
|
|
||||||
nRF5xGattClient() : _discovery(this) {
|
|
||||||
/* empty */
|
|
||||||
}
|
|
||||||
|
|
||||||
nRF5xServiceDiscovery& discovery() {
|
|
||||||
return _discovery;
|
|
||||||
}
|
|
||||||
|
|
||||||
nRF5xCharacteristicDescriptorDiscoverer& characteristicDescriptorDiscoverer() {
|
|
||||||
return _characteristicDescriptorDiscoverer;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
nRF5xGattClient(const nRF5xGattClient &);
|
|
||||||
const nRF5xGattClient& operator=(const nRF5xGattClient &);
|
|
||||||
|
|
||||||
private:
|
|
||||||
nRF5xServiceDiscovery _discovery;
|
|
||||||
nRF5xCharacteristicDescriptorDiscoverer _characteristicDescriptorDiscoverer;
|
|
||||||
|
|
||||||
#endif // if !S110
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif // ifndef __NRF51822_GATT_CLIENT_H__
|
|
|
@ -131,6 +131,7 @@ ble_error_t nRF5xGattServer::addService(GattService &service)
|
||||||
}
|
}
|
||||||
GattCharacteristic *p_char = service.getCharacteristic(i);
|
GattCharacteristic *p_char = service.getCharacteristic(i);
|
||||||
GattAttribute *p_description_descriptor = NULL;
|
GattAttribute *p_description_descriptor = NULL;
|
||||||
|
GattAttribute *p_presentation_format_descriptor = NULL;
|
||||||
|
|
||||||
/* Skip any incompletely defined, read-only characteristics. */
|
/* Skip any incompletely defined, read-only characteristics. */
|
||||||
if ((p_char->getValueAttribute().getValuePtr() == NULL) &&
|
if ((p_char->getValueAttribute().getValuePtr() == NULL) &&
|
||||||
|
@ -141,11 +142,13 @@ ble_error_t nRF5xGattServer::addService(GattService &service)
|
||||||
|
|
||||||
nordicUUID = custom_convert_to_nordic_uuid(p_char->getValueAttribute().getUUID());
|
nordicUUID = custom_convert_to_nordic_uuid(p_char->getValueAttribute().getUUID());
|
||||||
|
|
||||||
/* The user-description descriptor is a special case which needs to be
|
/* The user-description and presentation-format descriptors are special cases
|
||||||
* handled at the time of adding the characteristic. The following block
|
* that need to be handled at the time of adding each characteristic. The
|
||||||
* is meant to discover its presence. */
|
* following block is meant to discover their presence. */
|
||||||
const uint8_t *userDescriptionDescriptorValuePtr = NULL;
|
const uint8_t *userDescriptionDescriptorValuePtr = NULL;
|
||||||
uint16_t userDescriptionDescriptorValueLen = 0;
|
uint16_t userDescriptionDescriptorValueLen = 0;
|
||||||
|
const uint8_t *presentationFormatDescriptorValuePtr = NULL;
|
||||||
|
uint16_t presentationFormatDescriptorValueLen = 0;
|
||||||
for (uint8_t j = 0; j < p_char->getDescriptorCount(); j++) {
|
for (uint8_t j = 0; j < p_char->getDescriptorCount(); j++) {
|
||||||
GattAttribute *p_desc = p_char->getDescriptor(j);
|
GattAttribute *p_desc = p_char->getDescriptor(j);
|
||||||
if (p_desc->getUUID() == BLE_UUID_DESCRIPTOR_CHAR_USER_DESC) {
|
if (p_desc->getUUID() == BLE_UUID_DESCRIPTOR_CHAR_USER_DESC) {
|
||||||
|
@ -153,6 +156,11 @@ ble_error_t nRF5xGattServer::addService(GattService &service)
|
||||||
userDescriptionDescriptorValuePtr = p_desc->getValuePtr();
|
userDescriptionDescriptorValuePtr = p_desc->getValuePtr();
|
||||||
userDescriptionDescriptorValueLen = p_desc->getLength();
|
userDescriptionDescriptorValueLen = p_desc->getLength();
|
||||||
}
|
}
|
||||||
|
if (p_desc->getUUID() == BLE_UUID_DESCRIPTOR_CHAR_PRESENTATION_FORMAT) {
|
||||||
|
p_presentation_format_descriptor = p_desc;
|
||||||
|
presentationFormatDescriptorValuePtr = p_desc->getValuePtr();
|
||||||
|
presentationFormatDescriptorValueLen = p_desc->getLength();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_TRUE ( ERROR_NONE ==
|
ASSERT_TRUE ( ERROR_NONE ==
|
||||||
|
@ -166,6 +174,8 @@ ble_error_t nRF5xGattServer::addService(GattService &service)
|
||||||
p_char->getValueAttribute().hasVariableLength(),
|
p_char->getValueAttribute().hasVariableLength(),
|
||||||
userDescriptionDescriptorValuePtr,
|
userDescriptionDescriptorValuePtr,
|
||||||
userDescriptionDescriptorValueLen,
|
userDescriptionDescriptorValueLen,
|
||||||
|
presentationFormatDescriptorValuePtr,
|
||||||
|
presentationFormatDescriptorValueLen,
|
||||||
p_char->isReadAuthorizationEnabled(),
|
p_char->isReadAuthorizationEnabled(),
|
||||||
p_char->isWriteAuthorizationEnabled(),
|
p_char->isWriteAuthorizationEnabled(),
|
||||||
&nrfCharacteristicHandles[characteristicCount]),
|
&nrfCharacteristicHandles[characteristicCount]),
|
||||||
|
@ -179,6 +189,10 @@ ble_error_t nRF5xGattServer::addService(GattService &service)
|
||||||
nrfCharacteristicHandles[characteristicCount].user_desc_handle
|
nrfCharacteristicHandles[characteristicCount].user_desc_handle
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (p_presentation_format_descriptor) {
|
||||||
|
// The handle is not available from the SoftDevice
|
||||||
|
p_presentation_format_descriptor->setHandle(GattAttribute::INVALID_HANDLE);
|
||||||
|
}
|
||||||
characteristicCount++;
|
characteristicCount++;
|
||||||
|
|
||||||
/* Add optional descriptors if any */
|
/* Add optional descriptors if any */
|
||||||
|
@ -188,8 +202,10 @@ ble_error_t nRF5xGattServer::addService(GattService &service)
|
||||||
}
|
}
|
||||||
|
|
||||||
GattAttribute *p_desc = p_char->getDescriptor(j);
|
GattAttribute *p_desc = p_char->getDescriptor(j);
|
||||||
/* skip the user-description-descriptor here; this has already been handled when adding the characteristic (above). */
|
/* skip the user-description or presentation-format descriptor here;
|
||||||
if (p_desc->getUUID() == BLE_UUID_DESCRIPTOR_CHAR_USER_DESC) {
|
* they have already been handled when adding the characteristic (above). */
|
||||||
|
if (p_desc->getUUID() == BLE_UUID_DESCRIPTOR_CHAR_USER_DESC
|
||||||
|
|| p_desc->getUUID() == BLE_UUID_DESCRIPTOR_CHAR_PRESENTATION_FORMAT) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,329 +0,0 @@
|
||||||
/* 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 "nRF5xServiceDiscovery.h"
|
|
||||||
|
|
||||||
ble_error_t
|
|
||||||
nRF5xServiceDiscovery::launchCharacteristicDiscovery(Gap::Handle_t connectionHandle,
|
|
||||||
Gap::Handle_t startHandle,
|
|
||||||
Gap::Handle_t endHandle)
|
|
||||||
{
|
|
||||||
characteristicDiscoveryStarted(connectionHandle);
|
|
||||||
|
|
||||||
ble_gattc_handle_range_t handleRange = {
|
|
||||||
(uint16_t) startHandle,
|
|
||||||
(uint16_t) endHandle
|
|
||||||
};
|
|
||||||
uint32_t rc = sd_ble_gattc_characteristics_discover(connectionHandle, &handleRange);
|
|
||||||
ble_error_t err = BLE_ERROR_NONE;
|
|
||||||
|
|
||||||
switch (rc) {
|
|
||||||
case NRF_SUCCESS:
|
|
||||||
err = BLE_ERROR_NONE;
|
|
||||||
break;
|
|
||||||
case BLE_ERROR_INVALID_CONN_HANDLE:
|
|
||||||
case NRF_ERROR_INVALID_ADDR:
|
|
||||||
err = BLE_ERROR_INVALID_PARAM;
|
|
||||||
break;
|
|
||||||
case NRF_ERROR_BUSY:
|
|
||||||
err = BLE_STACK_BUSY;
|
|
||||||
break;
|
|
||||||
case NRF_ERROR_INVALID_STATE:
|
|
||||||
err = BLE_ERROR_INVALID_STATE;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
err = BLE_ERROR_UNSPECIFIED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (err) {
|
|
||||||
terminateCharacteristicDiscovery(err);
|
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nRF5xServiceDiscovery::setupDiscoveredServices(const ble_gattc_evt_prim_srvc_disc_rsp_t *response)
|
|
||||||
{
|
|
||||||
serviceIndex = 0;
|
|
||||||
numServices = response->count;
|
|
||||||
|
|
||||||
/* Account for the limitation on the number of discovered services we can handle at a time. */
|
|
||||||
if (numServices > BLE_DB_DISCOVERY_MAX_SRV) {
|
|
||||||
numServices = BLE_DB_DISCOVERY_MAX_SRV;
|
|
||||||
}
|
|
||||||
|
|
||||||
serviceUUIDDiscoveryQueue.reset();
|
|
||||||
for (unsigned i = 0; i < numServices; ++i) {
|
|
||||||
if (response->services[i].uuid.type == BLE_UUID_TYPE_UNKNOWN) {
|
|
||||||
serviceUUIDDiscoveryQueue.enqueue(i);
|
|
||||||
services[i].setup(response->services[i].handle_range.start_handle,
|
|
||||||
response->services[i].handle_range.end_handle);
|
|
||||||
} else {
|
|
||||||
services[i].setup(response->services[i].uuid.uuid,
|
|
||||||
response->services[i].handle_range.start_handle,
|
|
||||||
response->services[i].handle_range.end_handle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Trigger discovery of service UUID if necessary. */
|
|
||||||
if (serviceUUIDDiscoveryQueue.getCount()) {
|
|
||||||
serviceUUIDDiscoveryQueue.triggerFirst();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nRF5xServiceDiscovery::setupDiscoveredCharacteristics(const ble_gattc_evt_char_disc_rsp_t *response)
|
|
||||||
{
|
|
||||||
numCharacteristics = response->count;
|
|
||||||
|
|
||||||
/* Account for the limitation on the number of discovered characteristics we can handle at a time. */
|
|
||||||
if (numCharacteristics > BLE_DB_DISCOVERY_MAX_CHAR_PER_SRV) {
|
|
||||||
numCharacteristics = BLE_DB_DISCOVERY_MAX_CHAR_PER_SRV;
|
|
||||||
}
|
|
||||||
|
|
||||||
charUUIDDiscoveryQueue.reset();
|
|
||||||
for (unsigned charIndex = 0; charIndex < numCharacteristics; charIndex++) {
|
|
||||||
if (response->chars[charIndex].uuid.type == BLE_UUID_TYPE_UNKNOWN) {
|
|
||||||
charUUIDDiscoveryQueue.enqueue(charIndex);
|
|
||||||
characteristics[charIndex].setup(gattc,
|
|
||||||
connHandle,
|
|
||||||
response->chars[charIndex].char_props,
|
|
||||||
response->chars[charIndex].handle_decl,
|
|
||||||
response->chars[charIndex].handle_value);
|
|
||||||
} else {
|
|
||||||
characteristics[charIndex].setup(gattc,
|
|
||||||
connHandle,
|
|
||||||
response->chars[charIndex].uuid.uuid,
|
|
||||||
response->chars[charIndex].char_props,
|
|
||||||
response->chars[charIndex].handle_decl,
|
|
||||||
response->chars[charIndex].handle_value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Trigger discovery of char UUID if necessary. */
|
|
||||||
if (charUUIDDiscoveryQueue.getCount()) {
|
|
||||||
charUUIDDiscoveryQueue.triggerFirst();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nRF5xServiceDiscovery::progressCharacteristicDiscovery(void)
|
|
||||||
{
|
|
||||||
if (state != CHARACTERISTIC_DISCOVERY_ACTIVE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((discoveredCharacteristic != nRF5xDiscoveredCharacteristic()) && (numCharacteristics > 0)) {
|
|
||||||
discoveredCharacteristic.setLastHandle(characteristics[0].getDeclHandle() - 1);
|
|
||||||
|
|
||||||
if ((matchingCharacteristicUUID == UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)) ||
|
|
||||||
((matchingCharacteristicUUID == discoveredCharacteristic.getUUID()) &&
|
|
||||||
(matchingServiceUUID != UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)))) {
|
|
||||||
if (characteristicCallback) {
|
|
||||||
characteristicCallback(&discoveredCharacteristic);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint8_t i = 0; i < numCharacteristics; ++i) {
|
|
||||||
if (state != CHARACTERISTIC_DISCOVERY_ACTIVE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i == (numCharacteristics - 1)) {
|
|
||||||
discoveredCharacteristic = characteristics[i];
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
characteristics[i].setLastHandle(characteristics[i + 1].getDeclHandle() - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((matchingCharacteristicUUID == UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)) ||
|
|
||||||
((matchingCharacteristicUUID == characteristics[i].getUUID()) &&
|
|
||||||
(matchingServiceUUID != UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)))) {
|
|
||||||
if (characteristicCallback) {
|
|
||||||
characteristicCallback(&characteristics[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (state != CHARACTERISTIC_DISCOVERY_ACTIVE) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Gap::Handle_t startHandle = (numCharacteristics > 0) ? characteristics[numCharacteristics - 1].getValueHandle() + 1 : SRV_DISC_END_HANDLE;
|
|
||||||
Gap::Handle_t endHandle = services[serviceIndex].getEndHandle();
|
|
||||||
resetDiscoveredCharacteristics(); /* Note: resetDiscoveredCharacteristics() must come after fetching start and end Handles. */
|
|
||||||
|
|
||||||
if (startHandle < endHandle) {
|
|
||||||
ble_gattc_handle_range_t handleRange = {
|
|
||||||
(uint16_t) startHandle,
|
|
||||||
(uint16_t) endHandle
|
|
||||||
};
|
|
||||||
if (sd_ble_gattc_characteristics_discover(connHandle, &handleRange) != NRF_SUCCESS) {
|
|
||||||
terminateCharacteristicDiscovery(BLE_ERROR_UNSPECIFIED);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
terminateCharacteristicDiscovery(BLE_ERROR_NONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nRF5xServiceDiscovery::progressServiceDiscovery(void)
|
|
||||||
{
|
|
||||||
/* Iterate through the previously discovered services cached in services[]. */
|
|
||||||
while ((state == SERVICE_DISCOVERY_ACTIVE) && (serviceIndex < numServices)) {
|
|
||||||
if ((matchingServiceUUID == UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)) ||
|
|
||||||
(matchingServiceUUID == services[serviceIndex].getUUID())) {
|
|
||||||
|
|
||||||
if (serviceCallback && (matchingCharacteristicUUID == UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN))) {
|
|
||||||
serviceCallback(&services[serviceIndex]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((state == SERVICE_DISCOVERY_ACTIVE) && characteristicCallback) {
|
|
||||||
launchCharacteristicDiscovery(connHandle, services[serviceIndex].getStartHandle(), services[serviceIndex].getEndHandle());
|
|
||||||
} else {
|
|
||||||
serviceIndex++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
serviceIndex++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Relaunch discovery of new services beyond the last entry cached in services[]. */
|
|
||||||
if ((state == SERVICE_DISCOVERY_ACTIVE) && (numServices > 0) && (serviceIndex > 0)) {
|
|
||||||
/* Determine the ending handle of the last cached service. */
|
|
||||||
Gap::Handle_t endHandle = services[serviceIndex - 1].getEndHandle();
|
|
||||||
resetDiscoveredServices(); /* Note: resetDiscoveredServices() must come after fetching endHandle. */
|
|
||||||
|
|
||||||
if (endHandle == SRV_DISC_END_HANDLE) {
|
|
||||||
terminateServiceDiscovery();
|
|
||||||
} else {
|
|
||||||
// the next service is located after the last handle discovered
|
|
||||||
// Launch a new discovery from [endHandle + 1 : 0xFFFF]
|
|
||||||
if (sd_ble_gattc_primary_services_discover(connHandle, endHandle + 1, NULL) != NRF_SUCCESS) {
|
|
||||||
terminateServiceDiscovery();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nRF5xServiceDiscovery::ServiceUUIDDiscoveryQueue::triggerFirst(void)
|
|
||||||
{
|
|
||||||
while (numIndices) { /* loop until a call to char_value_by_uuid_read() succeeds or we run out of pending indices. */
|
|
||||||
parentDiscoveryObject->state = DISCOVER_SERVICE_UUIDS;
|
|
||||||
|
|
||||||
unsigned serviceIndex = getFirst();
|
|
||||||
ble_uuid_t uuid = {
|
|
||||||
.uuid = BLE_UUID_SERVICE_PRIMARY,
|
|
||||||
.type = BLE_UUID_TYPE_BLE,
|
|
||||||
};
|
|
||||||
ble_gattc_handle_range_t handleRange = {
|
|
||||||
.start_handle = parentDiscoveryObject->services[serviceIndex].getStartHandle(),
|
|
||||||
.end_handle = parentDiscoveryObject->services[serviceIndex].getEndHandle(),
|
|
||||||
};
|
|
||||||
if (sd_ble_gattc_char_value_by_uuid_read(parentDiscoveryObject->connHandle, &uuid, &handleRange) == NRF_SUCCESS) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Skip this service if we fail to launch a read for its service-declaration
|
|
||||||
* attribute. Its UUID will remain INVALID, and it may not match any filters. */
|
|
||||||
dequeue();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Switch back to service discovery upon exhausting the service-indices pending UUID discovery. */
|
|
||||||
if (parentDiscoveryObject->state == DISCOVER_SERVICE_UUIDS) {
|
|
||||||
parentDiscoveryObject->state = SERVICE_DISCOVERY_ACTIVE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nRF5xServiceDiscovery::CharUUIDDiscoveryQueue::triggerFirst(void)
|
|
||||||
{
|
|
||||||
while (numIndices) { /* loop until a call to char_value_by_uuid_read() succeeds or we run out of pending indices. */
|
|
||||||
parentDiscoveryObject->state = DISCOVER_CHARACTERISTIC_UUIDS;
|
|
||||||
|
|
||||||
unsigned charIndex = getFirst();
|
|
||||||
ble_uuid_t uuid = {
|
|
||||||
.uuid = BLE_UUID_CHARACTERISTIC,
|
|
||||||
.type = BLE_UUID_TYPE_BLE,
|
|
||||||
};
|
|
||||||
ble_gattc_handle_range_t handleRange = { };
|
|
||||||
handleRange.start_handle = parentDiscoveryObject->characteristics[charIndex].getDeclHandle();
|
|
||||||
handleRange.end_handle = parentDiscoveryObject->characteristics[charIndex].getDeclHandle() + 1;
|
|
||||||
if (sd_ble_gattc_char_value_by_uuid_read(parentDiscoveryObject->connHandle, &uuid, &handleRange) == NRF_SUCCESS) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Skip this service if we fail to launch a read for its service-declaration
|
|
||||||
* attribute. Its UUID will remain INVALID, and it may not match any filters. */
|
|
||||||
dequeue();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Switch back to service discovery upon exhausting the service-indices pending UUID discovery. */
|
|
||||||
if (parentDiscoveryObject->state == DISCOVER_CHARACTERISTIC_UUIDS) {
|
|
||||||
parentDiscoveryObject->state = CHARACTERISTIC_DISCOVERY_ACTIVE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
nRF5xServiceDiscovery::processDiscoverUUIDResponse(const ble_gattc_evt_t *p_gattc_evt)
|
|
||||||
{
|
|
||||||
const ble_gattc_evt_char_val_by_uuid_read_rsp_t * response = &p_gattc_evt->params.char_val_by_uuid_read_rsp;
|
|
||||||
|
|
||||||
if (state == DISCOVER_SERVICE_UUIDS) {
|
|
||||||
if ((response->count == 1) && (response->value_len == UUID::LENGTH_OF_LONG_UUID)) {
|
|
||||||
UUID::LongUUIDBytes_t uuid;
|
|
||||||
|
|
||||||
#if (NRF_SD_BLE_API_VERSION >= 3)
|
|
||||||
ble_gattc_handle_value_t iter;
|
|
||||||
memset(&iter, 0, sizeof(ble_gattc_handle_value_t));
|
|
||||||
(void) sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter(const_cast<ble_gattc_evt_t*>(p_gattc_evt), &iter);
|
|
||||||
memcpy(uuid, iter.p_value, UUID::LENGTH_OF_LONG_UUID);
|
|
||||||
#else
|
|
||||||
memcpy(uuid, &(response->handle_value[0].p_value[0]), UUID::LENGTH_OF_LONG_UUID);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
unsigned serviceIndex = serviceUUIDDiscoveryQueue.dequeue();
|
|
||||||
services[serviceIndex].setupLongUUID(uuid, UUID::LSB);
|
|
||||||
|
|
||||||
serviceUUIDDiscoveryQueue.triggerFirst();
|
|
||||||
} else {
|
|
||||||
serviceUUIDDiscoveryQueue.dequeue();
|
|
||||||
}
|
|
||||||
} else if (state == DISCOVER_CHARACTERISTIC_UUIDS) {
|
|
||||||
if ((response->count == 1) && (response->value_len == UUID::LENGTH_OF_LONG_UUID + 1 /* props */ + 2 /* value handle */)) {
|
|
||||||
UUID::LongUUIDBytes_t uuid;
|
|
||||||
|
|
||||||
#if (NRF_SD_BLE_API_VERSION >= 3)
|
|
||||||
ble_gattc_handle_value_t iter;
|
|
||||||
memset(&iter, 0, sizeof(ble_gattc_handle_value_t));
|
|
||||||
(void) sd_ble_gattc_evt_char_val_by_uuid_read_rsp_iter(const_cast<ble_gattc_evt_t*>(p_gattc_evt), &iter);
|
|
||||||
memcpy(uuid, &(iter.p_value[3]), UUID::LENGTH_OF_LONG_UUID);
|
|
||||||
#else
|
|
||||||
memcpy(uuid, &(response->handle_value[0].p_value[3]), UUID::LENGTH_OF_LONG_UUID);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
unsigned charIndex = charUUIDDiscoveryQueue.dequeue();
|
|
||||||
characteristics[charIndex].setupLongUUID(uuid, UUID::LSB);
|
|
||||||
|
|
||||||
charUUIDDiscoveryQueue.triggerFirst();
|
|
||||||
} else {
|
|
||||||
charUUIDDiscoveryQueue.dequeue();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,366 +0,0 @@
|
||||||
/* 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 __NRF_SERVICE_DISCOVERY_H__
|
|
||||||
#define __NRF_SERVICE_DISCOVERY_H__
|
|
||||||
|
|
||||||
#include "ble/ServiceDiscovery.h"
|
|
||||||
#include "ble/DiscoveredService.h"
|
|
||||||
#include "nRF5xDiscoveredCharacteristic.h"
|
|
||||||
|
|
||||||
#include "headers/nrf_ble.h"
|
|
||||||
#include "headers/nrf_ble_gattc.h"
|
|
||||||
|
|
||||||
class nRF5xGattClient; /* forward declaration */
|
|
||||||
|
|
||||||
class nRF5xServiceDiscovery : public ServiceDiscovery
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static const uint16_t SRV_DISC_START_HANDLE = 0x0001; /**< The start handle value used during service discovery. */
|
|
||||||
static const uint16_t SRV_DISC_END_HANDLE = 0xFFFF; /**< The end handle value used during service discovery. */
|
|
||||||
|
|
||||||
public:
|
|
||||||
static const unsigned BLE_DB_DISCOVERY_MAX_SRV = 4; /**< Maximum number of services we can retain information for after a single discovery. */
|
|
||||||
static const unsigned BLE_DB_DISCOVERY_MAX_CHAR_PER_SRV = 4; /**< Maximum number of characteristics per service we can retain information for. */
|
|
||||||
|
|
||||||
public:
|
|
||||||
nRF5xServiceDiscovery(nRF5xGattClient *gattcIn) :
|
|
||||||
gattc(gattcIn),
|
|
||||||
serviceIndex(0),
|
|
||||||
numServices(0),
|
|
||||||
numCharacteristics(0),
|
|
||||||
state(INACTIVE),
|
|
||||||
services(),
|
|
||||||
characteristics(),
|
|
||||||
serviceUUIDDiscoveryQueue(this),
|
|
||||||
charUUIDDiscoveryQueue(this),
|
|
||||||
onTerminationCallback(NULL) {
|
|
||||||
/* empty */
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ble_error_t launch(Gap::Handle_t connectionHandle,
|
|
||||||
ServiceDiscovery::ServiceCallback_t sc,
|
|
||||||
ServiceDiscovery::CharacteristicCallback_t cc,
|
|
||||||
const UUID &matchingServiceUUIDIn,
|
|
||||||
const UUID &matchingCharacteristicUUIDIn)
|
|
||||||
{
|
|
||||||
if (isActive()) {
|
|
||||||
return BLE_ERROR_INVALID_STATE;
|
|
||||||
}
|
|
||||||
|
|
||||||
serviceCallback = sc;
|
|
||||||
characteristicCallback = cc;
|
|
||||||
matchingServiceUUID = matchingServiceUUIDIn;
|
|
||||||
matchingCharacteristicUUID = matchingCharacteristicUUIDIn;
|
|
||||||
|
|
||||||
serviceDiscoveryStarted(connectionHandle);
|
|
||||||
|
|
||||||
uint32_t rc;
|
|
||||||
if ((rc = sd_ble_gattc_primary_services_discover(connectionHandle, SRV_DISC_START_HANDLE, NULL)) != NRF_SUCCESS) {
|
|
||||||
terminate();
|
|
||||||
switch (rc) {
|
|
||||||
case NRF_ERROR_INVALID_PARAM:
|
|
||||||
case BLE_ERROR_INVALID_CONN_HANDLE:
|
|
||||||
return BLE_ERROR_INVALID_PARAM;
|
|
||||||
case NRF_ERROR_BUSY:
|
|
||||||
return BLE_STACK_BUSY;
|
|
||||||
default:
|
|
||||||
case NRF_ERROR_INVALID_STATE:
|
|
||||||
return BLE_ERROR_INVALID_STATE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual bool isActive(void) const {
|
|
||||||
return state != INACTIVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void terminate(void) {
|
|
||||||
terminateServiceDiscovery();
|
|
||||||
}
|
|
||||||
|
|
||||||
void terminate(Gap::Handle_t connectionHandle) {
|
|
||||||
if(connHandle == connectionHandle) {
|
|
||||||
terminate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void onTermination(ServiceDiscovery::TerminationCallback_t callback) {
|
|
||||||
onTerminationCallback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Clear nRF5xServiceDiscovery's state.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* BLE_ERROR_NONE if successful.
|
|
||||||
*/
|
|
||||||
virtual ble_error_t reset(void) {
|
|
||||||
/* Clear all state that is from the parent, including private members */
|
|
||||||
if (ServiceDiscovery::reset() != BLE_ERROR_NONE) {
|
|
||||||
return BLE_ERROR_INVALID_STATE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clear derived class members */
|
|
||||||
serviceIndex = 0;
|
|
||||||
numServices = 0;
|
|
||||||
numCharacteristics = 0;
|
|
||||||
|
|
||||||
state = INACTIVE;
|
|
||||||
|
|
||||||
serviceUUIDDiscoveryQueue.reset();
|
|
||||||
charUUIDDiscoveryQueue.reset();
|
|
||||||
|
|
||||||
onTerminationCallback = NULL;
|
|
||||||
|
|
||||||
return BLE_ERROR_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
ble_error_t launchCharacteristicDiscovery(Gap::Handle_t connectionHandle, Gap::Handle_t startHandle, Gap::Handle_t endHandle);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void setupDiscoveredServices(const ble_gattc_evt_prim_srvc_disc_rsp_t *response);
|
|
||||||
void setupDiscoveredCharacteristics(const ble_gattc_evt_char_disc_rsp_t *response);
|
|
||||||
|
|
||||||
void triggerServiceUUIDDiscovery(void);
|
|
||||||
void processDiscoverUUIDResponse(const ble_gattc_evt_t *p_gattc_evt);
|
|
||||||
void removeFirstServiceNeedingUUIDDiscovery(void);
|
|
||||||
|
|
||||||
void terminateServiceDiscovery(void) {
|
|
||||||
discoveredCharacteristic = nRF5xDiscoveredCharacteristic();
|
|
||||||
|
|
||||||
bool wasActive = isActive();
|
|
||||||
state = INACTIVE;
|
|
||||||
|
|
||||||
if (wasActive && onTerminationCallback) {
|
|
||||||
onTerminationCallback(connHandle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void terminateCharacteristicDiscovery(ble_error_t err) {
|
|
||||||
if (state == CHARACTERISTIC_DISCOVERY_ACTIVE) {
|
|
||||||
if(discoveredCharacteristic != nRF5xDiscoveredCharacteristic()) {
|
|
||||||
if(err == BLE_ERROR_NONE) {
|
|
||||||
// fullfill the last characteristic
|
|
||||||
discoveredCharacteristic.setLastHandle(services[serviceIndex].getEndHandle());
|
|
||||||
|
|
||||||
if ((matchingCharacteristicUUID == UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)) ||
|
|
||||||
((matchingCharacteristicUUID == discoveredCharacteristic.getUUID()) &&
|
|
||||||
(matchingServiceUUID != UUID::ShortUUIDBytes_t(BLE_UUID_UNKNOWN)))) {
|
|
||||||
if (characteristicCallback) {
|
|
||||||
characteristicCallback(&discoveredCharacteristic);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
discoveredCharacteristic = nRF5xDiscoveredCharacteristic();
|
|
||||||
}
|
|
||||||
|
|
||||||
state = SERVICE_DISCOVERY_ACTIVE;
|
|
||||||
}
|
|
||||||
serviceIndex++; /* Progress service index to keep discovery alive. */
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void resetDiscoveredServices(void) {
|
|
||||||
numServices = 0;
|
|
||||||
serviceIndex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void resetDiscoveredCharacteristics(void) {
|
|
||||||
numCharacteristics = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void serviceDiscoveryStarted(Gap::Handle_t connectionHandle) {
|
|
||||||
connHandle = connectionHandle;
|
|
||||||
resetDiscoveredServices();
|
|
||||||
state = SERVICE_DISCOVERY_ACTIVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void characteristicDiscoveryStarted(Gap::Handle_t connectionHandle) {
|
|
||||||
connHandle = connectionHandle;
|
|
||||||
resetDiscoveredCharacteristics();
|
|
||||||
state = CHARACTERISTIC_DISCOVERY_ACTIVE;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
/**
|
|
||||||
* A datatype to contain service-indices for which long UUIDs need to be
|
|
||||||
* discovered using read_val_by_uuid().
|
|
||||||
*/
|
|
||||||
class ServiceUUIDDiscoveryQueue {
|
|
||||||
public:
|
|
||||||
ServiceUUIDDiscoveryQueue(nRF5xServiceDiscovery *parent) :
|
|
||||||
numIndices(0),
|
|
||||||
serviceIndices(),
|
|
||||||
parentDiscoveryObject(parent) {
|
|
||||||
/* empty */
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
void reset(void) {
|
|
||||||
numIndices = 0;
|
|
||||||
for (unsigned i = 0; i < BLE_DB_DISCOVERY_MAX_SRV; i++) {
|
|
||||||
serviceIndices[i] = INVALID_INDEX;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void enqueue(int serviceIndex) {
|
|
||||||
serviceIndices[numIndices++] = serviceIndex;
|
|
||||||
}
|
|
||||||
int dequeue(void) {
|
|
||||||
if (numIndices == 0) {
|
|
||||||
return INVALID_INDEX;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned valueToReturn = serviceIndices[0];
|
|
||||||
numIndices--;
|
|
||||||
for (unsigned i = 0; i < numIndices; i++) {
|
|
||||||
serviceIndices[i] = serviceIndices[i + 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
return valueToReturn;
|
|
||||||
}
|
|
||||||
unsigned getFirst(void) const {
|
|
||||||
return serviceIndices[0];
|
|
||||||
}
|
|
||||||
size_t getCount(void) const {
|
|
||||||
return numIndices;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Trigger UUID discovery for the first of the enqueued ServiceIndices.
|
|
||||||
*/
|
|
||||||
void triggerFirst(void);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static const int INVALID_INDEX = -1;
|
|
||||||
|
|
||||||
private:
|
|
||||||
size_t numIndices;
|
|
||||||
int serviceIndices[BLE_DB_DISCOVERY_MAX_SRV];
|
|
||||||
|
|
||||||
nRF5xServiceDiscovery *parentDiscoveryObject;
|
|
||||||
};
|
|
||||||
friend class ServiceUUIDDiscoveryQueue;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A datatype to contain characteristic-indices for which long UUIDs need to
|
|
||||||
* be discovered using read_val_by_uuid().
|
|
||||||
*/
|
|
||||||
class CharUUIDDiscoveryQueue {
|
|
||||||
public:
|
|
||||||
CharUUIDDiscoveryQueue(nRF5xServiceDiscovery *parent) :
|
|
||||||
numIndices(0),
|
|
||||||
charIndices(),
|
|
||||||
parentDiscoveryObject(parent) {
|
|
||||||
/* empty */
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
void reset(void) {
|
|
||||||
numIndices = 0;
|
|
||||||
for (unsigned i = 0; i < BLE_DB_DISCOVERY_MAX_SRV; i++) {
|
|
||||||
charIndices[i] = INVALID_INDEX;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void enqueue(int serviceIndex) {
|
|
||||||
charIndices[numIndices++] = serviceIndex;
|
|
||||||
}
|
|
||||||
int dequeue(void) {
|
|
||||||
if (numIndices == 0) {
|
|
||||||
return INVALID_INDEX;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned valueToReturn = charIndices[0];
|
|
||||||
numIndices--;
|
|
||||||
for (unsigned i = 0; i < numIndices; i++) {
|
|
||||||
charIndices[i] = charIndices[i + 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
return valueToReturn;
|
|
||||||
}
|
|
||||||
unsigned getFirst(void) const {
|
|
||||||
return charIndices[0];
|
|
||||||
}
|
|
||||||
size_t getCount(void) const {
|
|
||||||
return numIndices;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Trigger UUID discovery for the first of the enqueued charIndices.
|
|
||||||
*/
|
|
||||||
void triggerFirst(void);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static const int INVALID_INDEX = -1;
|
|
||||||
|
|
||||||
private:
|
|
||||||
size_t numIndices;
|
|
||||||
int charIndices[BLE_DB_DISCOVERY_MAX_CHAR_PER_SRV];
|
|
||||||
|
|
||||||
nRF5xServiceDiscovery *parentDiscoveryObject;
|
|
||||||
};
|
|
||||||
friend class CharUUIDDiscoveryQueue;
|
|
||||||
|
|
||||||
private:
|
|
||||||
friend void bleGattcEventHandler(const ble_evt_t *p_ble_evt);
|
|
||||||
void progressCharacteristicDiscovery(void);
|
|
||||||
void progressServiceDiscovery(void);
|
|
||||||
|
|
||||||
private:
|
|
||||||
nRF5xGattClient *gattc;
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint8_t serviceIndex; /**< Index of the current service being discovered. This is intended for internal use during service discovery.*/
|
|
||||||
uint8_t numServices; /**< Number of services at the peers GATT database.*/
|
|
||||||
uint8_t numCharacteristics; /**< Number of characteristics within the service.*/
|
|
||||||
|
|
||||||
enum State_t {
|
|
||||||
INACTIVE,
|
|
||||||
SERVICE_DISCOVERY_ACTIVE,
|
|
||||||
CHARACTERISTIC_DISCOVERY_ACTIVE,
|
|
||||||
DISCOVER_SERVICE_UUIDS,
|
|
||||||
DISCOVER_CHARACTERISTIC_UUIDS,
|
|
||||||
} state;
|
|
||||||
|
|
||||||
DiscoveredService services[BLE_DB_DISCOVERY_MAX_SRV]; /**< Information related to the current service being discovered.
|
|
||||||
* This is intended for internal use during service discovery. */
|
|
||||||
nRF5xDiscoveredCharacteristic characteristics[BLE_DB_DISCOVERY_MAX_CHAR_PER_SRV];
|
|
||||||
|
|
||||||
ServiceUUIDDiscoveryQueue serviceUUIDDiscoveryQueue;
|
|
||||||
CharUUIDDiscoveryQueue charUUIDDiscoveryQueue;
|
|
||||||
|
|
||||||
TerminationCallback_t onTerminationCallback;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The currently discovered characteristic. Discovery of a characteristic
|
|
||||||
* is a two phase process.
|
|
||||||
* First, declaration handle is fetched, it provide the UUID, the value handle and
|
|
||||||
* the properties of a characteristic.
|
|
||||||
* Second, the next declaration handle is fetched, with its declaration handle, it is
|
|
||||||
* possible to compute the last handle of the discovered characteristic and fill the
|
|
||||||
* missing part of the object.
|
|
||||||
* If there is no remaining characteristic to discover, the last handle of the
|
|
||||||
* discovered characteristic will be set to the last handle of its enclosing service.
|
|
||||||
*/
|
|
||||||
nRF5xDiscoveredCharacteristic discoveredCharacteristic;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /*__NRF_SERVICE_DISCOVERY_H__*/
|
|
|
@ -31,6 +31,8 @@ extern "C" {
|
||||||
#include "softdevice_handler.h"
|
#include "softdevice_handler.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "nRF5XPalGattClient.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The singleton which represents the nRF51822 transport for the BLE.
|
* The singleton which represents the nRF51822 transport for the BLE.
|
||||||
*/
|
*/
|
||||||
|
@ -60,7 +62,7 @@ nRF5xn::nRF5xn(void) :
|
||||||
instanceID(BLE::DEFAULT_INSTANCE),
|
instanceID(BLE::DEFAULT_INSTANCE),
|
||||||
gapInstance(),
|
gapInstance(),
|
||||||
gattServerInstance(NULL),
|
gattServerInstance(NULL),
|
||||||
gattClientInstance(NULL),
|
gattClient(&(ble::pal::vendor::nordic::nRF5XGattClient::get_client())),
|
||||||
securityManagerInstance(NULL)
|
securityManagerInstance(NULL)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -189,11 +191,9 @@ ble_error_t nRF5xn::shutdown(void)
|
||||||
|
|
||||||
/* S110 does not support BLE client features, nothing to reset. */
|
/* S110 does not support BLE client features, nothing to reset. */
|
||||||
#if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110)
|
#if !defined(TARGET_MCU_NRF51_16K_S110) && !defined(TARGET_MCU_NRF51_32K_S110)
|
||||||
if (gattClientInstance != NULL) {
|
error = getGattClient().reset();
|
||||||
error = gattClientInstance->reset();
|
if (error != BLE_ERROR_NONE) {
|
||||||
if (error != BLE_ERROR_NONE) {
|
return error;
|
||||||
return error;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -20,10 +20,10 @@
|
||||||
#include "ble/BLE.h"
|
#include "ble/BLE.h"
|
||||||
#include "ble/blecommon.h"
|
#include "ble/blecommon.h"
|
||||||
#include "ble/BLEInstanceBase.h"
|
#include "ble/BLEInstanceBase.h"
|
||||||
|
#include "ble/generic/GenericGattClient.h"
|
||||||
|
|
||||||
#include "nRF5xGap.h"
|
#include "nRF5xGap.h"
|
||||||
#include "nRF5xGattServer.h"
|
#include "nRF5xGattServer.h"
|
||||||
#include "nRF5xGattClient.h"
|
|
||||||
#include "nRF5xSecurityManager.h"
|
#include "nRF5xSecurityManager.h"
|
||||||
|
|
||||||
#include "btle.h"
|
#include "btle.h"
|
||||||
|
@ -77,11 +77,8 @@ public:
|
||||||
*
|
*
|
||||||
* @return A reference to GattClient.
|
* @return A reference to GattClient.
|
||||||
*/
|
*/
|
||||||
virtual nRF5xGattClient &getGattClient() {
|
virtual GattClient &getGattClient() {
|
||||||
if (gattClientInstance == NULL) {
|
return gattClient;
|
||||||
gattClientInstance = new nRF5xGattClient();
|
|
||||||
}
|
|
||||||
return *gattClientInstance;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -171,10 +168,8 @@ private:
|
||||||
* If NULL, then GattServer has not been initialized.
|
* If NULL, then GattServer has not been initialized.
|
||||||
* The pointer has been declared as 'mutable' so that
|
* The pointer has been declared as 'mutable' so that
|
||||||
* it can be assigned inside a 'const' function. */
|
* it can be assigned inside a 'const' function. */
|
||||||
mutable nRF5xGattClient *gattClientInstance; /**< Pointer to the GattClient object instance.
|
ble::generic::GenericGattClient gattClient;
|
||||||
* If NULL, then GattClient has not been initialized.
|
|
||||||
* The pointer has been declared as 'mutable' so that
|
|
||||||
* it can be assigned inside a 'const' function. */
|
|
||||||
mutable nRF5xSecurityManager *securityManagerInstance; /**< Pointer to the SecurityManager object instance.
|
mutable nRF5xSecurityManager *securityManagerInstance; /**< Pointer to the SecurityManager object instance.
|
||||||
* If NULL, then SecurityManager has not been initialized.
|
* If NULL, then SecurityManager has not been initialized.
|
||||||
* The pointer has been declared as 'mutable' so that
|
* The pointer has been declared as 'mutable' so that
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue