프로젝트 정리: components/libraries 미사용 파일 삭제

This commit is contained in:
2026-04-15 11:02:11 +09:00
parent 8171d50a2e
commit 6fe7efa0d6
116 changed files with 0 additions and 41809 deletions

View File

@@ -1,269 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sdk_common.h"
#if NRF_MODULE_ENABLED(NRF_BLOCK_DEV_EMPTY)
#include "nrf_block_dev_empty.h"
#include <inttypes.h>
/**@file
*
* @ingroup nrf_block_dev
* @{
*
* @brief This module implements block device API. It would behave like:
* - /dev/empty for write operations
* - /dev/zero for read operations
*/
#if NRF_BLOCK_DEV_EMPTY_CONFIG_LOG_ENABLED
#define NRF_LOG_LEVEL NRF_BLOCK_DEV_EMPTY_CONFIG_LOG_LEVEL
#define NRF_LOG_INFO_COLOR NRF_BLOCK_DEV_EMPTY_CONFIG_INFO_COLOR
#define NRF_LOG_DEBUG_COLOR NRF_BLOCK_DEV_EMPTY_CONFIG_DEBUG_COLOR
#else
#define NRF_LOG_LEVEL 0
#endif
#include "nrf_log.h"
static ret_code_t block_dev_empty_init(nrf_block_dev_t const * p_blk_dev,
nrf_block_dev_ev_handler ev_handler,
void const * p_context)
{
ASSERT(p_blk_dev);
nrf_block_dev_empty_t const * p_empty_dev =
CONTAINER_OF(p_blk_dev, nrf_block_dev_empty_t, block_dev);
nrf_block_dev_empty_work_t * p_work = p_empty_dev->p_work;
NRF_LOG_INST_DEBUG(p_empty_dev->p_log, "Init.");
/* Calculate block device geometry.... */
p_work->geometry.blk_size = p_empty_dev->empty_config.block_size;
p_work->geometry.blk_count = p_empty_dev->empty_config.block_count;
p_work->p_context = p_context;
p_work->ev_handler = ev_handler;
if (p_work->ev_handler)
{
/*Asynchronous operation (simulation)*/
const nrf_block_dev_event_t ev = {
NRF_BLOCK_DEV_EVT_INIT,
NRF_BLOCK_DEV_RESULT_SUCCESS,
NULL,
p_work->p_context
};
p_work->ev_handler(p_blk_dev, &ev);
}
return NRF_SUCCESS;
}
static ret_code_t block_dev_empty_uninit(nrf_block_dev_t const * p_blk_dev)
{
ASSERT(p_blk_dev);
nrf_block_dev_empty_t const * p_empty_dev =
CONTAINER_OF(p_blk_dev, nrf_block_dev_empty_t, block_dev);
nrf_block_dev_empty_work_t * p_work = p_empty_dev->p_work;
NRF_LOG_INST_DEBUG(p_empty_dev->p_log, "Uninit.");
if (p_work->ev_handler)
{
/*Asynchronous operation (simulation)*/
const nrf_block_dev_event_t ev = {
NRF_BLOCK_DEV_EVT_UNINIT,
NRF_BLOCK_DEV_RESULT_SUCCESS,
NULL,
p_work->p_context
};
p_work->ev_handler(p_blk_dev, &ev);
}
memset(p_work, 0, sizeof(nrf_block_dev_empty_work_t));
return NRF_SUCCESS;
}
static ret_code_t block_dev_empty_read_req(nrf_block_dev_t const * p_blk_dev,
nrf_block_req_t const * p_blk)
{
ASSERT(p_blk_dev);
ASSERT(p_blk);
nrf_block_dev_empty_t const * p_empty_dev =
CONTAINER_OF(p_blk_dev, nrf_block_dev_empty_t, block_dev);
nrf_block_dev_empty_work_t * p_work = p_empty_dev->p_work;
NRF_LOG_INST_DEBUG(
p_empty_dev->p_log,
"Read req from block %"PRIu32" size %"PRIu32"(x%"PRIu32") to %"PRIXPTR,
p_blk->blk_id,
p_blk->blk_count,
p_blk_dev->p_ops->geometry(p_blk_dev)->blk_size,
p_blk->p_buff);
if ((p_blk->blk_id + p_blk->blk_count) > p_work->geometry.blk_count)
{
NRF_LOG_INST_ERROR(
p_empty_dev->p_log,
"Out of range read req block %"PRIu32" count %"PRIu32" while max is %"PRIu32,
p_blk->blk_id,
p_blk->blk_count,
p_blk_dev->p_ops->geometry(p_blk_dev)->blk_count);
return NRF_ERROR_INVALID_ADDR;
}
memset(p_blk->p_buff, 0, p_empty_dev->p_work->geometry.blk_size * p_blk->blk_count);
if (p_work->ev_handler)
{
/*Asynchronous operation (simulation)*/
const nrf_block_dev_event_t ev = {
NRF_BLOCK_DEV_EVT_BLK_READ_DONE,
NRF_BLOCK_DEV_RESULT_SUCCESS,
p_blk,
p_work->p_context
};
p_work->ev_handler(p_blk_dev, &ev);
}
return NRF_SUCCESS;
}
static ret_code_t block_dev_empty_write_req(nrf_block_dev_t const * p_blk_dev,
nrf_block_req_t const * p_blk)
{
ASSERT(p_blk_dev);
ASSERT(p_blk);
nrf_block_dev_empty_t const * p_empty_dev =
CONTAINER_OF(p_blk_dev, nrf_block_dev_empty_t, block_dev);
nrf_block_dev_empty_work_t * p_work = p_empty_dev->p_work;
NRF_LOG_INST_DEBUG(
p_empty_dev->p_log,
"Write req to block %"PRIu32" size %"PRIu32"(x%"PRIu32") from %"PRIXPTR,
p_blk->blk_id,
p_blk->blk_count,
p_blk_dev->p_ops->geometry(p_blk_dev)->blk_size,
p_blk->p_buff);
if ((p_blk->blk_id + p_blk->blk_count) > p_work->geometry.blk_count)
{
NRF_LOG_INST_ERROR(
p_empty_dev->p_log,
"Out of range write req block %"PRIu32" count %"PRIu32" while max is %"PRIu32,
p_blk->blk_id,
p_blk->blk_count,
p_blk_dev->p_ops->geometry(p_blk_dev)->blk_count);
return NRF_ERROR_INVALID_ADDR;
}
if (p_work->ev_handler)
{
/*Asynchronous operation (simulation)*/
const nrf_block_dev_event_t ev = {
NRF_BLOCK_DEV_EVT_BLK_WRITE_DONE,
NRF_BLOCK_DEV_RESULT_SUCCESS,
p_blk,
p_work->p_context
};
p_work->ev_handler(p_blk_dev, &ev);
}
return NRF_SUCCESS;
}
static ret_code_t block_dev_empty_ioctl(nrf_block_dev_t const * p_blk_dev,
nrf_block_dev_ioctl_req_t req, void * p_data)
{
nrf_block_dev_empty_t const * p_empty_dev =
CONTAINER_OF(p_blk_dev, nrf_block_dev_empty_t, block_dev);
switch (req)
{
case NRF_BLOCK_DEV_IOCTL_REQ_CACHE_FLUSH:
{
bool * p_flushing = p_data;
NRF_LOG_INST_DEBUG(p_empty_dev, "IOCtl: Cache flush");
if (p_flushing)
{
*p_flushing = false;
}
return NRF_SUCCESS;
}
case NRF_BLOCK_DEV_IOCTL_REQ_INFO_STRINGS:
{
if (p_data == NULL)
{
return NRF_ERROR_INVALID_PARAM;
}
nrf_block_dev_info_strings_t const * * pp_strings = p_data;
*pp_strings = &p_empty_dev->info_strings;
return NRF_SUCCESS;
}
default:
break;
}
return NRF_ERROR_NOT_SUPPORTED;
}
static nrf_block_dev_geometry_t const * block_dev_empty_geometry(nrf_block_dev_t const * p_blk_dev)
{
ASSERT(p_blk_dev);
nrf_block_dev_empty_t const * p_empty_dev =
CONTAINER_OF(p_blk_dev, nrf_block_dev_empty_t, block_dev);
nrf_block_dev_empty_work_t const * p_work = p_empty_dev->p_work;
return &p_work->geometry;
}
const nrf_block_dev_ops_t nrf_block_device_empty_ops = {
.init = block_dev_empty_init,
.uninit = block_dev_empty_uninit,
.read_req = block_dev_empty_read_req,
.write_req = block_dev_empty_write_req,
.ioctl = block_dev_empty_ioctl,
.geometry = block_dev_empty_geometry,
};
/** @} */
#endif // NRF_MODULE_ENABLED(NRF_BLOCK_DEV_EMPTY)

View File

@@ -1,152 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF_BLOCK_DEV_EMPTY_H__
#define NRF_BLOCK_DEV_EMPTY_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "nrf_block_dev.h"
#include "nrf_log_instance.h"
/**@file
*
* @defgroup nrf_block_dev_empty Empty implementation
* @ingroup nrf_block_dev
*
* This module implements block device API. It works like:
* - /dev/empty for write operations
* - /dev/zero for read operations
* @{
*
*/
/**
* @brief EMPTY block device operations
* */
extern const nrf_block_dev_ops_t nrf_block_device_empty_ops;
/**
* @brief Work structure of EMPTY block device.
*/
typedef struct {
nrf_block_dev_geometry_t geometry; //!< Block device geometry
nrf_block_dev_ev_handler ev_handler; //!< Block device event handler
void const * p_context; //!< Context handle passed to event handler
} nrf_block_dev_empty_work_t;
/**
* @brief EMPTY block device config initializer (@ref nrf_block_dev_empty_config_t)
*
* @param blk_size Block size
* @param blk_count Block count
* */
#define NRF_BLOCK_DEV_EMPTY_CONFIG(blk_size, blk_count) { \
.block_size = (blk_size), \
.block_count = (blk_count) \
}
/**
* @brief EMPTY block device config
*/
typedef struct {
uint32_t block_size; //!< Desired block size
uint32_t block_count; //!< Desired block count
} nrf_block_dev_empty_config_t;
/**
* @brief EMPTY block device
* */
typedef struct {
nrf_block_dev_t block_dev; //!< Block device
nrf_block_dev_info_strings_t info_strings; //!< Block device information strings
nrf_block_dev_empty_config_t empty_config; //!< EMPTY block device config
nrf_block_dev_empty_work_t * p_work; //!< EMPTY block device work structure
NRF_LOG_INSTANCE_PTR_DECLARE(p_log) //!< Pointer to instance of the logger object (Conditionally compiled).
} nrf_block_dev_empty_t;
/** @brief Name of the module used for logger messaging.
*/
#define NRF_BLOCK_DEV_EMPTY_LOG_NAME block_dev_empty
/**
* @brief Defines a EMPTY block device.
*
* @param name Instance name
* @param config Configuration @ref nrf_block_dev_empty_config_t
* @param info Info strings @ref NFR_BLOCK_DEV_INFO_CONFIG
* */
#define NRF_BLOCK_DEV_EMPTY_DEFINE(name, config, info) \
static nrf_block_dev_empty_work_t CONCAT_2(name, _work); \
NRF_LOG_INSTANCE_REGISTER(NRF_BLOCK_DEV_EMPTY_LOG_NAME, name, \
NRF_BLOCK_DEV_EMPTY_CONFIG_INFO_COLOR, \
NRF_BLOCK_DEV_EMPTY_CONFIG_DEBUG_COLOR, \
NRF_BLOCK_DEV_EMPTY_CONFIG_LOG_INIT_FILTER_LEVEL, \
NRF_BLOCK_DEV_EMPTY_CONFIG_LOG_ENABLED ? \
NRF_BLOCK_DEV_EMPTY_CONFIG_LOG_LEVEL : NRF_LOG_SEVERITY_NONE); \
static const nrf_block_dev_empty_t name = { \
.block_dev = { .p_ops = &nrf_block_device_empty_ops }, \
.info_strings = BRACKET_EXTRACT(info), \
.empty_config = config, \
.p_work = &CONCAT_2(name, _work), \
NRF_LOG_INSTANCE_PTR_INIT(p_log, NRF_BLOCK_DEV_EMPTY_LOG_NAME, name) \
}
/**
* @brief Returns block device API handle from EMPTY block device.
*
* @param[in] p_blk_empty EMPTY block device
* @return Block device handle
*/
static inline nrf_block_dev_t const *
nrf_block_dev_empty_ops_get(nrf_block_dev_empty_t const * p_blk_empty)
{
return &p_blk_empty->block_dev;
}
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* NRF_BLOCK_DEV_EMPTY_H__ */

View File

@@ -1,352 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF_BLOCK_DEV_H__
#define NRF_BLOCK_DEV_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "sdk_common.h"
#include "nrf_assert.h"
#include <stddef.h>
/**@file
*
* @defgroup nrf_block_dev Block device
* @{
* @ingroup app_common
*
* @brief This module implements unified block device API. It could used as a middle layer between
* filesystems and memories.
*/
/**
* @brief Block device request descriptor item.
*/
typedef struct {
uint32_t blk_id; //!< Block ID
uint32_t blk_count; //!< Block count
void * p_buff; //!< Data buffer
} nrf_block_req_t;
/**
* @brief Helper macro to create block device read/write request item
*
* @param name Instance name
* @param block_start Block number start
* @param block_count Number of blocks
* @param buff Buffer to read/write
*/
#define NRF_BLOCK_DEV_REQUEST(name, block_start, block_count, buff) \
nrf_block_req_t name = { \
.blk_id = block_start, \
.blk_count = block_count, \
.p_buff = buff, \
}
/**
* @brief Block device events.
*
* Events are propagated when event handler is defined (@ref nrf_blk_dev_init)
*
*/
typedef enum {
NRF_BLOCK_DEV_EVT_INIT, /**< Passed to event handler when init is done*/
NRF_BLOCK_DEV_EVT_UNINIT, /**< Passed to event handler when uninit is done*/
NRF_BLOCK_DEV_EVT_BLK_READ_DONE, /**< Passed to event handler block read operation is done*/
NRF_BLOCK_DEV_EVT_BLK_WRITE_DONE, /**< Passed to event handler block write operation is done*/
} nrf_block_dev_event_type_t;
typedef enum {
NRF_BLOCK_DEV_RESULT_SUCCESS = 0, /**< Operation completed succsefully*/
NRF_BLOCK_DEV_RESULT_IO_ERROR, /**< I/O error*/
NRF_BLOCK_DEV_RESULT_TIMEOUT, /**< Device timeout*/
} nrf_block_dev_result_t;
/**
* @brief Block device event
* */
typedef struct {
nrf_block_dev_event_type_t ev_type; //!< Event type
nrf_block_dev_result_t result; //!< Operation status
nrf_block_req_t const * p_blk_req; //!< Block request
void const * p_context; //!< Event context
} nrf_block_dev_event_t;
struct nrf_block_dev_s;
/**
* @brief Block device event handler.
*
* @param[in] p_blk_dev Block device handle
* @param[in] p_event Block device event
*/
typedef void (* nrf_block_dev_ev_handler)(struct nrf_block_dev_s const * p_blk_dev,
nrf_block_dev_event_t const * p_event);
/**
* @brief Block device geometry
*/
typedef struct {
uint32_t blk_count; //!< Block count
uint32_t blk_size; //!< Block size
} nrf_block_dev_geometry_t;
/**
* @brief Block device information strings
*/
typedef struct {
const char * p_vendor; //!< Vendor string
const char * p_product; //!< Product string
const char * p_revision; //!< Revision string
} nrf_block_dev_info_strings_t;
/**
* @brief Block device information config
*
* @param vendor Vendor string
* @param product Product string
* @param revision Revision string
* */
#define NFR_BLOCK_DEV_INFO_CONFIG(vendor, product, revision) ( { \
.p_vendor = vendor, \
.p_product = product, \
.p_revision = revision, \
})
/**
* @brief Empty info string initializer
* */
#define NFR_BLOCK_DEV_INFO_CONFIG_EMPTY \
NFR_BLOCK_DEV_INFO_CONFIG(NULL, NULL, NULL)
/**
* @brief Block device IOCTL requests
*/
typedef enum {
NRF_BLOCK_DEV_IOCTL_REQ_CACHE_FLUSH = 0, /**< Cache flush IOCTL request*/
NRF_BLOCK_DEV_IOCTL_REQ_INFO_STRINGS, /**< Get info strings IOCTL request*/
} nrf_block_dev_ioctl_req_t;
/**
* @brief Helper macro to get block device address from specific instance
*
* @param instance Block device instance
* @param member Block device member name
* */
#define NRF_BLOCKDEV_BASE_ADDR(instance, member) &(instance).member
/**
* @brief Block device API
* */
typedef struct nrf_block_dev_s {
struct nrf_block_dev_ops_s {
/**
* @brief @ref nrf_blk_dev_init
*/
ret_code_t (*init)(struct nrf_block_dev_s const * p_blk_dev,
nrf_block_dev_ev_handler ev_handler,
void const * p_context);
/**
* @brief @ref nrf_blk_dev_uninit
*/
ret_code_t (*uninit)(struct nrf_block_dev_s const * p_blk_dev);
/**
* @brief @ref nrf_blk_dev_read_req
*/
ret_code_t (*read_req)(struct nrf_block_dev_s const * p_blk_dev,
nrf_block_req_t const * p_blk);
/**
* @brief @ref nrf_blk_dev_write_req
*/
ret_code_t (*write_req)(struct nrf_block_dev_s const * p_blk_dev,
nrf_block_req_t const * p_blk);
/**
* @brief @ref nrf_blk_dev_ioctl
*/
ret_code_t (*ioctl)(struct nrf_block_dev_s const * p_blk_dev,
nrf_block_dev_ioctl_req_t req,
void * p_data);
/**
* @brief @ref nrf_blk_dev_geometry
*/
nrf_block_dev_geometry_t const * (*geometry)(struct nrf_block_dev_s const * p_blk_dev);
} const * p_ops;
} nrf_block_dev_t;
/**
* @brief Internals of @ref nrf_block_dev_t
* */
typedef struct nrf_block_dev_ops_s nrf_block_dev_ops_t;
/**
* @brief Initializes a block device.
*
* @param[in] p_blk_dev Block device handle
* @param[in] ev_handler Event handler (pass NULL to work in synchronous mode)
* @param[in] p_context Context passed to event handler
*
* @return Standard error code
*/
static inline ret_code_t nrf_blk_dev_init(nrf_block_dev_t const * p_blk_dev,
nrf_block_dev_ev_handler ev_handler,
void const * p_context)
{
ASSERT(p_blk_dev->p_ops->init);
return p_blk_dev->p_ops->init(p_blk_dev, ev_handler, p_context);
}
/**
* @brief Un-initializes a block device.
*
* @param[in] p_blk_dev Block device handle
*
* @return Standard error code
*/
static inline ret_code_t nrf_blk_dev_uninit(nrf_block_dev_t const * p_blk_dev)
{
ASSERT(p_blk_dev->p_ops->uninit);
return p_blk_dev->p_ops->uninit(p_blk_dev);
}
/**
* @brief Block read request.
*
* In synchronous mode this function will execute the read operation
* and wait for its completion. In asynchronous mode the function will only request
* the operation and return immediately. Then, the @ref NRF_BLOCK_DEV_EVT_BLK_READ_DONE
* event will signal that operation has been completed and the specified buffer contains
* valid data.
*
* @param[in] p_blk_dev Block device handle
* @param[in] p_blk Block device request
*
* @return Standard error code
*/
static inline ret_code_t nrf_blk_dev_read_req(nrf_block_dev_t const * p_blk_dev,
nrf_block_req_t const * p_blk)
{
ASSERT(p_blk_dev->p_ops->read_req);
ASSERT(p_blk_dev->p_ops->geometry);
if (p_blk->blk_id >= p_blk_dev->p_ops->geometry(p_blk_dev)->blk_count)
{
return NRF_ERROR_INVALID_PARAM;
}
return p_blk_dev->p_ops->read_req(p_blk_dev, p_blk);
}
/**
* @brief Block write request.
*
* In synchronous mode this function will execute the write operation
* and wait for its completion. In asynchronous mode the function will only request
* the operation and return immediately. Then, the @ref NRF_BLOCK_DEV_EVT_BLK_WRITE_DONE
* event will signal that operation has been completed and the specified buffer
* can be freed.
*
* @param[in] p_blk_dev Block device handle
* @param[in] p_blk Block device request
*
* @return Standard error code
*/
static inline ret_code_t nrf_blk_dev_write_req(nrf_block_dev_t const * p_blk_dev,
nrf_block_req_t const * p_blk)
{
ASSERT(p_blk_dev->p_ops->write_req);
ASSERT(p_blk_dev->p_ops->geometry);
if (p_blk->blk_id >= p_blk_dev->p_ops->geometry(p_blk_dev)->blk_count)
{
return NRF_ERROR_INVALID_PARAM;
}
return p_blk_dev->p_ops->write_req(p_blk_dev, p_blk);
}
/**
* @brief IO control function.
*
* @param[in] p_blk_dev Block device handle
* @param[in] req Block device ioctl request
* @param[in] p_data Block device ioctl data
*
* @return Standard error code
* */
static inline ret_code_t nrf_blk_dev_ioctl(nrf_block_dev_t const * p_blk_dev,
nrf_block_dev_ioctl_req_t req,
void * p_data)
{
ASSERT(p_blk_dev->p_ops->ioctl);
return p_blk_dev->p_ops->ioctl(p_blk_dev, req, p_data);
}
/**
* @brief Return a geometry of a block device.
*
* @param[in] p_blk_dev Block device handle
*
* @return Block size and count @ref nrf_block_dev_geometry_t
*/
static inline nrf_block_dev_geometry_t const *
nrf_blk_dev_geometry(nrf_block_dev_t const * p_blk_dev)
{
ASSERT(p_blk_dev->p_ops->geometry);
return p_blk_dev->p_ops->geometry(p_blk_dev);
}
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* NRF_BLOCK_DEV_H__ */

View File

@@ -1,831 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sdk_common.h"
#if NRF_MODULE_ENABLED(NRF_BLOCK_DEV_QSPI)
#include "nrf_serial_flash_params.h"
#include "nrf_block_dev_qspi.h"
#include <inttypes.h>
/**@file
*
* @ingroup nrf_block_dev_qspi
* @{
*
* @brief This module implements block device API. It should be used as a reference block device.
*/
#if NRF_BLOCK_DEV_QSPI_CONFIG_LOG_ENABLED
#define NRF_LOG_LEVEL NRF_BLOCK_DEV_QSPI_CONFIG_LOG_LEVEL
#define NRF_LOG_INFO_COLOR NRF_BLOCK_DEV_QSPI_CONFIG_INFO_COLOR
#define NRF_LOG_DEBUG_COLOR NRF_BLOCK_DEV_QSPI_CONFIG_DEBUG_COLOR
#else
#define NRF_LOG_LEVEL 0
#endif
#include "nrf_log.h"
#define QSPI_STD_CMD_WRSR 0x01 /**< Write status register command*/
#define QSPI_STD_CMD_RSTEN 0x66 /**< Reset enable command*/
#define QSPI_STD_CMD_RST 0x99 /**< Reset command*/
#define QSPI_STD_CMD_READ_ID 0x9F /**< Read ID command*/
#define BD_PAGE_PROGRAM_SIZE 256 /**< Page program size (minimum block size)*/
#define BD_ERASE_UNIT_INVALID_ID 0xFFFFFFFF /**< Invalid erase unit number*/
#define BD_ERASE_UNIT_ERASE_VAL 0xFFFFFFFF /**< Erased memory value*/
/**
* @brief Block to erase unit translation
*
* @param blk_id Block index
* @param blk_size Block size
* */
#define BD_BLOCK_TO_ERASEUNIT(blk_id, blk_size) \
((blk_id) * (blk_size)) / (NRF_BLOCK_DEV_QSPI_ERASE_UNIT_SIZE)
/**
* @brief Blocks per erase unit
*
* @param blk_size Block size
* */
#define BD_BLOCKS_PER_ERASEUNIT(blk_size) \
(NRF_BLOCK_DEV_QSPI_ERASE_UNIT_SIZE / (blk_size))
static ret_code_t block_dev_qspi_eunit_write(nrf_block_dev_qspi_t const * p_qspi_dev,
nrf_block_req_t * p_blk_left);
static void block_dev_qspi_read_from_eunit(nrf_block_dev_qspi_t const * p_qspi_dev)
{
nrf_block_dev_qspi_work_t const * p_work = p_qspi_dev->p_work;
/*In write-back mode data that we read might not be the same as in erase unit buffer*/
uint32_t eunit_start = BD_BLOCK_TO_ERASEUNIT(p_work->req.blk_id,
p_work->geometry.blk_size);
uint32_t eunit_end = BD_BLOCK_TO_ERASEUNIT(p_work->req.blk_id + p_work->req.blk_count,
p_work->geometry.blk_size);
if ((eunit_start > p_work->erase_unit_idx) || (eunit_end < p_work->erase_unit_idx))
{
/*Do nothing. Read request doesn't hit current cached erase unit*/
return;
}
/*Case 1: Copy data from start erase unit*/
if (eunit_start == p_work->erase_unit_idx)
{
size_t blk = p_work->req.blk_id %
BD_BLOCKS_PER_ERASEUNIT(p_work->geometry.blk_size);
size_t cnt = BD_BLOCKS_PER_ERASEUNIT(p_work->geometry.blk_size) - blk;
size_t off = p_work->geometry.blk_size * blk;
if (cnt > p_work->req.blk_count)
{
cnt = p_work->req.blk_count;
}
memcpy(p_work->req.p_buff,
p_work->p_erase_unit_buff + off,
cnt * p_work->geometry.blk_size);
return;
}
/*Case 2: Copy data from end erase unit*/
if (eunit_end == p_work->erase_unit_idx)
{
size_t cnt = (p_work->req.blk_id + p_work->req.blk_count) %
BD_BLOCKS_PER_ERASEUNIT(p_work->geometry.blk_size);
size_t off = (p_work->erase_unit_idx * BD_BLOCKS_PER_ERASEUNIT(p_work->geometry.blk_size) -
p_work->req.blk_id) * p_work->geometry.blk_size;
if (cnt > p_work->req.blk_count)
{
cnt = p_work->req.blk_count;
}
memcpy((uint8_t *)p_work->req.p_buff + off,
p_work->p_erase_unit_buff,
cnt * p_work->geometry.blk_size);
return;
}
/*Case 3: Copy data from eunit_start < p_work->erase_unit_idx < eunit_end*/
size_t off = (p_work->erase_unit_idx * BD_BLOCKS_PER_ERASEUNIT(p_work->geometry.blk_size) -
p_work->req.blk_id) * p_work->geometry.blk_size;
memcpy((uint8_t *)p_work->req.p_buff + off,
p_work->p_erase_unit_buff,
NRF_BLOCK_DEV_QSPI_ERASE_UNIT_SIZE);
}
/**
* @brief Active QSPI block device handle. Only one instance.
* */
static nrf_block_dev_qspi_t const * m_active_qspi_dev;
static void qspi_handler(nrf_drv_qspi_evt_t event, void * p_context)
{
if (m_active_qspi_dev != p_context)
{
return;
}
nrf_block_dev_qspi_t const * p_qspi_dev = p_context;
nrf_block_dev_qspi_work_t * p_work = p_qspi_dev->p_work;
nrf_block_req_t * p_blk_left = &p_work->left_req;
switch (p_work->state)
{
case NRF_BLOCK_DEV_QSPI_STATE_READ_EXEC:
{
if (p_work->writeback_mode)
{
block_dev_qspi_read_from_eunit(p_qspi_dev);
}
p_work->state = NRF_BLOCK_DEV_QSPI_STATE_IDLE;
if (p_work->ev_handler)
{
const nrf_block_dev_event_t ev = {
NRF_BLOCK_DEV_EVT_BLK_READ_DONE,
NRF_BLOCK_DEV_RESULT_SUCCESS,
&p_work->req,
p_work->p_context
};
p_work->ev_handler(&p_qspi_dev->block_dev, &ev);
}
break;
}
case NRF_BLOCK_DEV_QSPI_STATE_EUNIT_LOAD:
{
ret_code_t ret;
uint32_t erase_unit = BD_BLOCK_TO_ERASEUNIT(p_blk_left->blk_id,
p_work->geometry.blk_size);
UNUSED_VARIABLE(erase_unit);
ASSERT(erase_unit == p_work->erase_unit_idx);
/* Check if block is in erase unit buffer*/
ret = block_dev_qspi_eunit_write(p_qspi_dev, p_blk_left);
ASSERT(ret == NRF_SUCCESS);
UNUSED_VARIABLE(ret);
break;
}
case NRF_BLOCK_DEV_QSPI_STATE_WRITE_ERASE:
case NRF_BLOCK_DEV_QSPI_STATE_WRITE_EXEC:
{
/*Clear last programmed block*/
uint32_t block_to_program = __CLZ(__RBIT(p_work->erase_unit_dirty_blocks));
if (p_work->state == NRF_BLOCK_DEV_QSPI_STATE_WRITE_EXEC)
{
p_work->erase_unit_dirty_blocks ^= 1u << block_to_program;
}
if (p_work->erase_unit_dirty_blocks == 0)
{
if (p_work->left_req.blk_count)
{
/*Load next erase unit*/
ret_code_t ret;
uint32_t eunit = BD_BLOCK_TO_ERASEUNIT(p_blk_left->blk_id,
p_work->geometry.blk_size);
p_work->erase_unit_idx = eunit;
p_work->state = NRF_BLOCK_DEV_QSPI_STATE_EUNIT_LOAD;
ret = nrf_drv_qspi_read(p_work->p_erase_unit_buff,
NRF_BLOCK_DEV_QSPI_ERASE_UNIT_SIZE,
p_work->erase_unit_idx *
NRF_BLOCK_DEV_QSPI_ERASE_UNIT_SIZE);
UNUSED_VARIABLE(ret);
break;
}
/*All blocks are programmed. Call event handler if required.*/
p_work->state = NRF_BLOCK_DEV_QSPI_STATE_IDLE;
if (p_work->ev_handler && !p_work->cache_flushing)
{
const nrf_block_dev_event_t ev = {
NRF_BLOCK_DEV_EVT_BLK_WRITE_DONE,
NRF_BLOCK_DEV_RESULT_SUCCESS,
&p_work->req,
p_work->p_context
};
p_work->ev_handler(&p_qspi_dev->block_dev, &ev);
}
p_work->cache_flushing = false;
break;
}
/*Get next block to program from program mask*/
block_to_program = __CLZ(__RBIT(p_work->erase_unit_dirty_blocks));
uint32_t dst_address = (p_work->erase_unit_idx * NRF_BLOCK_DEV_QSPI_ERASE_UNIT_SIZE) +
(block_to_program * p_work->geometry.blk_size);
const void * p_src_address = p_work->p_erase_unit_buff +
block_to_program * p_work->geometry.blk_size;
p_work->state = NRF_BLOCK_DEV_QSPI_STATE_WRITE_EXEC;
ret_code_t ret = nrf_drv_qspi_write(p_src_address,
p_work->geometry.blk_size,
dst_address);
UNUSED_VARIABLE(ret);
break;
}
default:
ASSERT(0);
break;
}
}
static void wait_for_idle(nrf_block_dev_qspi_t const * p_qspi_dev)
{
nrf_block_dev_qspi_work_t * p_work = p_qspi_dev->p_work;
while (p_work->state != NRF_BLOCK_DEV_QSPI_STATE_IDLE)
{
__WFI();
}
}
static ret_code_t block_dev_qspi_init(nrf_block_dev_t const * p_blk_dev,
nrf_block_dev_ev_handler ev_handler,
void const * p_context)
{
ASSERT(p_blk_dev);
nrf_block_dev_qspi_t const * p_qspi_dev =
CONTAINER_OF(p_blk_dev, nrf_block_dev_qspi_t, block_dev);
nrf_block_dev_qspi_work_t * p_work = p_qspi_dev->p_work;
nrf_drv_qspi_config_t const * p_qspi_cfg = &p_qspi_dev->qspi_bdev_config.qspi_config;
ret_code_t ret = NRF_SUCCESS;
NRF_LOG_INST_DEBUG(p_qspi_dev->p_log, "Init");
if (p_qspi_dev->qspi_bdev_config.block_size % BD_PAGE_PROGRAM_SIZE)
{
/*Unsupported block size*/
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "Unsupported block size because of program page size");
return NRF_ERROR_NOT_SUPPORTED;
}
if (NRF_BLOCK_DEV_QSPI_ERASE_UNIT_SIZE % p_qspi_dev->qspi_bdev_config.block_size)
{
/*Unsupported block size*/
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "Unsupported block size because of erase unit size");
return NRF_ERROR_NOT_SUPPORTED;
}
if (m_active_qspi_dev)
{
/* QSPI instance is BUSY*/
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "Cannot init because QSPI is busy");
return NRF_ERROR_BUSY;
}
ret = nrf_drv_qspi_init(p_qspi_cfg, qspi_handler, (void *)p_blk_dev);
if (ret != NRF_SUCCESS)
{
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "QSPI init error: %"PRIu32"", ret);
return ret;
}
nrf_qspi_cinstr_conf_t cinstr_cfg = {
.opcode = QSPI_STD_CMD_RSTEN,
.length = NRF_QSPI_CINSTR_LEN_1B,
.io2_level = true,
.io3_level = true,
.wipwait = true,
.wren = true
};
/* Send reset enable */
ret = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);
if (ret != NRF_SUCCESS)
{
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "QSPI reset enable command error: %"PRIu32"", ret);
return ret;
}
/* Send reset command */
cinstr_cfg.opcode = QSPI_STD_CMD_RST;
ret = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);
if (ret != NRF_SUCCESS)
{
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "QSPI reset command error: %"PRIu32"", ret);
return ret;
}
/* Get 3 byte identification value */
uint8_t rdid_buf[3] = {0, 0, 0};
cinstr_cfg.opcode = QSPI_STD_CMD_READ_ID;
cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_4B;
ret = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, NULL, rdid_buf);
if (ret != NRF_SUCCESS)
{
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "QSPI get 3 byte id error: %"PRIu32"", ret);
return ret;
}
nrf_serial_flash_params_t const * serial_flash_id = nrf_serial_flash_params_get(rdid_buf);
if (!serial_flash_id)
{
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "QSPI FLASH not supported");
return NRF_ERROR_NOT_SUPPORTED;
}
if (serial_flash_id->erase_size != NRF_BLOCK_DEV_QSPI_ERASE_UNIT_SIZE)
{
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "QSPI FLASH erase unit size not supported");
return NRF_ERROR_NOT_SUPPORTED;
}
/* Calculate block device geometry.... */
uint32_t blk_size = p_qspi_dev->qspi_bdev_config.block_size;
uint32_t blk_count = serial_flash_id->size / p_qspi_dev->qspi_bdev_config.block_size;
if (!blk_count || (blk_count % BD_BLOCKS_PER_ERASEUNIT(blk_size)))
{
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "QSPI FLASH block size not supported");
return NRF_ERROR_NOT_SUPPORTED;
}
p_work->geometry.blk_size = blk_size;
p_work->geometry.blk_count = blk_count;
p_work->p_context = p_context;
p_work->ev_handler = ev_handler;
p_work->state = NRF_BLOCK_DEV_QSPI_STATE_IDLE;
p_work->erase_unit_idx = BD_ERASE_UNIT_INVALID_ID;
p_work->writeback_mode = (p_qspi_dev->qspi_bdev_config.flags &
NRF_BLOCK_DEV_QSPI_FLAG_CACHE_WRITEBACK) != 0;
m_active_qspi_dev = p_qspi_dev;
if (p_work->ev_handler)
{
/*Asynchronous operation (simulation)*/
const nrf_block_dev_event_t ev = {
NRF_BLOCK_DEV_EVT_INIT,
NRF_BLOCK_DEV_RESULT_SUCCESS,
NULL,
p_work->p_context
};
p_work->ev_handler(p_blk_dev, &ev);
}
return NRF_SUCCESS;
}
static ret_code_t block_dev_qspi_uninit(nrf_block_dev_t const * p_blk_dev)
{
ASSERT(p_blk_dev);
nrf_block_dev_qspi_t const * p_qspi_dev =
CONTAINER_OF(p_blk_dev, nrf_block_dev_qspi_t, block_dev);
nrf_block_dev_qspi_work_t * p_work = p_qspi_dev->p_work;
NRF_LOG_INST_DEBUG(p_qspi_dev->p_log, "Uninit");
if (m_active_qspi_dev != p_qspi_dev)
{
/* QSPI instance is BUSY*/
return NRF_ERROR_BUSY;
}
if (p_work->state != NRF_BLOCK_DEV_QSPI_STATE_IDLE)
{
/* Previous asynchronous operation in progress*/
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "Cannot uninit because QSPI is busy");
return NRF_ERROR_BUSY;
}
if (p_work->ev_handler)
{
/*Asynchronous operation*/
const nrf_block_dev_event_t ev = {
NRF_BLOCK_DEV_EVT_UNINIT,
NRF_BLOCK_DEV_RESULT_SUCCESS,
NULL,
p_work->p_context
};
p_work->ev_handler(p_blk_dev, &ev);
}
p_work->state = NRF_BLOCK_DEV_QSPI_STATE_DISABLED;
nrf_drv_qspi_uninit();
memset(p_work, 0, sizeof(nrf_block_dev_qspi_work_t));
m_active_qspi_dev = NULL;
return NRF_SUCCESS;
}
static ret_code_t block_dev_qspi_read_req(nrf_block_dev_t const * p_blk_dev,
nrf_block_req_t const * p_blk)
{
ASSERT(p_blk_dev);
ASSERT(p_blk);
nrf_block_dev_qspi_t const * p_qspi_dev =
CONTAINER_OF(p_blk_dev, nrf_block_dev_qspi_t, block_dev);
nrf_block_dev_qspi_work_t * p_work = p_qspi_dev->p_work;
ret_code_t ret = NRF_SUCCESS;
NRF_LOG_INST_DEBUG(
p_qspi_dev->p_log,
"Read req from block %"PRIu32" size %"PRIu32"(x%"PRIu32") to %"PRIXPTR,
p_blk->blk_id,
p_blk->blk_count,
p_blk_dev->p_ops->geometry(p_blk_dev)->blk_size,
p_blk->p_buff);
if ((p_blk->blk_id + p_blk->blk_count) > p_work->geometry.blk_count)
{
NRF_LOG_INST_ERROR(
p_qspi_dev->p_log,
"Out of range read req block %"PRIu32" count %"PRIu32" while max is %"PRIu32,
p_blk->blk_id,
p_blk->blk_count,
p_blk_dev->p_ops->geometry(p_blk_dev)->blk_count);
return NRF_ERROR_INVALID_ADDR;
}
if (m_active_qspi_dev != p_qspi_dev)
{
/* QSPI instance is BUSY*/
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "Cannot read because QSPI is busy");
return NRF_ERROR_BUSY;
}
if (p_work->state != NRF_BLOCK_DEV_QSPI_STATE_IDLE)
{
/* Previous asynchronous operation in progress*/
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "Cannot read because of ongoing previous operation");
return NRF_ERROR_BUSY;
}
p_work->left_req = *p_blk;
p_work->req = *p_blk;
nrf_block_req_t * p_blk_left = &p_work->left_req;
p_work->state = NRF_BLOCK_DEV_QSPI_STATE_READ_EXEC;
ret = nrf_drv_qspi_read(p_blk_left->p_buff,
p_blk_left->blk_count * p_work->geometry.blk_size,
p_blk_left->blk_id * p_work->geometry.blk_size);
if (ret != NRF_SUCCESS)
{
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "QSPI read error: %"PRIu32"", ret);
p_work->state = NRF_BLOCK_DEV_QSPI_STATE_IDLE;
return ret;
}
p_blk_left->p_buff = NULL;
p_blk_left->blk_count = 0;
if (!p_work->ev_handler && (p_work->state != NRF_BLOCK_DEV_QSPI_STATE_IDLE))
{
/*Synchronous operation*/
wait_for_idle(p_qspi_dev);
}
return ret;
}
static bool block_dev_qspi_update_eunit(nrf_block_dev_qspi_t const * p_qspi_dev,
size_t off,
const void * p_src,
size_t len)
{
ASSERT((len % sizeof(uint32_t)) == 0)
nrf_block_dev_qspi_work_t * p_work = p_qspi_dev->p_work;
uint32_t * p_dst32 = (uint32_t *)(p_work->p_erase_unit_buff + off);
const uint32_t * p_src32 = p_src;
bool erase_required = false;
len /= sizeof(uint32_t);
/*Do normal copying until erase unit is not required*/
do
{
if (*p_dst32 != *p_src32)
{
if (*p_dst32 != BD_ERASE_UNIT_ERASE_VAL)
{
erase_required = true;
}
/*Mark block as dirty*/
p_work->erase_unit_dirty_blocks |= 1u << (off / p_work->geometry.blk_size);
}
*p_dst32++ = *p_src32++;
off += sizeof(uint32_t);
} while (--len);
return erase_required;
}
static ret_code_t block_dev_qspi_write_start(nrf_block_dev_qspi_t const * p_qspi_dev)
{
nrf_block_dev_qspi_work_t * p_work = p_qspi_dev->p_work;
if (!p_work->erase_required)
{
/*Get first block to program from program mask*/
uint32_t block_to_program = __CLZ(__RBIT(p_work->erase_unit_dirty_blocks));
uint32_t dst_address = (p_work->erase_unit_idx * NRF_BLOCK_DEV_QSPI_ERASE_UNIT_SIZE) +
(block_to_program * p_work->geometry.blk_size);
const void * p_src_address = p_work->p_erase_unit_buff +
block_to_program * p_work->geometry.blk_size;
p_work->state = NRF_BLOCK_DEV_QSPI_STATE_WRITE_EXEC;
return nrf_drv_qspi_write(p_src_address,
p_work->geometry.blk_size,
dst_address);
}
/*Erase is required*/
uint32_t address = (p_work->erase_unit_idx * NRF_BLOCK_DEV_QSPI_ERASE_UNIT_SIZE);
p_work->state = NRF_BLOCK_DEV_QSPI_STATE_WRITE_ERASE;
p_work->erase_required = false;
return nrf_drv_qspi_erase(NRF_QSPI_ERASE_LEN_4KB, address);
}
static ret_code_t block_dev_qspi_eunit_write(nrf_block_dev_qspi_t const * p_qspi_dev,
nrf_block_req_t * p_blk_left)
{
nrf_block_dev_qspi_work_t * p_work = p_qspi_dev->p_work;
size_t blk = p_blk_left->blk_id %
BD_BLOCKS_PER_ERASEUNIT(p_work->geometry.blk_size);
size_t cnt = BD_BLOCKS_PER_ERASEUNIT(p_work->geometry.blk_size) - blk;
size_t off = p_work->geometry.blk_size * blk;
if (cnt > p_blk_left->blk_count)
{
cnt = p_blk_left->blk_count;
}
bool erase_required = block_dev_qspi_update_eunit(p_qspi_dev,
off,
p_blk_left->p_buff,
cnt * p_work->geometry.blk_size);
if (erase_required)
{
p_work->erase_required = true;
}
p_blk_left->blk_count -= cnt;
p_blk_left->blk_id += cnt;
p_blk_left->p_buff = (uint8_t *)p_blk_left->p_buff + cnt * p_work->geometry.blk_size;
if (p_work->erase_required)
{
uint32_t blk_size = p_work->geometry.blk_size;
p_work->erase_unit_dirty_blocks |= (1u << BD_BLOCKS_PER_ERASEUNIT(blk_size)) - 1;
}
if (p_work->erase_unit_dirty_blocks == 0 || p_work->writeback_mode)
{
/*No dirty blocks detected. Write end.*/
if (p_work->ev_handler && p_blk_left->blk_count == 0)
{
const nrf_block_dev_event_t ev = {
NRF_BLOCK_DEV_EVT_BLK_WRITE_DONE,
NRF_BLOCK_DEV_RESULT_SUCCESS,
&p_work->req,
p_work->p_context
};
p_work->state = NRF_BLOCK_DEV_QSPI_STATE_IDLE;
p_work->ev_handler(&p_qspi_dev->block_dev, &ev);
return NRF_SUCCESS;
}
}
return block_dev_qspi_write_start(p_qspi_dev);
}
static ret_code_t block_dev_qspi_write_req(nrf_block_dev_t const * p_blk_dev,
nrf_block_req_t const * p_blk)
{
ASSERT(p_blk_dev);
ASSERT(p_blk);
nrf_block_dev_qspi_t const * p_qspi_dev =
CONTAINER_OF(p_blk_dev, nrf_block_dev_qspi_t, block_dev);
nrf_block_dev_qspi_work_t * p_work = p_qspi_dev->p_work;
ret_code_t ret = NRF_SUCCESS;
NRF_LOG_INST_DEBUG(
p_qspi_dev->p_log,
"Write req to block %"PRIu32" size %"PRIu32"(x%"PRIu32") from %"PRIXPTR,
p_blk->blk_id,
p_blk->blk_count,
p_blk_dev->p_ops->geometry(p_blk_dev)->blk_size,
p_blk->p_buff);
if ((p_blk->blk_id + p_blk->blk_count) > p_work->geometry.blk_count)
{
NRF_LOG_INST_ERROR(
p_qspi_dev->p_log,
"Out of range write req block %"PRIu32" count %"PRIu32" while max is %"PRIu32,
p_blk->blk_id,
p_blk->blk_count,
p_blk_dev->p_ops->geometry(p_blk_dev)->blk_count);
return NRF_ERROR_INVALID_ADDR;
}
if (m_active_qspi_dev != p_qspi_dev)
{
/* QSPI instance is BUSY*/
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "Cannot write because QSPI is busy");
return NRF_ERROR_BUSY;
}
if (p_work->state != NRF_BLOCK_DEV_QSPI_STATE_IDLE)
{
/* Previous asynchronous operation in progress*/
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "Cannot write because of ongoing previous operation");
return NRF_ERROR_BUSY;
}
p_work->left_req = *p_blk;
p_work->req = *p_blk;
nrf_block_req_t * p_blk_left = &p_work->left_req;
uint32_t erase_unit = BD_BLOCK_TO_ERASEUNIT(p_blk_left->blk_id,
p_work->geometry.blk_size);
/* Check if block is in erase unit buffer*/
if (erase_unit == p_work->erase_unit_idx)
{
ret = block_dev_qspi_eunit_write(p_qspi_dev, p_blk_left);
}
else
{
if (p_work->writeback_mode &&
p_work->erase_unit_idx != BD_ERASE_UNIT_INVALID_ID &&
p_work->erase_unit_dirty_blocks)
{
ret = block_dev_qspi_write_start(p_qspi_dev);
}
else
{
p_work->erase_unit_idx = erase_unit;
p_work->state = NRF_BLOCK_DEV_QSPI_STATE_EUNIT_LOAD;
ret = nrf_drv_qspi_read(p_work->p_erase_unit_buff,
NRF_BLOCK_DEV_QSPI_ERASE_UNIT_SIZE,
erase_unit * NRF_BLOCK_DEV_QSPI_ERASE_UNIT_SIZE);
}
}
if (ret != NRF_SUCCESS)
{
NRF_LOG_INST_ERROR(p_qspi_dev->p_log, "QSPI write error: %"PRIu32"", ret);
p_work->state = NRF_BLOCK_DEV_QSPI_STATE_IDLE;
return ret;
}
if (!p_work->ev_handler && (p_work->state != NRF_BLOCK_DEV_QSPI_STATE_IDLE))
{
/*Synchronous operation*/
wait_for_idle(p_qspi_dev);
}
return ret;
}
static ret_code_t block_dev_qspi_ioctl(nrf_block_dev_t const * p_blk_dev,
nrf_block_dev_ioctl_req_t req,
void * p_data)
{
ASSERT(p_blk_dev);
nrf_block_dev_qspi_t const * p_qspi_dev =
CONTAINER_OF(p_blk_dev, nrf_block_dev_qspi_t, block_dev);
nrf_block_dev_qspi_work_t * p_work = p_qspi_dev->p_work;
switch (req)
{
case NRF_BLOCK_DEV_IOCTL_REQ_CACHE_FLUSH:
{
bool * p_flushing = p_data;
NRF_LOG_INST_DEBUG(p_qspi_dev->p_log, "IOCtl: Cache flush");
if (p_work->state != NRF_BLOCK_DEV_QSPI_STATE_IDLE)
{
return NRF_ERROR_BUSY;
}
if (!p_work->writeback_mode || p_work->erase_unit_dirty_blocks == 0)
{
if (p_flushing)
{
*p_flushing = false;
}
return NRF_SUCCESS;
}
ret_code_t ret = block_dev_qspi_write_start(p_qspi_dev);
if (ret == NRF_SUCCESS)
{
if (p_flushing)
{
*p_flushing = true;
}
p_work->cache_flushing = true;
}
return ret;
}
case NRF_BLOCK_DEV_IOCTL_REQ_INFO_STRINGS:
{
if (p_data == NULL)
{
return NRF_ERROR_INVALID_PARAM;
}
nrf_block_dev_info_strings_t const * * pp_strings = p_data;
*pp_strings = &p_qspi_dev->info_strings;
return NRF_SUCCESS;
}
default:
break;
}
return NRF_ERROR_NOT_SUPPORTED;
}
static nrf_block_dev_geometry_t const * block_dev_qspi_geometry(nrf_block_dev_t const * p_blk_dev)
{
ASSERT(p_blk_dev);
nrf_block_dev_qspi_t const * p_qspi_dev =
CONTAINER_OF(p_blk_dev, nrf_block_dev_qspi_t, block_dev);
nrf_block_dev_qspi_work_t const * p_work = p_qspi_dev->p_work;
return &p_work->geometry;
}
const nrf_block_dev_ops_t nrf_block_device_qspi_ops = {
.init = block_dev_qspi_init,
.uninit = block_dev_qspi_uninit,
.read_req = block_dev_qspi_read_req,
.write_req = block_dev_qspi_write_req,
.ioctl = block_dev_qspi_ioctl,
.geometry = block_dev_qspi_geometry,
};
/** @} */
#endif // NRF_MODULE_ENABLED(NRF_BLOCK_DEV_QSPI)

View File

@@ -1,185 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF_BLOCK_DEV_QSPI_H__
#define NRF_BLOCK_DEV_QSPI_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "nrf_block_dev.h"
#include "nrf_drv_qspi.h"
#include "nrf_log_instance.h"
/**@file
*
* @defgroup nrf_block_dev_qspi QSPI implementation
* @ingroup nrf_block_dev
* @{
*
*/
/**
* @brief QSPI block device operations
* */
extern const nrf_block_dev_ops_t nrf_block_device_qspi_ops;
/**
* @brief QSPI block device internal erase unit buffer size
* */
#define NRF_BLOCK_DEV_QSPI_ERASE_UNIT_SIZE (4096)
/**
* @brief Internal Block device state
*/
typedef enum {
NRF_BLOCK_DEV_QSPI_STATE_DISABLED = 0, /**< QSPI block device state DISABLED */
NRF_BLOCK_DEV_QSPI_STATE_IDLE, /**< QSPI block device state IDLE */
NRF_BLOCK_DEV_QSPI_STATE_READ_EXEC, /**< QSPI block device state READ_EXEC */
NRF_BLOCK_DEV_QSPI_STATE_EUNIT_LOAD, /**< QSPI block device state EUNIT_LOAD */
NRF_BLOCK_DEV_QSPI_STATE_WRITE_ERASE, /**< QSPI block device state WRITE_ERASE */
NRF_BLOCK_DEV_QSPI_STATE_WRITE_EXEC, /**< QSPI block device state WRITE_EXEC */
} nrf_block_dev_qspi_state_t;
/**
* @brief Work structure of QSPI block device
*/
typedef struct {
volatile nrf_block_dev_qspi_state_t state; //!< QSPI block device state
nrf_block_dev_geometry_t geometry; //!< Block device geometry
nrf_block_dev_ev_handler ev_handler; //!< Block device event handler
void const * p_context; //!< Context handle passed to event handler
nrf_block_req_t req; //!< Block READ/WRITE request: original value
nrf_block_req_t left_req; //!< Block READ/WRITE request: left value
bool cache_flushing; //!< QSPI cache flush in progress flag
bool writeback_mode; //!< QSPI write-back mode flag
bool erase_required; //!< QSPI erase required flag
uint32_t erase_unit_idx; //!< QSPI erase unit index
uint32_t erase_unit_dirty_blocks; //!< QSPI erase unit dirty blocks mask
uint8_t p_erase_unit_buff[NRF_BLOCK_DEV_QSPI_ERASE_UNIT_SIZE]; //!< QSPI erase unit buffer (fixed value)
} nrf_block_dev_qspi_work_t;
/**
* @brief QSPI block device flags*/
typedef enum {
NRF_BLOCK_DEV_QSPI_FLAG_CACHE_WRITEBACK = (1u << 0) //!< Cache write-back mode enable flag
} nrf_block_dev_qspi_flag_t;
/** @brief Name of the module used for logger messaging.
*/
#define NRF_BLOCK_DEV_QSPI_LOG_NAME block_dev_qspi
/**
* @brief QSPI block device config initializer (@ref nrf_block_dev_qspi_config_t)
*
* @param blk_size Block size
* @param blk_flags Block device flags, @ref nrf_block_dev_qspi_flag_t
* @param qspi_drv_config QPSI driver config
* */
#define NRF_BLOCK_DEV_QSPI_CONFIG(blk_size, blk_flags, qspi_drv_config) { \
.block_size = (blk_size), \
.flags = (blk_flags), \
.qspi_config = qspi_drv_config \
}
/**
* @brief QSPI block device config
*/
typedef struct {
uint32_t block_size; //!< Desired block size
uint32_t flags; //!< QSPI block device flags
nrf_drv_qspi_config_t qspi_config; //!< QSPI configuration
} nrf_block_dev_qspi_config_t;
/**
* @brief QSPI block device
* */
typedef struct {
nrf_block_dev_t block_dev; //!< Block device
nrf_block_dev_info_strings_t info_strings; //!< Block device information strings
nrf_block_dev_qspi_config_t qspi_bdev_config; //!< QSPI block device config
nrf_block_dev_qspi_work_t * p_work; //!< QSPI block device work structure
NRF_LOG_INSTANCE_PTR_DECLARE(p_log) //!< Pointer to instance of the logger object (Conditionally compiled).
} nrf_block_dev_qspi_t;
/**
* @brief Defines a QSPI block device.
*
* @param name Instance name
* @param config Configuration @ref nrf_block_dev_qspi_config_t
* @param info Info strings @ref NFR_BLOCK_DEV_INFO_CONFIG
* */
#define NRF_BLOCK_DEV_QSPI_DEFINE(name, config, info) \
static nrf_block_dev_qspi_work_t CONCAT_2(name, _work); \
NRF_LOG_INSTANCE_REGISTER(NRF_BLOCK_DEV_QSPI_LOG_NAME, name, \
NRF_BLOCK_DEV_QSPI_CONFIG_INFO_COLOR, \
NRF_BLOCK_DEV_QSPI_CONFIG_DEBUG_COLOR, \
NRF_BLOCK_DEV_QSPI_CONFIG_LOG_INIT_FILTER_LEVEL, \
NRF_BLOCK_DEV_QSPI_CONFIG_LOG_ENABLED ? \
NRF_BLOCK_DEV_QSPI_CONFIG_LOG_LEVEL : NRF_LOG_SEVERITY_NONE); \
static const nrf_block_dev_qspi_t name = { \
.block_dev = { .p_ops = &nrf_block_device_qspi_ops }, \
.info_strings = BRACKET_EXTRACT(info), \
.qspi_bdev_config = config, \
.p_work = &CONCAT_2(name, _work), \
NRF_LOG_INSTANCE_PTR_INIT(p_log, NRF_BLOCK_DEV_QSPI_LOG_NAME, name) \
}
/**
* @brief Returns block device API handle from QSPI block device.
*
* @param[in] p_blk_qspi QSPI block device
* @return Block device handle
*/
static inline nrf_block_dev_t const *
nrf_block_dev_qspi_ops_get(nrf_block_dev_qspi_t const * p_blk_qspi)
{
return &p_blk_qspi->block_dev;
}
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* NRF_BLOCK_DEV_QSPI_H__ */

View File

@@ -1,65 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "nrf_serial_flash_params.h"
static const nrf_serial_flash_params_t m_sflash_params[] = {
{ /*MXIC MX25R6435F*/
.read_id = { 0xC2, 0x28, 0x17 },
.capabilities = 0x00,
.size = 8 * 1024 * 1024,
.erase_size = 4 * 1024,
.program_size = 256,
}
};
nrf_serial_flash_params_t const * nrf_serial_flash_params_get(const uint8_t * p_read_id)
{
size_t i;
for (i = 0; i < ARRAY_SIZE(m_sflash_params); ++i)
{
if (memcmp(m_sflash_params[i].read_id, p_read_id, sizeof(m_sflash_params[i].read_id)) == 0)
{
return &m_sflash_params[i];
}
}
return NULL;
}

View File

@@ -1,83 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF_SERIAL_FLASH_PARAMS_H__
#define NRF_SERIAL_FLASH_PARAMS_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "sdk_common.h"
/**@file
*
* @defgroup nrf_serial_flash_params Serial flash memory parameters
* @ingroup nrf_block_dev
* @{
*
*/
/**
* @brief Serial flash memory parameters
* */
typedef struct {
uint8_t read_id[3]; //!< Read identification command (0x9F) result
uint8_t capabilities; //!< Serial flash memory capabilities
uint32_t size; //!< Serial flash memory size (bytes)
uint32_t erase_size; //!< Serial flash memory erase unit size (bytes)
uint32_t program_size; //!< Serial flash memory program size (bytes)
} nrf_serial_flash_params_t;
/**
* @brief Returns serial flash memory identification descriptor
*
* @param p_read_params Memory read identification command result
*
* @return Serial flash memory descriptor (NULL if not found)
* */
nrf_serial_flash_params_t const * nrf_serial_flash_params_get(const uint8_t * p_read_params);
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* NRF_SERIAL_FLASH_PARAMS_H__ */

View File

@@ -1,244 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sdk_common.h"
#if NRF_MODULE_ENABLED(NRF_BLOCK_DEV_RAM)
#include "nrf_block_dev_ram.h"
#include <inttypes.h>
/**@file
*
* @ingroup nrf_block_dev
* @{
*
* @brief This module implements block device API. It should be used as a reference block device.
*/
#if NRF_BLOCK_DEV_RAM_CONFIG_LOG_ENABLED
#define NRF_LOG_LEVEL NRF_BLOCK_DEV_RAM_CONFIG_LOG_LEVEL
#define NRF_LOG_INFO_COLOR NRF_BLOCK_DEV_RAM_CONFIG_INFO_COLOR
#define NRF_LOG_INST_DEBUG_COLOR NRF_BLOCK_DEV_RAM_CONFIG_DEBUG_COLOR
#else
#define NRF_LOG_LEVEL 0
#endif
#include "nrf_log.h"
static ret_code_t block_dev_ram_init(nrf_block_dev_t const * p_blk_dev,
nrf_block_dev_ev_handler ev_handler,
void const * p_context)
{
ASSERT(p_blk_dev);
nrf_block_dev_ram_t const * p_ram_dev = CONTAINER_OF(p_blk_dev, nrf_block_dev_ram_t, block_dev);
nrf_block_dev_ram_work_t * p_work = p_ram_dev->p_work;
NRF_LOG_INST_DEBUG(p_ram_dev->p_log, "Init");
/* Calculate block device geometry.... */
p_work->geometry.blk_size = p_ram_dev->ram_config.block_size;
p_work->geometry.blk_count = p_ram_dev->ram_config.size /
p_ram_dev->ram_config.block_size;
p_work->p_context = p_context;
p_work->ev_handler = ev_handler;
if (p_work->ev_handler)
{
/*Asynchronous operation (simulation)*/
const nrf_block_dev_event_t ev = {
NRF_BLOCK_DEV_EVT_INIT,
NRF_BLOCK_DEV_RESULT_SUCCESS,
NULL,
p_work->p_context
};
p_work->ev_handler(p_blk_dev, &ev);
}
return NRF_SUCCESS;
}
static ret_code_t block_dev_ram_uninit(nrf_block_dev_t const * p_blk_dev)
{
ASSERT(p_blk_dev);
nrf_block_dev_ram_t const * p_ram_dev = CONTAINER_OF(p_blk_dev, nrf_block_dev_ram_t, block_dev);
nrf_block_dev_ram_work_t * p_work = p_ram_dev->p_work;
NRF_LOG_INST_DEBUG(p_ram_dev->p_log, "Uninit");
if (p_work->ev_handler)
{
/*Asynchronous operation (simulation)*/
const nrf_block_dev_event_t ev = {
NRF_BLOCK_DEV_EVT_UNINIT,
NRF_BLOCK_DEV_RESULT_SUCCESS,
NULL,
p_work->p_context
};
p_work->ev_handler(p_blk_dev, &ev);
}
memset(p_work, 0, sizeof(nrf_block_dev_ram_work_t));
return NRF_SUCCESS;
}
static ret_code_t block_dev_ram_req(nrf_block_dev_t const * p_blk_dev,
nrf_block_req_t const * p_blk,
nrf_block_dev_event_type_t event)
{
ASSERT(p_blk_dev);
ASSERT(p_blk);
nrf_block_dev_ram_t const * p_ram_dev = CONTAINER_OF(p_blk_dev, nrf_block_dev_ram_t, block_dev);
nrf_block_dev_ram_config_t const * p_ram_config = &p_ram_dev->ram_config;
nrf_block_dev_ram_work_t const * p_work = p_ram_dev->p_work;
NRF_LOG_INST_DEBUG(p_ram_dev->p_log,
((event == NRF_BLOCK_DEV_EVT_BLK_READ_DONE) ?
"Read req from block %"PRIu32" size %"PRIu32"(x%"PRIu32") to %"PRIXPTR
:
"Write req to block %"PRIu32" size %"PRIu32"(x%"PRIu32") from %"PRIXPTR),
p_blk->blk_id,
p_blk->blk_count,
p_blk_dev->p_ops->geometry(p_blk_dev)->blk_size,
p_blk->p_buff);
if ((p_blk->blk_id + p_blk->blk_count) > p_work->geometry.blk_count)
{
NRF_LOG_INST_ERROR(p_ram_dev->p_log,
((event == NRF_BLOCK_DEV_EVT_BLK_READ_DONE) ?
"Out of range read req block %"PRIu32" count %"PRIu32" while max is %"PRIu32
:
"Out of range write req block %"PRIu32" count %"PRIu32", while max is %"PRIu32),
p_blk->blk_id,
p_blk->blk_count,
p_blk_dev->p_ops->geometry(p_blk_dev)->blk_count);
return NRF_ERROR_INVALID_ADDR;
}
/*Synchronous operation*/
uint8_t * p_buff = p_ram_config->p_work_buffer;
p_buff += p_blk->blk_id * p_work->geometry.blk_size;
const void * p_src = (event == NRF_BLOCK_DEV_EVT_BLK_READ_DONE) ? p_buff : p_blk->p_buff;
void * p_dst = (event == NRF_BLOCK_DEV_EVT_BLK_READ_DONE) ? p_blk->p_buff : p_buff;
memcpy(p_dst, p_src, p_work->geometry.blk_size * p_blk->blk_count);
if (p_work->ev_handler)
{
/*Asynchronous operation (simulation)*/
const nrf_block_dev_event_t ev = {
event,
NRF_BLOCK_DEV_RESULT_SUCCESS,
p_blk,
p_work->p_context
};
p_work->ev_handler(p_blk_dev, &ev);
}
return NRF_SUCCESS;
}
static ret_code_t block_dev_ram_read_req(nrf_block_dev_t const * p_blk_dev,
nrf_block_req_t const * p_blk)
{
return block_dev_ram_req(p_blk_dev, p_blk, NRF_BLOCK_DEV_EVT_BLK_READ_DONE);
}
static ret_code_t block_dev_ram_write_req(nrf_block_dev_t const * p_blk_dev,
nrf_block_req_t const * p_blk)
{
return block_dev_ram_req(p_blk_dev, p_blk, NRF_BLOCK_DEV_EVT_BLK_WRITE_DONE);
}
static ret_code_t block_dev_ram_ioctl(nrf_block_dev_t const * p_blk_dev,
nrf_block_dev_ioctl_req_t req,
void * p_data)
{
nrf_block_dev_ram_t const * p_ram_dev = CONTAINER_OF(p_blk_dev, nrf_block_dev_ram_t, block_dev);
switch (req)
{
case NRF_BLOCK_DEV_IOCTL_REQ_CACHE_FLUSH:
{
bool * p_flushing = p_data;
NRF_LOG_INST_DEBUG(p_ram_dev->p_log, "IOCtl: Cache flush");
if (p_flushing)
{
*p_flushing = false;
}
return NRF_SUCCESS;
}
case NRF_BLOCK_DEV_IOCTL_REQ_INFO_STRINGS:
{
if (p_data == NULL)
{
return NRF_ERROR_INVALID_PARAM;
}
nrf_block_dev_info_strings_t const * * pp_strings = p_data;
*pp_strings = &p_ram_dev->info_strings;
return NRF_SUCCESS;
}
default:
break;
}
return NRF_ERROR_NOT_SUPPORTED;
}
static nrf_block_dev_geometry_t const * block_dev_ram_geometry(nrf_block_dev_t const * p_blk_dev)
{
ASSERT(p_blk_dev);
nrf_block_dev_ram_t const * p_ram_dev = CONTAINER_OF(p_blk_dev, nrf_block_dev_ram_t, block_dev);
nrf_block_dev_ram_work_t const * p_work = p_ram_dev->p_work;
return &p_work->geometry;
}
const nrf_block_dev_ops_t nrf_block_device_ram_ops = {
.init = block_dev_ram_init,
.uninit = block_dev_ram_uninit,
.read_req = block_dev_ram_read_req,
.write_req = block_dev_ram_write_req,
.ioctl = block_dev_ram_ioctl,
.geometry = block_dev_ram_geometry,
};
/** @} */
#endif // NRF_MODULE_ENABLED(NRF_BLOCK_DEV_RAM)

View File

@@ -1,152 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF_BLOCK_DEV_RAM_H__
#define NRF_BLOCK_DEV_RAM_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "nrf_block_dev.h"
#include "nrf_log_instance.h"
/**@file
*
* @defgroup nrf_block_dev_ram RAM implementation
* @ingroup nrf_block_dev
* @{
*
* @brief This module implements block device API. It should be used as a reference block device.
*/
/**
* @brief RAM block device operations
* */
extern const nrf_block_dev_ops_t nrf_block_device_ram_ops;
/**
* @brief Work structure of RAM block device
*/
typedef struct {
nrf_block_dev_geometry_t geometry; //!< Block device geometry
nrf_block_dev_ev_handler ev_handler; //!< Block device event handler
void const * p_context; //!< Context handle passed to event handler
} nrf_block_dev_ram_work_t;
/** @brief Name of the module used for logger messaging.
*/
#define NRF_BLOCK_DEV_RAM_LOG_NAME block_dev_ram
/**
* @brief RAM block device config initializer (@ref nrf_block_dev_ram_config_t)
*
* @param blk_size Block size
* @param buffer RAM work buffer
* @param buffer_size RAM work buffer size
* */
#define NRF_BLOCK_DEV_RAM_CONFIG(blk_size, buffer, buffer_size) { \
.block_size = (blk_size), \
.p_work_buffer = (buffer), \
.size = (buffer_size), \
}
/**
* @brief Ram block device config
*/
typedef struct {
uint32_t block_size; //!< Desired block size
void * p_work_buffer; //!< Ram work buffer
size_t size; //!< Ram work buffer size
} nrf_block_dev_ram_config_t;
/**
* @brief Ram block device
* */
typedef struct {
nrf_block_dev_t block_dev; //!< Block device
nrf_block_dev_info_strings_t info_strings; //!< Block device information strings
nrf_block_dev_ram_config_t ram_config; //!< Ram block device config
nrf_block_dev_ram_work_t * p_work; //!< Ram block device work structure
NRF_LOG_INSTANCE_PTR_DECLARE(p_log) //!< Pointer to instance of the logger object (Conditionally compiled).
} nrf_block_dev_ram_t;
/**
* @brief Defines a RAM block device.
*
* @param name Instance name
* @param config Configuration @ref nrf_block_dev_ram_config_t
* @param info Info strings @ref NFR_BLOCK_DEV_INFO_CONFIG
* */
#define NRF_BLOCK_DEV_RAM_DEFINE(name, config, info) \
static nrf_block_dev_ram_work_t CONCAT_2(name, _work); \
NRF_LOG_INSTANCE_REGISTER(NRF_BLOCK_DEV_RAM_LOG_NAME, name, \
NRF_BLOCK_DEV_RAM_CONFIG_INFO_COLOR, \
NRF_BLOCK_DEV_RAM_CONFIG_DEBUG_COLOR, \
NRF_BLOCK_DEV_RAM_CONFIG_LOG_INIT_FILTER_LEVEL, \
NRF_BLOCK_DEV_RAM_CONFIG_LOG_ENABLED ? \
NRF_BLOCK_DEV_RAM_CONFIG_LOG_LEVEL : NRF_LOG_SEVERITY_NONE); \
static const nrf_block_dev_ram_t name = { \
.block_dev = { .p_ops = &nrf_block_device_ram_ops }, \
.info_strings = BRACKET_EXTRACT(info), \
.ram_config = config, \
.p_work = &CONCAT_2(name, _work), \
NRF_LOG_INSTANCE_PTR_INIT(p_log, NRF_BLOCK_DEV_RAM_LOG_NAME, name) \
}
/**
* @brief Returns block device API handle from RAM block device.
*
* @param[in] p_blk_ram Ram block device
* @return Block device handle
*/
static inline nrf_block_dev_t const *
nrf_block_dev_ram_ops_get(nrf_block_dev_ram_t const * p_blk_ram)
{
return &p_blk_ram->block_dev;
}
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* NRF_BLOCK_DEV_RAM_H__ */

View File

@@ -1,399 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "nrf_block_dev_sdc.h"
/**@file
*
* @ingroup nrf_block_dev_sdc
* @{
*
* @brief This module implements block device API. It should be used as a reference block device.
*/
static volatile sdc_result_t m_last_result;
/**
* @brief Active SDC block device handle. Only one instance.
* */
static nrf_block_dev_sdc_t const * m_active_sdc_dev;
static ret_code_t block_dev_sdc_uninit(nrf_block_dev_t const * p_blk_dev);
static void wait_func(void)
{
}
static void sdc_wait()
{
while (app_sdc_busy_check())
{
wait_func();
}
}
static void sdc_handler(sdc_evt_t const * p_event)
{
m_last_result = p_event->result;
nrf_block_dev_sdc_t const * p_sdc_dev = m_active_sdc_dev;
nrf_block_dev_sdc_work_t * p_work = p_sdc_dev->p_work;
switch (p_event->type)
{
case SDC_EVT_INIT:
{
if (p_event->result != SDC_SUCCESS)
{
nrf_block_dev_t const * block_dev = &(p_sdc_dev->block_dev);
ret_code_t err_code = block_dev_sdc_uninit(block_dev);
APP_ERROR_CHECK(err_code);
}
p_work->geometry.blk_count = app_sdc_info_get()->num_blocks;
p_work->geometry.blk_size = SDC_SECTOR_SIZE;
if (m_active_sdc_dev->p_work->ev_handler)
{
const nrf_block_dev_event_t ev = {
NRF_BLOCK_DEV_EVT_INIT,
((p_event->result == SDC_SUCCESS) ? \
NRF_BLOCK_DEV_RESULT_SUCCESS : NRF_BLOCK_DEV_RESULT_IO_ERROR),
NULL,
p_work->p_context
};
p_work->ev_handler(&p_sdc_dev->block_dev, &ev);
}
}
break;
case SDC_EVT_READ:
if (m_active_sdc_dev->p_work->ev_handler)
{
const nrf_block_dev_event_t ev = {
NRF_BLOCK_DEV_EVT_BLK_READ_DONE,
((p_event->result == SDC_SUCCESS) ? \
NRF_BLOCK_DEV_RESULT_SUCCESS : NRF_BLOCK_DEV_RESULT_IO_ERROR),
&p_work->req,
p_work->p_context
};
p_work->ev_handler(&p_sdc_dev->block_dev, &ev);
}
break;
case SDC_EVT_WRITE:
if (m_active_sdc_dev->p_work->ev_handler)
{
const nrf_block_dev_event_t ev = {
NRF_BLOCK_DEV_EVT_BLK_WRITE_DONE,
((p_event->result == SDC_SUCCESS) ? \
NRF_BLOCK_DEV_RESULT_SUCCESS : NRF_BLOCK_DEV_RESULT_IO_ERROR),
&p_work->req,
p_work->p_context
};
p_work->ev_handler(&p_sdc_dev->block_dev, &ev);
}
break;
default:
APP_ERROR_CHECK(NRF_ERROR_INTERNAL);
return;
}
}
static ret_code_t block_dev_sdc_init(nrf_block_dev_t const * p_blk_dev,
nrf_block_dev_ev_handler ev_handler,
void const * p_context)
{
ASSERT(p_blk_dev);
nrf_block_dev_sdc_t const * p_sdc_dev =
CONTAINER_OF(p_blk_dev, nrf_block_dev_sdc_t, block_dev);
nrf_block_dev_sdc_work_t * p_work = p_sdc_dev->p_work;
if (p_sdc_dev->sdc_bdev_config.block_size != SDC_SECTOR_SIZE)
{
/* Unsupported block size. */
return NRF_ERROR_NOT_SUPPORTED;
}
if (m_active_sdc_dev)
{
/* SDC instance is busy. */
return NRF_ERROR_BUSY;
}
p_work->p_context = p_context;
p_work->ev_handler = ev_handler;
m_active_sdc_dev = p_sdc_dev;
ret_code_t err_code = NRF_SUCCESS;
err_code = app_sdc_init(&p_sdc_dev->sdc_bdev_config.sdc_config, sdc_handler);
if (err_code == NRF_SUCCESS)
{
if (!ev_handler)
{
/* Synchronous mode - wait for the card. */
sdc_wait();
err_code = ((m_last_result == SDC_SUCCESS) ? NRF_SUCCESS : NRF_ERROR_TIMEOUT);
}
}
if (err_code != NRF_SUCCESS)
{
m_active_sdc_dev = NULL;
if (ev_handler)
{
/* Call the user handler with an error status. */
const nrf_block_dev_event_t ev = {
NRF_BLOCK_DEV_EVT_INIT,
NRF_BLOCK_DEV_RESULT_IO_ERROR,
NULL,
p_work->p_context
};
p_work->ev_handler(p_blk_dev, &ev);
}
}
return err_code;
}
static ret_code_t block_dev_sdc_uninit(nrf_block_dev_t const * p_blk_dev)
{
ASSERT(p_blk_dev);
nrf_block_dev_sdc_t const * p_sdc_dev =
CONTAINER_OF(p_blk_dev, nrf_block_dev_sdc_t, block_dev);
nrf_block_dev_sdc_work_t * p_work = p_sdc_dev->p_work;
if (m_active_sdc_dev != p_sdc_dev)
{
/* SDC instance is busy. */
return NRF_ERROR_BUSY;
}
if (app_sdc_busy_check())
{
/* Previous asynchronous operation in progress. */
return NRF_ERROR_BUSY;
}
ret_code_t err_code = app_sdc_uninit();
if (err_code == NRF_SUCCESS)
{
/* Free the instance on success. */
m_active_sdc_dev = NULL;
}
if (p_work->ev_handler)
{
/* SDC uninitialization is a synchronous operation. Call event handler. */
const nrf_block_dev_event_t ev = {
NRF_BLOCK_DEV_EVT_UNINIT,
((err_code == NRF_SUCCESS) ? \
NRF_BLOCK_DEV_RESULT_SUCCESS : NRF_BLOCK_DEV_RESULT_IO_ERROR),
NULL,
p_work->p_context
};
p_work->ev_handler(p_blk_dev, &ev);
}
return err_code;
}
static ret_code_t block_dev_sdc_read_req(nrf_block_dev_t const * p_blk_dev,
nrf_block_req_t const * p_blk)
{
ASSERT(p_blk_dev);
ASSERT(p_blk);
nrf_block_dev_sdc_t const * p_sdc_dev =
CONTAINER_OF(p_blk_dev, nrf_block_dev_sdc_t, block_dev);
nrf_block_dev_sdc_work_t * p_work = p_sdc_dev->p_work;
ret_code_t err_code = NRF_SUCCESS;
if (m_active_sdc_dev != p_sdc_dev)
{
/* SDC instance is busy. */
return NRF_ERROR_BUSY;
}
if (app_sdc_busy_check())
{
/* Previous asynchronous operation in progress. */
return NRF_ERROR_BUSY;
}
p_work->req = *p_blk;
err_code = app_sdc_block_read(p_blk->p_buff, p_blk->blk_id, p_blk->blk_count);
if (err_code == NRF_SUCCESS)
{
if (!p_work->ev_handler)
{
/* Synchronous mode - wait for the card. */
sdc_wait();
err_code = ((m_last_result == SDC_SUCCESS) ? NRF_SUCCESS : NRF_ERROR_TIMEOUT);
}
}
if ((p_work->ev_handler) && (err_code != NRF_SUCCESS))
{
/* Call the user handler with an error status. */
const nrf_block_dev_event_t ev = {
NRF_BLOCK_DEV_EVT_BLK_READ_DONE,
NRF_BLOCK_DEV_RESULT_IO_ERROR,
&p_work->req,
p_work->p_context
};
p_work->ev_handler(p_blk_dev, &ev);
}
return err_code;
}
static ret_code_t block_dev_sdc_write_req(nrf_block_dev_t const * p_blk_dev,
nrf_block_req_t const * p_blk)
{
ASSERT(p_blk_dev);
ASSERT(p_blk);
nrf_block_dev_sdc_t const * p_sdc_dev =
CONTAINER_OF(p_blk_dev, nrf_block_dev_sdc_t, block_dev);
nrf_block_dev_sdc_work_t * p_work = p_sdc_dev->p_work;
ret_code_t err_code = NRF_SUCCESS;
if (m_active_sdc_dev != p_sdc_dev)
{
/* SDC instance is busy. */
return NRF_ERROR_BUSY;
}
if (app_sdc_busy_check())
{
/* Previous asynchronous operation in progress. */
return NRF_ERROR_BUSY;
}
p_work->req = *p_blk;
err_code = app_sdc_block_write(p_blk->p_buff, p_blk->blk_id, p_blk->blk_count);
if (err_code == NRF_SUCCESS)
{
if (!p_work->ev_handler)
{
/* Synchronous mode - wait for the card. */
sdc_wait();
err_code = ((m_last_result == SDC_SUCCESS) ? NRF_SUCCESS : NRF_ERROR_TIMEOUT);
}
}
if ((p_work->ev_handler) && (err_code != NRF_SUCCESS))
{
/* Call the user handler with an error status. */
const nrf_block_dev_event_t ev = {
NRF_BLOCK_DEV_EVT_BLK_READ_DONE,
NRF_BLOCK_DEV_RESULT_IO_ERROR,
&p_work->req,
p_work->p_context
};
p_work->ev_handler(p_blk_dev, &ev);
}
return err_code;
}
static ret_code_t block_dev_sdc_ioctl(nrf_block_dev_t const * p_blk_dev,
nrf_block_dev_ioctl_req_t req,
void * p_data)
{
nrf_block_dev_sdc_t const * p_sdc_dev =
CONTAINER_OF(p_blk_dev, nrf_block_dev_sdc_t, block_dev);
switch (req)
{
case NRF_BLOCK_DEV_IOCTL_REQ_CACHE_FLUSH:
{
bool * p_flushing = p_data;
if (p_flushing)
{
*p_flushing = false;
}
return NRF_SUCCESS;
}
case NRF_BLOCK_DEV_IOCTL_REQ_INFO_STRINGS:
{
if (p_data == NULL)
{
return NRF_ERROR_INVALID_PARAM;
}
nrf_block_dev_info_strings_t const * * pp_strings = p_data;
*pp_strings = &p_sdc_dev->info_strings;
return NRF_SUCCESS;
}
default:
break;
}
return NRF_ERROR_NOT_SUPPORTED;
}
static nrf_block_dev_geometry_t const * block_dev_sdc_geometry(nrf_block_dev_t const * p_blk_dev)
{
ASSERT(p_blk_dev);
nrf_block_dev_sdc_t const * p_sdc_dev =
CONTAINER_OF(p_blk_dev, nrf_block_dev_sdc_t, block_dev);
nrf_block_dev_sdc_work_t const * p_work = p_sdc_dev->p_work;
return &p_work->geometry;
}
const nrf_block_dev_ops_t nrf_block_device_sdc_ops = {
.init = block_dev_sdc_init,
.uninit = block_dev_sdc_uninit,
.read_req = block_dev_sdc_read_req,
.write_req = block_dev_sdc_write_req,
.ioctl = block_dev_sdc_ioctl,
.geometry = block_dev_sdc_geometry,
};
/** @} */

View File

@@ -1,139 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@file
*
* @defgroup nrf_block_dev_sdc SDC implementation
* @ingroup nrf_block_dev
* @{
*
*/
#ifndef NRF_BLOCK_DEV_SDC_H__
#define NRF_BLOCK_DEV_SDC_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "nrf_block_dev.h"
#include "app_sdcard.h"
/**
* @brief SDC block device operations
* */
extern const nrf_block_dev_ops_t nrf_block_device_sdc_ops;
/**
* @brief Work structure of SDC block device
*/
typedef struct {
nrf_block_dev_geometry_t geometry; //!< Block device geometry
nrf_block_dev_ev_handler ev_handler; //!< Block device event handler
nrf_block_req_t req; //!< Block READ/WRITE request
void const * p_context; //!< Context handle passed to event handler
} nrf_block_dev_sdc_work_t;
/**
* @brief SDC block device config initializer (@ref nrf_block_dev_sdc_config_t)
*
* @param blk_size Block size
* @param sdc_lib_config SDC library config (@ref app_sdc_config_t)
* */
#define NRF_BLOCK_DEV_SDC_CONFIG(blk_size, sdc_lib_config) \
{ \
.block_size = (blk_size), \
.sdc_config = sdc_lib_config \
}
/**
* @brief SDC block device config
*/
typedef struct {
uint32_t block_size; //!< Desired block size
app_sdc_config_t sdc_config; //!< SDC library configuration
} nrf_block_dev_sdc_config_t;
/**
* @brief SDC block device
* */
typedef struct {
nrf_block_dev_t block_dev; //!< Block device
nrf_block_dev_info_strings_t info_strings; //!< Block device information strings
nrf_block_dev_sdc_config_t sdc_bdev_config; //!< SDC block device config
nrf_block_dev_sdc_work_t * p_work; //!< SDC block device work structure
} nrf_block_dev_sdc_t;
/**
* @brief Defines a SDC block device.
*
* @param name Instance name
* @param config Configuration @ref nrf_block_dev_sdc_config_t
* @param info Info strings @ref NFR_BLOCK_DEV_INFO_CONFIG
* */
#define NRF_BLOCK_DEV_SDC_DEFINE(name, config, info) \
static nrf_block_dev_sdc_work_t CONCAT_2(name, _work); \
static const nrf_block_dev_sdc_t name = { \
.block_dev = { .p_ops = &nrf_block_device_sdc_ops }, \
.info_strings = BRACKET_EXTRACT(info), \
.sdc_bdev_config = config, \
.p_work = &CONCAT_2(name, _work), \
}
/**
* @brief Returns block device API handle from SDC block device.
*
* @param[in] p_blk_sdc SDC block device
* @return Block device handle
*/
static inline nrf_block_dev_t const *
nrf_block_dev_sdc_ops_get(nrf_block_dev_sdc_t const * p_blk_sdc)
{
return &p_blk_sdc->block_dev;
}
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* NRF_BLOCK_DEV_SDC_H__ */

View File

@@ -1,662 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sdk_common.h"
#if NRF_MODULE_ENABLED(NRF_CSENSE)
#include <string.h>
#include <nrfx.h>
#include "nrf_csense.h"
#include "nrf_peripherals.h"
#include "nrf_assert.h"
#if defined(__CC_ARM)
#elif defined(__ICCARM__)
#elif defined(__GNUC__)
#ifndef __CLZ
#define __CLZ(x) __builtin_clz(x)
#endif
#endif
APP_TIMER_DEF(nrf_csense_timer);
typedef struct
{
nrf_csense_event_handler_t event_handler; //!< Event handler for module.
nrfx_drv_state_t state; //!< State of module.
uint32_t ticks; //!< Timeout ticks of app_timer instance controlling csense module.
uint16_t raw_analog_values[MAX_ANALOG_INPUTS]; //!< Raw values of measurements.
uint8_t enabled_analog_channels_mask; //!< Mask of enabled channels.
} nrf_csense_t;
/* Module instance. */
static nrf_csense_t m_nrf_csense;
/* First of touch elements instances that creates linked list. */
static nrf_csense_instance_t * mp_nrf_csense_instance_head;
/* Buffer for values got from measurements. */
static uint16_t m_values_buffer[NRF_CSENSE_MAX_PADS_NUMBER];
/**
* @brief Function for handling time-outs.
*
* @param[in] p_context General purpose pointer. Will be passed to the time-out handler
* when the timer expires.
*/
static void csense_timer_handler(void * p_context)
{
if (m_nrf_csense.state != NRFX_DRV_STATE_POWERED_ON)
{
return;
}
if (nrf_drv_csense_sample() == NRF_ERROR_BUSY)
{
return;
}
}
/**
* @brief Function for updating maximum or minimum value.
*
* @param [in] p_instance Pointer to csense instance.
* @param [in] p_pad Pointer to pad which should be checked for minimum or maximum value.
*/
__STATIC_INLINE void min_or_max_update(nrf_csense_instance_t const * p_instance,
nrf_csense_pad_t * p_pad)
{
uint16_t val = m_nrf_csense.raw_analog_values[p_pad->analog_input_number];
if (p_instance->min_max[p_pad->pad_index].min_value > val)
{
p_instance->min_max[p_pad->pad_index].min_value = val;
}
if (p_instance->min_max[p_pad->pad_index].max_value < val)
{
p_instance->min_max[p_pad->pad_index].max_value = val;
}
}
/**
* @brief Function for calculating proportions on slider pad.
*
* @note This function help to self calibrate the pads.
*
* @param [in] p_instance Pointer to csense instance.
* @param [in] p_pad Pointer to pad to calculate ratio for.
*
* @return Difference between maximum and minimum values read on pads or 0 if minimum is bigger than maximum.
*
*/
__STATIC_INLINE uint16_t ratio_calculate(nrf_csense_instance_t const * p_instance,
nrf_csense_pad_t * p_pad)
{
if (p_instance->min_max[p_pad->pad_index].max_value > p_instance->min_max[p_pad->pad_index].min_value)
{
uint16_t scale;
scale = (uint16_t)(p_instance->min_max[p_pad->pad_index].max_value -
p_instance->min_max[p_pad->pad_index].min_value);
return scale;
}
else
{
return 0;
}
}
/**
* @brief Function for calculating step.
*
* Function calculates step for slider basing on index of touched pads and values measured on
* them and neighboring pads.
*
* @param[in] p_instance Pointer to csense instance.
* @param[in] pad_index Index of the pad.
*
* @return Detected touched step.
*/
static uint16_t calculate_step(nrf_csense_instance_t * p_instance,
uint8_t pad_index)
{
uint16_t step = 0;
uint32_t values_sum;
uint32_t values_product;
pad_index += 1;
values_sum = m_values_buffer[pad_index] + m_values_buffer[pad_index - 1] +
m_values_buffer[pad_index + 1];
values_product = (uint32_t)(p_instance->steps-1) *
(m_values_buffer[pad_index - 1] * (pad_index - 2)
+ m_values_buffer[pad_index] * (pad_index - 1)
+ m_values_buffer[pad_index + 1] * (pad_index));
step = 1 + ROUNDED_DIV(values_product, (values_sum * (p_instance->number_of_pads - 1))); // Add 1 to the result of the division
// to get the appropriate range of values.
memset((void*)m_values_buffer, 0, sizeof(m_values_buffer));
return step;
}
/**
* @brief Function for finding mask of touched pads.
*
* @param [in] p_instance Pointer to csense instance.
*
* @return Mask of touched pads.
*/
static uint32_t find_touched_mask(nrf_csense_instance_t const * p_instance)
{
uint32_t touched_mask = 0;
uint16_t max_value = 0;
uint16_t ratio;
nrf_csense_pad_t * p_pad;
for (p_pad = p_instance->p_nrf_csense_pad; NULL != p_pad; p_pad = p_pad->p_next_pad) // run through all pads and look for those with biggest value
{
min_or_max_update(p_instance, p_pad);
ratio = ratio_calculate(p_instance, p_pad);
if (ratio == 0)
{
return 0;
}
uint16_t val =
(uint16_t)(((uint32_t)(m_nrf_csense.raw_analog_values[p_pad->analog_input_number] -
p_instance->min_max[p_pad->pad_index].min_value) *
NRF_CSENSE_MAX_VALUE) / ratio);
m_values_buffer[p_pad->pad_index+1] = val;
if (val > max_value)
{
max_value = val;
touched_mask = (1UL << (p_pad->pad_index));
}
else if (val == max_value)
{
max_value = val;
touched_mask |= (1UL << (p_pad->pad_index));
}
}
return touched_mask;
}
/**
* @brief Function for finding touched pad.
*
* If there is more than one pad connected to an analog channel this functions which one was actually touched. This is done by
* comparing values of neighboring pads.
*
* @param [in] instance Pointer to csense instance.
* @param [in] touched_mask Mask of touched pads.
*
* @return Touched pad.
*/
static uint16_t find_touched_pad(nrf_csense_instance_t const * p_instance,
uint32_t touched_mask)
{
uint8_t i;
uint8_t biggest_deviation = 0;
uint8_t temp_biggest = 0;
uint16_t pad = UINT16_MAX;
static uint16_t previous_pad = 0;
for (i = 0; i < (p_instance->number_of_pads); i++)
{
if ((1UL << i) & touched_mask)
{
temp_biggest = m_values_buffer[i];
temp_biggest += m_values_buffer[i + 2];
if ((i != 0) && (i != ((p_instance->number_of_pads-1))))
{
temp_biggest /= 2;
}
if ((temp_biggest > NRF_CSENSE_PAD_DEVIATION) &&
(temp_biggest > biggest_deviation))
{
biggest_deviation = temp_biggest;
pad = i;
}
}
}
if (pad == UINT16_MAX)
{
pad = previous_pad;
}
else
{
previous_pad = pad;
}
return pad;
}
/**
* @brief Function for finding touched step.
*
* @param [in] instance Pointer to csense instance.
*
* @return Detected touched step.
*/
static uint16_t find_touched_step(nrf_csense_instance_t * p_instance)
{
uint32_t touched_mask = 0;
uint16_t pad = 0;
uint16_t step;
touched_mask = find_touched_mask(p_instance);
if (touched_mask == 0)
{
return UINT16_MAX;
}
if ((touched_mask & (-(int32_t)touched_mask)) == touched_mask) // Check if there is only one pad with greatest value.
{
pad = 31 - __CLZ(touched_mask);
}
else
{
pad = find_touched_pad(p_instance, touched_mask);
}
step = calculate_step(p_instance, pad);
return step;
}
/**
* @brief Event handler for csense.
*
* param [in] p_event_struct Pointer to event structure.
*/
static void csense_event_handler(nrf_drv_csense_evt_t * p_event_struct)
{
nrf_csense_evt_t event;
static uint16_t prev_analog_values[MAX_ANALOG_INPUTS];
bool touched = false;
nrf_csense_instance_t * instance;
uint8_t i;
if ((m_nrf_csense.enabled_analog_channels_mask & (1UL << (p_event_struct->analog_channel))) == 0)
{
return;
}
m_nrf_csense.raw_analog_values[p_event_struct->analog_channel] = p_event_struct->read_value;
if (nrf_drv_csense_is_busy())
{
return;
}
for (instance = mp_nrf_csense_instance_head; instance != NULL;
instance = instance->p_next_instance) // run through all instances
{
if (instance->is_active)
{
event.p_instance = instance;
nrf_csense_pad_t * p_pad = instance->p_nrf_csense_pad;
for (i = 0; i < MAX_ANALOG_INPUTS; i++)
{
if ((m_nrf_csense.raw_analog_values[i] <
(prev_analog_values[i] - NRF_CSENSE_PAD_HYSTERESIS)) ||
(m_nrf_csense.raw_analog_values[i] >
(prev_analog_values[i] + NRF_CSENSE_PAD_HYSTERESIS)))
{
touched = true;
break;
}
}
if (touched)
{
touched = false;
for (p_pad = instance->p_nrf_csense_pad; p_pad != NULL;
p_pad = p_pad->p_next_pad)
{
if (m_nrf_csense.raw_analog_values[p_pad->analog_input_number] >
p_pad->threshold)
{
touched = true;
break;
}
}
}
else
{
continue;
}
// Specify the event
if ((instance->is_touched) && touched)
{
// dragged
if (instance->number_of_pads > 1)
{
event.params.slider.step = find_touched_step(instance);
event.nrf_csense_evt_type = NRF_CSENSE_SLIDER_EVT_DRAGGED;
m_nrf_csense.event_handler(&event);
}
}
else if ((!(instance->is_touched)) && touched)
{
// pressed
if (instance->number_of_pads > 1)
{
event.params.slider.step = find_touched_step(instance);
event.nrf_csense_evt_type = NRF_CSENSE_SLIDER_EVT_PRESSED;
}
else
{
event.nrf_csense_evt_type = NRF_CSENSE_BTN_EVT_PRESSED;
}
instance->is_touched = true;
m_nrf_csense.event_handler(&event);
}
else if ((instance->is_touched) && (!touched))
{
// released
if (instance->number_of_pads > 1)
{
event.params.slider.step = find_touched_step(instance);
event.nrf_csense_evt_type = NRF_CSENSE_SLIDER_EVT_RELEASED;
}
else
{
event.nrf_csense_evt_type = NRF_CSENSE_BTN_EVT_RELEASED;
}
instance->is_touched = false;
m_nrf_csense.event_handler(&event);
}
else
{
// nothing changed
}
}
touched = false;
}
memset(m_values_buffer, 0, sizeof(m_values_buffer));
memcpy(prev_analog_values, m_nrf_csense.raw_analog_values,
sizeof(m_nrf_csense.raw_analog_values));
}
ret_code_t nrf_csense_init(nrf_csense_event_handler_t event_handler,
uint32_t ticks)
{
ASSERT(event_handler != NULL);
ASSERT(m_nrf_csense.state == NRFX_DRV_STATE_UNINITIALIZED);
ret_code_t err_code;
static const nrf_drv_csense_config_t m_csense_config =
{
.output_pin = NRF_CSENSE_OUTPUT_PIN
};
m_nrf_csense.event_handler = event_handler;
m_nrf_csense.ticks = ticks;
mp_nrf_csense_instance_head = NULL;
err_code = app_timer_create(&nrf_csense_timer, APP_TIMER_MODE_REPEATED, csense_timer_handler);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
err_code = nrf_drv_csense_init(&m_csense_config, csense_event_handler);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
m_nrf_csense.state = NRFX_DRV_STATE_INITIALIZED;
return NRF_SUCCESS;
}
ret_code_t nrf_csense_uninit(void)
{
ASSERT(m_nrf_csense.state != NRFX_DRV_STATE_UNINITIALIZED);
ret_code_t err_code;
nrf_csense_instance_t ** pp_instance = &mp_nrf_csense_instance_head;
err_code = nrf_drv_csense_uninit();
if (err_code != NRF_SUCCESS)
{
return err_code;
}
if (m_nrf_csense.enabled_analog_channels_mask != 0)
{
err_code = app_timer_stop(nrf_csense_timer);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
while ((*pp_instance) != NULL)
{
nrf_csense_instance_t ** pp_instance_next = (&(*pp_instance)->p_next_instance);
(*pp_instance) = NULL;
pp_instance = pp_instance_next;
}
memset((void *)&m_nrf_csense, 0, sizeof(nrf_csense_t));
m_nrf_csense.state = NRFX_DRV_STATE_UNINITIALIZED;
return NRF_SUCCESS;
}
ret_code_t nrf_csense_add(nrf_csense_instance_t * const p_instance)
{
ASSERT(m_nrf_csense.state != NRFX_DRV_STATE_UNINITIALIZED);
ASSERT(p_instance->p_next_instance == NULL);
ASSERT(p_instance != NULL);
ret_code_t err_code;
nrf_csense_instance_t ** pp_instance = &mp_nrf_csense_instance_head;
while ((*pp_instance) != NULL)
{
ASSERT((*pp_instance) != p_instance);
pp_instance = &((*pp_instance)->p_next_instance);
}
*pp_instance = p_instance;
err_code = nrf_csense_enable(p_instance);
return err_code;
}
ret_code_t nrf_csense_enable(nrf_csense_instance_t * const p_instance)
{
ASSERT(m_nrf_csense.state != NRFX_DRV_STATE_UNINITIALIZED);
ASSERT(p_instance != NULL);
ret_code_t err_code;
nrf_csense_pad_t const * p_pad;
uint8_t analog_channels_mask = 0;
if (m_nrf_csense.enabled_analog_channels_mask == 0)
{
err_code = app_timer_start(nrf_csense_timer, m_nrf_csense.ticks, NULL);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
p_instance->is_active = true;
for (p_pad = p_instance->p_nrf_csense_pad; p_pad != NULL; p_pad = p_pad->p_next_pad)
{
p_instance->min_max[p_pad->pad_index].min_value = UINT16_MAX;
// If channel was already enabled skip it.
if ((m_nrf_csense.enabled_analog_channels_mask & (1UL << (p_pad->analog_input_number))) == 0)
{
analog_channels_mask |= (1UL << (p_pad->analog_input_number));
m_nrf_csense.enabled_analog_channels_mask |= (1UL << (p_pad->analog_input_number));
}
}
m_nrf_csense.state = NRFX_DRV_STATE_POWERED_ON;
nrf_drv_csense_channels_enable(analog_channels_mask);
return NRF_SUCCESS;
}
ret_code_t nrf_csense_disable(nrf_csense_instance_t * const p_instance)
{
ASSERT(m_nrf_csense.state == NRFX_DRV_STATE_POWERED_ON);
ret_code_t err_code;
nrf_csense_instance_t * p_instance_temp = mp_nrf_csense_instance_head;
nrf_csense_pad_t const * p_pad;
uint8_t channels_mask = 0;
uint8_t instance_channels_mask = 0;
for (p_instance_temp = mp_nrf_csense_instance_head; p_instance_temp != NULL;
p_instance_temp = p_instance_temp->p_next_instance)
{
for (p_pad = p_instance_temp->p_nrf_csense_pad; p_pad != NULL; p_pad = p_pad->p_next_pad)
{
if (p_instance_temp == p_instance)
{
instance_channels_mask |= (1UL << (p_pad->analog_input_number));
p_instance->is_active = false;
}
else
{
channels_mask |= (1UL << (p_pad->analog_input_number));
}
}
}
nrf_drv_csense_channels_disable((~channels_mask) & instance_channels_mask);
m_nrf_csense.enabled_analog_channels_mask = channels_mask;
if (m_nrf_csense.enabled_analog_channels_mask == 0)
{
err_code = app_timer_stop(nrf_csense_timer);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
m_nrf_csense.state = NRFX_DRV_STATE_INITIALIZED;
}
return NRF_SUCCESS;
}
ret_code_t nrf_csense_ticks_set(uint32_t ticks)
{
ASSERT(m_nrf_csense.state != NRFX_DRV_STATE_UNINITIALIZED);
ret_code_t err_code;
if (nrf_drv_csense_is_busy())
{
return NRF_ERROR_BUSY;
}
m_nrf_csense.ticks = ticks;
if (m_nrf_csense.state == NRFX_DRV_STATE_POWERED_ON)
{
err_code = app_timer_stop(nrf_csense_timer);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
err_code = app_timer_start(nrf_csense_timer, ticks, NULL);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
return NRF_SUCCESS;
}
ret_code_t nrf_csense_steps_set(nrf_csense_instance_t * const p_instance, uint16_t steps)
{
if (p_instance->is_active)
{
return NRF_ERROR_INVALID_STATE;
}
p_instance->steps = steps;
return NRF_SUCCESS;
}
#endif //NRF_MODULE_ENABLED(NRF_CSENSE)

View File

@@ -1,344 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF_CSENSE_H__
#define NRF_CSENSE_H__
#include <stdint.h>
#include "nrf.h"
#include "sdk_errors.h"
#include "app_timer.h"
#include "nrf_drv_csense.h"
#include "nrf_csense_macros.h"
#include "app_util.h"
/** @file
*
* @defgroup nrf_csense Capacitive sensor library
* @{
* @ingroup app_common
*
* @brief Module for using the capacitive sensor library with support for many instances of sliders, wheels, and buttons.
*/
/**
* @brief Macro for returning the address of a variable.
*/
#define NRF_CSENSE_GET_INSTANCE_ID(instance) (&instance)
/**
* @brief Statically allocate memory for the instance of a capacitive sensor.
*
* @param[in,out] name Name of the capacitive sensor instance that will be created.
* @param[in] p1 Pair of two arguments: threshold and analog_input_number. Must be passed as (analog_input_number, threshold).
*/
#define NRF_CSENSE_BUTTON_DEF(name, p1) NRF_CSENSE_INTERNAL_BUTTON_DEF(name, p1)
/**
* @brief Macro for creating a 2-pad slider instance.
*
* @param[in,out] name Name of the capacitive sensor instance that will be created.
* @param[in] steps_no Number of relative pads. It means that the slider in its handler will give values (1, steps_no).
* @param[in] p1 Pair of two arguments: threshold and analog_input_number. Must be passed as (analog_input_number, threshold).
* @param[in] p2 Pair of two arguments: threshold and analog_input_number. Must be passed as (analog_input_number, threshold).
*/
#define NRF_CSENSE_SLIDER_2_DEF(name, steps_no, p1, p2) NRF_CSENSE_INTERNAL_SLIDER_2_DEF(name, steps_no, p1, p2)
/**
* @brief Macro for creating a 3-pad slider instance.
*
* @param[in,out] name Name of the capacitive sensor instance that will be created.
* @param[in] steps_no Number of relative pads. It means that the slider in its handler will give values (1, steps_no).
* @param[in] p1 Pair of two arguments: threshold and analog_input_number. Must be passed as (analog_input_number, threshold).
* @param[in] p2 Pair of two arguments: threshold and analog_input_number. Must be passed as (analog_input_number, threshold).
* @param[in] p3 Pair of two arguments: threshold and analog_input_number. Must be passed as (analog_input_number, threshold).
*/
#define NRF_CSENSE_SLIDER_3_DEF(name, steps_no, p1, p2, p3) NRF_CSENSE_INTERNAL_SLIDER_3_DEF(name, steps_no, p1, p2, p3)
/**
* @brief Macro for creating a 4-pad slider instance.
*
* @param[in,out] name Name of the capacitive sensor instance that will be created.
* @param[in] steps_no Number of relative pads. It means that the slider in its handler will give values (1, steps_no).
* @param[in] p1 Pair of two arguments: threshold and analog_input_number. Must be passed as (analog_input_number, threshold).
* @param[in] p2 Pair of two arguments: threshold and analog_input_number. Must be passed as (analog_input_number, threshold).
* @param[in] p3 Pair of two arguments: threshold and analog_input_number. Must be passed as (analog_input_number, threshold).
* @param[in] p4 Pair of two arguments: threshold and analog_input_number. Must be passed as (analog_input_number, threshold).
*/
#define NRF_CSENSE_SLIDER_4_DEF(name, steps_no, p1, p2, p3, p4) NRF_CSENSE_INTERNAL_SLIDER_4_DEF(name, steps_no, p1, p2, p3, p4)
/**
* @brief Macro for creating a 5-pad slider instance.
*
* @param[in,out] name Name of the capacitive sensor instance that will be created.
* @param[in] steps_no Number of relative pads. It means that the slider in its handler will give values (1, steps_no).
* @param[in] p1 Pair of two arguments: threshold and analog_input_number. Must be passed as (analog_input_number, threshold).
* @param[in] p2 Pair of two arguments: threshold and analog_input_number. Must be passed as (analog_input_number, threshold).
* @param[in] p3 Pair of two arguments: threshold and analog_input_number. Must be passed as (analog_input_number, threshold).
* @param[in] p4 Pair of two arguments: threshold and analog_input_number. Must be passed as (analog_input_number, threshold).
* @param[in] p5 Pair of two arguments: threshold and analog_input_number. Must be passed as (analog_input_number, threshold).
*/
#define NRF_CSENSE_SLIDER_5_DEF(name, steps_no, p1, p2, p3, p4, p5) NRF_CSENSE_INTERNAL_SLIDER_5_DEF(name, steps_no, p1, p2, p3, p4, p5)
/**
* @brief Macro for creating a 3-pad wheel instance.
*
* @param[in,out] name Name of the capacitive sensor instance that will be created.
* @param[in] steps_no Number of relative pads. It means that the slider in its handler will give values (1, steps_no).
* @param[in] p1 Pair of two arguments: threshold and analog_input_number. Must be passed as (analog_input_number, threshold).
* @param[in] p2 Pair of two arguments: threshold and analog_input_number. Must be passed as (analog_input_number, threshold).
* @param[in] p3 Pair of two arguments: threshold and analog_input_number. Must be passed as (analog_input_number, threshold).
*/
#define NRF_CSENSE_WHEEL_3_DEF(name, steps_no, p1, p2, p3) NRF_CSENSE_INTERNAL_WHEEL_3_DEF(name, steps_no, p1, p2, p3)
/**
* @brief Macro for creating a 4-pad wheel instance.
*
* @param[in,out] name Name of the capacitive sensor instance that will be created.
* @param[in] steps_no Number of relative pads. It means that the slider in its handler will give values (1, steps_no).
* @param[in] p1 Pair of two arguments: threshold and analog_input_number. Must be passed as (analog_input_number, threshold).
* @param[in] p2 Pair of two arguments: threshold and analog_input_number. Must be passed as (analog_input_number, threshold).
* @param[in] p3 Pair of two arguments: threshold and analog_input_number. Must be passed as (analog_input_number, threshold).
* @param[in] p4 Pair of two arguments: threshold and analog_input_number. Must be passed as (analog_input_number, threshold).
*/
#define NRF_CSENSE_WHEEL_4_DEF(name, steps_no, p1, p2, p3, p4) NRF_CSENSE_INTERNAL_WHEEL_4_DEF(name, steps_no, p1, p2, p3, p4)
/**
* @brief Macro for creating a 5-pad wheel instance.
*
* @param[in,out] name Name of the capacitive sensor instance that will be created.
* @param[in] steps_no Number of relative pads. It means that the slider in its handler will give values (1, steps_no).
* @param[in] p1 Pair of two arguments: threshold and analog_input_number. Must be passed as (analog_input_number, threshold).
* @param[in] p2 Pair of two arguments: threshold and analog_input_number. Must be passed as (analog_input_number, threshold).
* @param[in] p3 Pair of two arguments: threshold and analog_input_number. Must be passed as (analog_input_number, threshold).
* @param[in] p4 Pair of two arguments: threshold and analog_input_number. Must be passed as (analog_input_number, threshold).
* @param[in] p5 Pair of two arguments: threshold and analog_input_number. Must be passed as (analog_input_number, threshold).
*/
#define NRF_CSENSE_WHEEL_5_DEF(name, steps_no, p1, p2, p3, p4, p5) NRF_CSENSE_INTERNAL_WHEEL_5_DEF(name, steps_no, p1, p2, p3, p4, p5)
/**
* @cond (NODOX)
* @defgroup nrf_csense_internal Auxiliary internal types declarations
* @brief Module for internal usage inside the library only.
* @details These definitions are available to the user, but they should not
* be accessed directly. Use the API to access them.
* @{
*
*/
/*
* @brief Forward declaration of capacitive sensor instance.
*/
typedef struct nrf_csense_instance_s nrf_csense_instance_t;
/*
* @brief Forward declaration of a capacitive sensor pad.
*/
typedef struct nrf_csense_pad_s nrf_csense_pad_t;
/**
* @brief Structure with pointer to min and max values measured on pads.
*/
typedef struct
{
uint16_t max_value; //!< Max value measured on pads.
uint16_t min_value; //!< Min value measured on pads.
}nrf_csense_min_max_t;
/**
* @brief Structure with single instance parameters. This can be either a slider or a button.
*/
struct nrf_csense_instance_s
{
nrf_csense_instance_t * p_next_instance; //!< Pointer to the next instance.
nrf_csense_pad_t * p_nrf_csense_pad; //!< Pointer to the first pad of the module.
nrf_csense_min_max_t * min_max; //!< Structure with pointers to min and max values measured on pads.
uint16_t steps; //!< Number of relative pads. It means that the slider in its handler will give values (1, steps_no).
uint8_t number_of_pads; //!< Number of pads that the instance is using.
bool is_active; //!< Flag to indicate if the instance is active.
bool is_touched; //!< Flag to indicate if the instance is touched.
void * p_context; //!< General purpose pointer.
};
/* Structure with single pad parameters used for initialization. */
struct nrf_csense_pad_s
{
nrf_csense_pad_t * p_next_pad; //!< Pointer to the next pad.
uint16_t threshold; //!< Threshold voltage on pad/time of charging to decide if the pad was touched.
uint8_t pad_index; //!< Index of the pad.
uint8_t analog_input_number; //!< Analog input connected to the pad.
};
/** @}
* @endcond
*/
/**
* @brief Enum for nrf_csense events.
*/
typedef enum
{
NRF_CSENSE_BTN_EVT_PRESSED, //!< Event for pad pressed.
NRF_CSENSE_BTN_EVT_RELEASED, //!< Event for pad released.
NRF_CSENSE_SLIDER_EVT_PRESSED, //!< Event for pad pressed.
NRF_CSENSE_SLIDER_EVT_RELEASED, //!< Event for pad released.
NRF_CSENSE_SLIDER_EVT_DRAGGED, //!< Event for pad dragged.
}nrf_csense_evt_type_t;
/**
* @brief Structure with slider event data including the measured step.
*/
typedef struct
{
uint16_t step; //!< Measured step.
} nrf_csense_slider_evt_t;
/**
* @brief Event data union for nrf_csense events.
*/
typedef union
{
nrf_csense_slider_evt_t slider; //!< Structure with slider event data including the measured step.
} nrf_csense_evt_param_t;
/**
* @brief Structure with event parameters.
*/
typedef struct
{
nrf_csense_evt_type_t nrf_csense_evt_type; //!< Type of event.
nrf_csense_instance_t * p_instance; //!< Pointer to instance.
nrf_csense_evt_param_t params; //!< Event data union for nrf_csense events.
}nrf_csense_evt_t;
/**
* @brief Capacitive sensor handler type.
*/
typedef void (* nrf_csense_event_handler_t)(nrf_csense_evt_t * p_evt);
/**
* @brief Function for setting a handler of the instance.
*
* @param [in] p_instance Pointer to the instance whose steps are going to be changed.
* @param [in] p_context General purpose pointer. Will be passed to the callback function.
*/
__STATIC_INLINE void nrf_csense_instance_context_set(nrf_csense_instance_t * const p_instance, void * p_context)
{
p_instance->p_context = p_context;
}
/**
* @brief Function for initializing the module. After initialization, no instances are enabled.
*
* @param [in] event_handler Event handler for the Capacitive Sensor module.
* @param [in] ticks Time in app_timer ticks between next conversions.
*
* @retval NRF_ERROR_INVALID_PARAM If invalid parameter was provided.
* @retval NRF_ERROR_INVALID_STATE If one of the used modules is in invalid state.
* @retval NRF_ERROR_INTERNAL If an error occured while initializing one of the modules used by the capacitive sensor library.
* @retval NRF_SUCCESS If the module was initialized successfully.
*/
ret_code_t nrf_csense_init(nrf_csense_event_handler_t event_handler, uint32_t ticks);
/**
* @brief Function for uninitializing the module.
*
* @return Values returned by @ref nrf_drv_csense_uninit and @ref app_timer_stop.
*/
ret_code_t nrf_csense_uninit(void);
/**
* @brief Function for adding an instance of capacitive sensor to a linked list.
*
* The function calls @ref nrf_csense_enable to enable the instance that was added to the linked list.
*
* @param [in] p_instance Pointer to the capacitive sensor instance. It is saved by the module and is used whenever the instance is referred.
*
* @return Values returned by @ref nrf_csense_enable.
*/
ret_code_t nrf_csense_add(nrf_csense_instance_t * const p_instance);
/**
* @brief Function for enabling a single instance.
*
* @param [in,out] p_instance Pointer to the capacitive sensor instance. It is saved by the module and is used whenever the instance is referred.
*
* @return Values returned by @ref app_timer_start.
*/
ret_code_t nrf_csense_enable(nrf_csense_instance_t * const p_instance);
/**
* @brief Function for disabling an instance.
*
* @param [in] p_instance Pointer to the instance to be disabled.
*
* @retval NRF_ERROR_INVALID_PARAM If the instance was already disabled.
* @retval NRF_SUCCESS If the instance was disabled successfully.
*/
ret_code_t nrf_csense_disable(nrf_csense_instance_t * const p_instance);
/**
* @brief Function for setting ticks between next measurements.
*
* @param [in] ticks New time between conversions in app_timer ticks.
*
* @retval NRF_ERROR_BUSY If the capacitive sensor was busy.
* @retval NRF_ERROR_INVALID_PARAM If an invalid parameter was provided.
* @retval NRF_ERROR_INVALID_STATE If app_timer was in invalid state.
* @retval NRF_SUCCESS If ticks were set successfully.
*/
ret_code_t nrf_csense_ticks_set(uint32_t ticks);
/**
* @brief Function for setting steps of an instance.
*
* Note that you have do disable the instance before you can change its number of steps.
*
* @param [in] p_instance Pointer to the instance whose steps are going to be changed.
* @param [in] steps New steps value.
*
* @retval NRF_ERROR_BUSY If the capacitive sensor was busy.
* @retval NRF_SUCCESS If steps were set successfully.
*/
ret_code_t nrf_csense_steps_set(nrf_csense_instance_t * const p_instance, uint16_t steps);
/** @} */
#endif //NRF_CSENSE_H__

View File

@@ -1,359 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF_CSENSE_MACROS_H__
#define NRF_CSENSE_MACROS_H__
/** @file
*
* @defgroup nrf_csense_macros Capacitive sensor macros
* @{
* @ingroup nrf_csense
*
* @brief A set of macros to facilitate creation of a new capacitive sensor instance.
*/
#define NRF_CSENSE_INTERNAL_BUTTON_DEF(name, p1) \
static nrf_csense_pad_t CONCAT_2(name, _pad) = \
{ \
.p_next_pad = NULL, \
.threshold = GET_ARG_2 p1, \
.pad_index = 0, \
.analog_input_number = GET_ARG_1 p1 \
}; \
static nrf_csense_min_max_t CONCAT_2(name, _minmax); \
static nrf_csense_instance_t name = \
{ \
.p_nrf_csense_pad = &CONCAT_2(name, _pad), \
.min_max = &CONCAT_2(name, _minmax), \
.steps = 1, \
.number_of_pads = 1, \
.is_active = false, \
.is_touched = false \
};
#define NRF_CSENSE_INTERNAL_SLIDER_2_DEF(name, steps_no, p1, p2) \
static nrf_csense_pad_t CONCAT_2(name, _pad)[2] = \
{ \
{ \
.p_next_pad = &CONCAT_2(name, _pad)[1], \
.threshold = GET_ARG_2 p1, \
.pad_index = 0, \
.analog_input_number = GET_ARG_1 p1 \
}, \
{ \
.p_next_pad = NULL, \
.threshold = GET_ARG_2 p2, \
.pad_index = 1, \
.analog_input_number = GET_ARG_1 p2 \
} \
}; \
\
static nrf_csense_min_max_t CONCAT_2(name, _minmax)[2]; \
static nrf_csense_instance_t name = \
{ \
.p_nrf_csense_pad = CONCAT_2(name, _pad), \
.min_max = CONCAT_2(name, _minmax), \
.steps = steps_no, \
.number_of_pads = 2, \
.is_active = false, \
.is_touched = false \
};
#define NRF_CSENSE_INTERNAL_SLIDER_3_DEF(name, steps_no, p1, p2, p3) \
static nrf_csense_pad_t CONCAT_2(name, _pad)[3] = \
{ \
{ \
.p_next_pad = &CONCAT_2(name, _pad)[1], \
.threshold = GET_ARG_2 p1, \
.pad_index = 0, \
.analog_input_number = GET_ARG_1 p1 \
}, \
{ \
.p_next_pad = &CONCAT_2(name, _pad)[2], \
.threshold = GET_ARG_2 p2, \
.pad_index = 1, \
.analog_input_number = GET_ARG_1 p2 \
}, \
{ \
.p_next_pad = NULL, \
.threshold = GET_ARG_2 p3, \
.pad_index = 2, \
.analog_input_number = GET_ARG_1 p3 \
} \
}; \
\
static nrf_csense_min_max_t CONCAT_2(name, _minmax)[3]; \
static nrf_csense_instance_t name = \
{ \
.p_nrf_csense_pad = CONCAT_2(name, _pad), \
.min_max = CONCAT_2(name, _minmax), \
.steps = steps_no, \
.number_of_pads = 3, \
.is_active = false, \
.is_touched = false \
};
#define NRF_CSENSE_INTERNAL_SLIDER_4_DEF(name, steps_no, p1, p2, p3, p4) \
static nrf_csense_pad_t CONCAT_2(name, _pad)[4] = \
{ \
{ \
.p_next_pad = &CONCAT_2(name, _pad)[1], \
.threshold = GET_ARG_2 p1, \
.pad_index = 0, \
.analog_input_number = GET_ARG_1 p1 \
}, \
{ \
.p_next_pad = &CONCAT_2(name, _pad)[2], \
.threshold = GET_ARG_2 p2, \
.pad_index = 1, \
.analog_input_number = GET_ARG_1 p2 \
}, \
{ \
.p_next_pad = &CONCAT_2(name, _pad)[3], \
.threshold = GET_ARG_2 p3, \
.pad_index = 2, \
.analog_input_number = GET_ARG_1 p3 \
}, \
{ \
.p_next_pad = NULL, \
.threshold = GET_ARG_2 p4, \
.pad_index = 3, \
.analog_input_number = GET_ARG_1 p4 \
} \
}; \
static nrf_csense_min_max_t CONCAT_2(name, _minmax)[4]; \
static nrf_csense_instance_t name = \
{ \
.p_nrf_csense_pad = CONCAT_2(name, _pad), \
.min_max = CONCAT_2(name, _minmax), \
.steps = steps_no, \
.number_of_pads = 4, \
.is_active = false, \
.is_touched = false \
};
#define NRF_CSENSE_INTERNAL_SLIDER_5_DEF(name, steps_no, p1, p2, p3, p4, p5) \
static nrf_csense_pad_t CONCAT_2(name, _pad)[5] = \
{ \
{ \
.p_next_pad = &CONCAT_2(name, _pad)[1], \
.threshold = GET_ARG_2 p1, \
.pad_index = 0, \
.analog_input_number = GET_ARG_1 p1 \
}, \
{ \
.p_next_pad = &CONCAT_2(name, _pad)[2], \
.threshold = GET_ARG_2 p2, \
.pad_index = 1, \
.analog_input_number = GET_ARG_1 p2 \
}, \
{ \
.p_next_pad = &CONCAT_2(name, _pad)[3], \
.threshold = GET_ARG_2 p3, \
.pad_index = 2, \
.analog_input_number = GET_ARG_1 p3 \
}, \
{ \
.p_next_pad = &CONCAT_2(name, _pad)[4], \
.threshold = GET_ARG_2 p4, \
.pad_index = 3, \
.analog_input_number = GET_ARG_1 p4 \
}, \
{ \
.p_next_pad = NULL, \
.threshold = GET_ARG_2 p5, \
.pad_index = 4, \
.analog_input_number = GET_ARG_1 p5 \
} \
}; \
\
static nrf_csense_min_max_t CONCAT_2(name, _minmax)[5]; \
static nrf_csense_instance_t name = \
{ \
.p_nrf_csense_pad = CONCAT_2(name, _pad), \
.min_max = CONCAT_2(name, _minmax), \
.steps = steps_no, \
.number_of_pads = 5, \
.is_active = false, \
.is_touched = false \
};
#define NRF_CSENSE_INTERNAL_WHEEL_3_DEF(name, steps_no, p1, p2, p3) \
static nrf_csense_pad_t CONCAT_2(name, _pad)[4] = \
{ \
{ \
.p_next_pad = &CONCAT_2(name, _pad)[1], \
.threshold = GET_ARG_2 p1, \
.pad_index = 0, \
.analog_input_number = GET_ARG_1 p1 \
}, \
{ \
.p_next_pad = &CONCAT_2(name, _pad)[2], \
.threshold = GET_ARG_2 p2, \
.pad_index = 1, \
.analog_input_number = GET_ARG_1 p2 \
}, \
{ \
.p_next_pad = &CONCAT_2(name, _pad)[3], \
.threshold = GET_ARG_2 p3, \
.pad_index = 2, \
.analog_input_number = GET_ARG_1 p3 \
}, \
{ \
.p_next_pad = NULL, \
.threshold = GET_ARG_2 p1, \
.pad_index = 3, \
.analog_input_number = GET_ARG_1 p1 \
} \
}; \
\
static nrf_csense_min_max_t CONCAT_2(name, _minmax)[4]; \
static nrf_csense_instance_t name = \
{ \
.p_nrf_csense_pad = CONCAT_2(name, _pad), \
.min_max = CONCAT_2(name, _minmax), \
.steps = steps_no, \
.number_of_pads = 4, \
.is_active = false, \
.is_touched = false \
};
#define NRF_CSENSE_INTERNAL_WHEEL_4_DEF(name, steps_no, p1, p2, p3, p4) \
static nrf_csense_pad_t CONCAT_2(name, _pad)[5] = \
{ \
{ \
.p_next_pad = &CONCAT_2(name, _pad)[1], \
.threshold = GET_ARG_2 p1, \
.pad_index = 0, \
.analog_input_number = GET_ARG_1 p1 \
}, \
{ \
.p_next_pad = &CONCAT_2(name, _pad)[2], \
.threshold = GET_ARG_2 p2, \
.pad_index = 1, \
.analog_input_number = GET_ARG_1 p2 \
}, \
{ \
.p_next_pad = &CONCAT_2(name, _pad)[3], \
.threshold = GET_ARG_2 p3, \
.pad_index = 2, \
.analog_input_number = GET_ARG_1 p3 \
}, \
{ \
.p_next_pad = &CONCAT_2(name, _pad)[4], \
.threshold = GET_ARG_2 p4, \
.pad_index = 3, \
.analog_input_number = GET_ARG_1 p4 \
}, \
{ \
.p_next_pad = NULL, \
.threshold = GET_ARG_2 p1, \
.pad_index = 4, \
.analog_input_number = GET_ARG_1 p1 \
} \
}; \
\
static nrf_csense_min_max_t CONCAT_2(name, _minmax)[5]; \
static nrf_csense_instance_t name = \
{ \
.p_nrf_csense_pad = CONCAT_2(name, _pad), \
.min_max = CONCAT_2(name, _minmax), \
.steps = steps_no, \
.number_of_pads = 5, \
.is_active = false, \
.is_touched = false \
};
#define NRF_CSENSE_INTERNAL_WHEEL_5_DEF(name, steps_no, p1, p2, p3, p4, p5)\
static nrf_csense_pad_t CONCAT_2(name, _pad)[6] = \
{ \
{ \
.p_next_pad = &CONCAT_2(name, _pad)[1], \
.threshold = GET_ARG_2 p1, \
.pad_index = 0, \
.analog_input_number = GET_ARG_1 p1 \
}, \
{ \
.p_next_pad = &CONCAT_2(name, _pad)[2], \
.threshold = GET_ARG_2 p2, \
.pad_index = 1, \
.analog_input_number = GET_ARG_1 p2 \
}, \
{ \
.p_next_pad = &CONCAT_2(name, _pad)[3], \
.threshold = GET_ARG_2 p3, \
.pad_index = 2, \
.analog_input_number = GET_ARG_1 p3 \
}, \
{ \
.p_next_pad = &CONCAT_2(name, _pad)[4], \
.threshold = GET_ARG_2 p4, \
.pad_index = 3, \
.analog_input_number = GET_ARG_1 p4 \
}, \
{ \
.p_next_pad = &CONCAT_2(name, _pad)[5], \
.threshold = GET_ARG_2 p5, \
.pad_index = 4, \
.analog_input_number = GET_ARG_1 p5 \
}, \
{ \
.p_next_pad = NULL, \
.threshold = GET_ARG_2 p1, \
.pad_index = 5, \
.analog_input_number = GET_ARG_1 p1 \
} \
}; \
\
static nrf_csense_min_max_t CONCAT_2(name, _minmax)[6]; \
static nrf_csense_instance_t name = \
{ \
.p_nrf_csense_pad = CONCAT_2(name, _pad), \
.min_max = CONCAT_2(name, _minmax), \
.steps = steps_no, \
.number_of_pads = 6, \
.is_active = false, \
.is_touched = false \
};
/** @} */
#endif // NRF_CSENSE_MACROS_H__

View File

@@ -1,633 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sdk_common.h"
#if NRF_MODULE_ENABLED(NRF_DRV_CSENSE)
#include "nrf_drv_csense.h"
#include "nrf_peripherals.h"
#include "nrf_gpio.h"
#include "app_error.h"
#include "app_util_platform.h"
#include "nrf_assert.h"
#include "string.h"
#include <stdio.h>
#if defined(__CORTEX_M) && (__CORTEX_M < 4)
#ifndef ARM_MATH_CM0PLUS
#define ARM_MATH_CM0PLUS
#endif
/*lint -save -e689 */
#include "arm_math.h"
/*lint -restore */
#endif
#if USE_COMP
#include "nrf_drv_comp.h"
#include "nrf_drv_ppi.h"
#include "nrf_drv_timer.h"
#endif //USE_COMP
#if USE_COMP == 0
#ifdef ADC_PRESENT
#include "nrfx_adc.h"
/**
* @defgroup adc_defines ADC defines to count input voltage.
* @{
*/
#define ADC_RES_10BIT 1024
#define ADC_INPUT_PRESCALER 3
#define ADC_REF_VBG_VOLTAGE 1.2
/* @} */
/* ADC channel used to call conversion. */
static nrfx_adc_channel_t adc_channel = NRFX_ADC_DEFAULT_CHANNEL(NRF_ADC_CONFIG_INPUT_0);
#elif defined(SAADC_PRESENT)
#include "nrf_drv_saadc.h"
/**
* @defgroup saadc_defines SAADC defines to count input voltage.
* @{
*/
#define SAADC_RES_10BIT 1024
#define SAADC_INPUT_PRESCALER 3
#define SAADC_REF_VBG_VOLTAGE 0.6
/* @} */
/* SAADC channel used to call conversion. */
static nrf_saadc_channel_config_t saadc_channel = NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN0);
#endif //ADC_PRESENT
#endif //USE_COMP
#if USE_COMP
/* Number of channels required by PPI. */
#define PPI_REQUIRED_CHANNELS 3
/* Array of PPI channels. */
static nrf_ppi_channel_t m_ppi_channels[PPI_REQUIRED_CHANNELS];
/**
* @defgroup timer_instances Timer instances.
* @{
*/
static const nrf_drv_timer_t m_timer0 = NRF_DRV_TIMER_INSTANCE(TIMER0_FOR_CSENSE);
static const nrf_drv_timer_t m_timer1 = NRF_DRV_TIMER_INSTANCE(TIMER1_FOR_CSENSE);
/* @} */
#endif //USE_COMP
/* Configuration of the capacitive sensor module. */
typedef struct
{
volatile nrfx_drv_state_t module_state; /**< State of the module. */
nrf_drv_csense_event_handler_t event_handler; /**< Event handler for capacitor sensor events. */
uint16_t analog_values[MAX_ANALOG_INPUTS]; /**< Array containing analog values measured on the corresponding COMP/ADC channel. */
volatile bool busy; /**< Indicates state of module - busy if there are ongoing conversions. */
volatile uint8_t cur_chann_idx; /**< Current channel to be read if enabled. */
volatile uint8_t adc_channels_input_mask; /**< Enabled channels. */
uint8_t output_pin; /**< Pin to generate signal charging capacitors. */
uint8_t channels_to_read; /**< Mask of channels remaining to be read in the current measurement. */
volatile bool timers_powered_on; /**< Flag to indicate if timers were already started. */
}csense_t;
static csense_t m_csense;
/**
* @brief Function for determining the next analog channel to be read.
*/
__STATIC_INLINE void calculate_next_channel(void)
{
m_csense.cur_chann_idx = 31 - __CLZ(m_csense.channels_to_read);
}
/**
* @brief Function for handling conversion values.
*
* @param[in] val Value received from ADC or COMP.
*/
static void conversion_handler(uint16_t val)
{
nrf_drv_csense_evt_t event_struct;
#if USE_COMP == 0
nrf_gpio_pin_set(m_csense.output_pin);
#endif //USE_COMP
m_csense.analog_values[m_csense.cur_chann_idx] = val;
event_struct.read_value = val;
event_struct.analog_channel = m_csense.cur_chann_idx;
m_csense.channels_to_read &= ~(1UL<<m_csense.cur_chann_idx);
// decide if there will be more conversions
if (m_csense.channels_to_read == 0)
{
m_csense.busy = false;
#if USE_COMP == 0 && defined(SAADC_PRESENT)
nrf_saadc_disable();
#endif
}
m_csense.event_handler(&event_struct);
if (m_csense.channels_to_read > 0) // Start new conversion.
{
ret_code_t err_code;
calculate_next_channel();
err_code = nrf_drv_csense_sample();
if (err_code != NRF_SUCCESS)
{
return;
}
}
}
#if USE_COMP
/**
* @brief Timer0 interrupt handler.
*
* @param[in] event_type Timer event.
* @param[in] p_context General purpose parameter set during initialization of
* the timer. This parameter can be used to pass
* additional information to the handler function, for
* example, the timer ID.
*/
static void counter_compare_handler(nrf_timer_event_t event_type, void* p_context)
{
if (event_type == NRF_TIMER_EVENT_COMPARE0)
{
uint16_t val = nrf_drv_timer_capture_get(&m_timer1, NRF_TIMER_CC_CHANNEL1);
nrf_drv_timer_pause(&m_timer1);
nrf_drv_timer_clear(&m_timer1);
/* Handle finished measurement. */
conversion_handler(val);
}
}
/**
* @brief Dummy handler.
*
* @param[in] event_type Timer event.
* @param[in] p_context General purpose parameter set during initialization of
* the timer. This parameter can be used to pass
* additional information to the handler function, for
* example, the timer ID.
*/
static void dummy_handler(nrf_timer_event_t event_type, void* p_context){}
/**
* @brief Function for initializing timers.
*
* @retval NRF_ERROR_INTERNAL If there were error initializing timers.
* @retval NRF_SUCCESS If timers were initialized successfully.
*/
static ret_code_t timer_init(void)
{
ret_code_t err_code;
//set first timer in timer mode to get period of relaxation oscillator
nrf_drv_timer_config_t timer_config = NRF_DRV_TIMER_DEFAULT_CONFIG;
timer_config.mode = NRF_TIMER_MODE_TIMER;
err_code = nrf_drv_timer_init(&m_timer1, &timer_config, dummy_handler);
if (err_code != NRF_SUCCESS)
{
return NRF_ERROR_INTERNAL;
}
//set second timer in counter mode and generate event on tenth period
timer_config.mode = NRF_TIMER_MODE_COUNTER;
err_code = nrf_drv_timer_init(&m_timer0, &timer_config, counter_compare_handler);
if (err_code != NRF_SUCCESS)
{
return NRF_ERROR_INTERNAL;
}
nrf_drv_timer_extended_compare(&m_timer0, NRF_TIMER_CC_CHANNEL0, MEASUREMENT_PERIOD, (nrf_timer_short_mask_t)(NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK | NRF_TIMER_SHORT_COMPARE0_STOP_MASK), true);
return NRF_SUCCESS;
}
/**
* @brief Function for initializing and enabling PPI channels.
*
* @retval NRF_ERROR_INTERNAL If there were error initializing or enabling PPI channels.
* @retval NRF_SUCCESS If PPI channels were initialized and enabled successfully.
*/
static ret_code_t ppi_init(void)
{
ret_code_t err_code;
uint8_t i;
err_code = nrf_drv_ppi_init();
if ((err_code != NRF_SUCCESS) && (err_code != NRF_ERROR_MODULE_ALREADY_INITIALIZED))
{
return NRF_ERROR_INTERNAL;
}
for (i = 0; i < PPI_REQUIRED_CHANNELS ; i++)
{
err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channels[i]);
if (NRF_SUCCESS != err_code)
{
return NRF_ERROR_INTERNAL;
}
}
err_code = nrf_drv_ppi_channel_assign(m_ppi_channels[0], nrf_drv_comp_event_address_get(NRF_COMP_EVENT_CROSS), nrf_drv_timer_task_address_get(&m_timer0, NRF_TIMER_TASK_COUNT));
if (NRF_SUCCESS != err_code)
{
return NRF_ERROR_INTERNAL;
}
err_code = nrf_drv_ppi_channel_assign(m_ppi_channels[1], nrf_drv_timer_event_address_get(&m_timer0, NRF_TIMER_EVENT_COMPARE0), nrf_drv_timer_task_address_get(&m_timer1, NRF_TIMER_TASK_CAPTURE1));
if (NRF_SUCCESS != err_code)
{
return NRF_ERROR_INTERNAL;
}
err_code = nrf_drv_ppi_channel_fork_assign(m_ppi_channels[1], nrf_drv_comp_task_address_get(NRF_COMP_TASK_STOP));
if (NRF_SUCCESS != err_code)
{
return NRF_ERROR_INTERNAL;
}
err_code = nrf_drv_ppi_channel_assign(m_ppi_channels[2], nrf_drv_comp_event_address_get(NRF_COMP_EVENT_READY), nrf_drv_timer_task_address_get(&m_timer0, NRF_TIMER_TASK_CLEAR));
if (NRF_SUCCESS != err_code)
{
return NRF_ERROR_INTERNAL;
}
err_code = nrf_drv_ppi_channel_fork_assign(m_ppi_channels[2], nrf_drv_timer_task_address_get(&m_timer1, NRF_TIMER_TASK_CLEAR));
if (NRF_SUCCESS != err_code)
{
return NRF_ERROR_INTERNAL;
}
for (i = 0; i < PPI_REQUIRED_CHANNELS ; i++)
{
err_code = nrf_drv_ppi_channel_enable(m_ppi_channels[i]);
if (NRF_SUCCESS != err_code)
{
return NRF_ERROR_INTERNAL;
}
}
return NRF_SUCCESS;
}
/**
* @brief Dummy handler for COMP events.
*
* @param[in] event COMP event.
*/
static void comp_event_handler(nrf_comp_event_t event){}
/**
* @brief Function for initializing COMP module in relaxation oscillator mode.
*
* @note The frequency of the oscillator depends on threshold voltages, current source and capacitance of pad and can be calculated as f_OSC = I_SOURCE / (2C·(VUP-VDOWN) ).
*
* @retval NRF_ERROR_INTERNAL If there were error while initializing COMP driver.
* @retval NRF_SUCCESS If the COMP driver initialization was successful.
*/
static ret_code_t comp_init(void)
{
ret_code_t err_code;
nrf_drv_comp_config_t m_comp_config = NRF_DRV_COMP_DEFAULT_CONFIG(NRF_COMP_INPUT_0);
/* Workaround for Errata 12 "COMP: Reference ladder is not correctly calibrated" found at the Errata document
for your device located at https://infocenter.nordicsemi.com/ */
*(volatile uint32_t *)0x40013540 = (*(volatile uint32_t *)0x10000324 & 0x00001F00) >> 8;
m_comp_config.isource = NRF_COMP_ISOURCE_Ien10uA;
err_code = nrf_drv_comp_init(&m_comp_config, comp_event_handler);
if (err_code != NRF_SUCCESS)
{
return NRF_ERROR_INTERNAL;
}
return NRF_SUCCESS;
}
#endif //USE_COMP
#if USE_COMP == 0
#ifdef ADC_PRESENT
/**
* @brief ADC handler.
*
* @param[in] p_event Pointer to analog-to-digital converter driver event.
*/
void adc_handler(nrfx_adc_evt_t const * p_event)
{
nrf_gpio_pin_set(m_csense.output_pin);
uint16_t val;
val = (uint16_t)(p_event->data.sample.sample *
ADC_REF_VBG_VOLTAGE * 1000 *
ADC_INPUT_PRESCALER / ADC_RES_10BIT);
conversion_handler(val);
}
/**
* @brief Function for initializing ADC.
*/
static ret_code_t adc_init(void)
{
ret_code_t err_code;
adc_channel.config.config.input = NRF_ADC_CONFIG_SCALING_INPUT_ONE_THIRD;
nrfx_adc_config_t const adc_config = NRFX_ADC_DEFAULT_CONFIG;
err_code = nrfx_adc_init(&adc_config, adc_handler);
if (err_code != NRF_SUCCESS)
{
return NRF_ERROR_INTERNAL;
}
nrf_gpio_pin_set(m_csense.output_pin);
return NRF_SUCCESS;
}
#elif defined(SAADC_PRESENT)
/**
* @brief SAADC handler.
*
* @param[in] p_event Pointer to analog-to-digital converter driver event.
*/
void saadc_handler(nrf_drv_saadc_evt_t const * p_event)
{
nrf_gpio_pin_set(m_csense.output_pin);
uint16_t val;
(void)nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, 1);
val = (uint16_t)(*p_event->data.done.p_buffer *
SAADC_REF_VBG_VOLTAGE * 1000 *
SAADC_INPUT_PRESCALER / SAADC_RES_10BIT);
conversion_handler(val);
}
/**
* @brief Function for initializing SAADC.
*/
static ret_code_t saadc_init(void)
{
ret_code_t err_code;
static nrf_saadc_value_t saadc_value;
saadc_channel.gain = NRF_SAADC_GAIN1_3;
err_code = nrf_drv_saadc_init(NULL, saadc_handler);
if (err_code != NRF_SUCCESS)
{
return NRF_ERROR_INTERNAL;
}
nrf_gpio_pin_set(m_csense.output_pin);
err_code = nrf_drv_saadc_channel_init(0, &saadc_channel);
if (err_code != NRF_SUCCESS)
{
return NRF_ERROR_INTERNAL;
}
err_code = nrf_drv_saadc_buffer_convert(&saadc_value, 1);
if (err_code != NRF_SUCCESS)
{
return NRF_ERROR_INTERNAL;
}
nrf_saadc_disable();
return NRF_SUCCESS;
}
#endif //ADC_PRESENT
#endif //USE_COMP
ret_code_t nrf_drv_csense_init(nrf_drv_csense_config_t const * p_config, nrf_drv_csense_event_handler_t event_handler)
{
ASSERT(m_csense.module_state == NRFX_DRV_STATE_UNINITIALIZED);
ASSERT(p_config->output_pin <= NUMBER_OF_PINS);
ret_code_t err_code;
if (p_config == NULL)
{
return NRF_ERROR_INVALID_PARAM;
}
if (event_handler == NULL)
{
return NRF_ERROR_INVALID_PARAM;
}
m_csense.busy = false;
#if USE_COMP == 0
m_csense.output_pin = p_config->output_pin;
nrf_gpio_cfg_output(m_csense.output_pin);
nrf_gpio_pin_set(m_csense.output_pin);
#endif //COMP_PRESENT
m_csense.event_handler = event_handler;
#if USE_COMP
err_code = comp_init();
if (err_code != NRF_SUCCESS)
{
return err_code;
}
err_code = timer_init();
if (err_code != NRF_SUCCESS)
{
return err_code;
}
err_code = ppi_init();
if (err_code != NRF_SUCCESS)
{
return err_code;
}
#else
#ifdef ADC_PRESENT
err_code = adc_init();
if (err_code != NRF_SUCCESS)
{
return err_code;
}
#elif defined(SAADC_PRESENT)
err_code = saadc_init();
if (err_code != NRF_SUCCESS)
{
return err_code;
}
#endif //ADC_PRESENT
#endif //USE_COMP
m_csense.module_state = NRFX_DRV_STATE_INITIALIZED;
return NRF_SUCCESS;
}
ret_code_t nrf_drv_csense_uninit(void)
{
ASSERT(m_csense.module_state != NRFX_DRV_STATE_UNINITIALIZED);
nrf_drv_csense_channels_disable(0xFF);
#if USE_COMP
ret_code_t err_code;
uint8_t i;
nrf_drv_timer_uninit(&m_timer0);
nrf_drv_timer_uninit(&m_timer1);
nrf_drv_comp_uninit();
for (i =0; i < 3; i++)
{
err_code = nrf_drv_ppi_channel_free(m_ppi_channels[i]);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
}
err_code = nrf_drv_ppi_uninit();
if (err_code != NRF_SUCCESS)
{
return err_code;
}
#else
#ifdef ADC_PRESENT
nrfx_adc_uninit();
#elif defined(SAADC_PRESENT)
nrf_drv_saadc_uninit();
#endif //ADC_PRESENT
#endif //USE_COMP
m_csense.module_state = NRFX_DRV_STATE_UNINITIALIZED;
memset((void*)&m_csense, 0, sizeof(m_csense));
return NRF_SUCCESS;
}
void nrf_drv_csense_channels_enable(uint8_t channels_mask)
{
ASSERT(m_csense.module_state != NRFX_DRV_STATE_UNINITIALIZED);
m_csense.busy = true;
m_csense.module_state = NRFX_DRV_STATE_POWERED_ON;
m_csense.adc_channels_input_mask |= channels_mask;
m_csense.busy = false;
}
void nrf_drv_csense_channels_disable(uint8_t channels_mask)
{
ASSERT(m_csense.module_state == NRFX_DRV_STATE_POWERED_ON);
m_csense.adc_channels_input_mask &= ~channels_mask;
if (m_csense.adc_channels_input_mask == 0)
{
m_csense.module_state = NRFX_DRV_STATE_INITIALIZED;
}
}
uint16_t nrf_drv_csense_channel_read(uint8_t csense_channel)
{
return m_csense.analog_values[csense_channel];
}
ret_code_t nrf_drv_csense_sample(void)
{
ASSERT(m_csense.module_state == NRFX_DRV_STATE_POWERED_ON);
if (m_csense.adc_channels_input_mask != 0)
{
if (m_csense.channels_to_read == 0)
{
#if USE_COMP == 0 && defined(SAADC_PRESENT)
nrf_saadc_enable();
#endif
if (nrf_drv_csense_is_busy() == true)
{
return NRF_ERROR_BUSY;
}
m_csense.busy = true;
m_csense.channels_to_read = m_csense.adc_channels_input_mask;
calculate_next_channel();
}
#if USE_COMP
if (!m_csense.timers_powered_on)
{
nrf_drv_timer_enable(&m_timer0);
nrf_drv_timer_enable(&m_timer1);
m_csense.timers_powered_on = true;
}
else
{
nrf_drv_timer_resume(&m_timer0);
nrf_drv_timer_resume(&m_timer1);
}
nrf_drv_comp_pin_select((nrf_comp_input_t)m_csense.cur_chann_idx);
nrf_drv_comp_start(0, 0);
#else
ret_code_t err_code;
#ifdef ADC_PRESENT
adc_channel.config.config.ain = (nrf_adc_config_input_t)(1<<m_csense.cur_chann_idx);
nrf_gpio_pin_clear(m_csense.output_pin);
err_code = nrfx_adc_sample_convert(&adc_channel, NULL);
#elif defined(SAADC_PRESENT)
saadc_channel.pin_p = (nrf_saadc_input_t)(m_csense.cur_chann_idx + 1);
nrf_saadc_channel_input_set(0, saadc_channel.pin_p, NRF_SAADC_INPUT_DISABLED);
nrf_gpio_pin_clear(m_csense.output_pin);
err_code = nrf_drv_saadc_sample();
#endif //ADC_PRESENT
if (err_code != NRF_SUCCESS)
{
return err_code;
}
#endif //USE_COMP
}
return NRF_SUCCESS;
}
bool nrf_drv_csense_is_busy(void)
{
return m_csense.busy;
}
#endif //NRF_MODULE_ENABLED(NRF_DRV_CSENSE)

View File

@@ -1,150 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF_DRV_CSENSE_H__
#define NRF_DRV_CSENSE_H__
#include <stdint.h>
#include "sdk_errors.h"
#include "app_timer.h"
/** @file
*
* @defgroup nrf_drv_csense Capacitive sensor low-level library
* @{
* @ingroup app_common
*
* @brief Module for using the capacitive sensor on low-energy level.
*/
/** @brief Maximum number of analog inputs. */
#define MAX_ANALOG_INPUTS 8
/**
* @brief Module initializing structure.
*/
typedef struct
{
uint8_t output_pin; /**< Pin on which to generate voltage for charging the capacitors. */
}nrf_drv_csense_config_t;
/**
* @brief Structure holding event parameters.
*/
typedef struct
{
uint16_t read_value; /**< Value which was read on the analog channel. For nRF51, this value is voltage in millivolts. For nRF52, it is time in ticks of 10 periods of the relaxation oscillator. Voltage corresponds to capacitance of the pad attached to analog channel and gets higher once it
is touched. Period of relaxation also corresponds to the pad capacitance and increases its value when capacitance gets
higher. */
uint8_t analog_channel; /**< Index of the analog channel from which the value was read. */
}nrf_drv_csense_evt_t;
/**
* @brief Capacitive sensor event handler. Called from conversion handler.
*
* @param[in] event_struct Structure holding event parameters.
*/
typedef void (* nrf_drv_csense_event_handler_t) (nrf_drv_csense_evt_t * p_event_struct);
/**
* @brief Function for initializing the module.
*
* @details After calling this function, the module is in initialized state and all channels are disabled. The @ref nrf_drv_csense_channels_enable
* function must be called. This function initializes all modules required by the capacitive sensor library: ADC for (nRF51) or TIMERs, PPIs, and COMP (for nRF52).
*
* @param[in] p_config Structure for initializing the module.
* @param[in] event_handler Event handler for capacitive sensor events.
*
* @retval NRF_ERROR_INVALID_PARAM Invalid parameter.
* @retval NRF_ERROR_NO_MEM Timer operations queue was full.
* @retval NRF_ERROR_INTERNAL Error occurred during timers, PPI's, or COMP initialization.
* @retval NRF_SUCCESS Module was initialized successfully.
*
* @sa nrf_drv_csense_channels_enable
*/
ret_code_t nrf_drv_csense_init(nrf_drv_csense_config_t const * p_config, nrf_drv_csense_event_handler_t event_handler);
/**
* @brief Function for unintializing the capacitive sensor. Clears the mask of enabled channels.
*
* @return Values returned by @ref nrf_drv_ppi_channel_free.
*/
ret_code_t nrf_drv_csense_uninit(void);
/**
* @brief Function for enabling analog channels for the capacitive sensor.
*
* @param[in] channels_mask Mask of analog channels to be enabled.
*/
void nrf_drv_csense_channels_enable(uint8_t channels_mask);
/**
* @brief Function for disabling analog channels of the capacitive sensor.
*
* @param[in] channels_mask Mask of analog channels to be disabled.
*/
void nrf_drv_csense_channels_disable(uint8_t channels_mask);
/**
* @brief Function for getting the last read value from an analog channel.
*
* @param[in] csense_channel Number of the channel to get the value from.
*
* @return Analog value measured on the channel.
*/
uint16_t nrf_drv_csense_channel_read(uint8_t csense_channel);
/**
* @brief Function for triggering a measurement on all enabled analog channels. The handler will be called on every completed measurement.
*
* @retval NRF_ERROR_BUSY If the module was busy or SAADC module is in use and was busy.
* @retval NRF_SUCCESS If the measurement was triggered successfully.
*/
ret_code_t nrf_drv_csense_sample(void);
/**
* @brief Function for checking if the module is busy.
*
* @return True if busy or false if not busy.
*/
bool nrf_drv_csense_is_busy(void);
/** @} */
#endif //NRF_DRV_CSENSE_H__

View File

@@ -1,215 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
/**
* @brief Elliptic Curve Cryptography Interface
*
*/
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "nordic_common.h"
#include "app_timer.h"
#include "app_util.h"
#include "nrf_log.h"
#include "nrf_drv_rng.h"
#include "ecc.h"
#include "uECC.h"
static int ecc_rng(uint8_t *dest, unsigned size)
{
nrf_drv_rng_block_rand(dest, (uint32_t) size);
return 1;
}
void ecc_init(bool rng)
{
if (rng)
{
uECC_set_rng(ecc_rng);
}
}
ret_code_t ecc_p256_keypair_gen(uint8_t *p_le_sk, uint8_t *p_le_pk)
{
const struct uECC_Curve_t * p_curve;
if (!p_le_sk || !p_le_pk)
{
return NRF_ERROR_NULL;
}
if (!is_word_aligned(p_le_sk) || !is_word_aligned(p_le_pk))
{
return NRF_ERROR_INVALID_ADDR;
}
p_curve = uECC_secp256r1();
int ret = uECC_make_key((uint8_t *) p_le_pk, (uint8_t *) p_le_sk, p_curve);
if (!ret)
{
return NRF_ERROR_INTERNAL;
}
return NRF_SUCCESS;
}
ret_code_t ecc_p256_public_key_compute(uint8_t const *p_le_sk, uint8_t *p_le_pk)
{
const struct uECC_Curve_t * p_curve;
if (!p_le_sk || !p_le_pk)
{
return NRF_ERROR_NULL;
}
if (!is_word_aligned(p_le_sk) || !is_word_aligned(p_le_pk))
{
return NRF_ERROR_INVALID_ADDR;
}
p_curve = uECC_secp256r1();
//NRF_LOG_INFO("uECC_compute_public_key");
int ret = uECC_compute_public_key((uint8_t *) p_le_sk, (uint8_t *) p_le_pk, p_curve);
if (!ret)
{
return NRF_ERROR_INTERNAL;
}
//NRF_LOG_INFO("uECC_compute_public_key complete: %d", ret);
return NRF_SUCCESS;
}
ret_code_t ecc_p256_shared_secret_compute(uint8_t const *p_le_sk, uint8_t const *p_le_pk, uint8_t *p_le_ss)
{
int ret;
const struct uECC_Curve_t * p_curve;
if (!p_le_sk || !p_le_pk || !p_le_ss)
{
return NRF_ERROR_NULL;
}
if (!is_word_aligned(p_le_sk) || !is_word_aligned(p_le_pk) || !is_word_aligned(p_le_ss))
{
return NRF_ERROR_INVALID_ADDR;
}
p_curve = uECC_secp256r1();
// Validate the remote public key
ret = uECC_valid_public_key((uint8_t*) p_le_pk, p_curve);
if (!ret)
{
return NRF_ERROR_INTERNAL;
}
//NRF_LOG_INFO("uECC_shared_secret");
ret = uECC_shared_secret((uint8_t *) p_le_pk, (uint8_t *) p_le_sk, p_le_ss, p_curve);
if (!ret)
{
return NRF_ERROR_INTERNAL;
}
//NRF_LOG_INFO("uECC_shared_secret complete: %d", ret);
return NRF_SUCCESS;
}
ret_code_t ecc_p256_sign(uint8_t const *p_le_sk, uint8_t const * p_le_hash, uint32_t hlen, uint8_t *p_le_sig)
{
const struct uECC_Curve_t * p_curve;
if (!p_le_sk || !p_le_hash || !p_le_sig)
{
return NRF_ERROR_NULL;
}
if (!is_word_aligned(p_le_sk) || !is_word_aligned(p_le_hash) || !is_word_aligned(p_le_sig))
{
return NRF_ERROR_INVALID_ADDR;
}
p_curve = uECC_secp256r1();
//NRF_LOG_INFO("uECC_sign");
int ret = uECC_sign((const uint8_t *) p_le_sk, (const uint8_t *) p_le_hash, (unsigned) hlen, (uint8_t *) p_le_sig, p_curve);
if (!ret)
{
return NRF_ERROR_INTERNAL;
}
//NRF_LOG_INFO("uECC_sign complete: %d", ret);
return NRF_SUCCESS;
}
ret_code_t ecc_p256_verify(uint8_t const *p_le_pk, uint8_t const * p_le_hash, uint32_t hlen, uint8_t const *p_le_sig)
{
const struct uECC_Curve_t * p_curve;
if (!p_le_pk || !p_le_hash || !p_le_sig)
{
return NRF_ERROR_NULL;
}
if (!is_word_aligned(p_le_pk) || !is_word_aligned(p_le_hash) || !is_word_aligned(p_le_sig))
{
return NRF_ERROR_INVALID_ADDR;
}
p_curve = uECC_secp256r1();
//NRF_LOG_INFO("uECC_verify");
int ret = uECC_verify((const uint8_t *) p_le_pk, (const uint8_t *) p_le_hash, (unsigned) hlen, (uint8_t *) p_le_sig, p_curve);
if (!ret)
{
return NRF_ERROR_INVALID_DATA;
}
//NRF_LOG_INFO("uECC_verify complete: %d", ret);
return NRF_SUCCESS;
}

View File

@@ -1,143 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**
* @defgroup ecc Elliptic Curve Cryptography interface
* @{
* @ingroup app_common
* @brief Elliptic Curve Cryptography interface
*/
#ifndef ECC_H__
#define ECC_H__
#include <stdint.h>
#include <stdbool.h>
#include "nordic_common.h"
#include "nrf_error.h"
#include "sdk_errors.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ECC_P256_SK_LEN 32
#define ECC_P256_PK_LEN 64
/**@brief Initialize the ECC module.
*
* @param[in] rng Use a random number generator.
*
* */
void ecc_init(bool rng);
/**@brief Create a public/private key pair.
*
* @param[out] p_le_sk Private key. Pointer must be aligned to a 4-byte boundary.
* @param[out] p_le_pk Public key. Pointer must be aligned to a 4-byte boundary.
*
* @retval NRF_SUCCESS Key pair successfuly created.
* @retval NRF_ERROR_NULL NULL pointer provided.
* @retval NRF_ERROR_INVALID_ADDR Unaligned pointer provided.
* @retval NRF_ERROR_INTERNAL Internal error during key generation.
*/
ret_code_t ecc_p256_keypair_gen(uint8_t *p_le_sk, uint8_t* p_le_pk);
/**@brief Create a public key from a provided private key.
*
* @param[in] p_le_sk Private key. Pointer must be aligned to a 4-byte boundary.
* @param[out] p_le_pk Public key. Pointer must be aligned to a 4-byte boundary.
*
* @retval NRF_SUCCESS Public key successfuly created.
* @retval NRF_ERROR_NULL NULL pointer provided.
* @retval NRF_ERROR_INVALID_ADDR Unaligned pointer provided.
* @retval NRF_ERROR_INTERNAL Internal error during key generation.
*/
ret_code_t ecc_p256_public_key_compute(uint8_t const *p_le_sk, uint8_t* p_le_pk);
/**@brief Create a shared secret from a provided public/private key pair.
*
* @param[in] p_le_sk Private key. Pointer must be aligned to a 4-byte boundary.
* @param[in] p_le_pk Public key. Pointer must be aligned to a 4-byte boundary.
* @param[out] p_le_ss Shared secret. Pointer must be aligned to a 4-byte boundary.
*
* @retval NRF_SUCCESS Shared secret successfuly created.
* @retval NRF_ERROR_NULL NULL pointer provided.
* @retval NRF_ERROR_INVALID_ADDR Unaligned pointer provided.
* @retval NRF_ERROR_INTERNAL Internal error during key generation.
*/
ret_code_t ecc_p256_shared_secret_compute(uint8_t const *p_le_sk, uint8_t const * p_le_pk, uint8_t *p_le_ss);
/**@brief Sign a hash or digest using a private key.
*
* @param[in] p_le_sk Private key. Pointer must be aligned to a 4-byte boundary.
* @param[in] p_le_hash Hash. Pointer must be aligned to a 4-byte boundary.
* @param[in] hlen Hash length in bytes.
* @param[out] p_le_sig Signature. Pointer must be aligned to a 4-byte boundary.
*
* @retval NRF_SUCCESS Signature successfuly created.
* @retval NRF_ERROR_NULL NULL pointer provided.
* @retval NRF_ERROR_INVALID_ADDR Unaligned pointer provided.
* @retval NRF_ERROR_INTERNAL Internal error during signature generation.
*/
ret_code_t ecc_p256_sign(uint8_t const *p_le_sk, uint8_t const * p_le_hash, uint32_t hlen, uint8_t *p_le_sig);
/**@brief Verify a signature using a public key.
*
* @param[in] p_le_pk Public key. Pointer must be aligned to a 4-byte boundary.
* @param[in] p_le_hash Hash. Pointer must be aligned to a 4-byte boundary.
* @param[in] hlen Hash length in bytes.
* @param[in] p_le_sig Signature. Pointer must be aligned to a 4-byte boundary.
*
* @retval NRF_SUCCESS Signature verified.
* @retval NRF_ERROR_INVALID_DATA Signature failed verification.
* @retval NRF_ERROR_NULL NULL pointer provided.
* @retval NRF_ERROR_INVALID_ADDR Unaligned pointer provided.
* @retval NRF_ERROR_INTERNAL Internal error during signature verification.
*/
ret_code_t ecc_p256_verify(uint8_t const *p_le_pk, uint8_t const * p_le_hash, uint32_t hlen, uint8_t const *p_le_sig);
#ifdef __cplusplus
}
#endif
#endif // ECC_H__
/** @} */

View File

@@ -1,543 +0,0 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sdk_common.h"
#if NRF_MODULE_ENABLED(TASK_MANAGER)
#include "nrf_mpu_lib.h"
#include "nrf_atomic.h"
#include "app_util_platform.h"
#include "task_manager.h"
#if TASK_MANAGER_CLI_CMDS
#include "nrf_cli.h"
#endif
#define NRF_LOG_MODULE_NAME task_manager
#if TASK_MANAGER_CONFIG_LOG_ENABLED
#define NRF_LOG_LEVEL TASK_MANAGER_CONFIG_LOG_LEVEL
#define NRF_LOG_INFO_COLOR TASK_MANAGER_CONFIG_INFO_COLOR
#define NRF_LOG_DEBUG_COLOR TASK_MANAGER_CONFIG_DEBUG_COLOR
#endif
#include "nrf_log.h"
NRF_LOG_MODULE_REGISTER();
#if TASK_MANAGER_CONFIG_STACK_GUARD
#define STACK_GUARD_SIZE (1 << (TASK_MANAGER_CONFIG_STACK_GUARD + 1))
STATIC_ASSERT((TASK_MANAGER_CONFIG_STACK_SIZE % STACK_GUARD_SIZE) == 0);
#endif
STATIC_ASSERT((TASK_MANAGER_CONFIG_MAX_TASKS) > 0);
STATIC_ASSERT((TASK_MANAGER_CONFIG_STACK_SIZE % 8) == 0);
// Support older CMSIS avaiable in Keil 4
#if (__CORTEX_M == 4)
# ifndef CONTROL_FPCA_Pos
# define CONTROL_FPCA_Pos 2u
# define CONTROL_FPCA_Msk (1ul << CONTROL_FPCA_Pos)
# endif
# ifndef CONTROL_SPSEL_Pos
# define CONTROL_SPSEL_Pos 1u
# define CONTROL_SPSEL_Msk (1ul << CONTROL_SPSEL_Pos)
# endif
#endif
/*lint -save -esym(526,task_switch)*/
// Declare task switching function.
extern void task_switch(void);
/*lint -restore*/
/**@brief Idle Task ID */
#define IDLE_TASK_ID TASK_MANAGER_CONFIG_MAX_TASKS
#define TASK_STACK_MAGIC_WORD 0xDEADD00E
#define TASK_FLAG_SIGNAL_MASK 0x00FFFFFF
#define TASK_FLAG_DESTROY 0x80000000
/** @brief Total number of tasks includes user configuration and idle task. */
#define TOTAL_NUM_OF_TASKS (TASK_MANAGER_CONFIG_MAX_TASKS + 1)
/**@brief Task stack with saved task state (does not include FPU state). */
typedef struct
{
uint32_t r0;
uint32_t r4;
uint32_t r5;
uint32_t r6;
uint32_t r7;
uint32_t r8;
uint32_t r9;
uint32_t r10;
uint32_t r11;
uint32_t r12;
uint32_t lr;
uint32_t control;
} task_stack_t;
/**@brief Task State */
typedef struct
{
void *p_stack; /**< Pointer to task stack. NULL if task does not exist. */
const char *p_task_name;
nrf_atomic_u32_t flags; /**< Task flags */
} task_state_t;
/* Allocate space for task stacks:
*
* Layout:
* +---------------+
* | Idle Task |
* +---------------+
* | Stack Guard |
* +---------------+
* | Task N |
* +---------------+
* | Stack Guard |
* +---------------+
* | ... |
* +---------------+
* | Task 0 |
* +---------------+
* | Stack Guard |
* +---------------+
*/
typedef struct
{
#if TASK_MANAGER_CONFIG_STACK_GUARD
uint8_t guard[STACK_GUARD_SIZE];
#endif
uint8_t stack[TASK_MANAGER_CONFIG_STACK_SIZE];
} task_manager_stack_t;
/**@brief Stack space for tasks */
#if TASK_MANAGER_CONFIG_STACK_GUARD
/**@brief Handle to MPU region used as a guard */
static nrf_mpu_lib_region_t s_guard_region;
__ALIGN(STACK_GUARD_SIZE)
#else
__ALIGN(8)
#endif
static task_manager_stack_t s_task_stacks[TOTAL_NUM_OF_TASKS];
/**@brief Task States
* Addtional state reserved for idle task which is mandatory.
* */
static task_state_t s_task_state[TOTAL_NUM_OF_TASKS];
/**@brief Mask indicating which tasks are runnable */
static nrf_atomic_u32_t s_runnable_tasks_mask;
/**@brief ID of currently executed task */
static task_id_t s_current_task_id;
/**@brief Guard page attributes: Normal memory, WBWA/WBWA, RO/RO, XN */
#define TASK_GUARD_ATTRIBUTES ((0x05 << MPU_RASR_TEX_Pos) | (1 << MPU_RASR_B_Pos) | \
(0x07 << MPU_RASR_AP_Pos) | (1 << MPU_RASR_XN_Pos))
/**@brief Macro for getting pointer to bottom of stack for given task id */
#define BOTTOM_OF_TASK_STACK(_task_id) ((void *)(&s_task_stacks[(_task_id)].stack[0]))
/**@brief Macro for getting pointer to top of stack for given task id */
#define TOP_OF_TASK_STACK(_task_id) ((void *)(&s_task_stacks[(_task_id)].stack[TASK_MANAGER_CONFIG_STACK_SIZE]))
/**@brief Macro for getting pointer to base of stack guard for given task id */
#define TASK_STACK_GUARD_BASE(_task_id) ((void *)(&s_task_stacks[(_task_id)].guard[0]))
#define TASK_ID_TO_MASK(_task_id) (0x80000000 >> (_task_id))
/**@brief Puts task in RUNNABLE state */
#define TASK_STATE_RUNNABLE(_task_id) \
(void)nrf_atomic_u32_or(&s_runnable_tasks_mask, TASK_ID_TO_MASK(_task_id))
/**@brief Puts task in SUSPENDED state */
#define TASK_STATE_SUSPENDED(_task_id) \
(void)nrf_atomic_u32_and(&s_runnable_tasks_mask, ~TASK_ID_TO_MASK(_task_id));
static void task_stack_poison(task_id_t task_id)
{
#if TASK_MANAGER_CONFIG_STACK_PROFILER_ENABLED
unsigned int i = TASK_MANAGER_CONFIG_STACK_SIZE / sizeof(uint32_t);
uint32_t *p_stack_top = TOP_OF_TASK_STACK(task_id);
while (i--)
{
*(--p_stack_top) = TASK_STACK_MAGIC_WORD;
}
#endif
}
static void task_stack_protect(task_id_t task_id)
{
#if TASK_MANAGER_CONFIG_STACK_GUARD
APP_ERROR_CHECK(nrf_mpu_lib_region_create(&s_guard_region,
TASK_STACK_GUARD_BASE(task_id),
STACK_GUARD_SIZE,
TASK_GUARD_ATTRIBUTES));
#endif
}
PRAGMA_OPTIMIZATION_FORCE_START
void task_manager_start(task_main_t idle_task, void *p_idle_task_context)
{
unsigned long control;
// Idle task must be specified.
ASSERT(idle_task != NULL);
// Make sure that we are in privledged thread level using MSP stack.
ASSERT((__get_IPSR() & IPSR_ISR_Msk) == 0);
ASSERT((__get_CONTROL() & CONTROL_nPRIV_Msk) == 0);
ASSERT((__get_CONTROL() & CONTROL_SPSEL_Msk) == 0);
// Prepare task state structure.
s_current_task_id = IDLE_TASK_ID;
s_task_state[s_current_task_id].p_task_name = "Idle Task";
// Prepare stack instrumentation and protection.
task_stack_poison(s_current_task_id);
task_stack_protect(s_current_task_id);
NRF_LOG_INFO("Task %u created (name: '%s', stack: 0x%08X-0x%08X).",
s_current_task_id,
s_task_state[s_current_task_id].p_task_name,
(uint32_t)BOTTOM_OF_TASK_STACK(s_current_task_id),
(uint32_t)TOP_OF_TASK_STACK(s_current_task_id) - 1);
// Prepare context for idle task. This must be done with all interrupts disabled.
__disable_irq();
// Set process and exception stacks.
__set_PSP((uint32_t)(TOP_OF_TASK_STACK(s_current_task_id)));
__set_MSP((uint32_t)(STACK_TOP));
// Update CONTROL register.
control = __get_CONTROL();
control &= CONTROL_FPCA_Msk; // Clear FPCA since FPU state does not need to be preserved.
control |= CONTROL_SPSEL_Msk; // Use MSP only for excpetions, leaving PSP for tasks.
__set_CONTROL(control);
// Context is ready. Enable interrupts.
__enable_irq();
// Perform task switch to run non-idle tasks as soon as possible.
task_switch();
// Jump to idle task.
idle_task(p_idle_task_context);
// This should be never reached.
APP_ERROR_CHECK_BOOL(false);
}
PRAGMA_OPTIMIZATION_FORCE_END
task_id_t task_create(task_main_t task, char const * p_task_name, void *p_context)
{
task_state_t *p_state = NULL;
task_stack_t *p_stack;
task_id_t task_id;
// Check arguments.
if (task == NULL)
{
return TASK_ID_INVALID;
}
// Find free task state structure.
CRITICAL_REGION_ENTER();
for (task_id = 0; task_id < TASK_MANAGER_CONFIG_MAX_TASKS; task_id++)
{
if (s_task_state[task_id].p_stack == NULL)
{
p_state = &s_task_state[task_id];
p_state->p_stack = TOP_OF_TASK_STACK(task_id);
break;
}
}
CRITICAL_REGION_EXIT();
// Return invalid Task ID if new task cannot be created.
if (p_state == NULL)
{
return TASK_ID_INVALID;
}
// Prepare initial stack for the task.
task_stack_poison(task_id);
p_state->p_stack = (uint8_t *)(p_state->p_stack) - sizeof(*p_stack);
p_state->p_task_name = (char *)p_task_name;
p_state->flags = 0;
p_stack = p_state->p_stack;
p_stack->control = CONTROL_SPSEL_Msk;
p_stack->lr = (uint32_t)(task); // Start from this function.
p_stack->r0 = (uint32_t)(p_context); // Pass p_context as first argument.
// Mark task as ready to run.
TASK_STATE_RUNNABLE(task_id);
NRF_LOG_INFO("Task %u created (name: '%s', stack: 0x%08X-0x%08X).",
task_id,
p_task_name,
(uint32_t)BOTTOM_OF_TASK_STACK(task_id),
(uint32_t)TOP_OF_TASK_STACK(task_id) - 1);
return task_id;
}
/**@brief Task scheduler.
*
* @param[in] Pointer to task stack with saved task state.
* @return Pointer to new task stack with saved task state.
*/
void *task_schedule(void *p_stack)
{
uint32_t runnable_tasks_mask;
#if TASK_MANAGER_CONFIG_STACK_GUARD
// Destroy stack guard allocated for current task.
APP_ERROR_CHECK(nrf_mpu_lib_region_destroy(s_guard_region));
#endif
// Save current task state if task if switching from valid task.
if ((s_task_state[s_current_task_id].flags & TASK_FLAG_DESTROY) == 0)
{
s_task_state[s_current_task_id].p_stack = p_stack;
}
else
{
TASK_STATE_SUSPENDED(s_current_task_id);
s_task_state[s_current_task_id].p_stack = NULL;
NRF_LOG_INFO("Task %u terminated (name: '%s').",
s_current_task_id,
s_task_state[s_current_task_id].p_task_name);
}
// Atomically fetch list of runnable tasks.
runnable_tasks_mask = s_runnable_tasks_mask;
// Check if there are any tasks to execute.
if (runnable_tasks_mask != 0)
{
// Check if we could continue this round.
if ((runnable_tasks_mask << (s_current_task_id + 1)) != 0)
{
// There are tasks to execute in this round. Select next runnable task:
s_current_task_id += 1 + __CLZ((runnable_tasks_mask << (s_current_task_id + 1)));
}
else
{
// No more tasks in this round. Select first avaiable task:
s_current_task_id = __CLZ(runnable_tasks_mask);
}
}
else
{
// Fall back to idle task if other tasks cannot be run.
s_current_task_id = IDLE_TASK_ID;
}
task_stack_protect(s_current_task_id);
// Switch to new task.
return s_task_state[s_current_task_id].p_stack;
}
void task_yield(void)
{
// Make sure that we are in privledged thread level using PSP stack.
ASSERT((__get_IPSR() & IPSR_ISR_Msk) == 0);
ASSERT((__get_CONTROL() & CONTROL_nPRIV_Msk) == 0);
ASSERT((__get_CONTROL() & CONTROL_SPSEL_Msk) != 0);
// Perform task switch.
task_switch();
}
uint32_t task_events_wait(uint32_t evt_mask)
{
uint32_t current_events;
ASSERT((evt_mask & ~TASK_FLAG_SIGNAL_MASK) == 0);
for (;;)
{
current_events = s_task_state[s_current_task_id].flags & evt_mask;
if (current_events != 0)
{
(void)nrf_atomic_u32_and(&s_task_state[s_current_task_id].flags, ~current_events);
break;
}
TASK_STATE_SUSPENDED(s_current_task_id);
task_yield();
}
return current_events;
}
void task_events_set(task_id_t task_id, uint32_t evt_mask)
{
ASSERT((task_id != TASK_ID_INVALID) && (task_id < TASK_MANAGER_CONFIG_MAX_TASKS));
ASSERT((evt_mask & ~TASK_FLAG_SIGNAL_MASK) == 0);
ASSERT(s_task_state[task_id].p_stack != NULL);
(void)nrf_atomic_u32_or(&s_task_state[task_id].flags, evt_mask);
TASK_STATE_RUNNABLE(task_id);
}
void task_exit(void)
{
// Make sure that we are in privledged thread level using PSP stack.
ASSERT((__get_IPSR() & IPSR_ISR_Msk) == 0);
ASSERT((__get_CONTROL() & CONTROL_nPRIV_Msk) == 0);
ASSERT((__get_CONTROL() & CONTROL_SPSEL_Msk) != 0);
s_task_state[s_current_task_id].flags = TASK_FLAG_DESTROY;
task_switch();
}
task_id_t task_id_get(void)
{
// Make sure that we are in privledged thread level using PSP stack.
ASSERT((__get_IPSR() & IPSR_ISR_Msk) == 0);
ASSERT((__get_CONTROL() & CONTROL_nPRIV_Msk) == 0);
ASSERT((__get_CONTROL() & CONTROL_SPSEL_Msk) != 0);
return s_current_task_id;
}
uint32_t task_stack_max_usage_get(task_id_t task_id)
{
#if TASK_MANAGER_CONFIG_STACK_PROFILER_ENABLED
unsigned int stack_usage;
uint32_t *p_stack, *p_stack_top;
ASSERT((task_id != TASK_ID_INVALID) || (task_id < TASK_MANAGER_CONFIG_MAX_TASKS));
ASSERT(s_task_state[task_id].p_stack != NULL);
p_stack_top = TOP_OF_TASK_STACK(task_id);
p_stack = BOTTOM_OF_TASK_STACK(task_id);
stack_usage = TASK_MANAGER_CONFIG_STACK_SIZE;
while (p_stack < p_stack_top)
{
if (*(p_stack++) != TASK_STACK_MAGIC_WORD)
{
break;
}
stack_usage -= sizeof(*p_stack);
}
return stack_usage;
#else
return 0;
#endif
}
#if TASK_MANAGER_CLI_CMDS
static void task_mnanager_info(nrf_cli_t const * p_cli, size_t argc, char **argv)
{
task_id_t task_id;
for (task_id = 0; task_id < TOTAL_NUM_OF_TASKS; task_id++)
{
const char *p_task_name = NULL;
CRITICAL_REGION_ENTER();
if (s_task_state[task_id].p_stack != NULL)
{
p_task_name = (s_task_state[task_id].p_task_name) ? s_task_state[task_id].p_task_name
: "<NULL>";
}
CRITICAL_REGION_EXIT();
if (p_task_name)
{
uint32_t stack_usage = task_stack_max_usage_get(task_id);
nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "Task %u:\r\n", task_id);
nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "\tName:\t'%s'\r\n", p_task_name);
if (stack_usage)
{
nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "\tStack:\t0x%08X-0x%08X used in %u%% (%u out of %u bytes)\r\n",
(uint32_t)BOTTOM_OF_TASK_STACK(task_id),
(uint32_t)TOP_OF_TASK_STACK(task_id) - 1,
100 * stack_usage / TASK_MANAGER_CONFIG_STACK_SIZE,
stack_usage,
TASK_MANAGER_CONFIG_STACK_SIZE);
}
else
{
nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "\tStack:\t0x%08X-0x%08X\r\n",
(uint32_t)BOTTOM_OF_TASK_STACK(task_id),
(uint32_t)TOP_OF_TASK_STACK(task_id) - 1);
}
nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "\tState:\t%s\r\n",
(s_current_task_id == task_id) ? "Running" :
(s_runnable_tasks_mask & TASK_ID_TO_MASK(task_id)) ? "Runnable" : "Suspended");
nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "\tFlags:\t0x%08X\r\n\r\n",
s_task_state[task_id].flags);
}
}
}
NRF_CLI_CREATE_STATIC_SUBCMD_SET(m_sub_task_mngr)
{
NRF_CLI_CMD(info, NULL, "tasks info", task_mnanager_info),
NRF_CLI_SUBCMD_SET_END
};
NRF_CLI_CMD_REGISTER(task_manager, &m_sub_task_mngr, "commands for task manager", NULL);
#endif //TASK_MANAGER_CLI_CMDS
#else //TASK_MANAGER_ENABLED
void *task_schedule(void *p_stack)
{
return (void *)0;
}
#endif //TASK_MANAGER_ENABLED

View File

@@ -1,143 +0,0 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef __TASK_MANAGER_H__
#define __TASK_MANAGER_H__
/**
* @defgroup task_manager Task manager (Cooperative Scheduler)
* @{
* @ingroup app_common
* @brief Functions for managing tasks
*/
#include <stdbool.h>
#include <stdint.h>
#include "nrf.h"
#include "sdk_errors.h"
#ifdef __cplusplus
extern "C" {
#endif
/**@brief Main function of the task. */
typedef void (* task_main_t)(void * p_context);
/**@brief Task ID */
typedef uint8_t task_id_t;
/**@brief Invalid task ID */
#define TASK_ID_INVALID ((task_id_t)(-1))
/**@brief Start task manager.
*
* @details This function starts the task manager and configures given function as idle task.
* This function never returns.
*
* @param[in] idle_task Main function of the task scheduled when no other tasks could be run.
* @param[in] p_idle_task_context Context passed to idle task.
*/
void task_manager_start(task_main_t idle_task, void * p_idle_task_context);
/**@brief Create new task.
*
* @param[in] task Function which become main procedure of new task.
* @param[in] p_task_name Task name.
* @param[in] p_context Context passed to task procedure.
*
* @return ID of the task on success, otherwise TASK_ID_INVALID.
*/
task_id_t task_create(task_main_t task, char const * p_task_name, void * p_context);
/**@brief Yield CPU to other tasks.
*/
void task_yield(void);
/**@brief Complete current task.
*
* Task stack returns to the pool of available stacks.
*/
void task_exit(void);
/**@brief Wait for events. Set events are cleared after this function returns.
*
* @param[in] evt_mask Mask of events to wait
*
* @return Mask with set events (can be a subset of evt_mask).
*/
uint32_t task_events_wait(uint32_t evt_mask);
/**@brief Set events for given task.
*
* @param[in] task_id Id of the task which shall receive events.
* @param[in] evt_mask Events for the task.
*
*/
void task_events_set(task_id_t task_id, uint32_t evt_mask);
/**@brief Returns maximum depth of task stack.
*
* @param[in] task_id Id of the task (use @ref TASK_ID_INVALID for current task).
* @return Number of bytes ever used on task stack.
*/
uint32_t task_stack_max_usage_get(task_id_t task_id);
/**@brief Returns ID of currently running task.
*
* @return ID of active task.
*/
task_id_t task_id_get(void);
/**@brief Set events for given task.
*
* @param[in] task_id Id of the task which name will be returned.
* @return Task name
*
*/
char const * task_name_get(task_id_t task_id);
#ifdef __cplusplus
}
#endif
#endif /* __TASK_MANAGER_H__ */
/** @} */

View File

@@ -1,89 +0,0 @@
/**
* Copyright (c) 2017 - 2017, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
*
*/
.syntax unified
.arch armv7-m
.text
.thumb
.thumb_func
.align 1
.global task_switch
.type task_switch, %function
task_switch:
.fnstart
MRS R0, CONTROL /* Fetch CONTROL register to R0 */
#ifdef FLOAT_ABI_HARD
TST R0, #(1 << 2) /* Check FPCA flag. */
ITTT NE
VMRSNE R1, FPSCR /* If FPCA set, fetch FPSCR. */
STMDBNE SP!, {R0, R1} /* If FPCA set, save FPSCR (also pad stack to 8-byte alignment) */
VSTMDBNE SP!, {S0-S31} /* If FPCA set, save FPU registers. */
#endif
STMDB SP!, {R0} /* Save CONTROL register. */
AND R0, R0, #~(1 << 2) /* Clear FPCA bit. */
MSR CONTROL, R0 /* Update CONTROL register. */
STMDB SP!, {R0, R4-R12, LR} /* Save CPU registers. Reserve space for R0, needed to pass argument to new task. */
MOV R0, SP /* Call task scheduler with current stack pointer as argument. */
LDR R1, =task_schedule
BLX R1
MOV SP, R0 /* Switch to new stack, returned by task scheduler. */
LDMIA SP!, {R3, R4-R12, LR} /* Restore CPU registers. Argument to new task is in R3. */
LDMIA SP!, {R0} /* Restore CONTROL register. */
MSR CONTROL, R0 /* Update CONTROL register. */
#ifdef FLOAT_ABI_HARD
TST R0, #(1 << 2) /* Check FPCA flag. */
ITTT NE
VLDMIANE SP!, {S0-S31} /* If FPCA set, restore FPU registers. */
LDMIANE SP!, {R0, R1} /* If FPCA set, restore FPSCR (also remove padding). */
VMSRNE FPSCR, R1 /* If FPCA set, update FPSCR */
#endif
MOV R0, R3 /* Place optional task argument in R0. */
BX LR /* Return to new task. */

View File

@@ -1,83 +0,0 @@
; Copyright (c) 2017 - 2017, Nordic Semiconductor ASA
;
; All rights reserved.
;
; Redistribution and use in source and binary forms, with or without modification,
; are permitted provided that the following conditions are met:
;
; 1. Redistributions of source code must retain the above copyright notice, this
; list of conditions and the following disclaimer.
;
; 2. Redistributions in binary form, except as embedded into a Nordic
; Semiconductor ASA integrated circuit in a product or a software update for
; such product, must reproduce the above copyright notice, this list of
; conditions and the following disclaimer in the documentation and/or other
; materials provided with the distribution.
;
; 3. Neither the name of Nordic Semiconductor ASA nor the names of its
; contributors may be used to endorse or promote products derived from this
; software without specific prior written permission.
;
; 4. This software, with or without modification, must only be used with a
; Nordic Semiconductor ASA integrated circuit.
;
; 5. Any software provided in binary form under this license must not be reverse
; engineered, decompiled, modified and/or disassembled.
;
; THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
; OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
; DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
;
SECTION .text:CODE:REORDER:NOROOT(2)
THUMB
PUBLIC task_switch
EXTERN task_schedule
task_switch
MRS R0, CONTROL ; Fetch CONTROL register to R0
#ifdef FLOAT_ABI_HARD
TST R0, #(1 << 2) ; Check FPCA flag.
ITTT NE
VMRSNE R1, FPSCR ; If FPCA set, fetch FPSCR.
STMDBNE SP!, {R0, R1} ; If FPCA set, save FPSCR (also pad stack to 8-byte alignment)
VSTMDBNE SP!, {S0-S31} ; If FPCA set, save FPU registers.
#endif
STMDB SP!, {R0} ; Save CONTROL register.
AND R0, R0, #~(1 << 2) ; Clear FPCA bit.
MSR CONTROL, R0 ; Update CONTROL register.
STMDB SP!, {R0, R4-R12, LR} ; Save CPU registers. Reserve space for R0, needed to pass argument to new task.
MOV R0, SP ; Call task scheduler with current stack pointer as argument.
LDR R1, =task_schedule ;
BLX R1 ;
MOV SP, R0 ; Switch to new stack, returned by task scheduler.
LDMIA SP!, {R3, R4-R12, LR} ; Restore CPU registers. Argument to new task is in R3.
LDMIA SP!, {R0} ; Restore CONTROL register.
MSR CONTROL, R0 ; Update CONTROL register.
#ifdef FLOAT_ABI_HARD
TST R0, #(1 << 2) ; Check FPCA flag.
ITTT NE
VLDMIANE SP!, {S0-S31} ; If FPCA set, restore FPU registers.
LDMIANE SP!, {R0, R1} ; If FPCA set, restore FPSCR (also remove padding).
VMSRNE FPSCR, R1 ; If FPCA set, update FPSCR
#endif
MOV R0, R3 ; Place optional task argument in R0.
BX LR ; Return to new task.
END

View File

@@ -1,85 +0,0 @@
; Copyright (c) 2017 - 2017, Nordic Semiconductor ASA
;
; All rights reserved.
;
; Redistribution and use in source and binary forms, with or without modification,
; are permitted provided that the following conditions are met:
;
; 1. Redistributions of source code must retain the above copyright notice, this
; list of conditions and the following disclaimer.
;
; 2. Redistributions in binary form, except as embedded into a Nordic
; Semiconductor ASA integrated circuit in a product or a software update for
; such product, must reproduce the above copyright notice, this list of
; conditions and the following disclaimer in the documentation and/or other
; materials provided with the distribution.
;
; 3. Neither the name of Nordic Semiconductor ASA nor the names of its
; contributors may be used to endorse or promote products derived from this
; software without specific prior written permission.
;
; 4. This software, with or without modification, must only be used with a
; Nordic Semiconductor ASA integrated circuit.
;
; 5. Any software provided in binary form under this license must not be reverse
; engineered, decompiled, modified and/or disassembled.
;
; THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
; OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
; DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA 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.
;
PRESERVE8
THUMB
AREA |.text|, CODE, READONLY
task_switch PROC
EXPORT task_switch
IMPORT task_schedule
MRS R0, CONTROL ; Fetch CONTROL register to R0
IF :DEF: FLOAT_ABI_HARD
TST R0, #(1 << 2) ; Check FPCA flag.
ITTT NE
VMRSNE R1, FPSCR ; If FPCA set, fetch FPSCR.
STMDBNE SP!, {R0, R1} ; If FPCA set, save FPSCR (also pad stack to 8-byte alignment)
VSTMDBNE SP!, {S0-S31} ; If FPCA set, save FPU registers.
ENDIF
STMDB SP!, {R0} ; Save CONTROL register.
AND R0, R0, #~(1 << 2) ; Clear FPCA bit.
MSR CONTROL, R0 ; Update CONTROL register.
STMDB SP!, {R0, R4-R12, LR} ; Save CPU registers. Reserve space for R0, needed to pass argument to new task.
MOV R0, SP ; Call task scheduler with current stack pointer as argument.
LDR R1, =task_schedule ;
BLX R1 ;
MOV SP, R0 ; Switch to new stack, returned by task scheduler.
LDMIA SP!, {R3, R4-R12, LR} ; Restore CPU registers. Argument to new task is in R3.
LDMIA SP!, {R0} ; Restore CONTROL register.
MSR CONTROL, R0 ; Update CONTROL register.
IF :DEF: FLOAT_ABI_HARD
TST R0, #(1 << 2) ; Check FPCA flag.
ITTT NE
VLDMIANE SP!, {S0-S31} ; If FPCA set, restore FPU registers.
LDMIANE SP!, {R0, R1} ; If FPCA set, restore FPSCR (also remove padding).
VMSRNE FPSCR, R1 ; If FPCA set, update FPSCR
ENDIF
MOV R0, R3 ; Place optional task argument in R0.
BX LR ; Return to new task.
ENDP
END

View File

@@ -1,628 +0,0 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sdk_common.h"
#if NRF_MODULE_ENABLED(NRF_GFX)
#include "nrf_gfx.h"
#include <stdlib.h>
#include "app_util_platform.h"
#include "nrf_assert.h"
#define NRF_LOG_MODULE_NAME gfx
#include "nrf_log.h"
NRF_LOG_MODULE_REGISTER();
static inline void pixel_draw(nrf_lcd_t const * p_instance,
uint16_t x,
uint16_t y,
uint32_t color)
{
uint16_t lcd_width = nrf_gfx_width_get(p_instance);
uint16_t lcd_height = nrf_gfx_height_get(p_instance);
if ((x >= lcd_width) || (y >= lcd_height))
{
return;
}
p_instance->lcd_pixel_draw(x, y, color);
}
static void rect_draw(nrf_lcd_t const * p_instance,
uint16_t x,
uint16_t y,
uint16_t width,
uint16_t height,
uint32_t color)
{
uint16_t lcd_width = nrf_gfx_width_get(p_instance);
uint16_t lcd_height = nrf_gfx_height_get(p_instance);
if ((x >= lcd_width) || (y >= lcd_height))
{
return;
}
if (width > (lcd_width - x))
{
width = lcd_width - x;
}
if (height > (lcd_height - y))
{
height = lcd_height - y;
}
p_instance->lcd_rect_draw(x, y, width, height, color);
}
static void line_draw(nrf_lcd_t const * p_instance,
uint16_t x_0,
uint16_t y_0,
uint16_t x_1,
int16_t y_1,
uint32_t color)
{
uint16_t x = x_0;
uint16_t y = y_0;
int16_t d;
int16_t d_1;
int16_t d_2;
int16_t ai;
int16_t bi;
int16_t xi = (x_0 < x_1) ? 1 : (-1);
int16_t yi = (y_0 < y_1) ? 1 : (-1);
bool swapped = false;
d_1 = abs(x_1 - x_0);
d_2 = abs(y_1 - y_0);
pixel_draw(p_instance, x, y, color);
if (d_1 < d_2)
{
d_1 = d_1 ^ d_2;
d_2 = d_1 ^ d_2;
d_1 = d_2 ^ d_1;
swapped = true;
}
ai = (d_2 - d_1) * 2;
bi = d_2 * 2;
d = bi - d_1;
while ((y != y_1) || (x != x_1))
{
if (d >= 0)
{
x += xi;
y += yi;
d += ai;
}
else
{
d += bi;
if (swapped)
{
y += yi;
}
else
{
x += xi;
}
}
pixel_draw(p_instance, x, y, color);
}
}
static void write_character(nrf_lcd_t const * p_instance,
nrf_gfx_font_desc_t const * p_font,
uint8_t character,
uint16_t * p_x,
uint16_t y,
uint16_t font_color)
{
uint8_t char_idx = character - p_font->startChar;
uint16_t bytes_in_line = CEIL_DIV(p_font->charInfo[char_idx].widthBits, 8);
if (character == ' ')
{
*p_x += p_font->height / 2;
return;
}
for (uint16_t i = 0; i < p_font->height; i++)
{
for (uint16_t j = 0; j < bytes_in_line; j++)
{
for (uint8_t k = 0; k < 8; k++)
{
if ((1 << (7 - k)) &
p_font->data[p_font->charInfo[char_idx].offset + i * bytes_in_line + j])
{
pixel_draw(p_instance, *p_x + j * 8 + k, y + i, font_color);
}
}
}
}
*p_x += p_font->charInfo[char_idx].widthBits + p_font->spacePixels;
}
ret_code_t nrf_gfx_init(nrf_lcd_t const * p_instance)
{
ASSERT(p_instance != NULL);
ASSERT(p_instance->p_lcd_cb->state == NRFX_DRV_STATE_UNINITIALIZED);
ASSERT(p_instance->lcd_init != NULL);
ASSERT(p_instance->lcd_uninit != NULL);
ASSERT(p_instance->lcd_pixel_draw != NULL);
ASSERT(p_instance->lcd_rect_draw != NULL);
ASSERT(p_instance->lcd_display != NULL);
ASSERT(p_instance->lcd_rotation_set != NULL);
ASSERT(p_instance->lcd_display_invert != NULL);
ASSERT(p_instance->p_lcd_cb != NULL);
ret_code_t err_code;
err_code = p_instance->lcd_init();
if (err_code == NRF_SUCCESS)
{
p_instance->p_lcd_cb->state = NRFX_DRV_STATE_INITIALIZED;
}
return err_code;
}
void nrf_gfx_uninit(nrf_lcd_t const * p_instance)
{
ASSERT(p_instance != NULL);
ASSERT(p_instance->p_lcd_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
p_instance->p_lcd_cb->state = NRFX_DRV_STATE_UNINITIALIZED;
p_instance->lcd_uninit();
}
void nrf_gfx_point_draw(nrf_lcd_t const * p_instance,
nrf_gfx_point_t const * p_point,
uint32_t color)
{
ASSERT(p_instance != NULL);
ASSERT(p_instance->p_lcd_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
ASSERT(p_point != NULL);
pixel_draw(p_instance, p_point->x, p_point->y, color);
}
ret_code_t nrf_gfx_line_draw(nrf_lcd_t const * p_instance,
nrf_gfx_line_t const * p_line,
uint32_t color)
{
ASSERT(p_instance != NULL);
ASSERT(p_instance->p_lcd_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
ASSERT(p_line != NULL);
uint16_t x_thick = 0;
uint16_t y_thick = 0;
if (((p_line->x_start > nrf_gfx_width_get(p_instance)) &&
(p_line->x_end > nrf_gfx_height_get(p_instance))) ||
((p_line->y_start > nrf_gfx_width_get(p_instance)) &&
(p_line->y_end > nrf_gfx_height_get(p_instance))))
{
return NRF_ERROR_INVALID_PARAM;
}
if (abs(p_line->x_start - p_line->x_end) > abs(p_line->y_start - p_line->y_end))
{
y_thick = p_line->thickness;
}
else
{
x_thick = p_line->thickness;
}
if ((p_line->x_start == p_line->x_end) || (p_line->y_start == p_line->y_end))
{
rect_draw(p_instance,
p_line->x_start,
p_line->y_start,
abs(p_line->x_end - p_line->x_start) + x_thick,
abs(p_line->y_end - p_line->y_start) + y_thick,
color);
}
else
{
if (x_thick > 0)
{
for (uint16_t i = 0; i < p_line->thickness; i++)
{
line_draw(p_instance,
p_line->x_start + i,
p_line->y_start,
p_line->x_end + i,
p_line->y_end,
color);
}
}
else if (y_thick > 0)
{
for (uint16_t i = 0; i < p_line->thickness; i++)
{
line_draw(p_instance,
p_line->x_start,
p_line->y_start + i,
p_line->x_end,
p_line->y_end + i,
color);
}
}
else
{
line_draw(p_instance,
p_line->x_start + x_thick,
p_line->y_start + y_thick,
p_line->x_end + x_thick,
p_line->y_end + y_thick,
color);
}
}
return NRF_SUCCESS;
}
ret_code_t nrf_gfx_circle_draw(nrf_lcd_t const * p_instance,
nrf_gfx_circle_t const * p_circle,
uint32_t color,
bool fill)
{
ASSERT(p_instance != NULL);
ASSERT(p_instance->p_lcd_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
ASSERT(p_circle != NULL);
int16_t y = 0;
int16_t err = 0;
int16_t x = p_circle->r;
if ((p_circle->x - p_circle->r > nrf_gfx_width_get(p_instance)) ||
(p_circle->y - p_circle->r > nrf_gfx_height_get(p_instance)))
{
return NRF_ERROR_INVALID_PARAM;
}
while (x >= y)
{
if (fill)
{
if ((-y + p_circle->x < 0) || (-x + p_circle->x < 0))
{
rect_draw(p_instance, 0, (-x + p_circle->y), (y + p_circle->x + 1), 1, color);
rect_draw(p_instance, 0, (-y + p_circle->y), (x + p_circle->x + 1), 1, color);
rect_draw(p_instance, 0, (y + p_circle->y), (x + p_circle->x + 1), 1, color);
rect_draw(p_instance, 0, (x + p_circle->y), (y + p_circle->x + 1), 1, color);
}
else
{
rect_draw(p_instance, (-y + p_circle->x), (-x + p_circle->y), (2 * y + 1), 1, color);
rect_draw(p_instance, (-x + p_circle->x), (-y + p_circle->y), (2 * x + 1), 1, color);
rect_draw(p_instance, (-x + p_circle->x), (y + p_circle->y), (2 * x + 1), 1, color);
rect_draw(p_instance, (-y + p_circle->x), (x + p_circle->y), (2 * y + 1), 1, color);
}
}
else
{
pixel_draw(p_instance, (y + p_circle->x), (x + p_circle->y), color);
pixel_draw(p_instance, (-y + p_circle->x), (x + p_circle->y), color);
pixel_draw(p_instance, (x + p_circle->x), (y + p_circle->y), color);
pixel_draw(p_instance, (-x + p_circle->x), (y + p_circle->y), color);
pixel_draw(p_instance, (-y + p_circle->x), (-x + p_circle->y), color);
pixel_draw(p_instance, (y + p_circle->x), (-x + p_circle->y), color);
pixel_draw(p_instance, (-x + p_circle->x), (-y + p_circle->y), color);
pixel_draw(p_instance, (x + p_circle->x), (-y + p_circle->y), color);
}
if (err <= 0)
{
y += 1;
err += 2 * y + 1;
}
if (err > 0)
{
x -= 1;
err -= 2 * x + 1;
}
}
return NRF_SUCCESS;
}
ret_code_t nrf_gfx_rect_draw(nrf_lcd_t const * p_instance,
nrf_gfx_rect_t const * p_rect,
uint16_t thickness,
uint32_t color,
bool fill)
{
ASSERT(p_instance != NULL);
ASSERT(p_instance->p_lcd_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
ASSERT(p_rect != NULL);
uint16_t rect_width = p_rect->width - thickness;
uint16_t rect_height = p_rect->height - thickness;
if ((p_rect->width == 1) ||
(p_rect->height == 1) ||
(thickness * 2 > p_rect->width) ||
(thickness * 2 > p_rect->height) ||
((p_rect->x > nrf_gfx_width_get(p_instance)) &&
(p_rect->y > nrf_gfx_height_get(p_instance))))
{
return NRF_ERROR_INVALID_PARAM;
}
if (fill)
{
rect_draw(p_instance,
p_rect->x,
p_rect->y,
p_rect->width,
p_rect->height,
color);
}
else
{
nrf_gfx_line_t line;
// Top horizontal line.
line.x_start = p_rect->x;
line.y_start = p_rect->y;
line.x_end = p_rect->x + p_rect->width;
line.y_end = p_rect->y;
line.thickness = thickness;
(void)nrf_gfx_line_draw(p_instance, &line, color);
// Bottom horizontal line.
line.x_start = p_rect->x;
line.y_start = p_rect->y + rect_height;
line.x_end = p_rect->x + p_rect->width;
line.y_end = p_rect->y + rect_height;
(void)nrf_gfx_line_draw(p_instance, &line, color);
// Left vertical line.
line.x_start = p_rect->x;
line.y_start = p_rect->y + thickness;
line.x_end = p_rect->x;
line.y_end = p_rect->y + rect_height;
(void)nrf_gfx_line_draw(p_instance, &line, color);
// Right vertical line.
line.x_start = p_rect->x + rect_width;
line.y_start = p_rect->y + thickness;
line.x_end = p_rect->x + rect_width;
line.y_end = p_rect->y + rect_height;
(void)nrf_gfx_line_draw(p_instance, &line, color);
}
return NRF_SUCCESS;
}
void nrf_gfx_screen_fill(nrf_lcd_t const * p_instance, uint32_t color)
{
rect_draw(p_instance, 0, 0, nrf_gfx_width_get(p_instance), nrf_gfx_height_get(p_instance), color);
}
ret_code_t nrf_gfx_bmp565_draw(nrf_lcd_t const * p_instance,
nrf_gfx_rect_t const * p_rect,
uint16_t const * img_buf)
{
ASSERT(p_instance != NULL);
ASSERT(p_instance->p_lcd_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
ASSERT(p_rect != NULL);
ASSERT(img_buf != NULL);
if ((p_rect->x > nrf_gfx_width_get(p_instance)) || (p_rect->y > nrf_gfx_height_get(p_instance)))
{
return NRF_ERROR_INVALID_PARAM;
}
size_t idx;
uint16_t pixel;
uint8_t padding = p_rect->width % 2;
for (int32_t i = 0; i < p_rect->height; i++)
{
for (uint32_t j = 0; j < p_rect->width; j++)
{
idx = (uint32_t)((p_rect->height - i - 1) * (p_rect->width + padding) + j);
pixel = (img_buf[idx] >> 8) | (img_buf[idx] << 8);
pixel_draw(p_instance, p_rect->x + j, p_rect->y + i, pixel);
}
}
return NRF_SUCCESS;
}
void nrf_gfx_background_set(nrf_lcd_t const * p_instance, uint16_t const * img_buf)
{
ASSERT(p_instance != NULL);
ASSERT(p_instance->p_lcd_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
ASSERT(img_buf != NULL);
const nrf_gfx_rect_t rectangle =
{
.x = 0,
.y = 0,
.width = nrf_gfx_width_get(p_instance),
.height = nrf_gfx_height_get(p_instance)
};
(void)nrf_gfx_bmp565_draw(p_instance, &rectangle, img_buf);
}
void nrf_gfx_display(nrf_lcd_t const * p_instance)
{
ASSERT(p_instance != NULL);
p_instance->lcd_display();
}
void nrf_gfx_rotation_set(nrf_lcd_t const * p_instance, nrf_lcd_rotation_t rotation)
{
ASSERT(p_instance != NULL);
ASSERT(p_instance->p_lcd_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
bool rotated = (bool)(p_instance->p_lcd_cb->rotation % 2);
uint16_t height = !rotated ? nrf_gfx_height_get(p_instance) :
nrf_gfx_width_get(p_instance);
uint16_t width = !rotated ? nrf_gfx_width_get(p_instance) :
nrf_gfx_height_get(p_instance);
p_instance->p_lcd_cb->rotation = rotation;
switch (rotation) {
case NRF_LCD_ROTATE_0:
p_instance->p_lcd_cb->height = height;
p_instance->p_lcd_cb->width = width;
break;
case NRF_LCD_ROTATE_90:
p_instance->p_lcd_cb->height = width;
p_instance->p_lcd_cb->width = height;
break;
case NRF_LCD_ROTATE_180:
p_instance->p_lcd_cb->height = height;
p_instance->p_lcd_cb->width = width;
break;
case NRF_LCD_ROTATE_270:
p_instance->p_lcd_cb->height = width;
p_instance->p_lcd_cb->width = height;
break;
default:
break;
}
p_instance->lcd_rotation_set(rotation);
}
void nrf_gfx_invert(nrf_lcd_t const * p_instance, bool invert)
{
ASSERT(p_instance != NULL);
p_instance->lcd_display_invert(invert);
}
ret_code_t nrf_gfx_print(nrf_lcd_t const * p_instance,
nrf_gfx_point_t const * p_point,
uint16_t font_color,
const char * string,
const nrf_gfx_font_desc_t * p_font,
bool wrap)
{
ASSERT(p_instance != NULL);
ASSERT(p_instance->p_lcd_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
ASSERT(p_point != NULL);
ASSERT(string != NULL);
ASSERT(p_font != NULL);
uint16_t x = p_point->x;
uint16_t y = p_point->y;
if (y > (nrf_gfx_height_get(p_instance) - p_font->height))
{
// Not enough space to write even single char.
return NRF_ERROR_INVALID_PARAM;
}
for (size_t i = 0; string[i] != '\0' ; i++)
{
if (string[i] == '\n')
{
x = p_point->x;
y += p_font->height + p_font->height / 10;
}
else
{
write_character(p_instance, p_font, (uint8_t)string[i], &x, y, font_color);
}
uint8_t char_idx = string[i] - p_font->startChar;
uint16_t char_width = string[i] == ' ' ? (p_font->height / 2) :
p_font->charInfo[char_idx].widthBits;
if (x > (nrf_gfx_width_get(p_instance) - char_width))
{
if (wrap)
{
x = p_point->x;
y += p_font->height + p_font->height / 10;
}
else
{
break;
}
if (y > (nrf_gfx_height_get(p_instance) - p_font->height))
{
break;
}
}
}
return NRF_SUCCESS;
}
uint16_t nrf_gfx_height_get(nrf_lcd_t const * p_instance)
{
ASSERT(p_instance != NULL);
return p_instance->p_lcd_cb->height;
}
uint16_t nrf_gfx_width_get(nrf_lcd_t const * p_instance)
{
ASSERT(p_instance != NULL);
return p_instance->p_lcd_cb->width;
}
#endif //NRF_MODULE_ENABLED(NRF_GFX)

View File

@@ -1,320 +0,0 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF_GFX_H__
#define NRF_GFX_H__
#include <stdint.h>
#include <stdbool.h>
#include "sdk_errors.h"
#include "nrf_lcd.h"
#include "nrf_font.h"
/** @file
*
* @addtogroup ili9341_config
* @ingroup ext_drivers
*
* @addtogroup st7735_config
* @ingroup ext_drivers
*
* @defgroup nrf_gfx GFX Library
* @{
* @ingroup app_common
*
* @brief Module for drawing graphical objects like lines, circles, and rectangles.
Provides support for different fonts.
*/
/**
* @brief GFX point object structure.
*/
typedef struct
{
uint16_t x; /**< Horizontal coordinate of the point where to start drawing the object. */
uint16_t y; /**< Vertical coordinate of the point where to start drawing the object. */
}nrf_gfx_point_t;
/**
* @brief GFX line object structure.
*/
typedef struct
{
uint16_t x_start; /**< Horizontal coordinate of the point where to start drawing the object. */
uint16_t y_start; /**< Vertical coordinate of the point where to start drawing the object. */
uint16_t x_end; /**< Horizontal coordinate of the point where to end drawing the object. */
uint16_t y_end; /**< Vertical coordinate of the point where to end drawing the object. */
uint16_t thickness; /**< Thickness of the border of the object. */
}nrf_gfx_line_t;
/**
* @brief GFX circle object structure.
*/
typedef struct
{
uint16_t x; /**< Horizontal coordinate of the centre of the object. */
uint16_t y; /**< Vertical coordinate of the centre of the object. */
uint16_t r; /**< Radius of the object. */
}nrf_gfx_circle_t;
/**
* @brief GFX rectangle object structure.
*/
typedef struct
{
uint16_t x; /**< Horizontal coordinate of the point where to start drawing the object. */
uint16_t y; /**< Vertical coordinate of the point where to start drawing the object. */
uint16_t width; /**< Width of the object. */
uint16_t height; /**< Height of the object. */
}nrf_gfx_rect_t;
/**
* @defgroup nrf_gfx_macros Macros for defining new graphic objects
* @{
*/
#define NRF_GFX_POINT(_x, _y) \
{ \
.x = (_x), \
.y = (_y) \
}
#define NRF_GFX_LINE(_x_0, _y_0, _x_1, _y_1, _thickness) \
{ \
.x_start = (_x_0), \
.y_start = (_y_0), \
.x_end = (_x_1), \
.y_end = (_y_1), \
.thickness = (_thickness) \
}
#define NRF_GFX_CIRCLE(_x, _y, _radius) \
{ \
.x = (_x), \
.y = (_y), \
.r = (_radius) \
}
#define NRF_GFX_RECT(_x, _y, _width, _height) \
{ \
.x = (_x), \
.y = (_y), \
.width = (_width), \
.height = (_height) \
}
/* @} */
/**
* @brief Font descriptor type.
*/
typedef FONT_INFO nrf_gfx_font_desc_t;
/**
* @brief Function for initializing the GFX library.
*
* @param[in] p_instance Pointer to the LCD instance.
*
* @return Values returned by @ref nrf_lcd_t::lcd_init.
*/
ret_code_t nrf_gfx_init(nrf_lcd_t const * p_instance);
/**
* @brief Function for uninitializing the GFX library.
*
* @param[in] p_instance Pointer to the LCD instance.
*
* @return Values returned by @ref nrf_lcd_t::lcd_uninit.
*/
void nrf_gfx_uninit(nrf_lcd_t const * p_instance);
/**
* @brief Function for drawing a point.
*
* @param[in] p_instance Pointer to the LCD instance.
* @param[in] p_point Pointer to the point object.
* @param[in] color Color of the object in the display accepted format.
*/
void nrf_gfx_point_draw(nrf_lcd_t const * p_instance, nrf_gfx_point_t const * p_point, uint32_t color);
/**
* @brief Function for drawing a line.
*
* @param[in] p_instance Pointer to the LCD instance.
* @param[in] p_line Pointer to the line object.
* @param[in] color Color of the object in the display accepted format.
*
* @retval NRF_ERROR_INVALID_PARAM If object position is not on the screen.
* @retval NRF_SUCCESS If object was successfully drawn.
*/
ret_code_t nrf_gfx_line_draw(nrf_lcd_t const * p_instance, nrf_gfx_line_t const * p_line, uint32_t color);
/**
* @brief Function for drawing a circle.
*
* @param[in] p_instance Pointer to the LCD instance.
* @param[in] p_circle Pointer to the circle object.
* @param[in] color Color of the object in the display accepted format.
* @param[in] fill If true, the circle will be filled.
*
* @retval NRF_ERROR_INVALID_PARAM If object position is not on the screen.
* @retval NRF_SUCCESS If object was successfully drawn.
*
* @note The height and width of the drawn circle are determined by: radius * 2 + 1.
*
*/
ret_code_t nrf_gfx_circle_draw(nrf_lcd_t const * p_instance,
nrf_gfx_circle_t const * p_circle,
uint32_t color,
bool fill);
/**
* @brief Function for drawing a rectangle.
*
* @param[in] p_instance Pointer to the LCD instance.
* @param[in] p_rect Pointer to the rectangle object.
* @param[in] thickness Thickness of the rectangle border.
* @param[in] color Color of the object in the display accepted format.
* @param[in] fill If true, the rectangle will be filled.
*
* @retval NRF_ERROR_INVALID_PARAM If object position is not on the screen.
* @retval NRF_SUCCESS If object was successfully drawn.
*/
ret_code_t nrf_gfx_rect_draw(nrf_lcd_t const * p_instance,
nrf_gfx_rect_t const * p_rect,
uint16_t thickness,
uint32_t color,
bool fill);
/**
* @brief Function for filling the screen with selected color.
*
* @param[in] p_instance Pointer to the LCD instance.
* @param[in] color Color of the screen in the display accepted format.
*/
void nrf_gfx_screen_fill(nrf_lcd_t const * p_instance, uint32_t color);
/**
* @brief Function for drawing an image from a .bmp file.
*
* Data in img_buf is expected to be stored in 2-byte samples, little endianness, RGB565 format.
* Pointer should skip the header and point to the first byte of data.
*
* @param[in] p_instance Pointer to the LCD instance.
* @param[in] p_rect Pointer to the rectangle object.
* @param[in] img_buf Pointer to data from the .bmp file.
*
* @note Only compatible with displays that accept pixels in RGB565 format.
*/
ret_code_t nrf_gfx_bmp565_draw(nrf_lcd_t const * p_instance,
nrf_gfx_rect_t const * p_rect,
uint16_t const * img_buf);
/**
* @brief Function for drawing an image from a .bmp file.
*
* Data in img_buf is expected to be stored in 2-byte samples, little endianness, RGB565 format.
* Pointer should skip the header and point to the first byte of data.
*
* @param[in] p_instance Pointer to the LCD instance.
* @param[in] img_buf Pointer to data from the .bmp file.
*
* @note Only compatible with displays that accept pixels in RGB565 format.
*/
void nrf_gfx_background_set(nrf_lcd_t const * p_instance, uint16_t const * img_buf);
/**
* @brief Function for displaying data from an internal frame buffer.
*
* @param[in] p_instance Pointer to the LCD instance.
*/
void nrf_gfx_display(nrf_lcd_t const * p_instance);
/**
* @brief Function for setting screen rotation.
*
* @param[in] p_instance Pointer to the LCD instance.
* @param[in] rotation Rotation to be made.
*/
void nrf_gfx_rotation_set(nrf_lcd_t const * p_instance, nrf_lcd_rotation_t rotation);
/**
* @brief Function for setting inversion of colors.
*
* @param[in] p_instance Pointer to the LCD instance.
* @param[in] invert If true, inversion will be set.
*/
void nrf_gfx_invert(nrf_lcd_t const * p_instance, bool invert);
/**
* @brief Function for printing a string to the screen.
*
* @param[in] p_instance Pointer to the LCD instance.
* @param[in] p_point Pointer to the point where to start drawing the object.
* @param[in] font_color Color of the font in the display accepted format.
* @param[in] p_string Pointer to the string.
* @param[in] p_font Pointer to the font descriptor.
* @param[in] wrap If true, the string will be wrapped to the new line.
*/
ret_code_t nrf_gfx_print(nrf_lcd_t const * p_instance,
nrf_gfx_point_t const * p_point,
uint16_t font_color,
const char * p_string,
const nrf_gfx_font_desc_t * p_font,
bool wrap);
/**
* @brief Function for getting the height of the screen.
*
* @param[in] p_instance Pointer to the LCD instance.
*
*/
uint16_t nrf_gfx_height_get(nrf_lcd_t const * p_instance);
/**
* @brief Function for getting the width of the screen.
*
* @param[in] p_instance Pointer to the LCD instance.
*
*/
uint16_t nrf_gfx_width_get(nrf_lcd_t const * p_instance);
/* @} */
#endif //NRF_GFX_H__

View File

@@ -1,144 +0,0 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF_LCD_H__
#define NRF_LCD_H__
#include <nrfx.h>
/** @file
*
* @defgroup nrf_lcd LCD Library
* @{
* @ingroup nrf_gfx
*
* @brief This module defines generic API for LCDs.
*/
/**
* @brief Enumerator with available rotations.
*/
typedef enum{
NRF_LCD_ROTATE_0 = 0, /**< Rotate 0 degrees, clockwise. */
NRF_LCD_ROTATE_90, /**< Rotate 90 degrees, clockwise. */
NRF_LCD_ROTATE_180, /**< Rotate 180 degrees, clockwise. */
NRF_LCD_ROTATE_270 /**< Rotate 270 degrees, clockwise. */
}nrf_lcd_rotation_t;
/**
* @brief LCD instance control block.
*/
typedef struct
{
nrfx_drv_state_t state; /**< State of LCD instance. */
uint16_t height; /**< LCD height. */
uint16_t width; /**< LCD width. */
nrf_lcd_rotation_t rotation; /**< LCD rotation. */
}lcd_cb_t;
/**
* @brief LCD instance type.
*
* This structure provides generic API for LCDs.
*/
typedef struct
{
/**
* @brief Function for initializing the LCD controller.
*/
ret_code_t (* lcd_init)(void);
/**
* @brief Function for uninitializing the LCD controller.
*/
void (* lcd_uninit)(void);
/**
* @brief Function for drawing a single pixel.
*
* @param[in] x Horizontal coordinate of the pixel.
* @param[in] y Vertical coordinate of the pixel.
* @param[in] color Color of the pixel in LCD accepted format.
*/
void (* lcd_pixel_draw)(uint16_t x, uint16_t y, uint32_t color);
/**
* @brief Function for drawing a filled rectangle.
*
* @param[in] x Horizontal coordinate of the point where to start drawing the rectangle.
* @param[in] y Vertical coordinate of the point where to start drawing the rectangle.
* @param[in] width Width of the image.
* @param[in] height Height of the image.
* @param[in] color Color with which to fill the rectangle in LCD accepted format.
*/
void (* lcd_rect_draw)(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint32_t color);
/**
* @brief Function for displaying data from an internal frame buffer.
*
* This function may be used when functions for drawing do not write directly to
* LCD but to an internal frame buffer. It could be implemented to write data from this
* buffer to LCD.
*/
void (* lcd_display)(void);
/**
* @brief Function for rotating the screen.
*
* @param[in] rotation Rotation as enumerated value.
*/
void (* lcd_rotation_set)(nrf_lcd_rotation_t rotation);
/**
* @brief Function for setting inversion of colors on the screen.
*
* @param[in] invert If true, inversion will be set.
*/
void (* lcd_display_invert)(bool invert);
/**
* @brief Pointer to the LCD instance control block.
*/
lcd_cb_t * p_lcd_cb;
}nrf_lcd_t;
/* @} */
#endif // NRF_LCD_H__

View File

@@ -1,360 +0,0 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sdk_common.h"
#if NRF_MODULE_ENABLED(APP_GPIOTE)
#include "app_gpiote.h"
#include "nrf_bitmask.h"
#define MODULE_INITIALIZED (mp_users != NULL) /**< Macro designating whether the module has been initialized properly. */
#if (GPIO_COUNT == 1)
#define MAX_PIN_NUMBER 32
#elif (GPIO_COUNT == 2)
#define MAX_PIN_NUMBER (32 + P1_PIN_NUM)
#else
#error "Not supported."
#endif
/**@brief GPIOTE user type. */
typedef struct
{
uint32_t pins_mask[GPIO_COUNT]; /**< Mask defining which pins user wants to monitor. */
uint32_t pins_low_to_high_mask[GPIO_COUNT]; /**< Mask defining which pins will generate events to this user when toggling low->high. */
uint32_t pins_high_to_low_mask[GPIO_COUNT]; /**< Mask defining which pins will generate events to this user when toggling high->low. */
uint32_t sense_high_pins[GPIO_COUNT]; /**< Mask defining which pins are configured to generate GPIOTE interrupt on transition to high level. */
app_gpiote_event_handler_t event_handler; /**< Pointer to function to be executed when an event occurs. */
bool enabled; /**< Flag indicating whether user is enabled. */
} gpiote_user_t;
STATIC_ASSERT(sizeof(gpiote_user_t) <= GPIOTE_USER_NODE_SIZE);
STATIC_ASSERT(sizeof(gpiote_user_t) % 4 == 0);
static uint8_t m_user_array_size; /**< Size of user array. */
static uint8_t m_user_count; /**< Number of registered users. */
static gpiote_user_t * mp_users = NULL; /**< Array of GPIOTE users. */
static uint32_t m_pins[GPIO_COUNT]; /**< Mask of initialized pins. */
static uint32_t m_last_pins_state[GPIO_COUNT]; /**< Most recent state of pins. */
void gpiote_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
int i;
uint32_t pin_mask[GPIO_COUNT] = {0};
uint32_t empty_pin_mask[GPIO_COUNT] = {0};
nrf_bitmask_bit_set(pin, pin_mask);
bool hitolo = nrf_bitmask_bit_is_set(pin, m_last_pins_state);
nrf_gpio_ports_read(0, GPIO_COUNT, m_last_pins_state);
for (i = 0; i < m_user_count; i++)
{
if (mp_users[i].enabled && nrf_bitmask_bit_is_set(pin, mp_users[i].pins_mask))
{
if (
nrf_bitmask_bit_is_set(pin, mp_users[i].pins_high_to_low_mask)
&& hitolo)
{
mp_users[i].event_handler(empty_pin_mask,pin_mask);
}
else if (
nrf_bitmask_bit_is_set(pin, mp_users[i].pins_low_to_high_mask)
&& !hitolo)
{
mp_users[i].event_handler(pin_mask,empty_pin_mask);
}
}
}
}
uint32_t app_gpiote_init(uint8_t max_users, void * p_buffer)
{
uint32_t ret_code = NRF_SUCCESS;
if (p_buffer == NULL)
{
return NRF_ERROR_INVALID_PARAM;
}
// Check that buffer is correctly aligned.
if (!is_word_aligned(p_buffer))
{
return NRF_ERROR_INVALID_PARAM;
}
// Initialize file globals.
mp_users = (gpiote_user_t *)p_buffer;
m_user_array_size = max_users;
m_user_count = 0;
memset(m_pins,0, sizeof(m_pins));
memset(mp_users, 0, m_user_array_size * sizeof(gpiote_user_t));
if (nrf_drv_gpiote_is_init()==false)
{
ret_code = nrf_drv_gpiote_init();
}
return ret_code;
}
uint32_t app_gpiote_user_register(app_gpiote_user_id_t * p_user_id,
uint32_t const * p_pins_low_to_high_mask,
uint32_t const * p_pins_high_to_low_mask,
app_gpiote_event_handler_t event_handler)
{
uint32_t user_pin_mask[GPIO_COUNT];
ASSERT(event_handler != NULL);
// Check state and parameters.
VERIFY_MODULE_INITIALIZED();
if (m_user_count >= m_user_array_size)
{
return NRF_ERROR_NO_MEM;
}
nrf_bitmask_masks_or(p_pins_low_to_high_mask, p_pins_high_to_low_mask,
user_pin_mask, sizeof(user_pin_mask));
// Allocate new user.
mp_users[m_user_count].enabled = false;
mp_users[m_user_count].event_handler = event_handler;
memcpy(mp_users[m_user_count].pins_mask,
user_pin_mask,
sizeof(mp_users[m_user_count].pins_mask));
memcpy(mp_users[m_user_count].pins_low_to_high_mask,
p_pins_low_to_high_mask,
sizeof(mp_users[m_user_count].pins_low_to_high_mask));
memcpy(mp_users[m_user_count].pins_high_to_low_mask,
p_pins_high_to_low_mask,
sizeof(mp_users[m_user_count].pins_high_to_low_mask));
uint32_t i;
const nrf_drv_gpiote_in_config_t config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(false);
uint32_t num_of_pins = MAX_PIN_NUMBER;
for (i = 0; i < num_of_pins; i++)
{
if (nrf_bitmask_bit_is_set(i, user_pin_mask) &&
!nrf_bitmask_bit_is_set(i, m_pins))
{
uint32_t ret_val = nrf_drv_gpiote_in_init(i, &config, gpiote_handler);
VERIFY_SUCCESS(ret_val);
nrf_bitmask_bit_set(i, m_pins);
}
}
/* Success - return user id and increment counter */
*p_user_id = m_user_count++;
return NRF_SUCCESS;
}
uint32_t app_gpiote_user_register_ex(app_gpiote_user_id_t * p_user_id,
app_gpiote_user_pin_config_t const * p_pins_config,
size_t pin_count,
app_gpiote_event_handler_t event_handler)
{
ASSERT(event_handler != NULL);
// Check state and parameters.
VERIFY_MODULE_INITIALIZED();
if (m_user_count >= m_user_array_size)
{
return NRF_ERROR_NO_MEM;
}
/* Prepare user structure */
gpiote_user_t * p_user = &mp_users[m_user_count];
p_user->enabled = false;
memset(p_user, 0, sizeof(gpiote_user_t));
mp_users[m_user_count].event_handler = event_handler;
for (; pin_count != 0; --pin_count, ++p_pins_config)
{
nrfx_gpiote_pin_t pin = (nrfx_gpiote_pin_t)p_pins_config->pin_number;
const nrf_drv_gpiote_in_config_t config = GPIOTE_RAW_CONFIG_IN_SENSE_TOGGLE(false);
if (!nrf_bitmask_bit_is_set(pin, m_pins))
{
uint32_t ret_val = nrf_drv_gpiote_in_init(pin, &config, gpiote_handler);
VERIFY_SUCCESS(ret_val);
nrf_bitmask_bit_set(pin, m_pins);
}
//lint -save -e650 Lint seems not properly support bitfields that uses enum as a base type
if ((p_pins_config->sense == NRF_GPIOTE_POLARITY_LOTOHI) ||
(p_pins_config->sense == NRF_GPIOTE_POLARITY_TOGGLE))
{
nrf_bitmask_bit_set(pin, p_user->pins_low_to_high_mask);
}
if ((p_pins_config->sense == NRF_GPIOTE_POLARITY_HITOLO) ||
(p_pins_config->sense == NRF_GPIOTE_POLARITY_TOGGLE))
{
nrf_bitmask_bit_set(pin, p_user->pins_high_to_low_mask);
}
//lint -restore
}
/* Mark all pins used by the selected user */
nrf_bitmask_masks_or(
p_user->pins_low_to_high_mask,
p_user->pins_high_to_low_mask,
p_user->pins_mask,
sizeof(p_user->pins_mask));
/* Success - return user id and increment counter */
*p_user_id = m_user_count++;
return NRF_SUCCESS;
}
__STATIC_INLINE uint32_t error_check(app_gpiote_user_id_t user_id)
{
// Check state and parameters.
VERIFY_MODULE_INITIALIZED();
if (user_id >= m_user_count)
{
return NRF_ERROR_INVALID_PARAM;
}
return NRF_SUCCESS;
}
/**
* @brief Function for enabling event on pin (if not yet enabled) or disabling the event if no other
* user requires it.
*
* @param pin Pin to enable
* @param enable If true function will attempt to enable the pin else it will attempt to disable it.
*/
static void pin_event_enable(uint32_t pin, bool enable)
{
uint32_t i;
bool enabled = false;
//search if any user already enabled given pin
for (i = 0; i < m_user_count; i++)
{
if (mp_users[i].enabled &&
nrf_bitmask_bit_is_set(pin, mp_users[i].pins_mask))
{
enabled = true;
break;
}
}
if (!enabled)
{
if (enable)
{
nrf_gpio_ports_read(0, GPIO_COUNT, m_last_pins_state);
nrf_drv_gpiote_in_event_enable(pin, true);
}
else
{
nrf_drv_gpiote_in_event_disable(pin);
}
}
}
/**
* @brief Function for enabling or disabling events for pins used by the user.
*
* Function will enable pin events only if they are not yet enabled. Function will disable pin
* events only if there is no other enabled user that is using them.
*
* @param user_id User id.
* @param enable If true function will attempt to enable the pin else it will attempt to disable it.
*/
static uint32_t user_enable(app_gpiote_user_id_t user_id, bool enable)
{
uint32_t ret_code = error_check(user_id);
if (ret_code == NRF_SUCCESS)
{
uint32_t i;
for (i = 0; i < MAX_PIN_NUMBER; i++)
{
if (nrf_bitmask_bit_is_set(i, mp_users[user_id].pins_mask))
{
pin_event_enable(i, enable);
}
}
}
return ret_code;
}
uint32_t app_gpiote_user_enable(app_gpiote_user_id_t user_id)
{
uint32_t ret_code = NRF_SUCCESS;
if (mp_users[user_id].enabled == false)
{
ret_code = user_enable(user_id, true);
VERIFY_SUCCESS(ret_code);
mp_users[user_id].enabled = true;
return ret_code;
}
else
{
return ret_code;
}
}
uint32_t app_gpiote_user_disable(app_gpiote_user_id_t user_id)
{
uint32_t ret_code = NRF_SUCCESS;
if (mp_users[user_id].enabled)
{
mp_users[user_id].enabled = false;
ret_code = user_enable(user_id, false);
}
return ret_code;
}
uint32_t app_gpiote_pins_state_get(app_gpiote_user_id_t user_id, uint32_t * p_pins)
{
gpiote_user_t * p_user;
uint32_t ret_code = error_check(user_id);
if (ret_code == NRF_SUCCESS)
{
p_user = &mp_users[user_id];
nrf_gpio_ports_read(0, GPIO_COUNT, p_pins);
nrf_bitmask_masks_and(p_pins, p_user->pins_mask, p_pins, sizeof(p_user->pins_mask));
}
return ret_code;
}
#endif //NRF_MODULE_ENABLED(APP_GPIOTE)

View File

@@ -1,266 +0,0 @@
/**
* Copyright (c) 2012 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/** @file
*
* @defgroup app_gpiote GPIOTE Handler
* @{
* @ingroup app_common
*
* @brief GPIOTE handler module.
*
* @details The GPIOTE handler allows several modules ("users") to share the GPIOTE interrupt,
* each user defining a set of pins able to generate events to the user.
* When a GPIOTE interrupt occurs, the GPIOTE interrupt handler will call the event handler
* of each user for which at least one of the pins generated an event.
*
* The GPIOTE users are responsible for configuring all their corresponding pins, except
* the SENSE field, which should be initialized to GPIO_PIN_CNF_SENSE_Disabled.
* The SENSE field will be updated by the GPIOTE module when it is enabled or disabled,
* and also while it is enabled.
*
* The module specifies on which pins events should be generated if the pin(s) goes
* from low->high or high->low or both directions.
*
* @note Even if the application is using the @ref app_scheduler, the GPIOTE event handlers will
* be called directly from the GPIOTE interrupt handler.
*
* @warning If multiple users registers for the same pins the behavior for those pins are undefined.
*/
#ifndef APP_GPIOTE_H__
#define APP_GPIOTE_H__
#include <stdint.h>
#include <stdbool.h>
#include "nrf.h"
#include "nrf_drv_gpiote.h"
#include "app_error.h"
#include "app_util.h"
#ifdef __cplusplus
extern "C" {
#endif
#define GPIOTE_USER_NODE_SIZE ((4*sizeof(uint32_t)*GPIO_COUNT)+8) /**< Size of app_gpiote.gpiote_user_t (only for use inside APP_GPIOTE_BUF_SIZE()). */
/**@brief Compute number of bytes required to hold the GPIOTE data structures.
*
* @param[in] MAX_USERS Maximum number of GPIOTE users.
*
* @retval Required buffer size (in bytes).
*/
#define APP_GPIOTE_BUF_SIZE(MAX_USERS) ((MAX_USERS) * GPIOTE_USER_NODE_SIZE)
typedef uint8_t app_gpiote_user_id_t;
/**@brief GPIOTE event handler type. */
typedef void (*app_gpiote_event_handler_t)(uint32_t const * p_event_pins_low_to_high,
uint32_t const * p_event_pins_high_to_low);
/**@brief GPIOTE input event handler type. */
typedef void (*app_gpiote_input_event_handler_t)(void);
/* Make the pin config descriptor packed */
#pragma pack(push, 1)
/**
* @brief Single pin configuration
*
* Structure used to describe single pin configuration
* when registering user.
* @sa app_gpiote_user_register_ex
*/
typedef struct
{
/** Pin number to observe */
uint32_t pin_number : VBITS(NRF_GPIO_PIN_MAP(GPIO_COUNT - 1, 31));
/** Transition to observe */
nrf_gpiote_polarity_t sense : 2;
} app_gpiote_user_pin_config_t;
// Check if we can fitt all the nrf_gpiote_polarity_t values into 2 bits field
STATIC_ASSERT(NRF_GPIOTE_POLARITY_LOTOHI <= 3);
STATIC_ASSERT(NRF_GPIOTE_POLARITY_HITOLO <= 3);
STATIC_ASSERT(NRF_GPIOTE_POLARITY_TOGGLE <= 3);
#pragma pack(pop)
/**@brief Macro for initializing the GPIOTE module.
*
* @details It will handle dimensioning and allocation of the memory buffer required by the module,
* making sure that the buffer is correctly aligned.
*
* @param[in] MAX_USERS Maximum number of GPIOTE users.
*
* @note Since this macro allocates a buffer, it must only be called once (it is OK to call it
* several times as long as it is from the same location, e.g. to do a reinitialization).
*/
/*lint -emacro(506, APP_GPIOTE_INIT) */ /* Suppress "Constant value Boolean */
#define APP_GPIOTE_INIT(MAX_USERS) \
do \
{ \
static uint32_t app_gpiote_buf[CEIL_DIV(APP_GPIOTE_BUF_SIZE(MAX_USERS), sizeof(uint32_t))];\
uint32_t ERR_CODE = app_gpiote_init((MAX_USERS), app_gpiote_buf); \
APP_ERROR_CHECK(ERR_CODE); \
} while (0)
/**@brief Function for initializing the GPIOTE module.
*
* @note Normally initialization should be done using the APP_GPIOTE_INIT() macro, as that will
* allocate the buffer needed by the GPIOTE module (including aligning the buffer correctly).
*
* @param[in] max_users Maximum number of GPIOTE users.
* @param[in] p_buffer Pointer to memory buffer for internal use in the app_gpiote
* module. The size of the buffer can be computed using the
* APP_GPIOTE_BUF_SIZE() macro. The buffer must be aligned to
* a 4 byte boundary.
*
* @retval NRF_SUCCESS Successful initialization.
* @retval NRF_ERROR_INVALID_PARAM Invalid parameter (buffer not aligned to a 4 byte
* boundary).
*/
uint32_t app_gpiote_init(uint8_t max_users, void * p_buffer);
/**@brief Function for registering a GPIOTE user.
*
* @param[out] p_user_id Id for the new GPIOTE user.
* @param[in] p_pins_low_to_high_mask Pointer to word array with mask defining which pins
* will generate events to this user when state is changed
* from low->high. Size of array depends on number of ports
* in the device.
* @param[in] p_pins_high_to_low_mask Pointer to word array with mask defining which pins
* will generate events to this user when state is changed
* from high->low. Size of array depends on number of ports
* in the device.
* @param[in] event_handler Pointer to function to be executed when an event occurs.
* Cannot be NULL.
*
* @retval NRF_SUCCESS Successful initialization.
* @retval NRF_ERROR_INALID_STATE If @ref app_gpiote_init has not been called on the GPIOTE
* module.
* @retval NRF_ERROR_NO_MEM Returned if the application tries to register more users
* than defined when the GPIOTE module was initialized in
* @ref app_gpiote_init.
*
* @note The function can also return error codes from internally
* called @ref nrf_drv_gpiote_in_init
*
* @sa app_gpiote_user_register_ex
*/
uint32_t app_gpiote_user_register(app_gpiote_user_id_t * p_user_id,
uint32_t const * p_pins_low_to_high_mask,
uint32_t const * p_pins_high_to_low_mask,
app_gpiote_event_handler_t event_handler);
/**@brief Function for registering GPIOTE user using pins configuration list.
*
* Function for registering GPIOTE user that uses array of pins configuration.
* This function do not change pins configuration.
* Pins must be configured before calling this function.
*
* @param[out] p_user_id Id for the new GPIOTE user.
* @param[in] p_pins_config Pointer to the array of pins configuration for the user.
* @param[in] pin_count Number of pins to configure for the user.
* @param[in] event_handler Pointer to function to be executed when an event occurs.
* Cannot be NULL.
*
* @retval NRF_SUCCESS Successful user registration.
* @retval NRF_ERROR_INVALID_STATE If @ref app_gpiote_init has not been called before calling
* this function.
* @retval NRF_ERROR_NO_MEM Returned if the application tries to register more users
* than defined when the GPIOTE module was initialized in
* @ref app_gpiote_init.
*
* @note The function can also return error codes from internally
* called @ref nrf_drv_gpiote_in_init
*
* @sa app_gpiote_user_register
*/
uint32_t app_gpiote_user_register_ex(app_gpiote_user_id_t * p_user_id,
app_gpiote_user_pin_config_t const * p_pins_config,
size_t pin_count,
app_gpiote_event_handler_t event_handler);
/**@brief Function for informing the GPIOTE module that the specified user wants to use the GPIOTE module.
*
* @param[in] user_id Id of user to enable.
*
* @retval NRF_SUCCESS On success.
* @retval NRF_ERROR_INVALID_PARAM Invalid user_id provided, No a valid user.
* @retval NRF_ERROR_INALID_STATE If @ref app_gpiote_init has not been called on the GPIOTE
* module.
*/
uint32_t app_gpiote_user_enable(app_gpiote_user_id_t user_id);
/**@brief Function for informing the GPIOTE module that the specified user is done using the GPIOTE module.
*
* @param[in] user_id Id of user to enable.
*
* @retval NRF_SUCCESS On success.
* @retval NRF_ERROR_INVALID_PARAM Invalid user_id provided, No a valid user.
* @retval NRF_ERROR_INALID_STATE If @ref app_gpiote_init has not been called on the GPIOTE
* module.
*/
uint32_t app_gpiote_user_disable(app_gpiote_user_id_t user_id);
/**@brief Function for getting the state of the pins which are registered for the specified user.
*
* @param[in] user_id Id of user to check.
* @param[out] p_pins Pointer to array of words with bit mask corresponding to the pins
* configured to generate events to the specified user. All bits
* corresponding to pins in the state 'high' will have value '1',
* all others will have value '0'. Size of array depends on number
* of ports in the device.
*
* @retval NRF_SUCCESS On success.
* @retval NRF_ERROR_INVALID_PARAM Invalid user_id provided, No a valid user.
* @retval NRF_ERROR_INALID_STATE If @ref app_gpiote_init has not been called on the GPIOTE
* module.
*/
uint32_t app_gpiote_pins_state_get(app_gpiote_user_id_t user_id, uint32_t * p_pins);
#ifdef __cplusplus
}
#endif
#endif // APP_GPIOTE_H__
/** @} */

View File

@@ -1,264 +0,0 @@
/**
* Copyright (c) 2013 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sdk_common.h"
#if NRF_MODULE_ENABLED(HCI_MEM_POOL)
#include "hci_mem_pool.h"
#include <stdbool.h>
#include <stdio.h>
/**@brief RX buffer element instance structure.
*/
typedef struct
{
uint8_t rx_buffer[HCI_RX_BUF_SIZE]; /**< RX buffer memory array. */
uint32_t length; /**< Length of the RX buffer memory array. */
} rx_buffer_elem_t;
/**@brief RX buffer queue element instance structure.
*/
typedef struct
{
rx_buffer_elem_t * p_buffer; /**< Pointer to RX buffer element. */
uint32_t free_window_count; /**< Free space element count. */
uint32_t free_available_count; /**< Free area element count. */
uint32_t read_available_count; /**< Read area element count. */
uint32_t write_index; /**< Write position index. */
uint32_t read_index; /**< Read position index. */
uint32_t free_index; /**< Free position index. */
} rx_buffer_queue_t;
static bool m_is_tx_allocated; /**< Boolean value to determine if the TX buffer is allocated. */
static rx_buffer_elem_t m_rx_buffer_elem_queue[HCI_RX_BUF_QUEUE_SIZE]; /**< RX buffer element instances. */
static rx_buffer_queue_t m_rx_buffer_queue; /**< RX buffer queue element instance. */
uint32_t hci_mem_pool_open(void)
{
m_is_tx_allocated = false;
m_rx_buffer_queue.p_buffer = m_rx_buffer_elem_queue;
m_rx_buffer_queue.free_window_count = HCI_RX_BUF_QUEUE_SIZE;
m_rx_buffer_queue.free_available_count = 0;
m_rx_buffer_queue.read_available_count = 0;
m_rx_buffer_queue.write_index = 0;
m_rx_buffer_queue.read_index = 0;
m_rx_buffer_queue.free_index = 0;
return NRF_SUCCESS;
}
uint32_t hci_mem_pool_close(void)
{
return NRF_SUCCESS;
}
uint32_t hci_mem_pool_tx_alloc(void ** pp_buffer)
{
static uint8_t tx_buffer[HCI_TX_BUF_SIZE];
uint32_t err_code;
if (pp_buffer == NULL)
{
return NRF_ERROR_NULL;
}
if (!m_is_tx_allocated)
{
m_is_tx_allocated = true;
*pp_buffer = tx_buffer;
err_code = NRF_SUCCESS;
}
else
{
err_code = NRF_ERROR_NO_MEM;
}
return err_code;
}
uint32_t hci_mem_pool_tx_free(void)
{
m_is_tx_allocated = false;
return NRF_SUCCESS;
}
uint32_t hci_mem_pool_rx_produce(uint32_t length, void ** pp_buffer)
{
uint32_t err_code;
if (pp_buffer == NULL)
{
return NRF_ERROR_NULL;
}
*pp_buffer = NULL;
if (m_rx_buffer_queue.free_window_count != 0)
{
if (length <= HCI_RX_BUF_SIZE)
{
--(m_rx_buffer_queue.free_window_count);
++(m_rx_buffer_queue.read_available_count);
*pp_buffer =
m_rx_buffer_queue.p_buffer[m_rx_buffer_queue.write_index].rx_buffer;
m_rx_buffer_queue.free_index |= (1u << m_rx_buffer_queue.write_index);
// @note: Adjust the write_index making use of the fact that the buffer size is of
// power of two and two's complement arithmetic. For details refer example to book
// "Making embedded systems: Elicia White".
m_rx_buffer_queue.write_index =
(m_rx_buffer_queue.write_index + 1u) & (HCI_RX_BUF_QUEUE_SIZE - 1u);
err_code = NRF_SUCCESS;
}
else
{
err_code = NRF_ERROR_DATA_SIZE;
}
}
else
{
err_code = NRF_ERROR_NO_MEM;
}
return err_code;
}
uint32_t hci_mem_pool_rx_consume(uint8_t * p_buffer)
{
uint32_t err_code;
uint32_t consume_index;
uint32_t start_index;
if (m_rx_buffer_queue.free_available_count != 0)
{
// Find the buffer that has been freed -
// Start at read_index minus free_available_count and then increment until read index.
err_code = NRF_ERROR_INVALID_ADDR;
consume_index = (m_rx_buffer_queue.read_index - m_rx_buffer_queue.free_available_count) &
(HCI_RX_BUF_QUEUE_SIZE - 1u);
start_index = consume_index;
do
{
if (m_rx_buffer_queue.p_buffer[consume_index].rx_buffer == p_buffer)
{
m_rx_buffer_queue.free_index ^= (1u << consume_index);
err_code = NRF_SUCCESS;
break;
}
else
{
consume_index = (consume_index + 1u) & (HCI_RX_BUF_QUEUE_SIZE - 1u);
}
}
while (consume_index != m_rx_buffer_queue.read_index);
while (!(m_rx_buffer_queue.free_index & (1 << start_index)) &&
(m_rx_buffer_queue.free_available_count != 0))
{
--(m_rx_buffer_queue.free_available_count);
++(m_rx_buffer_queue.free_window_count);
start_index = (consume_index + 1u) & (HCI_RX_BUF_QUEUE_SIZE - 1u);
}
}
else
{
err_code = NRF_ERROR_NO_MEM;
}
return err_code;
}
uint32_t hci_mem_pool_rx_data_size_set(uint32_t length)
{
// @note: Adjust the write_index making use of the fact that the buffer size is of power
// of two and two's complement arithmetic. For details refer example to book
// "Making embedded systems: Elicia White".
const uint32_t index = (m_rx_buffer_queue.write_index - 1u) & (HCI_RX_BUF_QUEUE_SIZE - 1u);
m_rx_buffer_queue.p_buffer[index].length = length;
return NRF_SUCCESS;
}
uint32_t hci_mem_pool_rx_extract(uint8_t ** pp_buffer, uint32_t * p_length)
{
uint32_t err_code;
if ((pp_buffer == NULL) || (p_length == NULL))
{
return NRF_ERROR_NULL;
}
if (m_rx_buffer_queue.read_available_count != 0)
{
--(m_rx_buffer_queue.read_available_count);
++(m_rx_buffer_queue.free_available_count);
*pp_buffer =
m_rx_buffer_queue.p_buffer[m_rx_buffer_queue.read_index].rx_buffer;
*p_length =
m_rx_buffer_queue.p_buffer[m_rx_buffer_queue.read_index].length;
// @note: Adjust the write_index making use of the fact that the buffer size is of power
// of two and two's complement arithmetic. For details refer example to book
// "Making embedded systems: Elicia White".
m_rx_buffer_queue.read_index =
(m_rx_buffer_queue.read_index + 1u) & (HCI_RX_BUF_QUEUE_SIZE - 1u);
err_code = NRF_SUCCESS;
}
else
{
err_code = NRF_ERROR_NO_MEM;
}
return err_code;
}
#endif //NRF_MODULE_ENABLED(HCI_MEM_POOL)

View File

@@ -1,168 +0,0 @@
/**
* Copyright (c) 2013 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/** @file
*
* @defgroup hci_mem_pool Memory pool
* @{
* @ingroup app_common
*
* @brief Memory pool implementation
*
* Memory pool implementation, based on circular buffer data structure, which supports asynchronous
* processing of RX data. The current default implementation supports 1 TX buffer and 4 RX buffers.
* The memory managed by the pool is allocated from static storage instead of heap. The internal
* design of the circular buffer implementing the RX memory layout is illustrated in the picture
* below.
*
* @image html memory_pool.svg "Circular buffer design"
*
* The expected call order for the RX APIs is as follows:
* - hci_mem_pool_rx_produce
* - hci_mem_pool_rx_data_size_set
* - hci_mem_pool_rx_extract
* - hci_mem_pool_rx_consume
*
* @warning If the above mentioned expected call order is violated the end result can be undefined.
*
* \par Component specific configuration options
*
* The following compile time configuration options are available to suit various implementations:
* - TX_BUF_SIZE TX buffer size in bytes.
* - RX_BUF_SIZE RX buffer size in bytes.
* - RX_BUF_QUEUE_SIZE RX buffer element size.
*/
#ifndef HCI_MEM_POOL_H__
#define HCI_MEM_POOL_H__
#include <stdint.h>
#include "nrf_error.h"
#ifdef __cplusplus
extern "C" {
#endif
/**@brief Function for opening the module.
*
* @retval NRF_SUCCESS Operation success.
*/
uint32_t hci_mem_pool_open(void);
/**@brief Function for closing the module.
*
* @retval NRF_SUCCESS Operation success.
*/
uint32_t hci_mem_pool_close(void);
/**@brief Function for allocating requested amount of TX memory.
*
* @param[out] pp_buffer Pointer to the allocated memory.
*
* @retval NRF_SUCCESS Operation success. Memory was allocated.
* @retval NRF_ERROR_NO_MEM Operation failure. No memory available for allocation.
* @retval NRF_ERROR_NULL Operation failure. NULL pointer supplied.
*/
uint32_t hci_mem_pool_tx_alloc(void ** pp_buffer);
/**@brief Function for freeing previously allocated TX memory.
*
* @note Memory management follows the FIFO principle meaning that free() order must match the
* alloc(...) order, which is the reason for omitting exact memory block identifier as an
* input parameter.
*
* @retval NRF_SUCCESS Operation success. Memory was freed.
*/
uint32_t hci_mem_pool_tx_free(void);
/**@brief Function for producing a free RX memory block for usage.
*
* @note Upon produce request amount being 0, NRF_SUCCESS is returned.
*
* @param[in] length Amount, in bytes, of free memory to be produced.
* @param[out] pp_buffer Pointer to the allocated memory.
*
* @retval NRF_SUCCESS Operation success. Free RX memory block produced.
* @retval NRF_ERROR_NO_MEM Operation failure. No suitable memory available for allocation.
* @retval NRF_ERROR_DATA_SIZE Operation failure. Request size exceeds limit.
* @retval NRF_ERROR_NULL Operation failure. NULL pointer supplied.
*/
uint32_t hci_mem_pool_rx_produce(uint32_t length, void ** pp_buffer);
/**@brief Function for setting the length of the last produced RX memory block.
*
* @warning If call to this API is omitted the end result is that the following call to
* mem_pool_rx_extract will return incorrect data in the p_length output parameter.
*
* @param[in] length Amount, in bytes, of actual memory used.
*
* @retval NRF_SUCCESS Operation success. Length was set.
*/
uint32_t hci_mem_pool_rx_data_size_set(uint32_t length);
/**@brief Function for extracting a packet, which has been filled with read data, for further
* processing.
*
* @param[out] pp_buffer Pointer to the packet data.
* @param[out] p_length Length of packet data in bytes.
*
* @retval NRF_SUCCESS Operation success.
* @retval NRF_ERROR_NO_MEM Operation failure. No packet available to extract.
* @retval NRF_ERROR_NULL Operation failure. NULL pointer supplied.
*/
uint32_t hci_mem_pool_rx_extract(uint8_t ** pp_buffer, uint32_t * p_length);
/**@brief Function for freeing previously extracted packet, which has been filled with read data.
*
* @param[in] p_buffer Pointer to consumed buffer.
*
* @retval NRF_SUCCESS Operation success.
* @retval NRF_ERROR_NO_MEM Operation failure. No packet available to free.
* @retval NRF_ERROR_INVALID_ADDR Operation failure. Not a valid pointer.
*/
uint32_t hci_mem_pool_rx_consume(uint8_t * p_buffer);
#ifdef __cplusplus
}
#endif
#endif // HCI_MEM_POOL_H__
/** @} */

View File

@@ -1,457 +0,0 @@
/**
* Copyright (c) 2013 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sdk_common.h"
#if NRF_MODULE_ENABLED(HCI_SLIP)
#include "hci_slip.h"
#include <stdlib.h>
#include "app_uart.h"
#include "nrf_error.h"
#define APP_SLIP_END 0xC0 /**< SLIP code for identifying the beginning and end of a packet frame.. */
#define APP_SLIP_ESC 0xDB /**< SLIP escape code. This code is used to specify that the following character is specially encoded. */
#define APP_SLIP_ESC_END 0xDC /**< SLIP special code. When this code follows 0xDB, this character is interpreted as payload data 0xC0.. */
#define APP_SLIP_ESC_ESC 0xDD /**< SLIP special code. When this code follows 0xDB, this character is interpreted as payload data 0xDB. */
/** @brief States for the SLIP state machine. */
typedef enum
{
SLIP_OFF, /**< SLIP state OFF. */
SLIP_READY, /**< SLIP state ON. */
SLIP_TRANSMITTING, /**< SLIP state is transmitting indicating write() has been called but data transmission has not completed. */
} slip_states_t;
static slip_states_t m_current_state = SLIP_OFF; /** Current state for the SLIP TX state machine. */
static hci_slip_event_handler_t m_slip_event_handler; /** Event callback function for handling of SLIP events, @ref hci_slip_evt_type_t . */
static const uint8_t * mp_tx_buffer; /** Pointer to the current TX buffer that is in transmission. */
static uint32_t m_tx_buffer_length; /** Length of the current TX buffer that is in transmission. */
static volatile uint32_t m_tx_buffer_index; /** Current index for next byte to transmit in the mp_tx_buffer. */
static uint8_t * mp_rx_buffer; /** Pointer to the current RX buffer where the next SLIP decoded packet will be stored. */
static uint32_t m_rx_buffer_length; /** Length of the current RX buffer. */
static uint32_t m_rx_received_count; /** Number of SLIP decoded bytes received and stored in mp_rx_buffer. */
/**@brief Function for parsing bytes received on the UART until a SLIP escape byte is received.
*
* @param[in] byte Byte received in UART module.
*/
static void handle_rx_byte_default(uint8_t byte);
/**@brief Function for parsing bytes received on the UART until SLIP end byte is received.
*
* @param[in] byte Byte received in UART module.
*/
static void handle_rx_byte_wait_start(uint8_t byte);
/**@brief Function for decoding a received SLIP escape byte.
* It will ensure correct decoding of the byte following the SLIP escape byte.
*
* @param[in] byte Byte received in UART module.
*/
static void handle_rx_byte_esc(uint8_t byte);
/**@brief Function pointer for parsing and decoding SLIP bytes from the UART module.
*
* @param[in] byte Byte received in UART module.
*/
static void (*handle_rx_byte) (uint8_t byte) = handle_rx_byte_wait_start;
/**@brief Function pointer for sending a byte through the UART module.
*/
static uint32_t send_tx_byte_default(void);
/**@brief Function for transferring a SLIP escape byte (0xDB) when special bytes are transferred,
* that is 0xC0 and 0xDB.
*/
static uint32_t send_tx_byte_esc(void);
/**@brief Function for transferring a byte when it collides with SLIP commands and follows the SLIP
* escape byte, that is 0xC0 => 0xDC and 0xDB => 0xDD.
*/
static uint32_t send_tx_byte_encoded(void);
/**@brief Function for transferring the SLIP end frame byte, 0xC0.
*/
static uint32_t send_tx_byte_end(void);
/**@brief Function pointer for sending a byte through the UART module.
*/
uint32_t (*send_tx_byte) (void) = send_tx_byte_default;
static uint32_t send_tx_byte_end(void)
{
uint32_t err_code = app_uart_put(APP_SLIP_END);
if ((err_code == NRF_SUCCESS) && (m_tx_buffer_index == 0))
{
// Packet transmission started.
send_tx_byte = send_tx_byte_default;
}
return err_code;
}
static uint32_t send_tx_byte_default(void)
{
uint32_t err_code = app_uart_put(mp_tx_buffer[m_tx_buffer_index]);
if (err_code == NRF_SUCCESS)
{
m_tx_buffer_index++;
}
return err_code;
}
static uint32_t send_tx_byte_encoded(void)
{
uint32_t err_code;
switch (mp_tx_buffer[m_tx_buffer_index])
{
case APP_SLIP_END:
err_code = app_uart_put(APP_SLIP_ESC_END);
break;
case APP_SLIP_ESC:
err_code = app_uart_put(APP_SLIP_ESC_ESC);
break;
default:
err_code = NRF_ERROR_NO_MEM;
break;
}
if (err_code == NRF_SUCCESS)
{
m_tx_buffer_index++;
send_tx_byte = send_tx_byte_default;
}
return err_code;
}
static uint32_t send_tx_byte_esc(void)
{
uint32_t err_code = app_uart_put(APP_SLIP_ESC);
if (err_code == NRF_SUCCESS)
{
send_tx_byte = send_tx_byte_encoded;
}
return err_code;
}
/** @brief Function for transferring the content of the mp_tx_buffer to the UART.
* It continues to transfer bytes until the UART buffer is full or the complete buffer is
* transferred.
*/
static void transmit_buffer(void)
{
uint32_t err_code = NRF_SUCCESS;
while (m_tx_buffer_index < m_tx_buffer_length)
{
if ((mp_tx_buffer[m_tx_buffer_index] == APP_SLIP_END ||
mp_tx_buffer[m_tx_buffer_index] == APP_SLIP_ESC) &&
send_tx_byte == send_tx_byte_default)
{
send_tx_byte = send_tx_byte_esc;
}
err_code = send_tx_byte();
if (err_code == NRF_ERROR_NO_MEM || err_code == NRF_ERROR_BUSY)
{
// No memory left in UART TX buffer. Abort and wait for APP_UART_TX_EMPTY to continue.
return;
}
}
send_tx_byte = send_tx_byte_end;
err_code = send_tx_byte();
if (err_code == NRF_SUCCESS)
{
// Packet transmission ended. Notify higher level.
m_current_state = SLIP_READY;
if (m_slip_event_handler != NULL)
{
hci_slip_evt_t event = {HCI_SLIP_TX_DONE, mp_tx_buffer, m_tx_buffer_index};
m_slip_event_handler(event);
}
}
}
/** @brief Function for handling the reception of a SLIP end byte.
* If the number of bytes received is greater than zero it will call m_slip_event_handler
* with number of bytes received and invalidate the mp_rx_buffer to protect against data
* corruption.
* No new bytes can be received until a new RX buffer is supplied.
*/
static void handle_slip_end(void)
{
if (m_rx_received_count > 0)
{
// Full packet received, push it up.
if (m_slip_event_handler != NULL)
{
hci_slip_evt_t event = {HCI_SLIP_RX_RDY, mp_rx_buffer, m_rx_received_count};
m_rx_received_count = 0;
mp_rx_buffer = NULL;
m_slip_event_handler(event);
}
}
}
static void handle_rx_byte_esc(uint8_t byte)
{
switch (byte)
{
case APP_SLIP_END:
handle_slip_end();
break;
case APP_SLIP_ESC_END:
mp_rx_buffer[m_rx_received_count++] = APP_SLIP_END;
break;
case APP_SLIP_ESC_ESC:
mp_rx_buffer[m_rx_received_count++] = APP_SLIP_ESC;
break;
default:
mp_rx_buffer[m_rx_received_count++] = byte;
break;
}
handle_rx_byte = handle_rx_byte_default;
}
static void handle_rx_byte_default(uint8_t byte)
{
switch (byte)
{
case APP_SLIP_END:
handle_slip_end();
break;
case APP_SLIP_ESC:
handle_rx_byte = handle_rx_byte_esc;
break;
default:
mp_rx_buffer[m_rx_received_count++] = byte;
break;
}
}
static void handle_rx_byte_wait_start(uint8_t byte)
{
if (byte == APP_SLIP_END)
{
handle_rx_byte = handle_rx_byte_default;
}
}
/** @brief Function for checking the current index and length of the RX buffer to determine if the
* buffer is full. If an event handler has been registered, the callback function will
* be executed..
*
* @retval true If RX buffer has overflowed.
* @retval false otherwise.
*
*/
static bool rx_buffer_overflowed(void)
{
if (mp_rx_buffer == NULL || m_rx_received_count >= m_rx_buffer_length)
{
if (m_slip_event_handler != NULL)
{
hci_slip_evt_t event = {HCI_SLIP_RX_OVERFLOW, mp_rx_buffer, m_rx_received_count};
m_slip_event_handler(event);
}
return true;
}
return false;
}
/** @brief Function for handling the UART module event. It parses events from the UART when
* bytes are received/transmitted.
*
* @param[in] uart_event Event received from app_uart module.
*/
static void slip_uart_eventhandler(app_uart_evt_t * uart_event)
{
if (uart_event->evt_type == APP_UART_TX_EMPTY && m_current_state == SLIP_TRANSMITTING)
{
transmit_buffer();
}
if ((uart_event->evt_type == APP_UART_DATA) && (!rx_buffer_overflowed()))
{
handle_rx_byte(uart_event->data.value);
}
}
/** @brief Function for enabling the UART module when the SLIP layer is opened.
*/
static uint32_t slip_uart_open(void)
{
uint32_t err_code;
app_uart_comm_params_t comm_params =
{
HCI_UART_RX_PIN,
HCI_UART_TX_PIN,
HCI_UART_RTS_PIN,
HCI_UART_CTS_PIN,
(app_uart_flow_control_t)HCI_UART_FLOW_CONTROL,
false,
HCI_UART_BAUDRATE
};
err_code = app_uart_init(&comm_params,
NULL,
slip_uart_eventhandler,
APP_IRQ_PRIORITY_LOWEST);
if (err_code == NRF_SUCCESS)
{
m_current_state = SLIP_READY;
}
return err_code;
}
uint32_t hci_slip_evt_handler_register(hci_slip_event_handler_t event_handler)
{
m_slip_event_handler = event_handler;
return NRF_SUCCESS;
}
uint32_t hci_slip_open()
{
switch (m_current_state)
{
case SLIP_OFF:
return slip_uart_open();
default:
// Do nothing.
break;
}
return NRF_SUCCESS;
}
uint32_t hci_slip_close()
{
m_current_state = SLIP_OFF;
uint32_t err_code = app_uart_close();
return err_code;
}
uint32_t hci_slip_write(const uint8_t * p_buffer, uint32_t length)
{
if (p_buffer == NULL)
{
return NRF_ERROR_INVALID_ADDR;
}
switch (m_current_state)
{
case SLIP_READY:
m_tx_buffer_index = 0;
m_tx_buffer_length = length;
mp_tx_buffer = p_buffer;
m_current_state = SLIP_TRANSMITTING;
send_tx_byte = send_tx_byte_end;
transmit_buffer();
return NRF_SUCCESS;
case SLIP_TRANSMITTING:
return NRF_ERROR_NO_MEM;
case SLIP_OFF:
default:
return NRF_ERROR_INVALID_STATE;
}
}
uint32_t hci_slip_rx_buffer_register(uint8_t * p_buffer, uint32_t length)
{
mp_rx_buffer = p_buffer;
m_rx_buffer_length = length;
m_rx_received_count = 0;
handle_rx_byte = handle_rx_byte_wait_start;
return NRF_SUCCESS;
}
#endif //NRF_MODULE_ENABLED(HCI_SLIP)

View File

@@ -1,165 +0,0 @@
/**
* Copyright (c) 2013 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/** @file
*
* @defgroup hci_slip SLIP module
* @{
* @ingroup app_common
*
* @brief SLIP layer for supporting packet framing in HCI transport.
*
* @details This module implements SLIP packet framing as described in the Bluetooth Core
* Specification 4.0, Volume 4, Part D, Chapter 3 SLIP Layer.
*
* SLIP framing ensures that all packets sent on the UART are framed as:
* <0xC0> SLIP packet 1 <0xC0> <0xC0> SLIP packet 2 <0xC0>.
*
* The SLIP layer uses events to notify the upper layer when data transmission is complete
* and when a SLIP packet is received.
*/
#ifndef HCI_SLIP_H__
#define HCI_SLIP_H__
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**@brief Event types from the SLIP Layer. */
typedef enum
{
HCI_SLIP_RX_RDY, /**< An event indicating that an RX packet is ready to be read. */
HCI_SLIP_TX_DONE, /**< An event indicating write completion of the TX packet provided in the function call \ref hci_slip_write . */
HCI_SLIP_RX_OVERFLOW, /**< An event indicating that RX data has been discarded due to lack of free RX memory. */
HCI_SLIP_ERROR, /**< An event indicating that an unrecoverable error has occurred. */
HCI_SLIP_EVT_TYPE_MAX /**< Enumeration upper bound. */
} hci_slip_evt_type_t;
/**@brief Structure containing an event from the SLIP layer.
*/
typedef struct
{
hci_slip_evt_type_t evt_type; /**< Type of event. */
const uint8_t * packet; /**< This field contains a pointer to the packet for which the event relates, i.e. SLIP_TX_DONE: the packet transmitted, SLIP_RX_RDY: the packet received, SLIP_RX_OVERFLOW: The packet which overflow/or NULL if no receive buffer is available. */
uint32_t packet_length; /**< Packet length, i.e. SLIP_TX_DONE: Bytes transmitted, SLIP_RX_RDY: Bytes received, SLIP_RX_OVERFLOW: index at which the packet overflowed. */
} hci_slip_evt_t;
/**@brief Function for the SLIP layer event callback.
*/
typedef void (*hci_slip_event_handler_t)(hci_slip_evt_t event);
/**@brief Function for registering the event handler provided as parameter and this event handler
* will be used by SLIP layer to send events described in \ref hci_slip_evt_type_t.
*
* @note Multiple registration requests will overwrite any existing registration.
*
* @param[in] event_handler This function is called by the SLIP layer upon an event.
*
* @retval NRF_SUCCESS Operation success.
*/
uint32_t hci_slip_evt_handler_register(hci_slip_event_handler_t event_handler);
/**@brief Function for opening the SLIP layer. This function must be called before
* \ref hci_slip_write and before any data can be received.
*
* @note Can be called multiple times.
*
* @retval NRF_SUCCESS Operation success.
*
* The SLIP layer module will propagate errors from underlying sub-modules.
* This implementation is using UART module as a physical transmission layer, and hci_slip_open
* executes \ref app_uart_init . For an extended error list, please refer to \ref app_uart_init .
*/
uint32_t hci_slip_open(void);
/**@brief Function for closing the SLIP layer. After this function is called no data can be
* transmitted or received in this layer.
*
* @note This function can be called multiple times and also for an unopened channel.
*
* @retval NRF_SUCCESS Operation success.
*/
uint32_t hci_slip_close(void);
/**@brief Function for writing a packet with SLIP encoding. Packet transmission is confirmed when
* the HCI_SLIP_TX_DONE event is received by the function caller.
*
* @param[in] p_buffer Pointer to the packet to transmit.
* @param[in] length Packet length, in bytes.
*
* @retval NRF_SUCCESS Operation success. Packet was encoded and added to the
* transmission queue and an event will be sent upon transmission
* completion.
* @retval NRF_ERROR_NO_MEM Operation failure. Transmission queue is full and packet was not
* added to the transmission queue. Application shall wait for
* the \ref HCI_SLIP_TX_DONE event. After HCI_SLIP_TX_DONE this
* function can be executed for transmission of next packet.
* @retval NRF_ERROR_INVALID_ADDR If a NULL pointer is provided.
* @retval NRF_ERROR_INVALID_STATE Operation failure. Module is not open.
*/
uint32_t hci_slip_write(const uint8_t * p_buffer, uint32_t length);
/**@brief Function for registering a receive buffer. The receive buffer will be used for storage of
* received and SLIP decoded data.
* No data can be received by the SLIP layer until a receive buffer has been registered.
*
* @note The lifetime of the buffer must be valid during complete reception of data. A static
* buffer is recommended.
*
* @warning Multiple registration requests will overwrite any existing registration.
*
* @param[in] p_buffer Pointer to receive buffer. The received and SLIP decoded packet
* will be placed in this buffer.
* @param[in] length Buffer length, in bytes.
*
* @retval NRF_SUCCESS Operation success.
*/
uint32_t hci_slip_rx_buffer_register(uint8_t * p_buffer, uint32_t length);
#ifdef __cplusplus
}
#endif
#endif // HCI_SLIP_H__
/** @} */

View File

@@ -1,808 +0,0 @@
/**
* Copyright (c) 2013 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sdk_common.h"
#if NRF_MODULE_ENABLED(HCI_TRANSPORT)
#include "hci_transport.h"
#include "hci_slip.h"
#include "crc16.h"
#include "hci_mem_pool.h"
#include "app_timer.h"
#include "app_error.h"
#include <stdio.h>
#define PKT_HDR_SIZE 4u /**< Packet header size in number of bytes. */
#define PKT_CRC_SIZE 2u /**< Packet CRC size in number of bytes. */
#define PKT_TYPE_VENDOR_SPECIFIC 14u /**< Packet type vendor specific. */
#define PKT_TYPE_ACK 0 /**< Packet type acknowledgement. */
#define DATA_INTEGRITY_MASK (1u << 6u) /**< Mask for data integrity bit in the packet header. */
#define RELIABLE_PKT_MASK (1u << 7u) /**< Mask for reliable packet bit in the packet header. */
#define INITIAL_ACK_NUMBER_EXPECTED 1u /**< Initial acknowledge number expected. */
#define INITIAL_ACK_NUMBER_TX INITIAL_ACK_NUMBER_EXPECTED /**< Initial acknowledge number transmitted. */
#define INVALID_PKT_TYPE 0xFFFFFFFFu /**< Internal invalid packet type value. */
#define HCI_UART_REG_VALUE_TO_BAUDRATE(BAUDRATE) ((BAUDRATE)/268) /**< Estimated relation between UART baudrate register value and actual baudrate */
#define MAX_TRANSMISSION_TIME \
(ROUNDED_DIV((HCI_MAX_PACKET_SIZE_IN_BITS * 1000u), \
HCI_UART_REG_VALUE_TO_BAUDRATE(HCI_UART_BAUDRATE))) /**< Max transmission time of a single application packet over UART in units of mseconds. */
#define RETRANSMISSION_TIMEOUT_IN_MS (3u * MAX_TRANSMISSION_TIME) /**< Retransmission timeout for application packet in units of mseconds. */
#define RETRANSMISSION_TIMEOUT_IN_TICKS APP_TIMER_TICKS(RETRANSMISSION_TIMEOUT_IN_MS) /**< Retransmission timeout for application packet in units of timer ticks. */
#define MAX_RETRY_COUNT 5u /**< Max retransmission retry count for application packets. */
#define ACK_BUF_SIZE 5u /**< Length of module internal RX buffer which is big enough to hold an acknowledgement packet. */
/**@brief States of the TX state machine. */
typedef enum
{
TX_STATE_IDLE, /**< State for: no application transmission packet processing in progress. */
TX_STATE_PENDING, /**< State for: TX in progress in slip layer and TX-done event is waited for to signal the end of transmission. */
TX_STATE_ACTIVE /**< State for: application packet has been delivered to slip for transmission and peer transport entity acknowledgement packet is waited for. */
} tx_state_t;
/**@brief TX state machine events. */
typedef enum
{
TX_EVENT_STATE_ENTRY, /**< Event for: state entry use case. */
TX_EVENT_SLIP_TX_DONE, /**< Event for: HCI_SLIP_TX_DONE event use case. */
TX_EVENT_TIMEOUT, /**< Event for: retransmission timeout use case. */
TX_EVENT_VALID_RX_ACK /**< Event for: valid acknowledgement received for TX packet use case. */
} tx_event_t;
static void tx_sm_state_change(tx_state_t new_state);
static tx_state_t m_tx_state; /**< Current TX state. */
static hci_transport_tx_done_handler_t m_transport_tx_done_handle; /**< TX done event callback function. */
static hci_transport_event_handler_t m_transport_event_handle; /**< Event handler callback function. */
static uint8_t * mp_slip_used_rx_buffer; /**< Reference to RX buffer used by the slip layer. */
static uint32_t m_packet_expected_seq_number; /**< Sequence number counter of the packet expected to be received . */
static uint32_t m_packet_transmit_seq_number; /**< Sequence number counter of the transmitted packet for which acknowledgement packet is waited for. */
static uint8_t * mp_tx_buffer; /**< Pointer to TX application buffer to be transmitted. */
static uint32_t m_tx_buffer_length; /**< Length of application TX packet data to be transmitted in bytes. */
static bool m_is_slip_decode_ready; /**< Boolean to determine has slip decode been completed or not. */
APP_TIMER_DEF(m_app_timer_id); /**< Application timer id. */
static uint32_t m_tx_retry_counter; /**< Application packet retransmission counter. */
static hci_transport_tx_done_result_t m_tx_done_result_code; /**< TX done event callback function result code. */
static uint8_t m_rx_ack_buffer[ACK_BUF_SIZE];/**< RX buffer big enough to hold an acknowledgement packet and which is taken in use upon receiving HCI_SLIP_RX_OVERFLOW event. */
/**@brief Function for validating a received packet.
*
* @param[in] p_buffer Pointer to the packet data.
* @param[in] length Length of packet data in bytes.
*
* @return true if received packet is valid, false in other case.
*/
static bool is_rx_pkt_valid(const uint8_t * p_buffer, uint32_t length)
{
// Executed packet filtering algorithm order:
// - verify packet overall length
// - verify data integrity bit set
// - verify reliable packet bit set
// - verify supported packet type
// - verify header checksum
// - verify payload length field
// - verify CRC
if (length <= PKT_HDR_SIZE)
{
return false;
}
if (!(p_buffer[0] & DATA_INTEGRITY_MASK))
{
return false;
}
if (!(p_buffer[0] & RELIABLE_PKT_MASK))
{
return false;
}
if ((p_buffer[1] & 0x0Fu) != PKT_TYPE_VENDOR_SPECIFIC)
{
return false;
}
const uint32_t expected_checksum =
((p_buffer[0] + p_buffer[1] + p_buffer[2] + p_buffer[3])) & 0xFFu;
if (expected_checksum != 0)
{
return false;
}
const uint16_t crc_calculated = crc16_compute(p_buffer, (length - PKT_CRC_SIZE), NULL);
const uint16_t crc_received = uint16_decode(&p_buffer[length - PKT_CRC_SIZE]);
if (crc_calculated != crc_received)
{
return false;
}
return true;
}
/**@brief Function for getting the sequence number of the next reliable packet expected.
*
* @return sequence number of the next reliable packet expected.
*/
static __INLINE uint8_t packet_number_expected_get(void)
{
return (uint8_t) m_packet_expected_seq_number;
}
/**@brief Function for calculating a packet header checksum.
*
* @param[in] p_hdr Pointer to the packet header.
*
* @return Calculated checksum.
*/
static uint8_t header_checksum_calculate(const uint8_t * p_hdr)
{
// @note: no pointer validation check needed as already checked by calling function.
uint32_t checksum;
checksum = p_hdr[0];
checksum += p_hdr[1];
checksum += p_hdr[2];
checksum &= 0xFFu;
checksum = (~checksum + 1u);
return (uint8_t)checksum;
}
/**@brief Function for writing an acknowledgment packet for transmission.
*/
static void ack_transmit(void)
{
static uint8_t ack_packet[PKT_HDR_SIZE];
// TX ACK packet format:
// - Unreliable Packet type
// - Payload Length set to 0
// - Sequence Number set to 0
// - Header checksum calculated
// - Acknowledge Number set correctly
ack_packet[0] = (packet_number_expected_get() << 3u);
ack_packet[1] = 0;
ack_packet[2] = 0;
ack_packet[3] = header_checksum_calculate(ack_packet);
// @note: no return value check needed for hci_slip_write(...) call as acknowledgement packets
// are considered to be from system design point of view unreliable packets.Use case where
// underlying slip layer does not accept a packet for transmission is managed either by:
// - acknowledged by possible future application packet as acknowledgement number header field
// is included
// - protocol peer entity will retransmit the packet
UNUSED_VARIABLE(hci_slip_write(ack_packet, sizeof(ack_packet)));
}
/**@brief Function for validating a received packet.
*
* @param[in] p_buffer Pointer to the packet data.
*
* @return sequence number field of the packet header with unrelated data masked out.
*/
static __INLINE uint8_t packet_seq_nmbr_extract(const uint8_t * p_buffer)
{
return (p_buffer[0] & 0x07u);
}
/**@brief Function for incrementing the sequence number counter for next reliable packet expected.
*/
static __INLINE void packet_number_expected_inc(void)
{
++m_packet_expected_seq_number;
m_packet_expected_seq_number &= 0x07u;
}
/**@brief Function for decoding a packet type field.
*
* @param[in] p_buffer Pointer to the packet data.
* @param[in] length Length of packet data in bytes.
*
* @return Packet type field or INVALID_PKT_TYPE in case of decode error.
*/
static __INLINE uint32_t packet_type_decode(const uint8_t * p_buffer, uint32_t length)
{
// @note: no pointer validation check needed as allready checked by calling function.
uint32_t return_value;
if (length >= PKT_HDR_SIZE)
{
return_value = (p_buffer[1] & 0x0Fu);
}
else
{
return_value = INVALID_PKT_TYPE;
}
return return_value;
}
/**@brief Function for processing a received vendor specific packet.
*
* @param[in] p_buffer Pointer to the packet data.
* @param[in] length Length of packet data in bytes.
*/
static void rx_vendor_specific_pkt_type_handle(const uint8_t * p_buffer, uint32_t length)
{
// @note: no pointer validation check needed as allready checked by calling function.
uint32_t err_code;
if (is_rx_pkt_valid(p_buffer, length))
{
// RX packet is valid: validate sequence number.
const uint8_t rx_seq_number = packet_seq_nmbr_extract(p_buffer);
if (packet_number_expected_get() == rx_seq_number)
{
// Sequence number is valid: transmit acknowledgement.
packet_number_expected_inc();
ack_transmit();
m_is_slip_decode_ready = true;
err_code = hci_mem_pool_rx_data_size_set(length);
APP_ERROR_CHECK(err_code);
err_code = hci_mem_pool_rx_produce(HCI_RX_BUF_SIZE, (void **)&mp_slip_used_rx_buffer);
APP_ERROR_CHECK_BOOL((err_code == NRF_SUCCESS) || (err_code == NRF_ERROR_NO_MEM));
// If memory pool RX buffer produce succeeded we register that buffer to slip layer
// otherwise we register the internal acknowledgement buffer.
err_code = hci_slip_rx_buffer_register(
(err_code == NRF_SUCCESS) ? mp_slip_used_rx_buffer : m_rx_ack_buffer,
(err_code == NRF_SUCCESS) ? HCI_RX_BUF_SIZE : ACK_BUF_SIZE);
APP_ERROR_CHECK(err_code);
if (m_transport_event_handle != NULL)
{
// Send application event of RX packet reception.
const hci_transport_evt_t evt = {HCI_TRANSPORT_RX_RDY};
m_transport_event_handle(evt);
}
}
else
{
// RX packet discarded: sequence number not valid, set the same buffer to slip layer in
// order to avoid buffer overrun.
err_code = hci_slip_rx_buffer_register(mp_slip_used_rx_buffer, HCI_RX_BUF_SIZE);
APP_ERROR_CHECK(err_code);
// As packet did not have expected sequence number: send acknowledgement with the
// current expected sequence number.
ack_transmit();
}
}
else
{
// RX packet discarded: reset the same buffer to slip layer in order to avoid buffer
// overrun.
err_code = hci_slip_rx_buffer_register(mp_slip_used_rx_buffer, HCI_RX_BUF_SIZE);
APP_ERROR_CHECK(err_code);
}
}
/**@brief Function for getting the sequence number of a reliable TX packet for which peer protocol
* entity acknowledgment is pending.
*
* @return sequence number of a reliable TX packet for which peer protocol entity acknowledgement
* is pending.
*/
static __INLINE uint8_t packet_number_to_transmit_get(void)
{
return m_packet_transmit_seq_number;
}
/**@brief Function for getting the expected acknowledgement number.
*
* @return expected acknowledgement number.
*/
static __INLINE uint8_t expected_ack_number_get(void)
{
uint8_t seq_nmbr = packet_number_to_transmit_get();
++seq_nmbr;
seq_nmbr &= 0x07u;
return seq_nmbr;
}
/**@brief Function for processing a received acknowledgement packet.
*
* Verifies does the received acknowledgement packet has the expected acknowledgement number and
* that the header checksum is correct.
*
* @param[in] p_buffer Pointer to the packet data.
*
* @return true if valid acknowledgement packet received.
*/
static __INLINE bool rx_ack_pkt_type_handle(const uint8_t * p_buffer)
{
// @note: no pointer validation check needed as allready checked by calling function.
// Verify header checksum.
const uint32_t expected_checksum =
((p_buffer[0] + p_buffer[1] + p_buffer[2] + p_buffer[3])) & 0xFFu;
if (expected_checksum != 0)
{
return false;
}
const uint8_t ack_number = (p_buffer[0] >> 3u) & 0x07u;
// Verify expected acknowledgment number.
return (ack_number == expected_ack_number_get());
}
/**@brief Function for incrementing the sequence number counter of the TX packet.
*/
static __INLINE void packet_number_tx_inc(void)
{
++m_packet_transmit_seq_number;
m_packet_transmit_seq_number &= 0x07u;
}
/**@brief Function for TX state machine event processing in a state centric manner.
*
* @param[in] event Type of event occurred.
*/
static void tx_sm_event_handle(tx_event_t event)
{
uint32_t err_code;
switch (m_tx_state)
{
case TX_STATE_IDLE:
if (event == TX_EVENT_STATE_ENTRY)
{
err_code = app_timer_stop(m_app_timer_id);
APP_ERROR_CHECK(err_code);
// Send TX-done event if registered handler exists.
if (m_transport_tx_done_handle != NULL)
{
m_transport_tx_done_handle(m_tx_done_result_code);
}
}
break;
case TX_STATE_PENDING:
if (event == TX_EVENT_SLIP_TX_DONE)
{
// @note: this call should always succeed as called from HCI_SLIP_TX_DONE context
// and error cases are managed by dedicated error event from the slip layer.
err_code = hci_slip_write(mp_tx_buffer,
(m_tx_buffer_length + PKT_HDR_SIZE + PKT_CRC_SIZE));
APP_ERROR_CHECK(err_code);
tx_sm_state_change(TX_STATE_ACTIVE);
}
break;
case TX_STATE_ACTIVE:
switch (event)
{
case TX_EVENT_VALID_RX_ACK:
// Tx sequence number counter incremented as packet transmission
// acknowledged by peer transport entity.
packet_number_tx_inc();
tx_sm_state_change(TX_STATE_IDLE);
break;
case TX_EVENT_STATE_ENTRY:
m_tx_retry_counter = 0;
err_code = app_timer_start(m_app_timer_id,
RETRANSMISSION_TIMEOUT_IN_TICKS,
NULL);
APP_ERROR_CHECK(err_code);
break;
case TX_EVENT_TIMEOUT:
if (m_tx_retry_counter != MAX_RETRY_COUNT)
{
++m_tx_retry_counter;
// @note: no return value check done for hci_slip_write(...) call as current
// system design allows use case where retransmission is not accepted by the
// slip layer due to existing acknowledgement packet transmission in the
// slip layer.
UNUSED_VARIABLE(hci_slip_write(mp_tx_buffer,
(m_tx_buffer_length +
PKT_HDR_SIZE +
PKT_CRC_SIZE)));
}
else
{
// Application packet retransmission count reached:
// - set correct TX done event callback function result code
// - execute state change
// @note: m_tx_retry_counter is reset in TX_STATE_ACTIVE state entry.
m_tx_done_result_code = HCI_TRANSPORT_TX_DONE_FAILURE;
tx_sm_state_change(TX_STATE_IDLE);
}
break;
default:
// No implementation needed.
break;
}
break;
default:
// No implementation needed.
break;
}
}
/**@brief Function for changing the state of the TX state machine.
*
* @param[in] new_state State TX state machine transits to.
*/
static void tx_sm_state_change(tx_state_t new_state)
{
m_tx_state = new_state;
tx_sm_event_handle(TX_EVENT_STATE_ENTRY);
}
/**@brief Function for handling slip events.
*
* @param[in] event The event structure.
*/
void slip_event_handle(hci_slip_evt_t event)
{
uint32_t return_code;
uint32_t err_code;
switch (event.evt_type)
{
case HCI_SLIP_TX_DONE:
tx_sm_event_handle(TX_EVENT_SLIP_TX_DONE);
break;
case HCI_SLIP_RX_RDY:
return_code = packet_type_decode(event.packet, event.packet_length);
switch (return_code)
{
case PKT_TYPE_VENDOR_SPECIFIC:
rx_vendor_specific_pkt_type_handle(event.packet, event.packet_length);
break;
case PKT_TYPE_ACK:
if (rx_ack_pkt_type_handle(event.packet))
{
// Valid expected acknowledgement packet received: set correct TX done event
// callback function result code and execute state change.
m_tx_done_result_code = HCI_TRANSPORT_TX_DONE_SUCCESS;
tx_sm_event_handle(TX_EVENT_VALID_RX_ACK);
}
/* fall-through */
default:
// RX packet dropped: reset memory buffer to slip in order to avoid RX buffer
// overflow.
// If existing mem pool produced RX buffer exists reuse that one. If existing
// mem pool produced RX buffer does not exist try to produce new one. If
// producing fails use the internal acknowledgement buffer.
if (mp_slip_used_rx_buffer != NULL)
{
err_code = hci_slip_rx_buffer_register(mp_slip_used_rx_buffer, HCI_RX_BUF_SIZE);
APP_ERROR_CHECK(err_code);
}
else
{
err_code = hci_mem_pool_rx_produce(HCI_RX_BUF_SIZE,
(void **)&mp_slip_used_rx_buffer);
APP_ERROR_CHECK_BOOL((err_code == NRF_SUCCESS) ||
(err_code == NRF_ERROR_NO_MEM));
err_code = hci_slip_rx_buffer_register(
(err_code == NRF_SUCCESS) ? mp_slip_used_rx_buffer : m_rx_ack_buffer,
(err_code == NRF_SUCCESS) ? HCI_RX_BUF_SIZE : ACK_BUF_SIZE);
APP_ERROR_CHECK(err_code);
}
break;
}
break;
case HCI_SLIP_RX_OVERFLOW:
err_code = hci_slip_rx_buffer_register(m_rx_ack_buffer, ACK_BUF_SIZE);
APP_ERROR_CHECK(err_code);
break;
case HCI_SLIP_ERROR:
APP_ERROR_HANDLER(event.evt_type);
break;
default:
APP_ERROR_HANDLER(event.evt_type);
break;
}
}
uint32_t hci_transport_evt_handler_reg(hci_transport_event_handler_t event_handler)
{
uint32_t err_code;
m_transport_event_handle = event_handler;
err_code = hci_slip_evt_handler_register(slip_event_handle);
APP_ERROR_CHECK(err_code);
return (event_handler != NULL) ? NRF_SUCCESS : NRF_ERROR_NULL;
}
uint32_t hci_transport_tx_done_register(hci_transport_tx_done_handler_t event_handler)
{
uint32_t err_code;
m_transport_tx_done_handle = event_handler;
err_code = hci_slip_evt_handler_register(slip_event_handle);
APP_ERROR_CHECK(err_code);
return (event_handler != NULL) ? NRF_SUCCESS : NRF_ERROR_NULL;
}
/**@brief Function for handling the application packet retransmission timeout.
*
* This function is registered in the @ref app_timer module when a timer is created on
* @ref hci_transport_open.
*
* @note This function must be executed in APP-LO context otherwise retransmission behaviour is
* undefined, see @ref nrf51_system_integration_serialization.
*
* @param[in] p_context The timeout context.
*/
void hci_transport_timeout_handle(void * p_context)
{
tx_sm_event_handle(TX_EVENT_TIMEOUT);
}
uint32_t hci_transport_open(void)
{
mp_tx_buffer = NULL;
m_tx_buffer_length = 0;
m_tx_retry_counter = 0;
m_is_slip_decode_ready = false;
m_tx_state = TX_STATE_IDLE;
m_packet_expected_seq_number = INITIAL_ACK_NUMBER_EXPECTED;
m_packet_transmit_seq_number = INITIAL_ACK_NUMBER_TX;
m_tx_done_result_code = HCI_TRANSPORT_TX_DONE_FAILURE;
uint32_t err_code = app_timer_create(&m_app_timer_id,
APP_TIMER_MODE_REPEATED,
hci_transport_timeout_handle);
if (err_code != NRF_SUCCESS)
{
// @note: conduct required interface adjustment.
return NRF_ERROR_INTERNAL;
}
err_code = hci_mem_pool_open();
VERIFY_SUCCESS(err_code);
err_code = hci_slip_open();
VERIFY_SUCCESS(err_code);
err_code = hci_mem_pool_rx_produce(HCI_RX_BUF_SIZE, (void **)&mp_slip_used_rx_buffer);
if (err_code != NRF_SUCCESS)
{
// @note: conduct required interface adjustment.
return NRF_ERROR_INTERNAL;
}
err_code = hci_slip_rx_buffer_register(mp_slip_used_rx_buffer, HCI_RX_BUF_SIZE);
return err_code;
}
uint32_t hci_transport_close(void)
{
uint32_t err_code;
m_transport_tx_done_handle = NULL;
m_transport_event_handle = NULL;
err_code = hci_mem_pool_close();
APP_ERROR_CHECK(err_code);
err_code = hci_slip_close();
APP_ERROR_CHECK(err_code);
// @note: NRF_ERROR_NO_MEM is the only return value which should never be returned.
err_code = app_timer_stop(m_app_timer_id);
APP_ERROR_CHECK_BOOL(err_code != NRF_ERROR_NO_MEM);
return NRF_SUCCESS;
}
uint32_t hci_transport_tx_alloc(uint8_t ** pp_memory)
{
const uint32_t err_code = hci_mem_pool_tx_alloc((void **)pp_memory);
if (err_code == NRF_SUCCESS)
{
// @note: no need to validate pp_memory against null as validation has already been done
// by hci_mem_pool_tx_alloc(...) and visible to us from the method return code.
//lint -e(413) "Likely use of null pointer"
*pp_memory += PKT_HDR_SIZE;
}
return err_code;
}
uint32_t hci_transport_tx_free(void)
{
return hci_mem_pool_tx_free();
}
/**@brief Function for constructing 1st byte of the packet header of the packet to be transmitted.
*
* @return 1st byte of the packet header of the packet to be transmitted
*/
static __INLINE uint8_t tx_packet_byte_zero_construct(void)
{
const uint32_t value = DATA_INTEGRITY_MASK |
RELIABLE_PKT_MASK |
(packet_number_expected_get() << 3u) |
packet_number_to_transmit_get();
return (uint8_t) value;
}
/**@brief Function for handling the application packet write request in tx-idle state.
*/
static uint32_t pkt_write_handle(void)
{
uint32_t err_code;
// Set packet header fields.
mp_tx_buffer -= PKT_HDR_SIZE;
mp_tx_buffer[0] = tx_packet_byte_zero_construct();
const uint16_t type_and_length_fields = ((m_tx_buffer_length << 4u) | PKT_TYPE_VENDOR_SPECIFIC);
// @note: no use case for uint16_encode(...) return value.
UNUSED_VARIABLE(uint16_encode(type_and_length_fields, &(mp_tx_buffer[1])));
mp_tx_buffer[3] = header_checksum_calculate(mp_tx_buffer);
// Calculate, append CRC to the packet and write it.
const uint16_t crc = crc16_compute(mp_tx_buffer, (PKT_HDR_SIZE + m_tx_buffer_length), NULL);
// @note: no use case for uint16_encode(...) return value.
UNUSED_VARIABLE(uint16_encode(crc, &(mp_tx_buffer[PKT_HDR_SIZE + m_tx_buffer_length])));
err_code = hci_slip_write(mp_tx_buffer, (m_tx_buffer_length + PKT_HDR_SIZE + PKT_CRC_SIZE));
switch (err_code)
{
case NRF_SUCCESS:
tx_sm_state_change(TX_STATE_ACTIVE);
break;
case NRF_ERROR_NO_MEM:
tx_sm_state_change(TX_STATE_PENDING);
err_code = NRF_SUCCESS;
break;
default:
// No implementation needed.
break;
}
return err_code;
}
uint32_t hci_transport_pkt_write(const uint8_t * p_buffer, uint16_t length)
{
uint32_t err_code;
if (p_buffer)
{
switch (m_tx_state)
{
case TX_STATE_IDLE:
mp_tx_buffer = (uint8_t *)p_buffer;
m_tx_buffer_length = length;
err_code = pkt_write_handle();
break;
default:
err_code = NRF_ERROR_NO_MEM;
break;
}
}
else
{
err_code = NRF_ERROR_NULL;
}
return err_code;
}
uint32_t hci_transport_rx_pkt_extract(uint8_t ** pp_buffer, uint16_t * p_length)
{
uint32_t err_code;
if (pp_buffer != NULL && p_length != NULL)
{
uint32_t length = 0;
if (m_is_slip_decode_ready)
{
m_is_slip_decode_ready = false;
err_code = hci_mem_pool_rx_extract(pp_buffer, &length);
length -= (PKT_HDR_SIZE + PKT_CRC_SIZE);
*p_length = (uint16_t)length;
*pp_buffer += PKT_HDR_SIZE;
}
else
{
err_code = NRF_ERROR_NO_MEM;
}
}
else
{
err_code = NRF_ERROR_NULL;
}
return err_code;
}
uint32_t hci_transport_rx_pkt_consume(uint8_t * p_buffer)
{
return (hci_mem_pool_rx_consume(p_buffer - PKT_HDR_SIZE));
}
#endif //NRF_MODULE_ENABLED(HCI_TRANSPORT)

View File

@@ -1,256 +0,0 @@
/**
* Copyright (c) 2013 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@file
*
* @defgroup hci_transport HCI Transport
* @{
* @ingroup app_common
*
* @brief HCI transport module implementation.
*
* This module implements certain specific features from the three-wire UART transport layer,
* defined by the Bluetooth specification version 4.0 [Vol 4] part D.
*
* \par Features supported
* - Transmission and reception of Vendor Specific HCI packet type application packets.
* - Transmission and reception of reliable packets: defined by chapter 6 of the specification.
*
* \par Features not supported
* - Link establishment procedure: defined by chapter 8 of the specification.
* - Low power: defined by chapter 9 of the specification.
*
* \par Implementation specific behaviour
* - As Link establishment procedure is not supported following static link configuration parameters
* are used:
* + TX window size is 1.
* + 16 bit CCITT-CRC must be used.
* + Out of frame software flow control not supported.
* + Parameters specific for resending reliable packets are compile time configurable (clarifed
* later in this document).
* + Acknowledgement packet transmissions are not timeout driven , meaning they are delivered for
* transmission within same context which the corresponding application packet was received.
*
* \par Implementation specific limitations
* Current implementation has the following limitations which will have impact to system wide
* behaviour:
* - Delayed acknowledgement scheduling not implemented:
* There exists a possibility that acknowledgement TX packet and application TX packet will collide
* in the TX pipeline having the end result that acknowledgement packet will be excluded from the TX
* pipeline which will trigger the retransmission algorithm within the peer protocol entity.
* - Delayed retransmission scheduling not implemented:
* There exists a possibility that retransmitted application TX packet and acknowledgement TX packet
* will collide in the TX pipeline having the end result that retransmitted application TX packet
* will be excluded from the TX pipeline.
* - Processing of the acknowledgement number from RX application packets:
* Acknowledgement number is not processed from the RX application packets having the end result
* that unnecessary application packet retransmissions can occur.
*
* The application TX packet processing flow is illustrated by the statemachine below.
*
* @image html hci_transport_tx_sm.svg "TX - application packet statemachine"
*
* \par Component specific configuration options
*
* The following compile time configuration options are available, and used to configure the
* application TX packet retransmission interval, in order to suite various application specific
* implementations:
* - MAC_PACKET_SIZE_IN_BITS Maximum size of a single application packet in bits.
* - USED_BAUD_RATE Used uart baudrate.
*
* The following compile time configuration option is available to configure module specific
* behaviour:
* - MAX_RETRY_COUNT Max retransmission retry count for applicaton packets.
*/
#ifndef HCI_TRANSPORT_H__
#define HCI_TRANSPORT_H__
#include <stdint.h>
#include "nrf_error.h"
#ifdef __cplusplus
extern "C" {
#endif
/**@brief Generic event callback function events. */
typedef enum
{
HCI_TRANSPORT_RX_RDY, /**< An event indicating that RX packet is ready for read. */
HCI_TRANSPORT_EVT_TYPE_MAX /**< Enumeration upper bound. */
} hci_transport_evt_type_t;
/**@brief Struct containing events from the Transport layer.
*/
typedef struct
{
hci_transport_evt_type_t evt_type; /**< Type of event. */
} hci_transport_evt_t;
/**@brief Transport layer generic event callback function type.
*
* @param[in] event Transport layer event.
*/
typedef void (*hci_transport_event_handler_t)(hci_transport_evt_t event);
/**@brief TX done event callback function result codes. */
typedef enum
{
HCI_TRANSPORT_TX_DONE_SUCCESS, /**< Transmission success, peer transport entity has acknowledged the transmission. */
HCI_TRANSPORT_TX_DONE_FAILURE /**< Transmission failure. */
} hci_transport_tx_done_result_t;
/**@brief Transport layer TX done event callback function type.
*
* @param[in] result TX done event result code.
*/
typedef void (*hci_transport_tx_done_handler_t)(hci_transport_tx_done_result_t result);
/**@brief Function for registering a generic event handler.
*
* @note Multiple registration requests will overwrite any possible existing registration.
*
* @param[in] event_handler The function to be called by the transport layer upon an event.
*
* @retval NRF_SUCCESS Operation success.
* @retval NRF_ERROR_NULL Operation failure. NULL pointer supplied.
*/
uint32_t hci_transport_evt_handler_reg(hci_transport_event_handler_t event_handler);
/**@brief Function for registering a handler for TX done event.
*
* @note Multiple registration requests will overwrite any possible existing registration.
*
* @param[in] event_handler The function to be called by the transport layer upon TX done
* event.
*
* @retval NRF_SUCCESS Operation success.
* @retval NRF_ERROR_NULL Operation failure. NULL pointer supplied.
*/
uint32_t hci_transport_tx_done_register(hci_transport_tx_done_handler_t event_handler);
/**@brief Function for opening the transport channel and initializing the transport layer.
*
* @warning Must not be called for a channel which has been allready opened.
*
* @retval NRF_SUCCESS Operation success.
* @retval NRF_ERROR_INTERNAL Operation failure. Internal error ocurred.
*/
uint32_t hci_transport_open(void);
/**@brief Function for closing the transport channel.
*
* @note Can be called multiple times and also for not opened channel.
*
* @retval NRF_SUCCESS Operation success.
*/
uint32_t hci_transport_close(void);
/**@brief Function for allocating tx packet memory.
*
* @param[out] pp_memory Pointer to the packet data.
*
* @retval NRF_SUCCESS Operation success. Memory was allocated.
* @retval NRF_ERROR_NO_MEM Operation failure. No memory available.
* @retval NRF_ERROR_NULL Operation failure. NULL pointer supplied.
*/
uint32_t hci_transport_tx_alloc(uint8_t ** pp_memory);
/**@brief Function for freeing tx packet memory.
*
* @note Memory management works in FIFO principle meaning that free order must match the alloc
* order.
*
* @retval NRF_SUCCESS Operation success. Memory was freed.
*/
uint32_t hci_transport_tx_free(void);
/**@brief Function for writing a packet.
*
* @note Completion of this method does not guarantee that actual peripheral transmission would
* have completed.
*
* @note In case of 0 byte packet length write request, message will consist of only transport
* module specific headers.
*
* @retval NRF_SUCCESS Operation success. Packet was added to the transmission queue
* and an event will be send upon transmission completion.
* @retval NRF_ERROR_NO_MEM Operation failure. Transmission queue is full and packet was not
* added to the transmission queue. User should wait for
* a appropriate event prior issuing this operation again.
* @retval NRF_ERROR_DATA_SIZE Operation failure. Packet size exceeds limit.
* @retval NRF_ERROR_NULL Operation failure. NULL pointer supplied.
* @retval NRF_ERROR_INVALID_STATE Operation failure. Channel is not open.
*/
uint32_t hci_transport_pkt_write(const uint8_t * p_buffer, uint16_t length);
/**@brief Function for extracting received packet.
*
* @note Extracted memory can't be reused by the underlying transport layer untill freed by call to
* hci_transport_rx_pkt_consume().
*
* @param[out] pp_buffer Pointer to the packet data.
* @param[out] p_length Length of packet data in bytes.
*
* @retval NRF_SUCCESS Operation success. Packet was extracted.
* @retval NRF_ERROR_NO_MEM Operation failure. No packet available to extract.
* @retval NRF_ERROR_NULL Operation failure. NULL pointer supplied.
*/
uint32_t hci_transport_rx_pkt_extract(uint8_t ** pp_buffer, uint16_t * p_length);
/**@brief Function for consuming extracted packet described by p_buffer.
*
* RX memory pointed to by p_buffer is freed and can be reused by the underlying transport layer.
*
* @param[in] p_buffer Pointer to the buffer that has been consumed.
*
* @retval NRF_SUCCESS Operation success.
* @retval NRF_ERROR_NO_MEM Operation failure. No packet available to consume.
* @retval NRF_ERROR_INVALID_ADDR Operation failure. Not a valid pointer.
*/
uint32_t hci_transport_rx_pkt_consume(uint8_t * p_buffer);
#ifdef __cplusplus
}
#endif
#endif // HCI_TRANSPORT_H__
/** @} */

View File

@@ -1,232 +0,0 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sdk_common.h"
#if NRF_MODULE_ENABLED(LED_SOFTBLINK)
#include <string.h>
#include "led_softblink.h"
#include "nrf_gpio.h"
#include "app_timer.h"
#include "nrf_assert.h"
#include "low_power_pwm.h"
/* Period for LED softblink PWM. */
#define PWM_PERIOD UINT8_MAX
/**@bref Structure to handle timer time-outs
*
*/
typedef struct
{
bool leds_is_on; /**< Flag for indicating if LEDs are on. */
bool is_counting_up; /**< Flag for indicating if counter is incrementing or decrementing. */
nrfx_drv_state_t led_sb_state; /**< Indicates current state of instance. */
uint16_t duty_cycle; /**< Current pulse width. */
uint32_t bit_mask; /**< Mask of used pins. */
led_sb_init_params_t params; /**< Structure holding initialization parameters. */
low_power_pwm_config_t pwm_config; /**< Structure holding parameters for initializing low level layer. */
low_power_pwm_t pwm_instance; /**< Structure holding low-power PWM instance parameters. */
}led_sb_context_t;
APP_TIMER_DEF(m_led_softblink_timer);
static led_sb_context_t m_led_sb = {0};
/**@brief Timer event handler for softblink.
*
* @param[in] p_context General purpose pointer. Will be passed to the time-out handler
* when the timer expires.
*
*/
static void led_softblink_on_timeout(void * p_context)
{
static int32_t pause_ticks;
ASSERT(m_led_sb.led_sb_state != NRFX_DRV_STATE_UNINITIALIZED);
ret_code_t err_code;
if (pause_ticks <= 0)
{
if (m_led_sb.is_counting_up)
{
if (m_led_sb.duty_cycle >= (m_led_sb.params.duty_cycle_max - m_led_sb.params.duty_cycle_step))
{
// Max PWM duty cycle is reached, start decrementing.
m_led_sb.is_counting_up = false;
m_led_sb.duty_cycle = m_led_sb.params.duty_cycle_max;
pause_ticks = m_led_sb.params.on_time_ticks ? m_led_sb.params.on_time_ticks + APP_TIMER_MIN_TIMEOUT_TICKS : 0;
}
else
{
m_led_sb.duty_cycle += m_led_sb.params.duty_cycle_step;
}
}
else
{
if (m_led_sb.duty_cycle <= (m_led_sb.params.duty_cycle_min + m_led_sb.params.duty_cycle_step))
{
// Min PWM duty cycle is reached, start incrementing.
m_led_sb.is_counting_up = true;
m_led_sb.duty_cycle = m_led_sb.params.duty_cycle_min;
pause_ticks = m_led_sb.params.off_time_ticks ? m_led_sb.params.off_time_ticks + APP_TIMER_MIN_TIMEOUT_TICKS : 0;
}
else
{
m_led_sb.duty_cycle -= m_led_sb.params.duty_cycle_step;
}
}
}
else
{
pause_ticks -= PWM_PERIOD;
}
err_code = low_power_pwm_duty_set(&m_led_sb.pwm_instance, m_led_sb.duty_cycle);
APP_ERROR_CHECK(err_code);
}
ret_code_t led_softblink_init(led_sb_init_params_t const * p_init_params)
{
ret_code_t err_code;
ASSERT(m_led_sb.led_sb_state == NRFX_DRV_STATE_UNINITIALIZED);
ASSERT(p_init_params);
if ( (p_init_params->duty_cycle_max == 0) ||
(p_init_params->duty_cycle_max <= p_init_params->duty_cycle_min) ||
(p_init_params->duty_cycle_step == 0) ||
(p_init_params->leds_pin_bm == 0))
{
return NRF_ERROR_INVALID_PARAM;
}
memset(&m_led_sb, 0, sizeof(led_sb_context_t));
memcpy(&m_led_sb.params, p_init_params, sizeof(led_sb_init_params_t));
m_led_sb.is_counting_up = true;
m_led_sb.duty_cycle = p_init_params->duty_cycle_min + p_init_params->duty_cycle_step;
m_led_sb.leds_is_on = false;
m_led_sb.bit_mask = p_init_params->leds_pin_bm;
m_led_sb.pwm_config.active_high = m_led_sb.params.active_high;
m_led_sb.pwm_config.bit_mask = p_init_params->leds_pin_bm;
m_led_sb.pwm_config.p_port = p_init_params->p_leds_port;
m_led_sb.pwm_config.period = PWM_PERIOD;
m_led_sb.pwm_config.p_timer_id = &m_led_softblink_timer;
err_code = low_power_pwm_init( &m_led_sb.pwm_instance, &m_led_sb.pwm_config, led_softblink_on_timeout);
if (err_code == NRF_SUCCESS)
{
m_led_sb.led_sb_state = NRFX_DRV_STATE_INITIALIZED;
}
else
{
return err_code;
}
err_code = low_power_pwm_duty_set( &m_led_sb.pwm_instance, p_init_params->duty_cycle_min + p_init_params->duty_cycle_step);
return err_code;
}
ret_code_t led_softblink_start(uint32_t leds_pin_bit_mask)
{
ret_code_t err_code;
ASSERT(m_led_sb.led_sb_state == NRFX_DRV_STATE_INITIALIZED);
err_code = low_power_pwm_start(&m_led_sb.pwm_instance, leds_pin_bit_mask);
return err_code;
}
ret_code_t led_softblink_stop(void)
{
ret_code_t err_code;
err_code = low_power_pwm_stop(&m_led_sb.pwm_instance);
return err_code;
}
void led_softblink_off_time_set(uint32_t off_time_ticks)
{
ASSERT(m_led_sb.led_sb_state != NRFX_DRV_STATE_UNINITIALIZED);
m_led_sb.params.off_time_ticks = off_time_ticks;
}
void led_softblink_on_time_set(uint32_t on_time_ticks)
{
ASSERT(m_led_sb.led_sb_state != NRFX_DRV_STATE_UNINITIALIZED);
m_led_sb.params.on_time_ticks = on_time_ticks;
}
ret_code_t led_softblink_uninit(void)
{
ASSERT(m_led_sb.led_sb_state != NRFX_DRV_STATE_UNINITIALIZED);
ret_code_t err_code;
err_code = led_softblink_stop();
if (err_code == NRF_SUCCESS)
{
m_led_sb.led_sb_state = NRFX_DRV_STATE_UNINITIALIZED;
}
else
{
return err_code;
}
memset(&m_led_sb, 0, sizeof(m_led_sb));
return NRF_SUCCESS;
}
#endif //NRF_MODULE_ENABLED(LED_SOFTBLINK)

View File

@@ -1,171 +0,0 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/** @file
*
* @defgroup led_softblink LED softblink
* @{
* @ingroup app_common
*
* @brief Module for generating a changing pulse-width modulated output signal that is used to smoothly blink LEDs.
*
* @details This module provides an LED softblink implementation using timers and GPIO.
*
* LED softblink needs one timer. It can use any number of output channels that are available.
*
* Only one instance of LED softblink can run at a time.
*/
#ifndef LED_SOFTBLINK_H__
#define LED_SOFTBLINK_H__
#include <stdbool.h>
#include <stdint.h>
#include "sdk_errors.h"
#include "nrf_gpio.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Structure holding the initialization parameters.
*/
typedef struct
{
bool active_high; /**< Activate negative polarity. */
uint8_t duty_cycle_max; /**< Maximum impulse width. */
uint8_t duty_cycle_min; /**< Minimum impulse width. */
uint8_t duty_cycle_step; /**< Cycle step. */
uint32_t off_time_ticks; /**< Ticks to stay in low impulse state. */
uint32_t on_time_ticks; /**< Ticks to stay in high impulse state. */
uint32_t leds_pin_bm; /**< Mask of used LEDs. */
NRF_GPIO_Type * p_leds_port; /**< Port of used LEDs mask. */
}led_sb_init_params_t;
/**
* @name Default settings
* @brief Default settings for LED softblink.
* @{
*/
#define LED_SB_INIT_PARAMS_ACTIVE_HIGH false
#define LED_SB_INIT_PARAMS_DUTY_CYCLE_MAX 220
#define LED_SB_INIT_PARAMS_DUTY_CYCLE_MIN 0
#define LED_SB_INIT_PARAMS_DUTY_CYCLE_STEP 5
#define LED_SB_INIT_PARAMS_OFF_TIME_TICKS 65536
#define LED_SB_INIT_PARAMS_ON_TIME_TICKS 0
#define LED_SB_INIT_PARAMS_LEDS_PIN_BM(mask) (mask)
#define LED_SB_INIT_PARAMS_LEDS_PORT NRF_GPIO
/** @} */
/**
* @brief LED softblink default configuration.
*/
#define LED_SB_INIT_DEFAULT_PARAMS(mask) \
{ \
.active_high = LED_SB_INIT_PARAMS_ACTIVE_HIGH, \
.duty_cycle_max = LED_SB_INIT_PARAMS_DUTY_CYCLE_MAX, \
.duty_cycle_min = LED_SB_INIT_PARAMS_DUTY_CYCLE_MIN, \
.duty_cycle_step = LED_SB_INIT_PARAMS_DUTY_CYCLE_STEP, \
.off_time_ticks = LED_SB_INIT_PARAMS_OFF_TIME_TICKS, \
.on_time_ticks = LED_SB_INIT_PARAMS_ON_TIME_TICKS, \
.leds_pin_bm = LED_SB_INIT_PARAMS_LEDS_PIN_BM(mask), \
.p_leds_port = LED_SB_INIT_PARAMS_LEDS_PORT \
}
/**
* @brief Function for initializing LED softblink.
*
* @param[in] p_init_params Pointer to the initialization structure.
*
* @return Values returned by @ref app_timer_create.
*/
ret_code_t led_softblink_init(led_sb_init_params_t const * p_init_params);
/**
* @brief Function for starting to blink LEDs.
*
* @param[in] leds_pin_bit_mask Bit mask containing the pins for the LEDs to be blinked.
*
* @return Values returned by @ref app_timer_start.
*/
ret_code_t led_softblink_start(uint32_t leds_pin_bit_mask);
/**
* @brief Function for stopping to blink LEDs.
*
* @return Values returned by @ref app_timer_stop.
*/
ret_code_t led_softblink_stop(void);
/**
* @brief Function for setting the off time.
*
* This function configures the time that the LEDs will be off between each blink.
*
* @param[in] off_time_ticks Off time in ticks.
*
*/
void led_softblink_off_time_set(uint32_t off_time_ticks);
/**
* @brief Function for setting the on time.
*
* This function configures the time that the LEDs will be on between each blink.
*
* @param[in] on_time_ticks On time in ticks.
*
*/
void led_softblink_on_time_set(uint32_t on_time_ticks);
/**
* @brief Function for uninitializing LED softblink.
*
* @retval NRF_SUCCESS If LED softblink was uninitialized successfully.
*/
ret_code_t led_softblink_uninit(void);
#ifdef __cplusplus
}
#endif
#endif // LED_SOFTBLINK_H__
/** @} */

View File

@@ -1,679 +0,0 @@
/**
* Copyright (c) 2019 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sdk_config.h"
#include "nrf_libuarte_async.h"
#include "app_error.h"
#include "nrf_balloc.h"
#include "nrfx_timer.h"
#include "nrfx_rtc.h"
#include "nrfx_ppi.h"
#include "nrf_uart.h"
#include "nrf_queue.h"
#define NRF_LOG_MODULE_NAME libUARTE_async
#if NRF_LIBUARTE_CONFIG_LOG_ENABLED
#define NRF_LOG_LEVEL NRF_LIBUARTE_CONFIG_LOG_LEVEL
#define NRF_LOG_INFO_COLOR NRF_LIBUARTE_CONFIG_INFO_COLOR
#define NRF_LOG_DEBUG_COLOR NRF_LIBUARTE_CONFIG_DEBUG_COLOR
#else // NRF_LIBUARTE_CONFIG_LOG_ENABLED
#define NRF_LOG_LEVEL 0
#endif // NRF_LIBUARTE_CONFIG_LOG_ENABLED
#include "nrf_log.h"
NRF_LOG_MODULE_REGISTER();
#if defined(NRFX_RTC_ENABLED) && NRFX_RTC_ENABLED
#define RTC_IN_USE 1
#else
#define RTC_IN_USE 0
#endif
#if defined(NRFX_TIMER_ENABLED) && NRFX_TIMER_ENABLED
#define TIMER_IN_USE 1
#else
#define TIMER_IN_USE 0
#endif
#define FAULT_IRQ_LEVEL 0xFF
/** Macro is setting up PPI channel set which consist of event, task and optional fork.
*
* @param _ch Channel.
* @param _evt Event.
* @param _tsk Task.
* @param _fork Fork. If NULL fork is not configured.
*/
#define PPI_CH_SETUP(_ch, _evt, _tsk, _fork) \
ret = nrfx_ppi_channel_assign(_ch, _evt, _tsk); \
if (ret != NRF_SUCCESS) \
{ \
return NRF_ERROR_INTERNAL; \
} \
if (_fork) \
{ \
ret = nrfx_ppi_channel_fork_assign(_ch, _fork); \
if (ret != NRF_SUCCESS) \
{ \
return NRF_ERROR_INTERNAL; \
} \
}
/* @brief Function returns interrupt level which is the next,lower priority.
*
* If SoftDevice is present then it takes into account which priorities are used
* by the SoftDevice.
*
* @note Caller of this function does not check if error is returned. Error is returned if input
* priority belongs to SoftDevice. In that case SoftDevice will detect attempt to interrupt level
* misuse.
*
* @param prio Interrupt priority.
*
* @return Priority which is one level lower or fault indicator (0xFF).
*/
static uint8_t irq_prio_inc(uint8_t prio)
{
#ifdef SOFTDEVICE_PRESENT
static const uint8_t sd_next_irq_lut[] = {
FAULT_IRQ_LEVEL, /* 0 used by softdevice */
FAULT_IRQ_LEVEL, /* 1 used by softdevice */
APP_IRQ_PRIORITY_MID, /* 2 + 1 = 3 */
APP_IRQ_PRIORITY_LOW_MID, /* 3 + 1 = 5 as 4 is used by softdevice */
FAULT_IRQ_LEVEL, /* 4 used by softdevice */
APP_IRQ_PRIORITY_LOW /* 5 + 1 = 6 */,
APP_IRQ_PRIORITY_LOWEST, /* 6 + 1 = 7 */
};
return sd_next_irq_lut[prio];
#else
return prio + 1;
#endif
}
#if NRF_LIBUARTE_ASYNC_WITH_APP_TIMER
static void app_timer_handler(void * p_context);
#define local_app_timer_cnt_get() app_timer_cnt_get()
#define local_app_timer_start(p_timer, ticks, p_context) app_timer_start(p_timer, ticks, p_context)
#define local_app_timer_stop(p_timer) app_timer_stop(p_timer)
#define local_app_timer_create(p_timer) app_timer_create(p_timer, APP_TIMER_MODE_SINGLE_SHOT, app_timer_handler)
#define local_app_timer_cnt_diff_compute(to, from) app_timer_cnt_diff_compute(to, from)
#else
#ifndef APP_TIMER_CONFIG_RTC_FREQUENCY
#define APP_TIMER_CONFIG_RTC_FREQUENCY 0
#endif
#ifndef APP_TIMER_CLOCK_FREQ
#define APP_TIMER_CLOCK_FREQ 1
#endif
#ifndef APP_TIMER_MIN_TIMEOUT_TICKS
#define APP_TIMER_MIN_TIMEOUT_TICKS 0
#endif
#ifndef APP_TIMER_CONFIG_IRQ_PRIORITY
#define APP_TIMER_CONFIG_IRQ_PRIORITY 1
#endif
static void app_timer_handler(void * p_context) __attribute__((unused));
#define local_app_timer_cnt_get() 0
#define local_app_timer_start(p_timer, ticks, p_context) NRF_SUCCESS
#define local_app_timer_stop(p_timer) NRF_SUCCESS
#define local_app_timer_create(p_timer) NRF_SUCCESS
#define local_app_timer_cnt_diff_compute(to, from) 0
#endif
static uint32_t app_timer_ticks_to_us(uint32_t ticks)
{
return (uint32_t)(((uint64_t)ticks * 1000000 * (APP_TIMER_CONFIG_RTC_FREQUENCY + 1)) /
APP_TIMER_CLOCK_FREQ);
}
static uint32_t app_timer_us_to_ticks(uint32_t us)
{
return (uint32_t)((((uint64_t)APP_TIMER_CLOCK_FREQ/(APP_TIMER_CONFIG_RTC_FREQUENCY + 1)) * us) /
1000000);
}
static bool rx_buffer_schedule(const nrf_libuarte_async_t * p_libuarte)
{
uint8_t * p_data = nrf_balloc_alloc(p_libuarte->p_rx_pool);
if (p_data == NULL)
{
return false;
}
ret_code_t ret = nrf_queue_push(p_libuarte->p_rx_queue, &p_data);
if (ret != NRF_SUCCESS)
{
NRF_LOG_ERROR("RX buffer queue full.");
return false;
}
p_libuarte->p_ctrl_blk->alloc_cnt++;
nrf_libuarte_drv_rx_buf_rsp(p_libuarte->p_libuarte, p_data, p_libuarte->rx_buf_size);
return true;
}
static void uart_evt_handler(void * context, nrf_libuarte_drv_evt_t * p_evt)
{
ret_code_t ret;
const nrf_libuarte_async_t * p_libuarte = (const nrf_libuarte_async_t *)context;
switch (p_evt->type)
{
case NRF_LIBUARTE_DRV_EVT_TX_DONE:
{
NRF_LOG_DEBUG("(evt) TX completed (%d)", p_evt->data.rxtx.length);
nrf_libuarte_async_evt_t evt = {
.type = NRF_LIBUARTE_ASYNC_EVT_TX_DONE,
.data = {
.rxtx = {
.p_data = p_evt->data.rxtx.p_data,
.length = p_evt->data.rxtx.length,
}
}
};
p_libuarte->p_ctrl_blk->evt_handler(p_libuarte->p_ctrl_blk->context, &evt);
break;
}
case NRF_LIBUARTE_DRV_EVT_RX_BUF_REQ:
{
if (p_libuarte->p_ctrl_blk->rx_halted)
{
break;
}
if (rx_buffer_schedule(p_libuarte) == false)
{
if (p_libuarte->p_ctrl_blk->hwfc)
{
p_libuarte->p_ctrl_blk->rx_halted = true;
}
else
{
NRF_LOG_ERROR("(evt) Failed to allocate buffer for RX.");
APP_ERROR_CHECK_BOOL(false);
}
}
break;
}
case NRF_LIBUARTE_DRV_EVT_RX_DATA:
{
uint32_t rx_amount = p_evt->data.rxtx.length - p_libuarte->p_ctrl_blk->sub_rx_count;
if (rx_amount)
{
p_libuarte->p_ctrl_blk->rx_count += rx_amount;
nrf_libuarte_async_evt_t evt = {
.type = NRF_LIBUARTE_ASYNC_EVT_RX_DATA,
.data = {
.rxtx = {
.p_data = &p_evt->data.rxtx.p_data[p_libuarte->p_ctrl_blk->sub_rx_count],
.length = rx_amount,
}
}
};
NRF_LOG_DEBUG("(evt) RX: %d (addr:0x%08X, internal index: %d)",
rx_amount,
p_evt->data.rxtx.p_data,
p_libuarte->p_ctrl_blk->sub_rx_count);
p_libuarte->p_ctrl_blk->sub_rx_count = 0;
if(p_evt->data.rxtx.p_data != p_libuarte->p_ctrl_blk->p_curr_rx_buf)
{
NRF_LOG_ERROR("(evt) RX buffer address mismatch");
}
ret = nrf_queue_pop(p_libuarte->p_rx_queue, &p_libuarte->p_ctrl_blk->p_curr_rx_buf);
if (ret != NRF_SUCCESS)
{
NRF_LOG_ERROR("RX buffer queue empty.");
APP_ERROR_CHECK_BOOL(false);
}
p_libuarte->p_ctrl_blk->evt_handler(p_libuarte->p_ctrl_blk->context, &evt);
}
else
{
NRF_LOG_ERROR("(evt) RX with 0 length: 0x%08X", p_evt->data.rxtx.p_data);
//zero length packet is freed immediately and not forwarded to the application.
APP_ERROR_CHECK_BOOL(false);
}
break;
}
case NRF_LIBUARTE_DRV_EVT_ERROR:
{
nrf_libuarte_async_evt_t evt = {
.type = NRF_LIBUARTE_ASYNC_EVT_ERROR,
.data = {
.errorsrc = p_evt->data.errorsrc
}
};
p_libuarte->p_ctrl_blk->evt_handler(p_libuarte->p_ctrl_blk->context, &evt);
break;
}
case NRF_LIBUARTE_DRV_EVT_OVERRUN_ERROR:
{
NRF_LOG_WARNING("Overrun error - data loss due to UARTE interrupt not handled on time.");
uint32_t rx_amount = p_evt->data.overrun_err.overrun_length - p_libuarte->p_ctrl_blk->sub_rx_count;
p_libuarte->p_ctrl_blk->rx_count += rx_amount;
nrf_libuarte_async_evt_t evt = {
.type = NRF_LIBUARTE_ASYNC_EVT_OVERRUN_ERROR,
.data = {
.overrun_err = { .overrun_length = p_evt->data.overrun_err.overrun_length}
}
};
p_libuarte->p_ctrl_blk->evt_handler(p_libuarte->p_ctrl_blk->context, &evt);
break;
}
default:
APP_ERROR_CHECK_BOOL(false);
break;
}
}
void nrf_libuarte_async_timeout_handler(const nrf_libuarte_async_t * p_libuarte)
{
NRFX_IRQ_DISABLE((IRQn_Type)NRFX_IRQ_NUMBER_GET(p_libuarte->p_libuarte->uarte));
uint32_t capt_rx_count = p_libuarte->p_libuarte->timer.p_reg->CC[3];
if (capt_rx_count > p_libuarte->p_ctrl_blk->rx_count)
{
uint32_t rx_amount = capt_rx_count - p_libuarte->p_ctrl_blk->rx_count;
nrf_libuarte_async_evt_t evt = {
.type = NRF_LIBUARTE_ASYNC_EVT_RX_DATA,
.data = {
.rxtx = {
.p_data = &p_libuarte->p_ctrl_blk->p_curr_rx_buf[p_libuarte->p_ctrl_blk->sub_rx_count],
.length = rx_amount,
}
}
};
NRF_LOG_DEBUG("(tmr evt) RX: %d (addr:0x%08X, internal index: %d)",
rx_amount,
evt.data.rxtx.p_data,
p_libuarte->p_ctrl_blk->sub_rx_count);
p_libuarte->p_ctrl_blk->sub_rx_count += rx_amount;
p_libuarte->p_ctrl_blk->rx_count = capt_rx_count;
p_libuarte->p_ctrl_blk->evt_handler(p_libuarte->p_ctrl_blk->context, &evt);
}
NRFX_IRQ_ENABLE((IRQn_Type)NRFX_IRQ_NUMBER_GET(p_libuarte->p_libuarte->uarte));
}
static void tmr_evt_handler(nrf_timer_event_t event_type, void * p_context)
{
nrf_libuarte_async_timeout_handler((const nrf_libuarte_async_t *)p_context);
}
static void app_timer_handler(void * p_context)
{
const nrf_libuarte_async_t * p_libuarte = p_context;
uint32_t current_rx_count;
uint32_t counter = local_app_timer_cnt_get();
uint32_t ticks = app_timer_us_to_ticks(p_libuarte->p_ctrl_blk->timeout_us)/2;
ticks = MAX(APP_TIMER_MIN_TIMEOUT_TICKS, ticks);
if (p_libuarte->p_ctrl_blk->enabled == false)
{
return;
}
nrf_timer_task_trigger( p_libuarte->p_libuarte->timer.p_reg, NRF_TIMER_TASK_CAPTURE3);
current_rx_count = p_libuarte->p_libuarte->timer.p_reg->CC[3];
UNUSED_RETURN_VALUE(local_app_timer_start(*p_libuarte->p_app_timer, ticks, (void *)p_libuarte));
if (p_libuarte->p_app_timer_ctrl_blk->rx_count != current_rx_count) {
p_libuarte->p_app_timer_ctrl_blk->rx_count = current_rx_count;
/* if number of bytes received changed reset timestamp and activate waiting
* for silent period.
*/
p_libuarte->p_app_timer_ctrl_blk->timestamp = counter;
p_libuarte->p_app_timer_ctrl_blk->activate = true;
} else {
uint32_t diff;
/* In case of detected silent period check if its length exceeds configured
* timeout. If yes trigger timeout handler.
*/
diff = local_app_timer_cnt_diff_compute(counter,
p_libuarte->p_app_timer_ctrl_blk->timestamp);
if (p_libuarte->p_app_timer_ctrl_blk->activate &&
(app_timer_ticks_to_us(diff) > p_libuarte->p_ctrl_blk->timeout_us)) {
p_libuarte->p_app_timer_ctrl_blk->activate = false;
nrf_libuarte_async_timeout_handler(p_libuarte);
}
}
}
ret_code_t nrf_libuarte_async_init(const nrf_libuarte_async_t * const p_libuarte,
nrf_libuarte_async_config_t const * p_config,
nrf_libuarte_async_evt_handler_t evt_handler,
void * context)
{
ret_code_t ret;
if (p_config->int_prio == APP_IRQ_PRIORITY_LOWEST ||
((p_libuarte->p_app_timer && NRF_LIBUARTE_ASYNC_WITH_APP_TIMER) &&
(p_config->int_prio >= APP_TIMER_CONFIG_IRQ_PRIORITY))) {
NRF_LOG_ERROR("Too low priority. Lowest possible priority is %d", APP_IRQ_PRIORITY_LOW);
return NRF_ERROR_INVALID_PARAM;
}
if (p_libuarte->p_ctrl_blk->enabled)
{
return NRF_ERROR_INVALID_STATE;
}
p_libuarte->p_ctrl_blk->evt_handler = evt_handler;
p_libuarte->p_ctrl_blk->rx_count = 0;
p_libuarte->p_ctrl_blk->p_curr_rx_buf = NULL;
p_libuarte->p_ctrl_blk->rx_free_cnt = 0;
p_libuarte->p_ctrl_blk->sub_rx_count = 0;
p_libuarte->p_ctrl_blk->alloc_cnt = 0;
p_libuarte->p_ctrl_blk->context = context;
p_libuarte->p_ctrl_blk->timeout_us = p_config->timeout_us;
p_libuarte->p_ctrl_blk->rx_halted = false;
p_libuarte->p_ctrl_blk->hwfc = (p_config->hwfc == NRF_UARTE_HWFC_ENABLED);
uint32_t i;
uint32_t tmr_start_tsk = 0;
uint32_t tmr_clear_tsk = 0;
uint32_t tmr_stop_tsk = 0;
uint32_t tmr_compare_evt = 0;
if (p_libuarte->p_rtc && RTC_IN_USE)
{
nrfx_rtc_config_t rtc_config = NRFX_RTC_DEFAULT_CONFIG;
rtc_config.interrupt_priority = irq_prio_inc(p_config->int_prio);
rtc_config.prescaler = 0;
ret = nrfx_rtc_init(p_libuarte->p_rtc, &rtc_config, p_libuarte->rtc_handler);
if (ret != NRFX_SUCCESS)
{
return NRF_ERROR_INTERNAL;
}
ret = nrfx_rtc_cc_set(p_libuarte->p_rtc, 0, p_config->timeout_us/32, true);
if (ret != NRFX_SUCCESS)
{
return NRF_ERROR_INTERNAL;
}
tmr_start_tsk = nrfx_rtc_task_address_get(p_libuarte->p_rtc, NRF_RTC_TASK_START);
tmr_clear_tsk = nrfx_rtc_task_address_get(p_libuarte->p_rtc, NRF_RTC_TASK_CLEAR);
tmr_stop_tsk = nrfx_rtc_task_address_get(p_libuarte->p_rtc, NRF_RTC_TASK_STOP);
tmr_compare_evt = nrfx_rtc_event_address_get(p_libuarte->p_rtc, NRF_RTC_EVENT_COMPARE_0);
}
else if (p_libuarte->p_timer && TIMER_IN_USE)
{
nrfx_timer_config_t tmr_config = NRFX_TIMER_DEFAULT_CONFIG;
tmr_config.frequency = NRF_TIMER_FREQ_1MHz;
tmr_config.p_context = (void *)p_libuarte;
tmr_config.interrupt_priority = irq_prio_inc(p_config->int_prio);
ret = nrfx_timer_init(p_libuarte->p_timer, &tmr_config, tmr_evt_handler);
if (ret != NRFX_SUCCESS)
{
return NRF_ERROR_INTERNAL;
}
nrfx_timer_compare(p_libuarte->p_timer, NRF_TIMER_CC_CHANNEL0, p_config->timeout_us, true);
tmr_start_tsk = nrfx_timer_task_address_get(p_libuarte->p_timer, NRF_TIMER_TASK_START);
tmr_clear_tsk = nrfx_timer_task_address_get(p_libuarte->p_timer, NRF_TIMER_TASK_CLEAR);
tmr_stop_tsk = nrfx_timer_task_address_get(p_libuarte->p_timer, NRF_TIMER_TASK_SHUTDOWN);
tmr_compare_evt = nrfx_timer_compare_event_address_get(p_libuarte->p_timer, 0);
}
else if (p_libuarte->p_app_timer && NRF_LIBUARTE_ASYNC_WITH_APP_TIMER) {
/* app_timer in use */
if(!p_libuarte->p_ctrl_blk->app_timer_created)
{
ret = local_app_timer_create(p_libuarte->p_app_timer);
if (ret != NRF_SUCCESS)
{
return ret;
}
p_libuarte->p_ctrl_blk->app_timer_created = true;
}
p_libuarte->p_app_timer_ctrl_blk->activate = false;
p_libuarte->p_app_timer_ctrl_blk->rx_count = 0;
p_libuarte->p_app_timer_ctrl_blk->timestamp = 0;
}
else
{
NRF_LOG_ERROR("No timer or rtc defined");
APP_ERROR_CHECK_BOOL(false);
return NRF_ERROR_INTERNAL;
}
/* if RTC or TIMER is used then PPI channels are allocated. */
if (p_libuarte->p_app_timer == NULL || !NRF_LIBUARTE_ASYNC_WITH_APP_TIMER)
{
for (i = 0; i < NRF_LIBUARTE_ASYNC_PPI_CH_MAX; i++)
{
ret = nrfx_ppi_channel_alloc(&p_libuarte->p_ctrl_blk->ppi_channels[i]);
if (ret != NRFX_SUCCESS)
{
//we don't free already allocated channels, system is wrongly configured.
return NRF_ERROR_INTERNAL;
}
}
/*lint -save -e666 */
PPI_CH_SETUP(p_libuarte->p_ctrl_blk->ppi_channels[NRF_LIBUARTE_ASYNC_PPI_CH_RXRDY_CLEAR],
nrf_uarte_event_address_get(p_libuarte->p_libuarte->uarte, NRF_UARTE_EVENT_RXDRDY),
tmr_start_tsk,
tmr_clear_tsk);
PPI_CH_SETUP(p_libuarte->p_ctrl_blk->ppi_channels[NRF_LIBUARTE_ASYNC_PPI_CH_COMPARE_SHUTDOWN],
tmr_compare_evt,
tmr_stop_tsk,
(uint32_t)&p_libuarte->p_libuarte->timer.p_reg->TASKS_CAPTURE[3]);
/*lint -restore */
}
nrf_libuarte_drv_config_t uart_config = {
.tx_pin = p_config->tx_pin,
.rx_pin = p_config->rx_pin,
.cts_pin = p_config->cts_pin,
.rts_pin = p_config->rts_pin,
.startrx_evt = nrf_uarte_event_address_get(p_libuarte->p_libuarte->uarte, NRF_UARTE_EVENT_ENDRX),
.endrx_evt = 0,
.rxstarted_tsk = 0,
.rxdone_tsk = 0,
.hwfc = p_config->hwfc,
.parity = p_config->parity,
.baudrate = p_config->baudrate,
.irq_priority = p_config->int_prio,
.pullup_rx = p_config->pullup_rx,
};
ret = nrf_libuarte_drv_init(p_libuarte->p_libuarte, &uart_config, uart_evt_handler, (void *)p_libuarte);
if (ret != NRF_SUCCESS)
{
return ret;
}
ret = nrf_balloc_init(p_libuarte->p_rx_pool);
if (ret != NRF_SUCCESS)
{
return ret;
}
nrf_queue_reset(p_libuarte->p_rx_queue);
p_libuarte->p_ctrl_blk->enabled = true;
return ret;
}
void nrf_libuarte_async_uninit(const nrf_libuarte_async_t * const p_libuarte)
{
if (p_libuarte->p_ctrl_blk->enabled == false)
{
return;
}
p_libuarte->p_ctrl_blk->enabled = false;
/* if HW timeout was used */
if (p_libuarte->p_app_timer == NULL || !NRF_LIBUARTE_ASYNC_WITH_APP_TIMER)
{
uint32_t i;
ret_code_t ret;
for (i = 0; i < NRF_LIBUARTE_ASYNC_PPI_CH_MAX; i++)
{
ret = nrfx_ppi_channel_disable(p_libuarte->p_ctrl_blk->ppi_channels[i]);
ASSERT(ret == NRF_SUCCESS)
ret = nrfx_ppi_channel_free(p_libuarte->p_ctrl_blk->ppi_channels[i]);
ASSERT(ret == NRF_SUCCESS)
}
}
if (p_libuarte->p_rtc && RTC_IN_USE)
{
nrfx_rtc_disable(p_libuarte->p_rtc);
nrfx_rtc_uninit(p_libuarte->p_rtc);
}
else if (p_libuarte->p_timer && TIMER_IN_USE)
{
nrfx_timer_disable(p_libuarte->p_timer);
nrfx_timer_uninit(p_libuarte->p_timer);
}
else if (p_libuarte->p_app_timer && NRF_LIBUARTE_ASYNC_WITH_APP_TIMER)
{
UNUSED_RETURN_VALUE(local_app_timer_stop(*p_libuarte->p_app_timer));
}
nrf_libuarte_drv_uninit(p_libuarte->p_libuarte);
}
void nrf_libuarte_async_enable(const nrf_libuarte_async_t * const p_libuarte)
{
uint8_t * p_data;
p_data = nrf_balloc_alloc(p_libuarte->p_rx_pool);
p_libuarte->p_ctrl_blk->alloc_cnt++;
if (p_data == NULL)
{
APP_ERROR_CHECK_BOOL(false);
}
if (p_libuarte->p_rtc && RTC_IN_USE)
{
nrfx_rtc_counter_clear(p_libuarte->p_rtc);
}
else if (p_libuarte->p_timer && TIMER_IN_USE)
{
nrfx_timer_clear(p_libuarte->p_timer);
}
if (!(p_libuarte->p_app_timer && NRF_LIBUARTE_ASYNC_WITH_APP_TIMER))
{
nrfx_err_t err;
err = nrfx_ppi_channel_enable(p_libuarte->p_ctrl_blk->ppi_channels[NRF_LIBUARTE_ASYNC_PPI_CH_RXRDY_CLEAR]);
APP_ERROR_CHECK_BOOL(err == NRFX_SUCCESS);
err = nrfx_ppi_channel_enable(p_libuarte->p_ctrl_blk->ppi_channels[NRF_LIBUARTE_ASYNC_PPI_CH_COMPARE_SHUTDOWN]);
APP_ERROR_CHECK_BOOL(err == NRFX_SUCCESS);
}
p_libuarte->p_ctrl_blk->p_curr_rx_buf = p_data;
ret_code_t ret = nrf_libuarte_drv_rx_start(p_libuarte->p_libuarte, p_data, p_libuarte->rx_buf_size, false);
APP_ERROR_CHECK_BOOL(ret == NRF_SUCCESS);
if (p_libuarte->p_app_timer && NRF_LIBUARTE_ASYNC_WITH_APP_TIMER)
{
uint32_t ticks = app_timer_us_to_ticks(p_libuarte->p_ctrl_blk->timeout_us)/2;
ticks = MAX(APP_TIMER_MIN_TIMEOUT_TICKS, ticks);
UNUSED_RETURN_VALUE(local_app_timer_start(*p_libuarte->p_app_timer, ticks, (void *)p_libuarte));
}
}
ret_code_t nrf_libuarte_async_tx(const nrf_libuarte_async_t * const p_libuarte, uint8_t * p_data, size_t length)
{
return nrf_libuarte_drv_tx(p_libuarte->p_libuarte, p_data, length);
}
void nrf_libuarte_async_rx_free(const nrf_libuarte_async_t * const p_libuarte, uint8_t * p_data, size_t length)
{
p_libuarte->p_ctrl_blk->rx_free_cnt += length;
if (p_libuarte->p_ctrl_blk->rx_free_cnt == p_libuarte->rx_buf_size)
{
p_data -= (p_libuarte->p_ctrl_blk->rx_free_cnt - length);
p_libuarte->p_ctrl_blk->rx_free_cnt = 0;
nrf_balloc_free(p_libuarte->p_rx_pool, p_data);
p_libuarte->p_ctrl_blk->alloc_cnt--;
if (p_libuarte->p_ctrl_blk->alloc_cnt<0)
{
NRF_LOG_ERROR("Freeing more RX buffers than allocated.");
APP_ERROR_CHECK_BOOL(false);
}
NRF_LOG_INFO("Freeing full buffer 0x%08X, %d, (currently allocated:%d).",p_data, length, p_libuarte->p_ctrl_blk->alloc_cnt);
if (p_libuarte->p_ctrl_blk->rx_halted)
{
bool ret = rx_buffer_schedule(p_libuarte);
ASSERT(ret);
p_libuarte->p_ctrl_blk->rx_halted = false;
}
}
else if (p_libuarte->p_ctrl_blk->rx_free_cnt > p_libuarte->rx_buf_size)
{
NRF_LOG_ERROR("Unexpected RX free input parameter.");
APP_ERROR_CHECK_BOOL(false);
}
else
{
NRF_LOG_INFO("Freeing partial buffer: 0x%08X, length:%d", p_data, length);
}
}
void nrf_libuarte_async_rts_clear(const nrf_libuarte_async_t * const p_libuarte)
{
nrf_libuarte_drv_rts_clear(p_libuarte->p_libuarte);
}
void nrf_libuarte_async_rts_set(const nrf_libuarte_async_t * const p_libuarte)
{
nrf_libuarte_drv_rts_set(p_libuarte->p_libuarte);
}

View File

@@ -1,385 +0,0 @@
/**
* Copyright (c) 2019 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef UART_ASYNC_H
#define UART_ASYNC_H
#include <stdint.h>
#include "sdk_errors.h"
#include "nrf_balloc.h"
#include "nrf_queue.h"
#include "nrfx_ppi.h"
#include "nrfx_timer.h"
#include "nrfx_rtc.h"
#include "nrf_libuarte_drv.h"
#include <hal/nrf_uarte.h>
/**
* @defgroup nrf_libuarte_async libUARTE asynchronous library
* @ingroup app_common
*
* @brief Module for reliable communication over UARTE.
*
* @{
*/
/* Safe guard for sdk_config.h now up to date. */
#ifndef NRF_LIBUARTE_ASYNC_WITH_APP_TIMER
#warning "sdk_config.h is missing NRF_LIBUARTE_ASYNC_WITH_APP_TIMER option"
#define NRF_LIBUARTE_ASYNC_WITH_APP_TIMER 0
#endif
#if NRF_LIBUARTE_ASYNC_WITH_APP_TIMER
#include "app_timer.h"
#endif
/** @brief Types of libuarte driver events. */
typedef enum
{
NRF_LIBUARTE_ASYNC_EVT_RX_DATA, ///< Requested TX transfer completed.
NRF_LIBUARTE_ASYNC_EVT_TX_DONE, ///< Requested RX transfer completed.
NRF_LIBUARTE_ASYNC_EVT_ERROR, ///< Error reported by UARTE peripheral.
NRF_LIBUARTE_ASYNC_EVT_OVERRUN_ERROR ///< Error reported by the driver.
} nrf_libuarte_async_evt_type_t;
typedef enum
{
NRF_LIBUARTE_ASYNC_PPI_CH_RXRDY_CLEAR,
NRF_LIBUARTE_ASYNC_PPI_CH_COMPARE_SHUTDOWN,
NRF_LIBUARTE_ASYNC_PPI_CH_MAX
} nrf_libuarte_async_ppi_channel_t;
/** @brief Structure for libuarte async transfer completion event. */
typedef struct
{
uint8_t * p_data; ///< Pointer to memory used for transfer.
size_t length; ///< Number of bytes transfered.
} nrf_libuarte_async_data_t;
/** @brief Structu for software error event. */
typedef struct
{
uint32_t overrun_length; ///< Number of bytes lost due to overrun.
} nrf_libuarte_async_overrun_err_evt_t;
/** @brief Structure for libuarte error event. */
typedef struct
{
nrf_libuarte_async_evt_type_t type; ///< Event type.
union {
nrf_libuarte_async_data_t rxtx; ///< RXD/TXD data.
uint8_t errorsrc; ///< Error source.
nrf_libuarte_async_overrun_err_evt_t overrun_err; ///< Overrun error data.
} data; ///< Union with data.
} nrf_libuarte_async_evt_t;
/**
* @brief Interrupt event handler.
*
* @param[in] p_evt Pointer to event structure. Event is allocated on the stack so it is available
* only within the context of the event handler.
*/
typedef void (*nrf_libuarte_async_evt_handler_t)(void * context, nrf_libuarte_async_evt_t * p_evt);
/** @brief Structure for libuarte async configuration. */
typedef struct
{
uint32_t rx_pin; ///< RXD pin number.
uint32_t tx_pin; ///< TXD pin number.
uint32_t cts_pin; ///< CTS pin number.
uint32_t rts_pin; ///< RTS pin number.
uint32_t timeout_us; ///< Receiver timeout in us unit.
nrf_uarte_hwfc_t hwfc; ///< Flow control configuration.
nrf_uarte_parity_t parity; ///< Parity configuration.
nrf_uarte_baudrate_t baudrate; ///< Baudrate.
bool pullup_rx; ///< Pull up on RX pin.
uint8_t int_prio; ///< Interrupt priority of UARTE (RTC, TIMER have int_prio - 1)
} nrf_libuarte_async_config_t;
/**
* @brief nrf_libuarte_async control block (placed in RAM).
*/
typedef struct {
nrf_libuarte_async_evt_handler_t evt_handler;
void * context;
nrf_ppi_channel_t ppi_channels[NRF_LIBUARTE_ASYNC_PPI_CH_MAX];
int32_t alloc_cnt;
uint32_t rx_count;
uint32_t sub_rx_count;
uint8_t * p_curr_rx_buf;
uint32_t rx_free_cnt;
uint32_t timeout_us;
bool app_timer_created;
bool hwfc;
bool rx_halted;
bool enabled;
} nrf_libuarte_async_ctrl_blk_t;
typedef struct {
uint32_t rx_count;
uint32_t timestamp;
bool activate;
} nrf_libuarte_app_timer_ctrl_blk_t;
/**
* @brief nrf_libuarte_async instance structure (placed in ROM).
*/
typedef struct {
const nrf_balloc_t * p_rx_pool;
const nrf_queue_t * p_rx_queue;
const nrfx_rtc_t * p_rtc;
const nrfx_timer_t * p_timer;
#if NRF_LIBUARTE_ASYNC_WITH_APP_TIMER
const app_timer_id_t * p_app_timer;
#else
void ** p_app_timer;
#endif
nrf_libuarte_app_timer_ctrl_blk_t * p_app_timer_ctrl_blk;
const nrf_libuarte_drv_t * p_libuarte;
nrf_libuarte_async_ctrl_blk_t * p_ctrl_blk;
nrfx_rtc_handler_t rtc_handler;
uint32_t rx_buf_size;
} nrf_libuarte_async_t;
void nrf_libuarte_async_timeout_handler(const nrf_libuarte_async_t * p_libuarte);
#define NRF_LIBUARTE_PERIPHERAL_NOT_USED 255
#define LIBUARTE_ASYNC_DEBRACKET(...) __VA_ARGS__
#define __LIBUARTE_ASYNC_ARG_2(ignore_this, val, ...) val
#define __LIBUARTE_ASYNC_ARG_2_DEBRACKET(ignore_this, val, ...) LIBUARTE_ASYNC_DEBRACKET val
/* Macro for injecting code based on flag evaluation. If flag exists and equals 1
* then first code is compiled in, else second option. Note that code must be
* in the brackets. Example usage:
* _LIBUARTE_ASYNC_EVAL(MY_FLAG, (foo();), () )
* If MY_FLAG exists and equals 1 then macros resolves to foo(); call, else it resolves to
* empty line.
*
* @param _eval_level Flag to be evaluated. It's positively evaluated if exists and equals 1.
* @param _iftrue Macro is resolved to that code on positive flag evaluation. Code must be
* in the brackets.
* @param _iffalse Macro is resolved to that code on negative flag evaluation. Code must be
* in the brackets.
*/
#define _LIBUARTE_ASYNC_EVAL(_eval_flag, _iftrue, _iffalse) \
_LIBUARTE_ASYNC_EVAL1(_eval_flag, _iftrue, _iffalse)
#define _LIBUARTE_ASYNC_EVAL1(_eval_flag, _iftrue, _iffalse) \
_LIBUARTE_ASYNC_EVAL2(_LIBUARTE_ASYNC_ZZZZ##_eval_flag, _iftrue, _iffalse)
#define _LIBUARTE_ASYNC_ZZZZ1 _LIBUARTE_ASYNC_YYYY,
#define _LIBUARTE_ASYNC_EVAL2(one_or_two_args, _iftrue, _iffalse) \
__LIBUARTE_ASYNC_ARG_2_DEBRACKET(one_or_two_args _iftrue, _iffalse)
/**
* @brief Macro for creating instance of libuarte_async.
*
* Libuarte_async requires one timer-like peripheral (RTC or TIMER) for triggering RX timeout.
* Macro will create instance only for peripheral which is used.
*
* @param _name Instance name.
* @param _uarte_idx UARTE instance used.
* @param _timer0_idx TIMER instance used by libuarte for bytes counting.
* @param _rtc1_idx RTC instance used for timeout. If set to NRF_LIBUARTE_PERIPHERAL_NOT_USED
* then TIMER instance is used or app_timer instance if _timer1_idx is also set
* to NRF_LIBUARTE_PERIPHERAL_NOT_USED.
* @param _timer1_idx TIMER instance used for timeout. If set to NRF_LIBUARTE_PERIPHERAL_NOT_USED
* then RTC instance is used or app_timer instance if _rtc1_idx is also set
* to NRF_LIBUARTE_PERIPHERAL_NOT_USED.
* @param _rx_buf_size Size of single RX buffer. Size impacts accepted latency between buffer
* request and providing next buffer. Next must be provided within before
* _rx_buf_size bytes is received.
* @param _rx_buf_cnt Number of buffers in the RX buffer pool. Size impacts accepted latency
* between NRF_LIBUARTE_ASYNC_EVT_RX_DATA event and
* @ref nrf_libuarte_async_rx_free.
*/
#define NRF_LIBUARTE_ASYNC_DEFINE(_name, _uarte_idx, _timer0_idx,\
_rtc1_idx, _timer1_idx,\
_rx_buf_size, _rx_buf_cnt) \
STATIC_ASSERT(_rx_buf_cnt >= 3, "Wrong number of RX buffers");\
STATIC_ASSERT(!((NRF_LIBUARTE_ASYNC_WITH_APP_TIMER == 0) && \
(_rtc1_idx == NRF_LIBUARTE_PERIPHERAL_NOT_USED) && \
(_timer1_idx == NRF_LIBUARTE_PERIPHERAL_NOT_USED)), \
"App timer support disabled");\
NRF_LIBUARTE_DRV_DEFINE(CONCAT_2(_name, _libuarte), _uarte_idx, _timer0_idx);\
NRF_QUEUE_DEF(uint8_t *, CONCAT_2(_name,_rxdata_queue), _rx_buf_cnt, NRF_QUEUE_MODE_NO_OVERFLOW);\
NRF_BALLOC_DEF(CONCAT_2(_name,_rx_pool), _rx_buf_size, _rx_buf_cnt);\
/* Create TIMER instance only if _timer1_idx != NRF_LIBUARTE_PERIPHERAL_NOT_USED */ \
_LIBUARTE_ASYNC_EVAL(\
NRFX_CONCAT_3(NRFX_TIMER, _timer1_idx, _ENABLED),\
(STATIC_ASSERT((_timer1_idx == NRF_LIBUARTE_PERIPHERAL_NOT_USED) || (CONCAT_3(NRFX_TIMER,_timer1_idx, _ENABLED) == 1), "TIMER instance not enabled");\
static const nrfx_timer_t CONCAT_2(_name, _timer) = NRFX_TIMER_INSTANCE(_timer1_idx);),\
(/* empty */))\
/* Create RTC instance only if _timer1_idx != NRF_LIBUARTE_PERIPHERAL_NOT_USED */ \
_LIBUARTE_ASYNC_EVAL(\
NRFX_CONCAT_3(NRFX_RTC, _rtc1_idx, _ENABLED),\
(STATIC_ASSERT((_rtc1_idx == NRF_LIBUARTE_PERIPHERAL_NOT_USED) || (CONCAT_3(NRFX_RTC,_rtc1_idx, _ENABLED) == 1), "RTC instance not enabled");\
static const nrfx_rtc_t CONCAT_2(_name, _rtc) = NRFX_RTC_INSTANCE(_rtc1_idx);),\
(/* empty */))\
_LIBUARTE_ASYNC_EVAL(NRFX_CONCAT_3(NRFX_TIMER, _timer1_idx, _ENABLED),\
(/* empty */),\
(_LIBUARTE_ASYNC_EVAL(NRFX_CONCAT_3(NRFX_RTC, _rtc1_idx, _ENABLED),(/* empty */), \
(APP_TIMER_DEF(CONCAT_2(_name,_app_timer)); \
nrf_libuarte_app_timer_ctrl_blk_t CONCAT_2(_name,_app_timer_ctrl_blk);))) \
)\
static nrf_libuarte_async_ctrl_blk_t CONCAT_2(_name, ctrl_blk);\
_LIBUARTE_ASYNC_EVAL(\
NRFX_CONCAT_3(NRFX_RTC, _rtc1_idx, _ENABLED), \
(static void CONCAT_2(_name, _rtc_handler)(nrfx_rtc_int_type_t int_type);),\
(/* empty */)) \
\
static const nrf_libuarte_async_t _name = {\
.p_rx_pool = &CONCAT_2(_name,_rx_pool),\
.p_rx_queue = &CONCAT_2(_name,_rxdata_queue),\
/* If p_rtc is not NULL it means that RTC is used for RX timeout */ \
.p_rtc = _LIBUARTE_ASYNC_EVAL(NRFX_CONCAT_3(NRFX_RTC, _rtc1_idx, _ENABLED), (&CONCAT_2(_name, _rtc)), (NULL)),\
/* If p_timer is not NULL it means that RTC is used for RX timeout */ \
.p_timer = _LIBUARTE_ASYNC_EVAL(NRFX_CONCAT_3(NRFX_TIMER, _timer1_idx, _ENABLED), (&CONCAT_2(_name, _timer)), (NULL)),\
/* If p_time and p_rtc is NULL it means that app_timer is used for RX timeout */ \
.p_app_timer = _LIBUARTE_ASYNC_EVAL(NRFX_CONCAT_3(NRFX_TIMER, _timer1_idx, _ENABLED),\
(NULL),\
(_LIBUARTE_ASYNC_EVAL(NRFX_CONCAT_3(NRFX_RTC, _rtc1_idx, _ENABLED),(NULL), \
(&CONCAT_2(_name,_app_timer)))) \
),\
.p_app_timer_ctrl_blk = _LIBUARTE_ASYNC_EVAL(NRFX_CONCAT_3(NRFX_TIMER, _timer1_idx, _ENABLED),\
(NULL),\
(_LIBUARTE_ASYNC_EVAL(NRFX_CONCAT_3(NRFX_RTC, _rtc1_idx, _ENABLED),(NULL), \
(&CONCAT_2(_name,_app_timer_ctrl_blk)))) \
),\
.p_libuarte = &CONCAT_2(_name, _libuarte),\
.p_ctrl_blk = &CONCAT_2(_name, ctrl_blk),\
.rx_buf_size = _rx_buf_size,\
_LIBUARTE_ASYNC_EVAL(\
NRFX_CONCAT_3(NRFX_RTC, _rtc1_idx, _ENABLED),\
(.rtc_handler =CONCAT_2(_name, _rtc_handler)),\
()\
)\
};\
/* RTC compare event is not periodic but need to be enabled again in the callback. */ \
_LIBUARTE_ASYNC_EVAL(\
NRFX_CONCAT_3(NRFX_RTC, _rtc1_idx, _ENABLED),\
(\
static void CONCAT_2(_name, _rtc_handler)(nrfx_rtc_int_type_t int_type)\
{ \
(void)nrfx_rtc_cc_set(_name.p_rtc, 0, _name.p_ctrl_blk->timeout_us/32, true);\
nrf_libuarte_async_timeout_handler(&_name);\
}\
),\
()\
)
/**
* @brief Function for initializing the libuarte async library.
*
* @param[in] p_libuarte Libuarte_async instance.
* @param[in] p_config Pointer to the structure with initial configuration.
* @param[in] evt_handler Event handler provided by the user. Must not be NULL.
* @param[in] context User context passed to the event handler.
*
* @return NRF_SUCCESS when properly initialized. NRF_ERROR_INTERNAL otherwise.
*/
ret_code_t nrf_libuarte_async_init(const nrf_libuarte_async_t * const p_libuarte,
nrf_libuarte_async_config_t const * p_config,
nrf_libuarte_async_evt_handler_t evt_handler,
void * context);
/** @brief Function for uninitializing the libuarte async library.
*
* @param[in] p_libuarte Libuarte_async instance.
*/
void nrf_libuarte_async_uninit(const nrf_libuarte_async_t * const p_libuarte);
/**
* @brief Function for enabling receiver.
*
* @param p_libuarte Libuarte_async instance.
*/
void nrf_libuarte_async_enable(const nrf_libuarte_async_t * const p_libuarte);
/**
* @brief Function for deasserting RTS to pause the transmission.
*
* Flow control must be enabled.
*
* @param p_libuarte Libuarte_async instance.
*/
void nrf_libuarte_async_rts_clear(const nrf_libuarte_async_t * const p_libuarte);
/**
* @brief Function for asserting RTS to restart the transmission.
*
* Flow control must be enabled.
*
* @param p_libuarte Libuarte_async instance.
*/
void nrf_libuarte_async_rts_set(const nrf_libuarte_async_t * const p_libuarte);
/**
* @brief Function for sending data asynchronously over UARTE.
*
* @param[in] p_libuarte Libuarte_async instance.
* @param[in] p_data Pointer to data.
* @param[in] length Number of bytes to send. Maximum possible length is
* dependent on the used SoC (see the MAXCNT register
* description in the Product Specification). The library
* checks it with assertion.
*
* @retval NRF_ERROR_BUSY Data is transferring.
* @retval NRF_ERROR_INTERNAL Error during configuration.
* @retval NRF_SUCCESS Buffer set for sending.
*/
ret_code_t nrf_libuarte_async_tx(const nrf_libuarte_async_t * const p_libuarte,
uint8_t * p_data, size_t length);
/**
* @brief Function for deallocating received buffer data.
*
* @param[in] p_libuarte Libuarte_async instance.
* @param[in] p_data Pointer to data.
* @param[in] length Number of bytes to free.
*/
void nrf_libuarte_async_rx_free(const nrf_libuarte_async_t * const p_libuarte,
uint8_t * p_data, size_t length);
/** @} */
#endif //UART_ASYNC_H

View File

@@ -1,868 +0,0 @@
/**
* Copyright (c) 2019 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sdk_config.h"
#include "nrf_libuarte_drv.h"
#include "nrf_uarte.h"
#include "nrf_gpio.h"
#include <nrfx_gpiote.h>
#include <../src/prs/nrfx_prs.h>
#define NRF_LOG_MODULE_NAME libUARTE
#if NRF_LIBUARTE_CONFIG_LOG_ENABLED
#define NRF_LOG_LEVEL NRF_LIBUARTE_CONFIG_LOG_LEVEL
#define NRF_LOG_INFO_COLOR NRF_LIBUARTE_CONFIG_INFO_COLOR
#define NRF_LOG_DEBUG_COLOR NRF_LIBUARTE_CONFIG_DEBUG_COLOR
#else // NRF_LIBUARTE_CONFIG_LOG_ENABLED
#define NRF_LOG_LEVEL 0
#endif // NRF_LIBUARTE_CONFIG_LOG_ENABLED
#include "nrf_log.h"
NRF_LOG_MODULE_REGISTER();
#define MAX_DMA_XFER_LEN ((1UL << UARTE0_EASYDMA_MAXCNT_SIZE) - 1)
#define INTERRUPTS_MASK \
(NRF_UARTE_INT_ENDRX_MASK | NRF_UARTE_INT_RXSTARTED_MASK | NRF_UARTE_INT_ERROR_MASK | \
NRF_UARTE_INT_ENDTX_MASK | NRF_UARTE_INT_TXSTOPPED_MASK)
static const nrf_libuarte_drv_t * m_libuarte_instance[2];
/* if it is defined it means that PRS for uart is not used. */
#ifdef nrfx_uarte_0_irq_handler
#define libuarte_0_irq_handler UARTE0_UART0_IRQHandler
#endif
#if NRFX_CHECK(NRF_LIBUARTE_DRV_UARTE0)
void libuarte_0_irq_handler(void);
#endif
#if NRFX_CHECK(NRF_LIBUARTE_DRV_UARTE1)
void libuarte_1_irq_handler(void);
#endif
#if defined(NRF_LIBUARTE_DRV_HWFC_ENABLED)
#define LIBUARTE_DRV_WITH_HWFC NRF_LIBUARTE_DRV_HWFC_ENABLED
#else
#define LIBUARTE_DRV_WITH_HWFC 1
#endif
#define RTS_PIN_DISABLED 0xff
/** @brief Macro executes given function on every allocated channel in the list between provided
* indexes.
*/
#define PPI_CHANNEL_FOR_M_N(p_libuarte, m, n, func) \
for (int i = m; i < n; i++) \
{ \
if (p_libuarte->ctrl_blk->ppi_channels[i] < PPI_CH_NUM) \
{ func(&p_libuarte->ctrl_blk->ppi_channels[i]); } \
}
/** @brief Macro executes provided function on every allocated PPI channel. */
#define PPI_CHANNEL_FOR_ALL(p_libuarte, func) \
PPI_CHANNEL_FOR_M_N(p_libuarte, 0, NRF_LIBUARTE_DRV_PPI_CH_MAX, func)
/** @brief Macro executes provided function on every allocated group in the list. */
#define PPI_GROUP_FOR_ALL(p_libuarte, func) \
for (int i = 0; i < NRF_LIBUARTE_DRV_PPI_GROUP_MAX; i++) \
{ \
if (p_libuarte->ctrl_blk->ppi_groups[i] < PPI_GROUP_NUM) \
{ func(&p_libuarte->ctrl_blk->ppi_groups[i]); } \
}
/** @brief Allocate and configure PPI channel. Fork is optional and it's not set if NULL.
* Channel parameter is field by the function.
*/
static ret_code_t ppi_channel_configure(nrf_ppi_channel_t * p_ch, uint32_t evt,
uint32_t task, uint32_t fork)
{
nrfx_err_t err;
err = nrfx_ppi_channel_alloc(p_ch);
if (err != NRFX_SUCCESS)
{
return NRF_ERROR_NO_MEM;
}
err = nrfx_ppi_channel_assign(*p_ch, evt, task);
if (err != NRFX_SUCCESS)
{
return NRF_ERROR_INTERNAL;
}
if (fork)
{
err = nrfx_ppi_channel_fork_assign(*p_ch, fork);
if (err != NRFX_SUCCESS)
{
return NRF_ERROR_INTERNAL;
}
}
return NRF_SUCCESS;
}
/** @brief Allocate and configure group with one channel. Fetch addresses of enable/disable tasks.*/
static ret_code_t ppi_group_configure(nrf_ppi_channel_group_t * p_ppi_group, nrf_ppi_channel_t ch,
uint32_t * p_en_task, uint32_t * p_dis_task, bool en)
{
nrfx_err_t err;
err = nrfx_ppi_group_alloc(p_ppi_group);
if (err != NRFX_SUCCESS)
{
return NRF_ERROR_NO_MEM;
}
err = nrfx_ppi_channel_include_in_group(ch, *p_ppi_group);
if (err != NRFX_SUCCESS)
{
return NRF_ERROR_INTERNAL;
}
if (en)
{
err = nrfx_ppi_group_enable(*p_ppi_group);
if (err != NRFX_SUCCESS)
{
return NRF_ERROR_INTERNAL;
}
}
*p_en_task = nrfx_ppi_task_addr_group_enable_get(*p_ppi_group);
*p_dis_task = nrfx_ppi_task_addr_group_disable_get(*p_ppi_group);
return NRF_SUCCESS;
}
/** @brief Disable and free PPI channel. */
static void ppi_ch_free(nrf_ppi_channel_t * p_ch)
{
nrfx_err_t err;
err = nrfx_ppi_channel_disable(*p_ch);
ASSERT(err == NRFX_SUCCESS);
err = nrfx_ppi_channel_free(*p_ch);
ASSERT(err == NRFX_SUCCESS);
*p_ch = (nrf_ppi_channel_t)PPI_CH_NUM;
}
/** @brief Disable and free PPI group. */
static void ppi_group_free(nrf_ppi_channel_group_t * p_group)
{
nrfx_err_t err;
err = nrfx_ppi_group_free(*p_group);
ASSERT(err == NRFX_SUCCESS);
*p_group = (nrf_ppi_channel_group_t)PPI_GROUP_NUM;
}
/** @brief Free all channels. */
static void ppi_free(const nrf_libuarte_drv_t * const p_libuarte)
{
PPI_CHANNEL_FOR_ALL(p_libuarte, ppi_ch_free);
PPI_GROUP_FOR_ALL(p_libuarte, ppi_group_free);
}
/** @brief Enable PPI channel. */
static void ppi_ch_enable(nrf_ppi_channel_t * p_ch)
{
nrfx_err_t err;
err = nrfx_ppi_channel_enable(*p_ch);
ASSERT(err == NRFX_SUCCESS);
}
/** @brief Disable PPI channel. */
static void ppi_ch_disable(nrf_ppi_channel_t * p_ch)
{
nrfx_err_t err;
err = nrfx_ppi_channel_disable(*p_ch);
ASSERT(err == NRFX_SUCCESS);
}
/** @brief Enable PPI channels for RX. */
static void rx_ppi_enable(const nrf_libuarte_drv_t * const p_libuarte)
{
PPI_CHANNEL_FOR_M_N(p_libuarte, 0, NRF_LIBUARTE_DRV_PPI_CH_RX_GROUP_MAX, ppi_ch_enable);
}
/** @brief Disable PPI channels for RX. */
static void rx_ppi_disable(const nrf_libuarte_drv_t * const p_libuarte)
{
PPI_CHANNEL_FOR_M_N(p_libuarte, 0, NRF_LIBUARTE_DRV_PPI_CH_RX_GROUP_MAX, ppi_ch_disable);
}
/** @brief Enable PPI channels for TX. */
static void tx_ppi_enable(const nrf_libuarte_drv_t * const p_libuarte)
{
PPI_CHANNEL_FOR_M_N(p_libuarte, NRF_LIBUARTE_DRV_PPI_CH_RX_GROUP_MAX,
NRF_LIBUARTE_DRV_PPI_CH_MAX, ppi_ch_enable);
}
/** @brief Disable PPI channels for TX. */
static void tx_ppi_disable(const nrf_libuarte_drv_t * const p_libuarte)
{
PPI_CHANNEL_FOR_M_N(p_libuarte, NRF_LIBUARTE_DRV_PPI_CH_RX_GROUP_MAX,
NRF_LIBUARTE_DRV_PPI_CH_MAX, ppi_ch_disable);
}
static ret_code_t ppi_configure(const nrf_libuarte_drv_t * const p_libuarte,
nrf_libuarte_drv_config_t * p_config)
{
ret_code_t ret;
uint32_t gr0_en_task = 0;
uint32_t gr0_dis_task = 0;
uint32_t gr1_en_task = 0;
uint32_t gr1_dis_task = 0;
for (int i = 0; i < NRF_LIBUARTE_DRV_PPI_CH_MAX; i++)
{
/* set to invalid value */
p_libuarte->ctrl_blk->ppi_channels[i] = (nrf_ppi_channel_t)PPI_CH_NUM;
}
for (int i = 0; i < NRF_LIBUARTE_DRV_PPI_GROUP_MAX; i++)
{
/* set to invalid value */
p_libuarte->ctrl_blk->ppi_groups[i] = (nrf_ppi_channel_group_t)PPI_GROUP_NUM;
}
if (MAX_DMA_XFER_LEN < UINT16_MAX)
{
ret = ppi_channel_configure(
&p_libuarte->ctrl_blk->ppi_channels[NRF_LIBUARTE_DRV_PPI_CH_ENDTX_STARTTX],
nrf_uarte_event_address_get(p_libuarte->uarte, NRF_UARTE_EVENT_ENDTX),
nrf_uarte_task_address_get(p_libuarte->uarte, NRF_UARTE_TASK_STARTTX),
0);
if (ret != NRF_SUCCESS)
{
goto complete_config;
}
}
ret = ppi_channel_configure(
&p_libuarte->ctrl_blk->ppi_channels[NRF_LIBUARTE_DRV_PPI_CH_RXRDY_TIMER_COUNT],
nrf_uarte_event_address_get(p_libuarte->uarte, NRF_UARTE_EVENT_RXDRDY),
nrfx_timer_task_address_get(&p_libuarte->timer, NRF_TIMER_TASK_COUNT),
0);
if (ret != NRF_SUCCESS)
{
goto complete_config;
}
ret = ppi_channel_configure(
&p_libuarte->ctrl_blk->ppi_channels[NRF_LIBUARTE_DRV_PPI_CH_ENDRX_STARTRX],
nrf_uarte_event_address_get(p_libuarte->uarte, NRF_UARTE_EVENT_ENDRX),
nrf_uarte_task_address_get(p_libuarte->uarte, NRF_UARTE_TASK_STARTRX),
nrfx_timer_capture_task_address_get(&p_libuarte->timer, 0));
if (ret != NRF_SUCCESS)
{
goto complete_config;
}
if (p_config->endrx_evt && p_config->rxdone_tsk)
{
ret = ppi_channel_configure(
&p_libuarte->ctrl_blk->ppi_channels[NRF_LIBUARTE_DRV_PPI_CH_ENDRX_EXT_TSK],
nrf_uarte_event_address_get(p_libuarte->uarte, NRF_UARTE_EVENT_ENDRX),
nrfx_timer_capture_task_address_get(&p_libuarte->timer, 0),
p_config->rxdone_tsk);
if (ret != NRF_SUCCESS)
{
goto complete_config;
}
ret = ppi_group_configure(&p_libuarte->ctrl_blk->ppi_groups[NRF_LIBUARTE_DRV_PPI_GROUP_ENDRX_STARTRX],
p_libuarte->ctrl_blk->ppi_channels[NRF_LIBUARTE_DRV_PPI_CH_ENDRX_STARTRX],
&gr0_en_task, &gr0_dis_task, true);
if (ret != NRF_SUCCESS)
{
goto complete_config;
}
ret = ppi_group_configure(&p_libuarte->ctrl_blk->ppi_groups[NRF_LIBUARTE_DRV_PPI_GROUP_ENDRX_EXT_RXDONE_TSK],
p_libuarte->ctrl_blk->ppi_channels[NRF_LIBUARTE_DRV_PPI_CH_ENDRX_EXT_TSK],
&gr1_en_task, &gr1_dis_task, false);
if (ret != NRF_SUCCESS)
{
goto complete_config;
}
ret = ppi_channel_configure(
&p_libuarte->ctrl_blk->ppi_channels[NRF_LIBUARTE_DRV_PPI_CH_EXT_STOP_STOPRX],
p_config->endrx_evt,
nrf_uarte_task_address_get(p_libuarte->uarte, NRF_UARTE_TASK_STOPRX),
nrfx_timer_capture_task_address_get(&p_libuarte->timer, 1));
if (ret != NRF_SUCCESS)
{
goto complete_config;
}
ret = ppi_channel_configure(
&p_libuarte->ctrl_blk->ppi_channels[NRF_LIBUARTE_DRV_PPI_CH_EXT_STOP_GROUPS_EN],
p_config->endrx_evt,
gr0_dis_task,
gr1_en_task);
if (ret != NRF_SUCCESS)
{
goto complete_config;
}
}
if (p_config->rxstarted_tsk || gr1_dis_task)
{
ret = ppi_channel_configure(
&p_libuarte->ctrl_blk->ppi_channels[NRF_LIBUARTE_DRV_PPI_CH_RXSTARTED_EXT_TSK],
nrf_uarte_event_address_get(p_libuarte->uarte, NRF_UARTE_EVENT_RXSTARTED),
gr1_dis_task ? gr1_dis_task : p_config->rxstarted_tsk,
gr1_dis_task ? p_config->rxstarted_tsk : 0);
if (ret != NRF_SUCCESS)
{
goto complete_config;
}
}
if (p_config->startrx_evt)
{
ret = ppi_channel_configure(
&p_libuarte->ctrl_blk->ppi_channels[NRF_LIBUARTE_DRV_PPI_CH_EXT_TRIGGER_STARTRX_EN_ENDRX_STARTX],
p_config->startrx_evt,
nrf_uarte_task_address_get(p_libuarte->uarte, NRF_UARTE_TASK_STARTRX),
gr0_en_task);
if (ret != NRF_SUCCESS)
{
goto complete_config;
}
}
if (p_config->endrx_evt)
{
}
if (LIBUARTE_DRV_WITH_HWFC && (p_config->rts_pin != NRF_UARTE_PSEL_DISCONNECTED))
{
ret = ppi_channel_configure(&p_libuarte->ctrl_blk->ppi_channels[NRF_LIBUARTE_DRV_PPI_CH_RTS_PIN],
nrfx_timer_compare_event_address_get(&p_libuarte->timer, 2),
nrfx_gpiote_set_task_addr_get(p_config->rts_pin),
0);
if (ret != NRF_SUCCESS)
{
goto complete_config;
}
}
complete_config:
if (ret == NRF_SUCCESS)
{
return ret;
}
ppi_free(p_libuarte);
return ret;
}
void tmr_evt_handler(nrf_timer_event_t event_type, void * p_context)
{
UNUSED_PARAMETER(event_type);
UNUSED_PARAMETER(p_context);
}
ret_code_t nrf_libuarte_drv_init(const nrf_libuarte_drv_t * const p_libuarte,
nrf_libuarte_drv_config_t * p_config,
nrf_libuarte_drv_evt_handler_t evt_handler,
void * context)
{
ret_code_t ret;
IRQn_Type irqn = nrfx_get_irq_number(p_libuarte->uarte);
if (p_libuarte->ctrl_blk->enabled)
{
return NRF_ERROR_INVALID_STATE;
}
p_libuarte->ctrl_blk->evt_handler = evt_handler;
p_libuarte->ctrl_blk->p_cur_rx = NULL;
p_libuarte->ctrl_blk->p_next_rx = NULL;
p_libuarte->ctrl_blk->p_next_next_rx = NULL;
p_libuarte->ctrl_blk->p_tx = NULL;
p_libuarte->ctrl_blk->context = context;
p_libuarte->ctrl_blk->rts_pin = RTS_PIN_DISABLED;
m_libuarte_instance[p_libuarte->uarte == NRF_UARTE0 ? 0 : 1] = p_libuarte;
//UART init
nrf_gpio_pin_set(p_config->tx_pin);
nrf_gpio_cfg_output(p_config->tx_pin);
nrf_gpio_cfg_input(p_config->rx_pin, p_config->pullup_rx ?
NRF_GPIO_PIN_PULLUP : NRF_GPIO_PIN_NOPULL);
nrf_uarte_baudrate_set(p_libuarte->uarte, p_config->baudrate);
nrf_uarte_configure(p_libuarte->uarte, p_config->parity, p_config->hwfc);
nrf_uarte_txrx_pins_set(p_libuarte->uarte, p_config->tx_pin, p_config->rx_pin);
if (LIBUARTE_DRV_WITH_HWFC && (p_config->hwfc == NRF_UARTE_HWFC_ENABLED))
{
if (p_config->cts_pin != NRF_UARTE_PSEL_DISCONNECTED)
{
nrf_gpio_cfg_input(p_config->cts_pin, NRF_GPIO_PIN_PULLUP);
}
if (p_config->rts_pin != NRF_UARTE_PSEL_DISCONNECTED)
{
nrfx_gpiote_out_config_t out_config = NRFX_GPIOTE_CONFIG_OUT_TASK_TOGGLE(true);
nrfx_err_t err = nrfx_gpiote_init();
if ((err != NRFX_SUCCESS) && (err != NRFX_ERROR_INVALID_STATE))
{
return err;
}
err = nrfx_gpiote_out_init(p_config->rts_pin, &out_config);
if (err != NRFX_SUCCESS)
{
return NRF_ERROR_INTERNAL;
}
nrfx_gpiote_out_task_enable(p_config->rts_pin);
nrf_gpio_cfg_output(p_config->rts_pin);
p_libuarte->ctrl_blk->rts_pin = p_config->rts_pin;
}
nrf_uarte_hwfc_pins_set(p_libuarte->uarte, NRF_UARTE_PSEL_DISCONNECTED, p_config->cts_pin);
}
else if ((p_config->hwfc == NRF_UARTE_HWFC_ENABLED) && !LIBUARTE_DRV_WITH_HWFC)
{
return NRFX_ERROR_INVALID_PARAM;
}
#if NRFX_CHECK(NRFX_PRS_ENABLED) && NRFX_CHECK(NRF_LIBUARTE_DRV_UARTE0)
if (irqn == UARTE0_UART0_IRQn)
{
if (nrfx_prs_acquire(p_libuarte->uarte, libuarte_0_irq_handler) != NRFX_SUCCESS)
{
return NRF_ERROR_BUSY;
}
}
#endif // NRFX_CHECK(NRFX_PRS_ENABLED) && NRFX_CHECK(NRF_LIBUARTE_DRV_UARTE0)
nrf_uarte_int_enable(p_libuarte->uarte, INTERRUPTS_MASK);
NVIC_SetPriority(irqn, p_config->irq_priority);
NVIC_ClearPendingIRQ(irqn);
NVIC_EnableIRQ(irqn);
nrf_uarte_enable(p_libuarte->uarte);
nrfx_timer_config_t tmr_config = NRFX_TIMER_DEFAULT_CONFIG;
tmr_config.mode = NRF_TIMER_MODE_COUNTER;
tmr_config.bit_width = NRF_TIMER_BIT_WIDTH_32;
ret = nrfx_timer_init(&p_libuarte->timer, &tmr_config, tmr_evt_handler);
if (ret != NRFX_SUCCESS)
{
return NRF_ERROR_INTERNAL;
}
ret = ppi_configure(p_libuarte, p_config);
if (ret != NRF_SUCCESS)
{
return NRF_ERROR_INTERNAL;
}
p_libuarte->ctrl_blk->enabled = true;
return NRF_SUCCESS;
}
void nrf_libuarte_drv_uninit(const nrf_libuarte_drv_t * const p_libuarte)
{
IRQn_Type irqn = nrfx_get_irq_number(p_libuarte->uarte);
if (p_libuarte->ctrl_blk->enabled == false)
{
return;
}
p_libuarte->ctrl_blk->enabled = false;
NVIC_DisableIRQ(irqn);
rx_ppi_disable(p_libuarte);
tx_ppi_disable(p_libuarte);
nrf_uarte_int_disable(p_libuarte->uarte, 0xFFFFFFFF);
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_TXSTOPPED);
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_RXTO);
nrf_uarte_task_trigger(p_libuarte->uarte, NRF_UARTE_TASK_STOPTX);
nrf_uarte_task_trigger(p_libuarte->uarte, NRF_UARTE_TASK_STOPRX);
while ( (p_libuarte->ctrl_blk->p_tx && !nrf_uarte_event_check(p_libuarte->uarte, NRF_UARTE_EVENT_TXSTOPPED)) ||
(p_libuarte->ctrl_blk->p_cur_rx && !nrf_uarte_event_check(p_libuarte->uarte, NRF_UARTE_EVENT_RXTO)))
{}
p_libuarte->ctrl_blk->p_tx = NULL;
p_libuarte->ctrl_blk->p_cur_rx = NULL;
nrf_uarte_disable(p_libuarte->uarte);
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_TXSTARTED);
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_TXSTOPPED);
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_ENDTX);
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_ENDRX);
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_RXSTARTED);
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_RXTO);
#if NRFX_CHECK(NRFX_PRS_ENABLED) && NRFX_CHECK(NRF_LIBUARTE_DRV_UARTE0)
if (irqn == UARTE0_UART0_IRQn)
{
nrfx_prs_release(p_libuarte->uarte);
}
#endif // NRFX_CHECK(NRFX_PRS_ENABLED) && NRFX_CHECK(NRF_LIBUARTE_DRV_UARTE0)
nrfx_timer_disable(&p_libuarte->timer);
nrfx_timer_uninit(&p_libuarte->timer);
if (LIBUARTE_DRV_WITH_HWFC && (p_libuarte->ctrl_blk->rts_pin != RTS_PIN_DISABLED))
{
nrfx_gpiote_out_uninit(p_libuarte->ctrl_blk->rts_pin);
}
ppi_free(p_libuarte);
}
ret_code_t nrf_libuarte_drv_tx(const nrf_libuarte_drv_t * const p_libuarte,
uint8_t * p_data, size_t len)
{
if (p_libuarte->ctrl_blk->p_tx)
{
return NRF_ERROR_BUSY;
}
p_libuarte->ctrl_blk->p_tx = p_data;
p_libuarte->ctrl_blk->tx_len = len;
p_libuarte->ctrl_blk->tx_cur_idx = 0;
uint16_t first_chunk;
if ((MAX_DMA_XFER_LEN <= UINT16_MAX) && (len <= MAX_DMA_XFER_LEN))
{
first_chunk = len;
p_libuarte->ctrl_blk->tx_chunk8 = 0;
}
else
{
uint32_t num_of_chunks = CEIL_DIV(len, MAX_DMA_XFER_LEN);
p_libuarte->ctrl_blk->tx_chunk8 = len/num_of_chunks;
first_chunk = p_libuarte->ctrl_blk->tx_chunk8 + len%p_libuarte->ctrl_blk->tx_chunk8;
}
NRF_LOG_WARNING("Started TX total length:%d, first chunk:%d", len, first_chunk);
nrf_uarte_tx_buffer_set(p_libuarte->uarte, p_data, first_chunk);
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_TXSTARTED);
nrf_uarte_task_trigger(p_libuarte->uarte, NRF_UARTE_TASK_STARTTX);
if ((MAX_DMA_XFER_LEN <= UINT16_MAX) && (len > MAX_DMA_XFER_LEN))
{
while(nrf_uarte_event_check(p_libuarte->uarte, NRF_UARTE_EVENT_TXSTARTED) == 0)
{
}
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_TXSTARTED);
tx_ppi_enable(p_libuarte);
nrf_uarte_tx_buffer_set(p_libuarte->uarte, &p_libuarte->ctrl_blk->p_tx[first_chunk], p_libuarte->ctrl_blk->tx_chunk8);
}
return NRF_SUCCESS;
}
ret_code_t nrf_libuarte_drv_rx_start(const nrf_libuarte_drv_t * const p_libuarte,
uint8_t * p_data, size_t len, bool ext_trigger_en)
{
ASSERT(len <= MAX_DMA_XFER_LEN);
if (p_libuarte->ctrl_blk->p_cur_rx)
{
return NRF_ERROR_BUSY;
}
p_libuarte->ctrl_blk->chunk_size = len;
if (p_data)
{
p_libuarte->ctrl_blk->p_cur_rx = p_data;
nrf_uarte_rx_buffer_set(p_libuarte->uarte, p_data, len);
}
/* Reset byte counting */
nrfx_timer_enable(&p_libuarte->timer);
nrfx_timer_clear(&p_libuarte->timer);
p_libuarte->ctrl_blk->last_rx_byte_cnt = 0;
p_libuarte->ctrl_blk->last_pin_rx_byte_cnt = 0;
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_ENDRX);
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_RXSTARTED);
rx_ppi_enable(p_libuarte);
if (LIBUARTE_DRV_WITH_HWFC && (p_libuarte->ctrl_blk->rts_pin != RTS_PIN_DISABLED))
{
uint32_t rx_limit = len - NRF_LIBUARTE_DRV_HWFC_BYTE_LIMIT;
*(uint32_t *)nrfx_gpiote_clr_task_addr_get(p_libuarte->ctrl_blk->rts_pin) = 1;
nrfx_timer_compare(&p_libuarte->timer, NRF_TIMER_CC_CHANNEL2, rx_limit, false);
}
if (!ext_trigger_en)
{
nrf_uarte_task_trigger(p_libuarte->uarte, NRF_UARTE_TASK_STARTRX);
}
NRF_LOG_DEBUG("Start continues RX. Provided buffer:0x%08X", p_data);
return NRF_SUCCESS;
}
void nrf_libuarte_drv_rx_buf_rsp(const nrf_libuarte_drv_t * const p_libuarte,
uint8_t * p_data, size_t len)
{
if (p_libuarte->ctrl_blk->p_next_rx == NULL)
{
p_libuarte->ctrl_blk->p_next_rx = p_data;
NRF_LOG_DEBUG("RX buf response (next). Provided buffer:0x%08X", p_data);
nrf_uarte_rx_buffer_set(p_libuarte->uarte, p_data, len);
}
else
{
NRF_LOG_DEBUG("RX buf response (mp_next_rx not NULL:0x%08X), Provided buffer:0x%08X",
p_libuarte->ctrl_blk->p_next_rx, p_data);
p_libuarte->ctrl_blk->p_next_next_rx = p_data;
}
if (LIBUARTE_DRV_WITH_HWFC && (p_libuarte->ctrl_blk->rts_pin != RTS_PIN_DISABLED))
{
uint32_t rx_limit = nrfx_timer_capture_get(&p_libuarte->timer, NRF_TIMER_CC_CHANNEL0) +
2*len - NRF_LIBUARTE_DRV_HWFC_BYTE_LIMIT;
nrfx_timer_compare(&p_libuarte->timer, NRF_TIMER_CC_CHANNEL2, rx_limit, false);
if (p_libuarte->ctrl_blk->rts_manual == false)
{
*(uint32_t *)nrfx_gpiote_clr_task_addr_get(p_libuarte->ctrl_blk->rts_pin) = 1;
}
}
}
void nrf_libuarte_drv_rx_stop(const nrf_libuarte_drv_t * const p_libuarte)
{
rx_ppi_disable(p_libuarte);
NRF_LOG_DEBUG("RX stopped.");
if (LIBUARTE_DRV_WITH_HWFC && (p_libuarte->ctrl_blk->rts_pin != RTS_PIN_DISABLED))
{
*(uint32_t *)nrfx_gpiote_set_task_addr_get(p_libuarte->ctrl_blk->rts_pin) = 1;
}
p_libuarte->ctrl_blk->p_cur_rx = NULL;
nrf_uarte_task_trigger(p_libuarte->uarte, NRF_UARTE_TASK_STOPRX);
}
void nrf_libuarte_drv_rts_clear(const nrf_libuarte_drv_t * const p_libuarte)
{
if (LIBUARTE_DRV_WITH_HWFC && (p_libuarte->ctrl_blk->rts_pin != RTS_PIN_DISABLED))
{
*(uint32_t *)nrfx_gpiote_clr_task_addr_get(p_libuarte->ctrl_blk->rts_pin) = 1;
p_libuarte->ctrl_blk->rts_manual = false;
}
}
void nrf_libuarte_drv_rts_set(const nrf_libuarte_drv_t * const p_libuarte)
{
if (LIBUARTE_DRV_WITH_HWFC && (p_libuarte->ctrl_blk->rts_pin != RTS_PIN_DISABLED))
{
p_libuarte->ctrl_blk->rts_manual = true;
*(uint32_t *)nrfx_gpiote_set_task_addr_get(p_libuarte->ctrl_blk->rts_pin) = 1;
}
}
static void irq_handler(const nrf_libuarte_drv_t * const p_libuarte)
{
if (nrf_uarte_event_check(p_libuarte->uarte, NRF_UARTE_EVENT_ERROR))
{
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_ERROR);
nrf_libuarte_drv_evt_t evt = {
.type = NRF_LIBUARTE_DRV_EVT_ERROR,
.data = { .errorsrc = nrf_uarte_errorsrc_get_and_clear(p_libuarte->uarte) }
};
p_libuarte->ctrl_blk->evt_handler(p_libuarte->ctrl_blk->context, &evt);
}
if (nrf_uarte_event_check(p_libuarte->uarte, NRF_UARTE_EVENT_RXSTARTED))
{
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_RXSTARTED);
nrf_libuarte_drv_evt_t evt = {
.type = NRF_LIBUARTE_DRV_EVT_RX_BUF_REQ,
};
p_libuarte->ctrl_blk->evt_handler(p_libuarte->ctrl_blk->context, &evt);
}
if (nrf_uarte_event_check(p_libuarte->uarte, NRF_UARTE_EVENT_ENDRX))
{
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_ENDRX);
uint32_t endrx_byte_cnt = nrfx_timer_capture_get(&p_libuarte->timer, NRF_TIMER_CC_CHANNEL0);
uint32_t stop_byte_cnt = nrfx_timer_capture_get(&p_libuarte->timer, NRF_TIMER_CC_CHANNEL1);
uint32_t dma_amount = endrx_byte_cnt - p_libuarte->ctrl_blk->last_rx_byte_cnt;
uint32_t pin_amount = stop_byte_cnt - p_libuarte->ctrl_blk->last_pin_rx_byte_cnt;
NRF_LOG_DEBUG("(evt) RX dma_cnt:%d, endrx_cnt:%d, stop_cnt:%d",
dma_amount,
endrx_byte_cnt,
stop_byte_cnt);
p_libuarte->ctrl_blk->last_rx_byte_cnt = endrx_byte_cnt;
p_libuarte->ctrl_blk->last_pin_rx_byte_cnt = stop_byte_cnt;
if (dma_amount || pin_amount)
{
uint32_t chunk0 = (dma_amount > p_libuarte->ctrl_blk->chunk_size) ?
p_libuarte->ctrl_blk->chunk_size : dma_amount;
uint32_t chunk1 = dma_amount - chunk0;
NRF_LOG_DEBUG("RX END chunk0:%d, chunk1:%d, data[0]=%d %d",
chunk0,
chunk1,
p_libuarte->ctrl_blk->p_cur_rx[0],
p_libuarte->ctrl_blk->p_cur_rx[1]);
nrf_libuarte_drv_evt_t evt = {
.type = NRF_LIBUARTE_DRV_EVT_RX_DATA,
.data = {
.rxtx = {
.p_data = p_libuarte->ctrl_blk->p_cur_rx,
.length = chunk0
}
}
};
p_libuarte->ctrl_blk->p_cur_rx = p_libuarte->ctrl_blk->p_next_rx;
p_libuarte->ctrl_blk->p_next_rx = NULL;
if (p_libuarte->ctrl_blk->p_next_next_rx)
{
p_libuarte->ctrl_blk->p_next_rx = p_libuarte->ctrl_blk->p_next_next_rx;
p_libuarte->ctrl_blk->p_next_next_rx = NULL;
nrf_uarte_rx_buffer_set(p_libuarte->uarte,
p_libuarte->ctrl_blk->p_next_rx,
p_libuarte->ctrl_blk->chunk_size);
}
p_libuarte->ctrl_blk->evt_handler(p_libuarte->ctrl_blk->context, &evt);
if ( chunk1 ||
((dma_amount == p_libuarte->ctrl_blk->chunk_size) && (endrx_byte_cnt == stop_byte_cnt)))
{
NRF_LOG_WARNING("RX END Chunk1:%d", chunk1);
nrf_libuarte_drv_evt_t err_evt = {
.type = NRF_LIBUARTE_DRV_EVT_OVERRUN_ERROR,
.data = {
.overrun_err = {
.overrun_length = chunk1
}
}
};
p_libuarte->ctrl_blk->evt_handler(p_libuarte->ctrl_blk->context, &err_evt);
p_libuarte->ctrl_blk->p_cur_rx = p_libuarte->ctrl_blk->p_next_rx;
p_libuarte->ctrl_blk->p_next_rx = NULL;
}
}
}
if (nrf_uarte_event_check(p_libuarte->uarte, NRF_UARTE_EVENT_TXSTOPPED))
{
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_TXSTOPPED);
nrf_libuarte_drv_evt_t evt = {
.type = NRF_LIBUARTE_DRV_EVT_TX_DONE,
.data = {
.rxtx = {
.p_data = p_libuarte->ctrl_blk->p_tx,
.length = p_libuarte->ctrl_blk->tx_len
}
}
};
p_libuarte->ctrl_blk->p_tx = NULL;
p_libuarte->ctrl_blk->evt_handler(p_libuarte->ctrl_blk->context, &evt);
}
if (nrf_uarte_event_check(p_libuarte->uarte, NRF_UARTE_EVENT_ENDTX))
{
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_ENDTX);
size_t amount = nrf_uarte_tx_amount_get(p_libuarte->uarte);
NRF_LOG_DEBUG("(evt) TX completed (%d)", amount);
p_libuarte->ctrl_blk->tx_cur_idx += amount;
if (p_libuarte->ctrl_blk->tx_cur_idx == p_libuarte->ctrl_blk->tx_len)
{
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_TXSTOPPED);
nrf_uarte_task_trigger(p_libuarte->uarte, NRF_UARTE_TASK_STOPTX);
}
else
{
size_t rem_len = (p_libuarte->ctrl_blk->tx_len - p_libuarte->ctrl_blk->tx_cur_idx);
if ( rem_len <= MAX_DMA_XFER_LEN)
{
tx_ppi_disable(p_libuarte);
}
else
{
uint8_t * p_buffer = &p_libuarte->ctrl_blk->p_tx[
p_libuarte->ctrl_blk->tx_cur_idx +
p_libuarte->ctrl_blk->tx_chunk8];
if (nrf_uarte_event_check(p_libuarte->uarte, NRF_UARTE_EVENT_TXSTARTED) == 0)
{
NRF_LOG_ERROR("Tx not started yet!");
ASSERT(false);
}
nrf_uarte_event_clear(p_libuarte->uarte, NRF_UARTE_EVENT_TXSTARTED);
nrf_uarte_tx_buffer_set(p_libuarte->uarte,
p_buffer,
p_libuarte->ctrl_blk->tx_chunk8);
}
}
}
}
#if NRF_LIBUARTE_DRV_UARTE0
void libuarte_0_irq_handler(void)
{
irq_handler(m_libuarte_instance[0]);
}
#endif
#if NRF_LIBUARTE_DRV_UARTE1
void UARTE1_IRQHandler(void)
{
irq_handler(m_libuarte_instance[1]);
}
#endif

View File

@@ -1,279 +0,0 @@
/**
* Copyright (c) 2018 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF_LIBUARTE_DRV_H
#define NRF_LIBUARTE_DRV_H
#include "sdk_errors.h"
#include "nrf_uarte.h"
#include "nrfx_ppi.h"
#include "nrfx_timer.h"
#include <stdint.h>
#include <stdbool.h>
/**
* @defgroup nrf_libuarte_drv libUARTE driver
* @ingroup app_common
*
* @brief Module for reliable communication over UARTE.
*
* @{
*/
/* Number of bytes available in the buffer when RTS line is set. */
#define NRF_LIBUARTE_DRV_HWFC_BYTE_LIMIT 4
typedef enum
{
NRF_LIBUARTE_DRV_EVT_RX_DATA, ///< Data received.
NRF_LIBUARTE_DRV_EVT_RX_BUF_REQ, ///< Requesting new buffer for receiving data.
NRF_LIBUARTE_DRV_EVT_TX_DONE, ///< Requested TX transfer completed.
NRF_LIBUARTE_DRV_EVT_ERROR, ///< Error reported by the UARTE peripheral.
NRF_LIBUARTE_DRV_EVT_OVERRUN_ERROR ///< Error reported by the driver.
} nrf_libuarte_drv_evt_type_t;
/**
* @brief PPI channels used by libuarte
*/
typedef enum
{
NRF_LIBUARTE_DRV_PPI_CH_EXT_TRIGGER_STARTRX_EN_ENDRX_STARTX,
NRF_LIBUARTE_DRV_PPI_CH_RXSTARTED_EXT_TSK,
NRF_LIBUARTE_DRV_PPI_CH_EXT_STOP_STOPRX,
NRF_LIBUARTE_DRV_PPI_CH_EXT_STOP_GROUPS_EN,
NRF_LIBUARTE_DRV_PPI_CH_RXRDY_TIMER_COUNT,
NRF_LIBUARTE_DRV_PPI_CH_ENDRX_STARTRX,
NRF_LIBUARTE_DRV_PPI_CH_ENDRX_EXT_TSK,
NRF_LIBUARTE_DRV_PPI_CH_RTS_PIN,
NRF_LIBUARTE_DRV_PPI_CH_RX_MAX,
NRF_LIBUARTE_DRV_PPI_CH_RX_GROUP_MAX = NRF_LIBUARTE_DRV_PPI_CH_RX_MAX,
NRF_LIBUARTE_DRV_PPI_CH_ENDTX_STARTTX = NRF_LIBUARTE_DRV_PPI_CH_RX_GROUP_MAX,
NRF_LIBUARTE_DRV_PPI_CH_MAX
} nrf_libuarte_drv_ppi_channel_t;
/**
* @brief PPI groups used by libuarte
*/
typedef enum
{
NRF_LIBUARTE_DRV_PPI_GROUP_ENDRX_STARTRX, ///< Group used for controlling PPI connection between ENDRX and STARTRX
NRF_LIBUARTE_DRV_PPI_GROUP_ENDRX_EXT_RXDONE_TSK, ///< Group used for controlling PPI connection between ENDRX and RXDONE
NRF_LIBUARTE_DRV_PPI_GROUP_MAX
} nrf_libuarte_drv_ppi_group_t;
typedef struct
{
uint8_t * p_data; ///< Pointer to the data to be sent or received.
size_t length; ///< Length of the data.
} nrf_libuarte_drv_data_t;
typedef struct
{
uint32_t overrun_length;
} nrf_libuarte_drv_overrun_err_evt_t;
typedef struct
{
nrf_libuarte_drv_evt_type_t type; ///< Event type.
union {
nrf_libuarte_drv_data_t rxtx; ///< Data provided for transfer completion events.
uint8_t errorsrc; ///< Error source flags.
nrf_libuarte_drv_overrun_err_evt_t overrun_err; ///< SW Error structure.
} data;
} nrf_libuarte_drv_evt_t;
typedef struct {
uint32_t tx_pin; ///< TXD pin number.
uint32_t rx_pin; ///< RXD pin number.
uint32_t cts_pin; ///< CTS pin number.
uint32_t rts_pin; ///< RTS pin number.
uint32_t startrx_evt; ///< Event to trigger STARTRX task in UARTE.
uint32_t endrx_evt; ///< Event to trigger STOPRX task in UARTE.
uint32_t rxstarted_tsk; ///< Task to be triggered when RXSTARTED UARTE event occurs.
uint32_t rxdone_tsk; ///< Task to be triggered when ENDRX UARTE event occurs.
nrf_uarte_hwfc_t hwfc; ///< Flow control configuration.
nrf_uarte_parity_t parity; ///< Parity configuration.
nrf_uarte_baudrate_t baudrate; ///< Baud rate.
uint8_t irq_priority; ///< Interrupt priority.
bool pullup_rx; ///< Pull up on RX pin.
} nrf_libuarte_drv_config_t;
typedef void (*nrf_libuarte_drv_evt_handler_t)(void * context,
nrf_libuarte_drv_evt_t * p_evt);
extern const IRQn_Type libuarte_irqn[];
typedef struct {
nrf_ppi_channel_t ppi_channels[NRF_LIBUARTE_DRV_PPI_CH_MAX];
nrf_ppi_channel_group_t ppi_groups[NRF_LIBUARTE_DRV_PPI_GROUP_MAX];
uint8_t * p_tx;
size_t tx_len;
size_t tx_cur_idx;
uint8_t * p_cur_rx;
uint8_t * p_next_rx;
uint8_t * p_next_next_rx;
nrf_libuarte_drv_evt_handler_t evt_handler;
uint32_t last_rx_byte_cnt;
uint32_t last_pin_rx_byte_cnt;
uint32_t chunk_size;
void * context;
uint16_t tx_chunk8;
uint8_t rts_pin;
bool rts_manual;
bool enabled;
} nrf_libuarte_drv_ctrl_blk_t;
typedef struct {
nrf_libuarte_drv_ctrl_blk_t * ctrl_blk;
nrfx_timer_t timer;
NRF_UARTE_Type * uarte;
} nrf_libuarte_drv_t;
#define NRF_LIBUARTE_DRV_DEFINE(_name, _uarte_idx, _timer_idx) \
STATIC_ASSERT(_uarte_idx < UARTE_COUNT, "UARTE instance not present");\
STATIC_ASSERT(CONCAT_2(NRF_LIBUARTE_DRV_UARTE,_uarte_idx) == 1, "UARTE instance not enabled");\
STATIC_ASSERT(CONCAT_3(NRFX_TIMER,_timer_idx, _ENABLED) == 1, "Timer instance not enabled");\
static nrf_libuarte_drv_ctrl_blk_t CONCAT_2(_name, ctrl_blk); \
static const nrf_libuarte_drv_t _name = { \
.ctrl_blk = &CONCAT_2(_name, ctrl_blk), \
.timer = NRFX_TIMER_INSTANCE(_timer_idx), \
.uarte = CONCAT_2(NRF_UARTE, _uarte_idx),\
}
/**
* @brief Function for initializing the libUARTE library.
*
* @param[in] p_libuarte Pointer to libuarte instance.
* @param[in] p_config Pointer to the structure with initial configuration.
* @param[in] evt_handler Event handler provided by the user. Must not be NULL.
* @param[in] context User context passed in the callback.
*
* @return NRF_SUCCESS when properly initialized. NRF_ERROR_INTERNAL otherwise.
*/
ret_code_t nrf_libuarte_drv_init(const nrf_libuarte_drv_t * const p_libuarte,
nrf_libuarte_drv_config_t * p_config,
nrf_libuarte_drv_evt_handler_t evt_handler, void * context);
/**
* @brief Function for uninitializing the libUARTE library.
*
* @param[in] p_libuarte Pointer to libuarte instance.
*/
void nrf_libuarte_drv_uninit(const nrf_libuarte_drv_t * const p_libuarte);
/**
* @brief Function for sending data over UARTE using EasyDMA.
*
* @param[in] p_libuarte Pointer to libuarte instance.
* @param[in] p_data Pointer to data.
* @param[in] len Number of bytes to send.
*
* @retval NRF_ERROR_BUSY Data is transferring.
* @retval NRF_ERROR_INTERNAL Error during PPI channel configuration.
* @retval NRF_SUCCESS Buffer set for sending.
*/
ret_code_t nrf_libuarte_drv_tx(const nrf_libuarte_drv_t * const p_libuarte,
uint8_t * p_data, size_t len);
/**
* @brief Function for starting receiving data with additional configuration of external
* trigger to start receiving.
*
* @param p_libuarte Pointer to libuarte instance.
* @param p_data Pointer to data.
* @param len Number of bytes to receive. Maximum possible length is
* dependent on the used SoC (see the MAXCNT register
* description in the Product Specification). The library
* checks it with an assertion.
* @param ext_trigger_en True to disable immediate start.
*
* @retval NRF_ERROR_INTERNAL Error during PPI channel configuration.
* @retval NRF_SUCCESS Buffer set for receiving.
*/
ret_code_t nrf_libuarte_drv_rx_start(const nrf_libuarte_drv_t * const p_libuarte,
uint8_t * p_data, size_t len, bool ext_trigger_en);
/**
* @brief Function for setting a buffer for data that will be later received in UARTE.
*
* @param p_libuarte Pointer to libuarte instance.
* @param p_data Pointer to data.
* @param len Number of bytes to receive. Maximum possible length is
* dependent on the used SoC (see the MAXCNT register
* description in the Product Specification). The library
* checks it with an assertion.
*/
void nrf_libuarte_drv_rx_buf_rsp(const nrf_libuarte_drv_t * const p_libuarte,
uint8_t * p_data, size_t len);
/**
* @brief Function for stopping receiving data over UARTE.
*
* @param p_libuarte Pointer to libuarte instance.
*/
void nrf_libuarte_drv_rx_stop(const nrf_libuarte_drv_t * const p_libuarte);
/**
* @brief Function for deasserting RTS to pause the transmission.
*
* Flow control must be enabled.
*
* @param p_libuarte Pointer to libuarte instance.
*/
void nrf_libuarte_drv_rts_clear(const nrf_libuarte_drv_t * const p_libuarte);
/**
* @brief Function for asserting RTS to restart the transmission.
*
* Flow control must be enabled.
*
* @param p_libuarte Pointer to libuarte instance.
*/
void nrf_libuarte_drv_rts_set(const nrf_libuarte_drv_t * const p_libuarte);
/** @} */
#endif //NRF_LIBUARTE_DRV_H

View File

@@ -1,258 +0,0 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sdk_common.h"
#if NRF_MODULE_ENABLED(LOW_POWER_PWM)
#include <string.h>
#include "low_power_pwm.h"
#include "nrf_gpio.h"
#include "app_timer.h"
#include "nrf_assert.h"
/**
* @brief Function for turning on pins.
*
* Sets the pin high state according to active_high parameter.
*
* @param[in] p_pwm_instance Pointer to instance of low-power PWM.
*/
__STATIC_INLINE void pin_on(low_power_pwm_t * p_pwm_instance)
{
if (p_pwm_instance->active_high)
{
nrf_gpio_port_out_set(p_pwm_instance->p_port, p_pwm_instance->bit_mask_toggle);
}
else
{
nrf_gpio_port_out_clear(p_pwm_instance->p_port, p_pwm_instance->bit_mask_toggle);
}
p_pwm_instance->pin_is_on = true;
}
/**
* @brief Function for turning off pins.
*
* Sets the pin low state according to active_high parameter.
*
* @param[in] p_pwm_instance Pointer to instance of low-power PWM.
*/
__STATIC_INLINE void pin_off(low_power_pwm_t * p_pwm_instance)
{
if (p_pwm_instance->active_high)
{
nrf_gpio_port_out_clear(p_pwm_instance->p_port, p_pwm_instance->bit_mask_toggle);
}
else
{
nrf_gpio_port_out_set(p_pwm_instance->p_port, p_pwm_instance->bit_mask_toggle);
}
p_pwm_instance->pin_is_on = false;
}
/**
* @brief Timer event handler for PWM.
*
* @param[in] p_context General purpose pointer. Will be passed to the time-out handler
* when the timer expires.
*
*/
static void pwm_timeout_handler(void * p_context)
{
ret_code_t err_code;
uint8_t duty_cycle;
low_power_pwm_t * p_pwm_instance = (low_power_pwm_t *)p_context;
if (p_pwm_instance->evt_type == LOW_POWER_PWM_EVENT_PERIOD)
{
if (p_pwm_instance->handler)
{
p_pwm_instance->handler(p_pwm_instance);
if (p_pwm_instance->pwm_state != NRFX_DRV_STATE_POWERED_ON)
{
return;
}
}
duty_cycle = p_pwm_instance->duty_cycle;
if (duty_cycle == p_pwm_instance->period) // Process duty cycle 100%
{
pin_on(p_pwm_instance);
p_pwm_instance->timeout_ticks = p_pwm_instance->period + APP_TIMER_MIN_TIMEOUT_TICKS;
}
else if (duty_cycle == 0) // Process duty cycle 0%
{
pin_off(p_pwm_instance);
p_pwm_instance->timeout_ticks = p_pwm_instance->period + APP_TIMER_MIN_TIMEOUT_TICKS;
}
else // Process any other duty cycle than 0 or 100%
{
pin_on(p_pwm_instance);
p_pwm_instance->timeout_ticks = ((duty_cycle * p_pwm_instance->period)>>8) +
APP_TIMER_MIN_TIMEOUT_TICKS;
// setting next state
p_pwm_instance->evt_type = LOW_POWER_PWM_EVENT_DUTY_CYCLE;
}
}
else
{
pin_off(p_pwm_instance);
p_pwm_instance->evt_type = LOW_POWER_PWM_EVENT_PERIOD;
p_pwm_instance->timeout_ticks = (((p_pwm_instance->period - p_pwm_instance->duty_cycle) *
p_pwm_instance->period)>>8) + APP_TIMER_MIN_TIMEOUT_TICKS;
}
if (p_pwm_instance->pwm_state == NRFX_DRV_STATE_POWERED_ON)
{
err_code = app_timer_start(*p_pwm_instance->p_timer_id, p_pwm_instance->timeout_ticks, p_pwm_instance);
APP_ERROR_CHECK(err_code);
}
}
ret_code_t low_power_pwm_init(low_power_pwm_t * p_pwm_instance,
low_power_pwm_config_t const * p_pwm_config,
app_timer_timeout_handler_t handler)
{
ASSERT(p_pwm_instance->pwm_state == NRFX_DRV_STATE_UNINITIALIZED);
ASSERT(p_pwm_config->bit_mask != 0);
ASSERT(p_pwm_config->p_port != NULL);
ASSERT(p_pwm_config->period != 0);
ret_code_t err_code;
uint32_t bit_mask;
uint32_t pin_number = 0;
p_pwm_instance->handler = handler;
bit_mask = p_pwm_config->bit_mask;
p_pwm_instance->active_high = p_pwm_config->active_high;
p_pwm_instance->bit_mask = p_pwm_config->bit_mask;
p_pwm_instance->bit_mask_toggle = p_pwm_config->bit_mask;
p_pwm_instance->p_port = p_pwm_config->p_port;
p_pwm_instance->period = p_pwm_config->period;
p_pwm_instance->p_timer_id = p_pwm_config->p_timer_id;
err_code = app_timer_create(p_pwm_instance->p_timer_id, APP_TIMER_MODE_SINGLE_SHOT, pwm_timeout_handler);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
while (bit_mask)
{
if (bit_mask & 0x1UL)
{
nrf_gpio_cfg_output(pin_number);
}
pin_number++;
bit_mask >>= 1UL;
}
pin_off(p_pwm_instance);
p_pwm_instance->pwm_state = NRFX_DRV_STATE_INITIALIZED;
return NRF_SUCCESS;
}
ret_code_t low_power_pwm_start(low_power_pwm_t * p_pwm_instance,
uint32_t pin_bit_mask)
{
ASSERT(p_pwm_instance->pwm_state != NRFX_DRV_STATE_UNINITIALIZED);
ASSERT(((p_pwm_instance->bit_mask) & pin_bit_mask) != 0x00);
p_pwm_instance->pwm_state = NRFX_DRV_STATE_POWERED_ON;
p_pwm_instance->bit_mask_toggle = pin_bit_mask;
pin_off(p_pwm_instance);
p_pwm_instance->bit_mask |= pin_bit_mask;
p_pwm_instance->evt_type = LOW_POWER_PWM_EVENT_PERIOD;
app_timer_timeout_handler_t handler = p_pwm_instance->handler;
p_pwm_instance->handler = NULL;
pwm_timeout_handler(p_pwm_instance);
p_pwm_instance->handler = handler;
return NRF_SUCCESS;
}
ret_code_t low_power_pwm_stop(low_power_pwm_t * p_pwm_instance)
{
ASSERT(p_pwm_instance->pwm_state == NRFX_DRV_STATE_POWERED_ON);
ret_code_t err_code;
err_code = app_timer_stop(*p_pwm_instance->p_timer_id);
pin_off(p_pwm_instance);
if (err_code != NRF_SUCCESS)
{
return err_code;
}
p_pwm_instance->pwm_state = NRFX_DRV_STATE_INITIALIZED;
return NRF_SUCCESS;
}
ret_code_t low_power_pwm_duty_set(low_power_pwm_t * p_pwm_instance, uint8_t duty_cycle)
{
if ( p_pwm_instance->period < duty_cycle)
{
return NRF_ERROR_INVALID_PARAM;
}
p_pwm_instance->duty_cycle = duty_cycle;
return NRF_SUCCESS;
}
#endif //NRF_MODULE_ENABLED(LOW_POWER_PWM)

View File

@@ -1,209 +0,0 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/** @file
*
* @defgroup low_power_pwm Low-power PWM
* @{
* @ingroup app_common
*
* @brief Module for generating a low-power pulse-width modulated output signal.
*
* This module provides a low-power PWM implementation using app_timers and GPIO.
*
* Each low-power PWM instance utilizes one app_timer. This means it runs on RTC
* and does not require HFCLK to be running. There can be any number of output
* channels per instance.
*/
#ifndef LOW_POWER_PWM_H__
#define LOW_POWER_PWM_H__
#include <nrfx.h>
#include "app_timer.h"
#include "sdk_errors.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Event types.
*/
typedef enum
{
LOW_POWER_PWM_EVENT_PERIOD = 0,
LOW_POWER_PWM_EVENT_DUTY_CYCLE
}low_power_pwm_evt_type_t;
/**@brief Application time-out handler type. */
typedef void (*low_power_pwm_timeout_user)(void * p_context, low_power_pwm_evt_type_t evt_type);
/**
* @brief Structure holding the initialization parameters.
*/
typedef struct
{
bool active_high; /**< Activate negative polarity. */
uint8_t period; /**< Width of the low_power_pwm period. */
NRF_GPIO_Type * p_port; /**< Port used to work on selected mask. */
uint32_t bit_mask; /**< Pins to be initialized. */
app_timer_id_t const * p_timer_id; /**< Pointer to the timer ID of low_power_pwm. */
} low_power_pwm_config_t;
/**
* @name Default settings
* @{
*
* @brief Default parameters for the @ref low_power_pwm_config_t structure.
*
*/
#define LOW_POWER_PWM_CONFIG_ACTIVE_HIGH false
#define LOW_POWER_PWM_CONFIG_PERIOD UINT8_MAX
#define LOW_POWER_PWM_CONFIG_PORT NRF_GPIO
#define LOW_POWER_PWM_CONFIG_BIT_MASK(mask) (mask)
/** @} */
/**
* @brief Low-power PWM default configuration.
*/
#define LOW_POWER_PWM_DEFAULT_CONFIG(mask) \
{ \
.active_high = LOW_POWER_PWM_CONFIG_ACTIVE_HIGH , \
.period = LOW_POWER_PWM_CONFIG_PERIOD , \
.p_port = LOW_POWER_PWM_CONFIG_PORT, \
.bit_mask = LOW_POWER_PWM_CONFIG_BIT_MASK(mask) \
}
/**
* @cond (NODOX)
* @defgroup low_power_pwm_internal Auxiliary internal types declarations
* @brief Module for internal usage inside the library only.
* @details These definitions are available to the user, but they should not
* be accessed directly. Use @ref low_power_pwm_duty_set instead.
* @{
*
*/
/**
* @brief Structure holding parameters of a given low-power PWM instance.
*/
struct low_power_pwm_s
{
bool active_high; /**< Activate negative polarity. */
bool pin_is_on; /**< Indicates the current state of the pin. */
uint8_t period; /**< Width of the low_power_pwm period. */
uint8_t duty_cycle; /**< Width of high pulse. */
nrfx_drv_state_t pwm_state; /**< Indicates the current state of the PWM instance. */
uint32_t bit_mask; /**< Pins to be initialized. */
uint32_t bit_mask_toggle; /**< Pins to be toggled. */
uint32_t timeout_ticks; /**< Value to start the next app_timer. */
low_power_pwm_evt_type_t evt_type; /**< Slope that triggered time-out. */
app_timer_timeout_handler_t handler; /**< User handler to be called in the time-out handler. */
app_timer_id_t const * p_timer_id; /**< Pointer to the timer ID of low_power_pwm. */
NRF_GPIO_Type * p_port; /**< Port used with pin bit mask. */
};
/** @}
* @endcond
*/
/**
* @brief Internal structure holding parameters of a low-power PWM instance.
*/
typedef struct low_power_pwm_s low_power_pwm_t;
/**
* @brief Function for initializing a low-power PWM instance.
*
* @param[in] p_pwm_instance Pointer to the instance to be started.
* @param[in] p_pwm_config Pointer to the configuration structure.
* @param[in] handler User function to be called in case of time-out.
*
* @return Values returned by @ref app_timer_create.
*/
ret_code_t low_power_pwm_init(low_power_pwm_t * p_pwm_instance,
low_power_pwm_config_t const * p_pwm_config,
app_timer_timeout_handler_t handler);
/**
* @brief Function for starting a low-power PWM instance.
*
* @param[in] p_pwm_instance Pointer to the instance to be started.
* @param[in] pins_bit_mask Bit mask of pins to be started.
*
* @return Values returned by @ref app_timer_start.
*/
ret_code_t low_power_pwm_start(low_power_pwm_t * p_pwm_instance,
uint32_t pins_bit_mask);
/**
* @brief Function for stopping a low-power PWM instance.
*
* @param[in] p_pwm_instance Pointer to the instance to be stopped.
*
* @return Values returned by @ref app_timer_stop.
*/
ret_code_t low_power_pwm_stop(low_power_pwm_t * p_pwm_instance);
/**
* @brief Function for setting a new high pulse width for a given instance.
*
* This function can be called from the timer handler.
*
* @param[in] p_pwm_instance Pointer to the instance to be changed.
* @param[in] duty_cycle New high pulse width. 0 means that the pin is always off. 255 means that it is always on.
*
* @retval NRF_SUCCESS If the function completed successfully.
* @retval NRF_ERROR_INVALID_PARAM If the function returned an error because of invalid parameters.
*/
ret_code_t low_power_pwm_duty_set(low_power_pwm_t * p_pwm_instance, uint8_t duty_cycle);
#ifdef __cplusplus
}
#endif
#endif // LOW_POWER_PWM_H__
/** @} */

View File

@@ -1,442 +0,0 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <stdint.h>
#include "nrf.h"
#include "nrf_mpu_lib.h"
#include "app_util_platform.h"
#include "sdk_config.h"
#if NRF_MPU_LIB_CLI_CMDS
#include "nrf_cli.h"
#endif
#define NRF_LOG_MODULE_NAME nrf_mpu_lib
#if NRF_MPU_LIB_CONFIG_LOG_ENABLED
#define NRF_LOG_LEVEL NRF_MPU_LIB_CONFIG_LOG_LEVEL
#define NRF_LOG_INFO_COLOR NRF_MPU_LIB_CONFIG_INFO_COLOR
#define NRF_LOG_DEBUG_COLOR NRF_MPU_LIB_CONFIG_DEBUG_COLOR
#else
#define NRF_LOG_LEVEL 0
#endif
#include "nrf_log.h"
NRF_LOG_MODULE_REGISTER();
// Check module requirements.
STATIC_ASSERT(__MPU_PRESENT);
STATIC_ASSERT(__CORTEX_M == 4);
/**@brief Return the number of unified regions avaiable in MPU. */
__STATIC_INLINE unsigned int nrf_mpu_lib_get_number_of_regions(void)
{
return (MPU->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos;
}
/**@brief Extract human-readable memory type from attributes. */
static const char *nrf_mpu_lib_mem_type(uint32_t attributes)
{
attributes &= MPU_RASR_TEX_Msk | MPU_RASR_C_Msk | MPU_RASR_B_Msk | MPU_RASR_S_Msk;
switch (attributes)
{
case (0x00 << MPU_RASR_TEX_Pos) | (0 << MPU_RASR_C_Pos) | (0 << MPU_RASR_B_Pos) | (0 << MPU_RASR_S_Pos):
case (0x00 << MPU_RASR_TEX_Pos) | (0 << MPU_RASR_C_Pos) | (0 << MPU_RASR_B_Pos) | (1 << MPU_RASR_S_Pos):
return "Strongly-ordered, Shareable";
case (0x00 << MPU_RASR_TEX_Pos) | (0 << MPU_RASR_C_Pos) | (1 << MPU_RASR_B_Pos) | (0 << MPU_RASR_S_Pos):
case (0x00 << MPU_RASR_TEX_Pos) | (0 << MPU_RASR_C_Pos) | (1 << MPU_RASR_B_Pos) | (1 << MPU_RASR_S_Pos):
return "Device, Shareable";
case (0x00 << MPU_RASR_TEX_Pos) | (1 << MPU_RASR_C_Pos) | (0 << MPU_RASR_B_Pos) | (0 << MPU_RASR_S_Pos):
case (0x00 << MPU_RASR_TEX_Pos) | (1 << MPU_RASR_C_Pos) | (1 << MPU_RASR_B_Pos) | (0 << MPU_RASR_S_Pos):
case (0x01 << MPU_RASR_TEX_Pos) | (0 << MPU_RASR_C_Pos) | (0 << MPU_RASR_B_Pos) | (0 << MPU_RASR_S_Pos):
case (0x01 << MPU_RASR_TEX_Pos) | (1 << MPU_RASR_C_Pos) | (1 << MPU_RASR_B_Pos) | (0 << MPU_RASR_S_Pos):
return "Normal";
case (0x00 << MPU_RASR_TEX_Pos) | (1 << MPU_RASR_C_Pos) | (0 << MPU_RASR_B_Pos) | (1 << MPU_RASR_S_Pos):
case (0x00 << MPU_RASR_TEX_Pos) | (1 << MPU_RASR_C_Pos) | (1 << MPU_RASR_B_Pos) | (1 << MPU_RASR_S_Pos):
case (0x01 << MPU_RASR_TEX_Pos) | (0 << MPU_RASR_C_Pos) | (0 << MPU_RASR_B_Pos) | (1 << MPU_RASR_S_Pos):
case (0x01 << MPU_RASR_TEX_Pos) | (1 << MPU_RASR_C_Pos) | (1 << MPU_RASR_B_Pos) | (1 << MPU_RASR_S_Pos):
return "Normal, Shareable";
case (0x02 << MPU_RASR_TEX_Pos) | (0 << MPU_RASR_C_Pos) | (0 << MPU_RASR_B_Pos) | (0 << MPU_RASR_S_Pos):
case (0x02 << MPU_RASR_TEX_Pos) | (0 << MPU_RASR_C_Pos) | (0 << MPU_RASR_B_Pos) | (1 << MPU_RASR_S_Pos):
return "Device";
default:
if (((attributes & MPU_RASR_TEX_Msk) >> MPU_RASR_TEX_Pos) >= 0x04)
{
return (attributes & MPU_RASR_S_Msk) ? "Normal, Shareable" : "Normal";
}
else
{
return "Reserved or Implementation Defined";
}
}
// Not reached.
}
/**@brief Extract human-readable access level from attributes. */
static const char *nrf_mpu_lib_mem_access(uint32_t attributes)
{
switch ((attributes & MPU_RASR_AP_Msk) >> MPU_RASR_AP_Pos)
{
case 0x00:
return "--/--";
case 0x01:
return "RW/--";
case 0x02:
return "RW/RO";
case 0x03:
return "RW/RW";
case 0x04:
return "\?\?/\?\?";
case 0x05:
return "RO/--";
case 0x06:
case 0x07:
return "RO/RO";
default:
return "Unknown";
}
// Not reached.
}
ret_code_t nrf_mpu_lib_init(void)
{
unsigned int i, regions;
// Make sure that MPU uses unified regions. Separate are not supported.
if ((MPU->TYPE & MPU_TYPE_SEPARATE_Msk) >> MPU_TYPE_SEPARATE_Pos)
{
NRF_LOG_ERROR("Non-unified MPU is not supported!");
return NRF_ERROR_NOT_SUPPORTED;
}
// Make sure that we can handle all avaiable regions.
regions = nrf_mpu_lib_get_number_of_regions();
if (regions > ((1 << (8 * sizeof(nrf_mpu_lib_region_t))) - 1))
{
NRF_LOG_ERROR("MPU with %u regions is not supported!", regions);
return NRF_ERROR_NOT_SUPPORTED;
}
// Disable MPU.
MPU->CTRL = 0;
// Clear all regions.
for (i = 0; i < regions; i++)
{
MPU->RNR = i;
MPU->RASR = 0;
MPU->RBAR = 0;
}
/* Enable MPU */
MPU->CTRL = (1 << MPU_CTRL_ENABLE_Pos) |
(1 << MPU_CTRL_PRIVDEFENA_Pos);
// Make sure that configuration changes are active.
__DSB();
NRF_LOG_INFO("MPU Initalized. %u unified regions avaiable.", regions);
return NRF_SUCCESS;
}
ret_code_t nrf_mpu_lib_region_create(nrf_mpu_lib_region_t *p_region,
void *address,
size_t size,
uint32_t attributes)
{
unsigned long addr = (unsigned long)(address);
unsigned int i, regions = nrf_mpu_lib_get_number_of_regions();
// Size must be power of 2, greater than or equal to 32
if ((size & (size - 1)) || (size < 32))
{
NRF_LOG_ERROR("Cannot create MPU region 0x%08X-0x%08X: Region size is not valid!", addr, addr + size - 1);
return NRF_ERROR_INVALID_PARAM;
}
// Region must be aligned to it's size.
if (addr & (size - 1))
{
NRF_LOG_ERROR("Cannot create MPU region 0x%08X-0x%08X: Region alignment is not valid!", addr, addr + size - 1);
return NRF_ERROR_INVALID_PARAM;
}
// Check if attributes are valid.
if (attributes & ~MPU_RASR_ATTRS_Msk)
{
NRF_LOG_ERROR("Cannot create MPU region 0x%08X-0x%08X: Region attributes are not valid!", addr, addr + size - 1);
return NRF_ERROR_INVALID_PARAM;
}
NRF_LOG_DEBUG("MPU region creating (location: 0x%08X-0x%08X)",
addr,
addr + size - 1);
// Create region.
CRITICAL_REGION_ENTER();
for (i = 0; i < regions; i++)
{
MPU->RNR = i;
if (MPU->RASR & MPU_RASR_ENABLE_Msk)
{
continue;
}
MPU->RBAR = addr;
MPU->RASR = attributes |
(1 << MPU_RASR_ENABLE_Pos) |
((31 - __CLZ(size) - 1) << MPU_RASR_SIZE_Pos);
break;
}
CRITICAL_REGION_EXIT();
if (i >= regions)
{
NRF_LOG_ERROR("Cannot create MPU region 0x%08X-0x%08X: No free region found!", addr, addr + size - 1);
return NRF_ERROR_NO_MEM;
}
// Apply changes.
__DSB();
// Save region number;
*p_region = i;
NRF_LOG_DEBUG("MPU region %u created (location: 0x%08X-0x%08X, access: %s, type: %s, flags: %s).",
i,
addr,
addr + size - 1,
(uint32_t)nrf_mpu_lib_mem_access(attributes),
(uint32_t)nrf_mpu_lib_mem_type(attributes),
(uint32_t)((attributes & MPU_RASR_XN_Msk) ? "XN" : "--"));
return NRF_SUCCESS;
}
ret_code_t nrf_mpu_lib_region_destroy(nrf_mpu_lib_region_t region)
{
if (region >= nrf_mpu_lib_get_number_of_regions())
{
NRF_LOG_ERROR("Cannot destroy MPU region %u: Invaid region!", region);
return NRF_ERROR_INVALID_PARAM;
}
CRITICAL_REGION_ENTER();
MPU->RNR = region;
MPU->RASR = 0;
MPU->RBAR = 0;
CRITICAL_REGION_EXIT();
// Apply changes.
__DSB();
NRF_LOG_DEBUG("MPU region %u destroyed.", region);
return NRF_SUCCESS;
}
#if NRF_MPU_LIB_CLI_CMDS
/**@brief Extract human-readable caching policy from attributes. */
static const char *nrf_mpu_lib_mem_caching(uint32_t attributes)
{
static const char *caching[] =
{
"--/--", "WBWA/--", "WT/--", "WB/--",
"--/WBWA", "WBWA/WBWA","WT/WBWA", "WB/WBWA",
"--/WT", "WBWA/WT", "WT/WT", "WB/WT",
"--/WB", "WBWA/WB", "WT/WB", "WB/WB",
};
uint32_t tex = (attributes & MPU_RASR_TEX_Msk) >> MPU_RASR_TEX_Pos;
uint32_t c = (attributes & MPU_RASR_C_Msk) >> MPU_RASR_C_Pos;
uint32_t b = (attributes & MPU_RASR_B_Msk) >> MPU_RASR_B_Pos;
attributes &= MPU_RASR_TEX_Msk | MPU_RASR_C_Msk | MPU_RASR_B_Msk | MPU_RASR_S_Msk;
switch (attributes)
{
case (0x00 << MPU_RASR_TEX_Pos) | (0 << MPU_RASR_C_Pos) | (0 << MPU_RASR_B_Pos) | (0 << MPU_RASR_S_Pos):
case (0x00 << MPU_RASR_TEX_Pos) | (0 << MPU_RASR_C_Pos) | (0 << MPU_RASR_B_Pos) | (1 << MPU_RASR_S_Pos):
case (0x00 << MPU_RASR_TEX_Pos) | (0 << MPU_RASR_C_Pos) | (1 << MPU_RASR_B_Pos) | (0 << MPU_RASR_S_Pos):
case (0x00 << MPU_RASR_TEX_Pos) | (0 << MPU_RASR_C_Pos) | (1 << MPU_RASR_B_Pos) | (1 << MPU_RASR_S_Pos):
case (0x00 << MPU_RASR_TEX_Pos) | (1 << MPU_RASR_C_Pos) | (0 << MPU_RASR_B_Pos) | (1 << MPU_RASR_S_Pos):
case (0x00 << MPU_RASR_TEX_Pos) | (1 << MPU_RASR_C_Pos) | (1 << MPU_RASR_B_Pos) | (1 << MPU_RASR_S_Pos):
case (0x01 << MPU_RASR_TEX_Pos) | (0 << MPU_RASR_C_Pos) | (0 << MPU_RASR_B_Pos) | (0 << MPU_RASR_S_Pos):
case (0x01 << MPU_RASR_TEX_Pos) | (0 << MPU_RASR_C_Pos) | (0 << MPU_RASR_B_Pos) | (1 << MPU_RASR_S_Pos):
case (0x01 << MPU_RASR_TEX_Pos) | (1 << MPU_RASR_C_Pos) | (1 << MPU_RASR_B_Pos) | (1 << MPU_RASR_S_Pos):
case (0x02 << MPU_RASR_TEX_Pos) | (0 << MPU_RASR_C_Pos) | (0 << MPU_RASR_B_Pos) | (0 << MPU_RASR_S_Pos):
case (0x02 << MPU_RASR_TEX_Pos) | (0 << MPU_RASR_C_Pos) | (0 << MPU_RASR_B_Pos) | (1 << MPU_RASR_S_Pos):
return "--/--";
case (0x00 << MPU_RASR_TEX_Pos) | (1 << MPU_RASR_C_Pos) | (0 << MPU_RASR_B_Pos) | (0 << MPU_RASR_S_Pos):
return "WT/WT";
case (0x00 << MPU_RASR_TEX_Pos) | (1 << MPU_RASR_C_Pos) | (1 << MPU_RASR_B_Pos) | (0 << MPU_RASR_S_Pos):
return "WB/WB";
case (0x01 << MPU_RASR_TEX_Pos) | (1 << MPU_RASR_C_Pos) | (1 << MPU_RASR_B_Pos) | (0 << MPU_RASR_S_Pos):
return "WBWA/WBWA";
default:
if (tex >= 0x04)
{
return caching[((tex & 0x03) << 2) | ((c & 0x01) << 1) | (b & 0x01)];
}
break;
}
return "Unknown";
}
/**@brief Implementation of "mpu info" command. */
static void nrf_mpu_lib_cmd_info(nrf_cli_t const *p_cli, size_t argc, char **argv)
{
if (nrf_cli_help_requested(p_cli))
{
nrf_cli_help_print(p_cli, NULL, 0);
return;
}
unsigned int i, regions = nrf_mpu_lib_get_number_of_regions();
nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "MPU State: %s, %u unified regions aviable.\r\n\r\n",
(MPU->CTRL & MPU_CTRL_ENABLE_Msk) ? "Enabled" : "Disabled",
regions);
for (i = 0; i < regions; i++)
{
uint32_t rasr, rbar;
uint32_t size;
CRITICAL_REGION_ENTER();
MPU->RNR = i;
rasr = MPU->RASR;
rbar = MPU->RBAR;
CRITICAL_REGION_EXIT();
if ((rasr & MPU_RASR_ENABLE_Msk) == 0)
{
nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "Region %u: Disabled\r\n", i);
continue;
}
nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "Region %u: Enabled\r\n", i);
size = 1ul << (((rasr & MPU_RASR_SIZE_Msk) >> MPU_RASR_SIZE_Pos) + 1);
nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "\t- Location:\t0x%08X-0x%08X (size: %u bytes)\r\n",
rbar,
rbar + size - 1,
size);
nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "\t- Access:\t%s\r\n", nrf_mpu_lib_mem_access(rasr));
nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "\t- Type:\t\t%s\r\n", nrf_mpu_lib_mem_type(rasr));
nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "\t- Caching:\t%s\r\n", nrf_mpu_lib_mem_caching(rasr));
nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "\t- Flags:\t%s\r\n\r\n", (rasr & MPU_RASR_XN_Msk) ? "XN" : "--");
}
}
/**@brief Implementation of "mpu dump" command. */
static void nrf_mpu_lib_cmd_dump(nrf_cli_t const *p_cli, size_t argc, char **argv)
{
unsigned int i, regions = nrf_mpu_lib_get_number_of_regions();
if (nrf_cli_help_requested(p_cli))
{
nrf_cli_help_print(p_cli, NULL, 0);
return;
}
nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "MPU_TYPE:\t0x%08X\r\n", MPU->TYPE);
nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "MPU_CTRL:\t0x%08X\r\n", MPU->CTRL);
for (i = 0; i < regions; i++)
{
uint32_t rasr, rbar;
CRITICAL_REGION_ENTER();
MPU->RNR = i;
rasr = MPU->RASR;
rbar = MPU->RBAR;
CRITICAL_REGION_EXIT();
nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "\r\nMPU_RBAR[%u]:\t0x%08X\r\n", i, rbar);
nrf_cli_fprintf(p_cli, NRF_CLI_NORMAL, "MPU_RASR[%u]:\t0x%08X\r\n", i, rasr);
}
}
/**@brief Implementation of "mpu" command. */
static void nrf_mpu_lib_cmd_unknown(nrf_cli_t const * p_cli, size_t argc, char **argv)
{
if ((argc == 1) || nrf_cli_help_requested(p_cli))
{
nrf_cli_help_print(p_cli, NULL, 0);
return;
}
nrf_cli_fprintf(p_cli, NRF_CLI_ERROR, "%s: unknown parameter: %s\r\n", argv[0], argv[1]);
}
// Register "mpu" command and it's subcommands in CLI.
NRF_CLI_CREATE_STATIC_SUBCMD_SET(nrf_mpu_lib_commands)
{
NRF_CLI_CMD(dump, NULL, "Dump MPU registers.", nrf_mpu_lib_cmd_dump),
NRF_CLI_CMD(info, NULL, "Print information about MPU state.", nrf_mpu_lib_cmd_info),
NRF_CLI_SUBCMD_SET_END
};
NRF_CLI_CMD_REGISTER(mpu, &nrf_mpu_lib_commands, "Commands for MPU management", nrf_mpu_lib_cmd_unknown);
#endif //NRF_MPU_LIB_CLI_CMDS

View File

@@ -1,94 +0,0 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef __NRF_MPU_LIB_H
#define __NRF_MPU_LIB_H
/**
* @defgroup nrf_mpu_lib MPU (Memory Protection Unit) driver
* @{
* @ingroup app_common
* @brief Functions for controlling MPU.
*/
#include <stdint.h>
#include <stdlib.h>
#include "sdk_errors.h"
#ifdef __cplusplus
extern "C" {
#endif
/**@brief MPU region handle. */
typedef uint8_t nrf_mpu_lib_region_t;
/**@brief Initialize MPU and driver.
*
* @return NRF_SUCCESS on success, otherwise error code.
*/
ret_code_t nrf_mpu_lib_init(void);
/**@brief Create a new MPU region.
*
* @param[out] p_region Region handle.
* @param[in] address Region base address.
* @param[in] size Region size.
* @param[in] attributes Region attributes. See ARM Cortex-M MPU documentation.
*
* @return NRF_SUCCESS on success, otherwise error code.
*/
ret_code_t nrf_mpu_lib_region_create(nrf_mpu_lib_region_t *p_region,
void *address,
size_t size,
uint32_t attributes);
/**@brief Destroy an MPU region.
*
* @param[in] region Region handle.
*
* @return NRF_SUCCESS on success, otherwise error code.
*/
ret_code_t nrf_mpu_lib_region_destroy(nrf_mpu_lib_region_t region);
#ifdef __cplusplus
}
#endif
#endif /* __NRF_MPU_LIB_H */
/** @} */

File diff suppressed because it is too large Load Diff

View File

@@ -1,338 +0,0 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/** @file
*
* @defgroup app_pwm Pulse-width modulation (PWM)
* @{
* @ingroup app_common
*
* @brief Module for generating a pulse-width modulated output signal.
*
* @details This module provides a PWM implementation using timers, GPIOTE, and PPI.
*
* Resource usage:
* - 2 PPI channels per instance + 2 PPI channels per PWM channel.
* - 1 PPI group per instance.
* - 1 GPIOTE channel per PWM channel.
*
* For example, a PWM instance with two channels will consume 2 + 4 PPI channels, 1 PPI group, and 2 GPIOTE channels.
*
* The maximum number of PWM channels per instance is 2.
*/
#ifndef APP_PWM_H__
#define APP_PWM_H__
#include <stdint.h>
#include "sdk_errors.h"
#include "nrf_drv_timer.h"
#include "nrf_drv_ppi.h"
#include "nrf_peripherals.h"
#ifdef __cplusplus
extern "C" {
#endif
#if defined(GPIOTE_FEATURE_SET_PRESENT) && defined(GPIOTE_FEATURE_CLR_PRESENT)
#define GPIOTE_SET_CLEAR_TASKS
#endif
#define APP_PWM_NOPIN 0xFFFFFFFF
/** @brief Number of channels for one timer instance (fixed to 2 due to timer properties).*/
#define APP_PWM_CHANNELS_PER_INSTANCE 2
/**@brief Macro for creating a PWM instance. */
#define APP_PWM_INSTANCE(name, num) \
const nrf_drv_timer_t m_pwm_##name##_timer = NRF_DRV_TIMER_INSTANCE(num); \
app_pwm_cb_t m_pwm_##name##_cb; \
/*lint -e{545}*/ \
const app_pwm_t name = { \
.p_cb = &m_pwm_##name##_cb, \
.p_timer = &m_pwm_##name##_timer, \
}
/**@brief PWM instance default configuration (1 channel). */
#define APP_PWM_DEFAULT_CONFIG_1CH(period_in_us, pin) \
{ \
.pins = {pin, APP_PWM_NOPIN}, \
.pin_polarity = {APP_PWM_POLARITY_ACTIVE_LOW, APP_PWM_POLARITY_ACTIVE_LOW}, \
.num_of_channels = 1, \
.period_us = period_in_us \
}
/**@brief PWM instance default configuration (2 channels). */
#define APP_PWM_DEFAULT_CONFIG_2CH(period_in_us, pin0, pin1) \
{ \
.pins = {pin0, pin1}, \
.pin_polarity = {APP_PWM_POLARITY_ACTIVE_LOW, APP_PWM_POLARITY_ACTIVE_LOW}, \
.num_of_channels = 2, \
.period_us = period_in_us \
}
typedef uint16_t app_pwm_duty_t;
/**
* @brief PWM callback that is executed when a PWM duty change has been completed.
*
* @param[in] pwm_id PWM instance ID.
*/
typedef void (* app_pwm_callback_t)(uint32_t);
/**
* @brief Channel polarity.
*/
typedef enum
{
APP_PWM_POLARITY_ACTIVE_LOW = 0,
APP_PWM_POLARITY_ACTIVE_HIGH = 1
} app_pwm_polarity_t;
/**@brief PWM configuration structure used for initialization. */
typedef struct
{
uint32_t pins[APP_PWM_CHANNELS_PER_INSTANCE]; //!< Pins configured as PWM output.
app_pwm_polarity_t pin_polarity[APP_PWM_CHANNELS_PER_INSTANCE]; //!< Polarity of active state on pin.
uint32_t num_of_channels; //!< Number of channels that can be used.
uint32_t period_us; //!< PWM signal output period to configure (in microseconds).
} app_pwm_config_t;
/**
* @cond (NODOX)
* @defgroup app_pwm_internal Auxiliary internal types declarations
* @{
* @internal
*
* @brief Module for internal usage inside the library only
*
* There are some definitions that must be included in the header file because
* of the way the library is set up. In this way, the are accessible to the user.
* However, any functions and variables defined here may change at any time
* without a warning, so you should not access them directly.
*/
/**
* @brief PWM channel instance
*
* This structure holds all data needed by a single PWM channel.
*/
typedef struct
{
uint32_t gpio_pin; //!< Pin that is used by this PWM channel.
uint32_t pulsewidth; //!< The copy of duty currently set (in ticks).
nrf_ppi_channel_t ppi_channels[2]; //!< PPI channels used by the PWM channel to clear and set the output.
app_pwm_polarity_t polarity; //!< The active state of the pin.
uint8_t initialized; //!< The internal information if the selected channel was initialized.
} app_pwm_channel_cb_t;
/**
* @brief Variable part of PWM instance
*
* This structure holds instance data that may change.
*/
typedef struct
{
app_pwm_channel_cb_t channels_cb[APP_PWM_CHANNELS_PER_INSTANCE]; //!< Channels data
uint32_t period; //!< Selected period in ticks
app_pwm_callback_t p_ready_callback; //!< Callback function called on PWM readiness
#ifdef GPIOTE_SET_CLEAR_TASKS
nrf_ppi_channel_t ppi_channel; //!< PPI channel used temporary while changing duty
#else
nrf_ppi_channel_t ppi_channels[2]; //!< PPI channels used temporary while changing duty
nrf_ppi_channel_group_t ppi_group; //!< PPI group used to synchronize changes on channels
#endif
nrfx_drv_state_t state; //!< Current driver status
} app_pwm_cb_t;
/** @}
* @endcond
*/
/**@brief PWM instance structure. */
typedef struct
{
app_pwm_cb_t *p_cb; //!< Pointer to control block internals.
nrf_drv_timer_t const * const p_timer; //!< Timer used by this PWM instance.
} app_pwm_t;
/**
* @brief Function for checking if the PWM instance is busy updating the duty cycle.
*
* @param[in] p_instance PWM instance.
*
* @retval True If the PWM instance is ready for duty cycle changes.
* @retval False If a change operation is in progress.
*/
bool app_pwm_busy_check(app_pwm_t const * const p_instance);
/**
* @brief Function for initializing a PWM instance.
*
* @param[in] p_instance PWM instance.
* @param[in] p_config Initial configuration.
* @param[in] p_ready_callback Pointer to ready callback function (or NULL to disable).
*
* @retval NRF_SUCCESS If initialization was successful.
* @retval NRF_ERROR_NO_MEM If there were not enough free resources.
* @retval NRF_ERROR_INVALID_PARAM If an invalid configuration structure was passed.
* @retval NRF_ERROR_INVALID_STATE If the timer/PWM is already in use or if initialization failed.
*/
ret_code_t app_pwm_init(app_pwm_t const * const p_instance, app_pwm_config_t const * const p_config,
app_pwm_callback_t p_ready_callback);
/**
* @brief Function for uninitializing a PWM instance and releasing the allocated resources.
*
* @param[in] p_instance PWM instance.
*
* @retval NRF_SUCCESS If uninitialization was successful.
* @retval NRF_ERROR_INVALID_STATE If the given instance was not initialized.
*/
ret_code_t app_pwm_uninit(app_pwm_t const * const p_instance);
/**
* @brief Function for enabling a PWM instance after initialization.
*
* @param[in] p_instance PWM instance.
*/
void app_pwm_enable(app_pwm_t const * const p_instance);
/**
* @brief Function for disabling a PWM instance after initialization.
*
* @param[in] p_instance PWM instance.
*/
void app_pwm_disable(app_pwm_t const * const p_instance);
/**
* @brief Function for setting the PWM channel duty cycle in percents.
*
* A duty cycle change requires one full PWM clock period to finish.
* If another change is attempted for any channel of given instance before
* the current change is complete, the new attempt will result in the error
* NRF_ERROR_BUSY.
*
* @param[in] p_instance PWM instance.
* @param[in] channel Channel number.
* @param[in] duty Duty cycle (0 - 100).
*
* @retval NRF_SUCCESS If the operation was successful.
* @retval NRF_ERROR_BUSY If the PWM is not ready yet.
* @retval NRF_ERROR_INVALID_STATE If the given instance was not initialized.
*
*/
ret_code_t app_pwm_channel_duty_set(app_pwm_t const * const p_instance,
uint8_t channel, app_pwm_duty_t duty);
/**
* @brief Function for retrieving the PWM channel duty cycle in percents.
*
* @param[in] p_instance PWM instance.
* @param[in] channel Channel number.
*
* @return Duty cycle value.
*/
app_pwm_duty_t app_pwm_channel_duty_get(app_pwm_t const * const p_instance, uint8_t channel);
/**
* @name Functions accessing values in ticks
*
* Auxiliary functions that allow to get values in actual timer ticks.
* @{
*/
/**
* @brief Function for setting PWM channel duty cycle in clock ticks.
*
* @note Duty cycle changes require one full PWM clock period to finish.
* Until that, the next change attempt (for any channel of given instance)
* will result in an NRF_ERROR_BUSY error.
*
* @param[in] p_instance PWM instance.
* @param[in] channel Channel number.
* @param[in] ticks Number of PWM clock ticks.
*
* @retval NRF_SUCCESS If the operation was successful.
* @retval NRF_ERROR_BUSY If PWM is not ready yet.
* @retval NRF_ERROR_INVALID_STATE If the given instance was not initialized.
*/
ret_code_t app_pwm_channel_duty_ticks_set(app_pwm_t const * const p_instance,
uint8_t channel,
uint16_t ticks);
/**
* @brief Function for retrieving the PWM channel duty cycle in ticks.
*
* This function retrieves the real, currently set duty cycle in ticks.
* For one full PWM cycle the value might be different than the value set by the last
* @ref app_pwm_channel_duty_ticks_set function call.
*
* @param[in] p_instance PWM instance.
* @param[in] channel Channel number.
*
* @return Number of ticks set for selected channel.
*
*/
uint16_t app_pwm_channel_duty_ticks_get(app_pwm_t const * const p_instance, uint8_t channel);
/**
* @brief Function for returning the number of ticks in a whole cycle.
*
* @param[in] p_instance PWM instance.
*
* @return Number of ticks that corresponds to 100% of the duty cycle.
*/
uint16_t app_pwm_cycle_ticks_get(app_pwm_t const * const p_instance);
/** @} */
#ifdef __cplusplus
}
#endif
#endif
/** @} */

File diff suppressed because it is too large Load Diff

View File

@@ -1,209 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@file
*
* @defgroup app_sdcard SD card library
* @{
* @ingroup app_common
*
* @brief Asynchronous Secure Digital card (SDC) and MultiMedia card (MMC) library.
*/
#ifndef APP_SDCARD_H_
#define APP_SDCARD_H_
#include "app_util_platform.h"
#include "sdk_config.h"
#define SDC_SECTOR_SIZE 512 ///< Size of a single SD card block in bytes.
#define APP_SDCARD_CONFIG(MOSI_PIN, MISO_PIN, SCK_PIN, CS_PIN) { \
.mosi_pin = MOSI_PIN, \
.miso_pin = MISO_PIN, \
.sck_pin = SCK_PIN, \
.cs_pin = CS_PIN \
}
/**
* @brief SDC operation result.
*/
typedef enum {
SDC_SUCCESS = 0, ///< Operation successful.
SDC_ERROR_NOT_RESPONDING, ///< Card is not responding or not present.
SDC_ERROR_TIMEOUT, ///< Card response timeout.
SDC_ERROR_NOT_SUPPORTED, ///< Operation not supported.
SDC_ERROR_COMMUNICATION, ///< Communication error.
SDC_ERROR_DATA, ///< Data read/write error.
SDC_ERROR_INTERNAL, ///< Internal error.
} sdc_result_t;
/**
* @brief SDC event type.
*/
typedef enum {
SDC_EVT_INIT = 0, ///< Initialization procedure.
SDC_EVT_READ, ///< Data read procedure.
SDC_EVT_WRITE ///< Data write procedure.
} sdc_evt_type_t;
/**
* @brief SDC event structure.
*/
typedef struct {
sdc_evt_type_t type; ///< Event type.
sdc_result_t result; ///< Operation result.
} sdc_evt_t;
/**
* @brief SDC type and version.
*/
typedef enum {
SDC_TYPE_UNKNOWN = 0, ///< Unknown / uninitialized card.
SDC_TYPE_MMCV3, ///< MultiMedia card (MMC) version 3.
SDC_TYPE_SDV1, ///< Secure Digital card (SDC) version 1.0.
SDC_TYPE_SDV2 ///< Secure Digital card (SDC) version 2.0.
} sdc_version_t;
/**
* @brief SDC type information structure.
*/
typedef struct {
sdc_version_t version : 3; ///< Card type and version (SD or MMC).
uint8_t sdhc : 1; ///< Standard Capacity or High Capacity card.
} sdc_type_t;
/**
* @brief SDC configuration structure.
*/
typedef struct {
uint8_t mosi_pin; ///< Serial data in (MOSI / DI) pin number.
uint8_t miso_pin; ///< Serial data out (MISO / DO) pin number.
uint8_t sck_pin; ///< Serial clock (SCK) pin number.
uint8_t cs_pin; ///< Chip select (CS) pin number.
} app_sdc_config_t;
/**
* @brief SDC information structure.
*/
typedef struct {
uint32_t num_blocks; ///< Number of available data blocks.
uint16_t block_len; ///< Length (in bytes) of a single data block.
sdc_type_t type; ///< Card type information structure.
} app_sdc_info_t;
/**
* @brief SDC event handler type.
*/
typedef void (*sdc_event_handler_t)(sdc_evt_t const * p_event);
/**
* @brief Function for initializing the card.
*
* @param[in] p_config Pointer to the SDC configuration structure.
* @param[in] event_handler Pointer to the event handler function.
*
* @retval NRF_SUCCESS If initialization process was started succesfully.
* @retval NRF_ERROR_INVALID_STATE If the card is already initialized or the initialization is in progress.
* @retval NRF_ERROR_INVALID_PARAM If invalid parameters were specified.
*/
ret_code_t app_sdc_init(app_sdc_config_t const * const p_config, sdc_event_handler_t event_handler);
/**
* @brief Function for uninitializing the card.
*
* @retval NRF_SUCCESS If card was uninitialized succesfully.
* @retval NRF_ERROR_INVALID_STATE If the card is not initialized.
* @retval NRF_ERROR_BUSY If there is an operation in progress.
*/
ret_code_t app_sdc_uninit(void);
/**
* @brief Function for retrieving the card busy state.
*
* @retval true If there is an operation in progress.
* @retval false If the card is in idle state.
*/
bool app_sdc_busy_check(void);
/**
* @brief Function for reading the data blocks from the card.
*
* @param[out] p_buf Pointer to the data buffer. Must not be null.
* @param[in] block_address Number of the first block to be read.
* @param[in] block_count Number of blocks to read. Must be greater than 0.
*
* @retval NRF_SUCCESS If block read operation was started succesfully.
* @retval NRF_ERROR_INVALID_STATE If the card is not initialized.
* @retval NRF_ERROR_BUSY If there is already an operation active.
* @retval NRF_ERROR_INVALID_PARAM If invalid parameters were specified.
*/
ret_code_t app_sdc_block_read(uint8_t * p_buf, uint32_t block_address, uint16_t block_count);
/**
* @brief Function for writing the data blocks to the card.
*
* @param[out] p_buf Pointer to the data to be written. Must not be null.
* @param[in] block_address Number of the first block to write.
* @param[in] block_count Number of blocks to write. Must be greater than 0.
*
* @retval NRF_SUCCESS If block write operation was started succesfully.
* @retval NRF_ERROR_INVALID_STATE If the card is not initialized.
* @retval NRF_ERROR_BUSY If there is already an operation active.
* @retval NRF_ERROR_INVALID_PARAM If invalid parameters were specified.
*/
ret_code_t app_sdc_block_write(uint8_t const * p_buf, uint32_t block_address, uint16_t block_count);
/**
* @brief Function for retrieving the card information structure.
*
* @return Pointer to the card information structure or NULL if card is not initialized.
*/
app_sdc_info_t const * app_sdc_info_get(void);
#endif //APP_SDC_H_
/** @} */

View File

@@ -1,100 +0,0 @@
/**
* Copyright (c) 2012 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sensorsim.h"
void sensorsim_init(sensorsim_state_t * p_state,
const sensorsim_cfg_t * p_cfg)
{
if (p_cfg->start_at_max)
{
p_state->current_val = p_cfg->max;
p_state->is_increasing = false;
}
else
{
p_state->current_val = p_cfg->min;
p_state->is_increasing = true;
}
}
uint32_t sensorsim_measure(sensorsim_state_t * p_state,
const sensorsim_cfg_t * p_cfg)
{
if (p_state->is_increasing)
{
sensorsim_increment(p_state, p_cfg);
}
else
{
sensorsim_decrement(p_state, p_cfg);
}
return p_state->current_val;
}
void sensorsim_increment(sensorsim_state_t * p_state,
const sensorsim_cfg_t * p_cfg)
{
if (p_cfg->max - p_state->current_val > p_cfg->incr)
{
p_state->current_val += p_cfg->incr;
}
else
{
p_state->current_val = p_cfg->max;
p_state->is_increasing = false;
}
}
void sensorsim_decrement(sensorsim_state_t * p_state,
const sensorsim_cfg_t * p_cfg)
{
if (p_state->current_val - p_cfg->min > p_cfg->incr)
{
p_state->current_val -= p_cfg->incr;
}
else
{
p_state->current_val = p_cfg->min;
p_state->is_increasing = true;
}
}

View File

@@ -1,121 +0,0 @@
/**
* Copyright (c) 2012 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/** @file
*
* @defgroup ble_sdk_lib_sensorsim Sensor Data Simulator
* @{
* @ingroup ble_sdk_lib
* @brief Functions for simulating sensor data.
*
* @details Currently only a triangular waveform simulator is implemented.
*/
#ifndef SENSORSIM_H__
#define SENSORSIM_H__
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/**@brief Triangular waveform sensor simulator configuration. */
typedef struct
{
uint32_t min; /**< Minimum simulated value. */
uint32_t max; /**< Maximum simulated value. */
uint32_t incr; /**< Increment between each measurement. */
bool start_at_max; /**< TRUE is measurement is to start at the maximum value, FALSE if it is to start at the minimum. */
} sensorsim_cfg_t;
/**@brief Triangular waveform sensor simulator state. */
typedef struct
{
uint32_t current_val; /**< Current sensor value. */
bool is_increasing; /**< TRUE if the simulator is in increasing state, FALSE otherwise. */
} sensorsim_state_t;
/**@brief Function for initializing a triangular waveform sensor simulator.
*
* @param[out] p_state Current state of simulator.
* @param[in] p_cfg Simulator configuration.
*/
void sensorsim_init(sensorsim_state_t * p_state,
const sensorsim_cfg_t * p_cfg);
/**@brief Function for generating a simulated sensor measurement using a triangular waveform generator.
*
* @param[in,out] p_state Current state of simulator.
* @param[in] p_cfg Simulator configuration.
*
* @return Simulator output.
*/
uint32_t sensorsim_measure(sensorsim_state_t * p_state,
const sensorsim_cfg_t * p_cfg);
/**@brief Function for incrementing a simulated sensor measurement value.
*
* @param[in,out] p_state Current state of simulator.
* @param[in] p_cfg Simulator configuration.
*
* @return Simulator output.
*/
void sensorsim_increment(sensorsim_state_t * p_state,
const sensorsim_cfg_t * p_cfg);
/**@brief Function for decrementing a simulated sensor measurement value.
*
* @param[in,out] p_state Current state of simulator.
* @param[in] p_cfg Simulator configuration.
*
* @return Simulator output.
*/
void sensorsim_decrement(sensorsim_state_t * p_state,
const sensorsim_cfg_t * p_cfg);
#ifdef __cplusplus
}
#endif
#endif // SENSORSIM_H__
/** @} */

View File

@@ -1,225 +0,0 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <stdlib.h>
#include "sha256.h"
#include "sdk_errors.h"
#include "sdk_common.h"
#define ROTLEFT(a,b) (((a) << (b)) | ((a) >> (32 - (b))))
#define ROTRIGHT(a,b) (((a) >> (b)) | ((a) << (32 - (b))))
#define CH(x,y,z) (((x) & (y)) ^ (~(x) & (z)))
#define MAJ(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
#define EP0(x) (ROTRIGHT(x,2) ^ ROTRIGHT(x,13) ^ ROTRIGHT(x,22))
#define EP1(x) (ROTRIGHT(x,6) ^ ROTRIGHT(x,11) ^ ROTRIGHT(x,25))
#define SIG0(x) (ROTRIGHT(x,7) ^ ROTRIGHT(x,18) ^ ((x) >> 3))
#define SIG1(x) (ROTRIGHT(x,17) ^ ROTRIGHT(x,19) ^ ((x) >> 10))
static const uint32_t k[64] = {
0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,
0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,
0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,
0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,
0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,
0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,
0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,
0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2
};
/**@brief Function for calculating the hash of a 64-byte section of data.
*
* @param[in,out] ctx Hash instance.
* @param[in] data Aray with data to be hashed. Assumed to be 64 bytes long.
*/
void sha256_transform(sha256_context_t *ctx, const uint8_t * data)
{
uint32_t a, b, c, d, e, f, g, h, i, j, t1, t2, m[64];
for (i = 0, j = 0; i < 16; ++i, j += 4)
m[i] = (data[j] << 24) | (data[j + 1] << 16) | (data[j + 2] << 8) | (data[j + 3]);
for ( ; i < 64; ++i)
m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
a = ctx->state[0];
b = ctx->state[1];
c = ctx->state[2];
d = ctx->state[3];
e = ctx->state[4];
f = ctx->state[5];
g = ctx->state[6];
h = ctx->state[7];
for (i = 0; i < 64; ++i) {
t1 = h + EP1(e) + CH(e,f,g) + k[i] + m[i];
t2 = EP0(a) + MAJ(a,b,c);
h = g;
g = f;
f = e;
e = d + t1;
d = c;
c = b;
b = a;
a = t1 + t2;
}
ctx->state[0] += a;
ctx->state[1] += b;
ctx->state[2] += c;
ctx->state[3] += d;
ctx->state[4] += e;
ctx->state[5] += f;
ctx->state[6] += g;
ctx->state[7] += h;
}
ret_code_t sha256_init(sha256_context_t *ctx)
{
VERIFY_PARAM_NOT_NULL(ctx);
ctx->datalen = 0;
ctx->bitlen = 0;
ctx->state[0] = 0x6a09e667;
ctx->state[1] = 0xbb67ae85;
ctx->state[2] = 0x3c6ef372;
ctx->state[3] = 0xa54ff53a;
ctx->state[4] = 0x510e527f;
ctx->state[5] = 0x9b05688c;
ctx->state[6] = 0x1f83d9ab;
ctx->state[7] = 0x5be0cd19;
return NRF_SUCCESS;
}
ret_code_t sha256_update(sha256_context_t *ctx, const uint8_t * data, size_t len)
{
VERIFY_PARAM_NOT_NULL(ctx);
if (((len > 0) && (data == NULL)))
{
return NRF_ERROR_NULL;
}
uint32_t i;
for (i = 0; i < len; ++i) {
ctx->data[ctx->datalen] = data[i];
ctx->datalen++;
if (ctx->datalen == 64) {
sha256_transform(ctx, ctx->data);
ctx->bitlen += 512;
ctx->datalen = 0;
}
}
return NRF_SUCCESS;
}
ret_code_t sha256_final(sha256_context_t *ctx, uint8_t * hash, uint8_t le)
{
uint32_t i;
VERIFY_PARAM_NOT_NULL(ctx);
VERIFY_PARAM_NOT_NULL(hash);
i = ctx->datalen;
// Pad whatever data is left in the buffer.
if (ctx->datalen < 56) {
ctx->data[i++] = 0x80;
while (i < 56)
ctx->data[i++] = 0x00;
}
else {
ctx->data[i++] = 0x80;
while (i < 64)
ctx->data[i++] = 0x00;
sha256_transform(ctx, ctx->data);
memset(ctx->data, 0, 56);
}
// Append to the padding the total message's length in bits and transform.
ctx->bitlen += (uint64_t)ctx->datalen * 8;
ctx->data[63] = ctx->bitlen;
ctx->data[62] = ctx->bitlen >> 8;
ctx->data[61] = ctx->bitlen >> 16;
ctx->data[60] = ctx->bitlen >> 24;
ctx->data[59] = ctx->bitlen >> 32;
ctx->data[58] = ctx->bitlen >> 40;
ctx->data[57] = ctx->bitlen >> 48;
ctx->data[56] = ctx->bitlen >> 56;
sha256_transform(ctx, ctx->data);
if (le)
{
for (i = 0; i < 4; ++i) {
hash[i] = (ctx->state[7] >> (i * 8)) & 0x000000ff;
hash[i + 4] = (ctx->state[6] >> (i * 8)) & 0x000000ff;
hash[i + 8] = (ctx->state[5] >> (i * 8)) & 0x000000ff;
hash[i + 12] = (ctx->state[4] >> (i * 8)) & 0x000000ff;
hash[i + 16] = (ctx->state[3] >> (i * 8)) & 0x000000ff;
hash[i + 20] = (ctx->state[2] >> (i * 8)) & 0x000000ff;
hash[i + 24] = (ctx->state[1] >> (i * 8)) & 0x000000ff;
hash[i + 28] = (ctx->state[0] >> (i * 8)) & 0x000000ff;
}
}
else
{
// Since this implementation uses little endian uint8_t ordering and SHA uses big endian,
// reverse all the uint8_ts when copying the final state to the output hash.
for (i = 0; i < 4; ++i) {
hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0x000000ff;
hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0x000000ff;
hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0x000000ff;
hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0x000000ff;
hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0x000000ff;
hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0x000000ff;
hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0x000000ff;
hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0x000000ff;
}
}
return NRF_SUCCESS;
}

View File

@@ -1,127 +0,0 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/** @file
*
* @defgroup sha256 SHA-256 hash library
* @{
* @ingroup app_common
*
* @brief This module calculates SHA-256 (SHA-2, FIPS-180) hashes.
*
* @details To use this module, first call @ref sha256_init on a @ref sha256_context_t instance. Then call @ref
* sha256_update with the data to be hashed. This step can optionally be done with multiple
* calls to @ref sha256_update, each with a section of the data (in the correct order).
* After all data has been passed to @ref sha256_update, call @ref sha256_final to finalize
* and extract the hash value.
*
* This code is adapted from code by Brad Conte, retrieved from
* https://github.com/B-Con/crypto-algorithms.
*
*/
#ifndef SHA256_H
#define SHA256_H
#include <stdint.h>
#include "sdk_errors.h"
#ifdef __cplusplus
extern "C" {
#endif
/**@brief Current state of a hash operation.
*/
typedef struct {
uint8_t data[64];
uint32_t datalen;
uint64_t bitlen;
uint32_t state[8];
} sha256_context_t;
/**@brief Function for initializing a @ref sha256_context_t instance.
*
* @param[out] ctx Context instance to be initialized.
*
* @retval NRF_SUCCESS If the instance was successfully initialized.
* @retval NRF_ERROR_NULL If the parameter was NULL.
*/
ret_code_t sha256_init(sha256_context_t *ctx);
/**@brief Function for calculating the hash of an array of uint8_t data.
*
* @details This function can be called multiple times in sequence. This is equivalent to calling
* the function once on a concatenation of the data from the different calls.
*
* @param[in,out] ctx Hash instance.
* @param[in] data Data to be hashed.
* @param[in] len Length of the data to be hashed.
*
* @retval NRF_SUCCESS If the data was successfully hashed.
* @retval NRF_ERROR_NULL If the ctx parameter was NULL or the data parameter was NULL, while the len parameter was not zero.
*/
ret_code_t sha256_update(sha256_context_t *ctx, const uint8_t * data, const size_t len);
/**@brief Function for extracting the hash value from a hash instance.
*
* @details This function should be called after all data to be hashed has been passed to the hash
* instance (by one or more calls to @ref sha256_update).
*
* Do not call @ref sha256_update again after @ref sha256_final has been called.
*
* @param[in,out] ctx Hash instance.
* @param[out] hash Array to hold the extracted hash value (assumed to be 32 bytes long).
* @param[in] le Store the hash in little-endian.
*
* @retval NRF_SUCCESS If the has value was successfully extracted.
* @retval NRF_ERROR_NULL If a parameter was NULL.
*/
ret_code_t sha256_final(sha256_context_t *ctx, uint8_t * hash, uint8_t le);
#ifdef __cplusplus
}
#endif
#endif // SHA256_H
/** @} */

View File

@@ -1,191 +0,0 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sdk_common.h"
#if NRF_MODULE_ENABLED(SIMPLE_TIMER)
#include "app_simple_timer.h"
#include "nrf.h"
#include "app_util_platform.h"
#include "app_error.h"
#include "nrf_timer.h"
#include "nrf_drv_timer.h"
/**@brief States of simple timer state machine.
*/
typedef enum
{
SIMPLE_TIMER_STATE_IDLE = 0,
SIMPLE_TIMER_STATE_INITIALIZED,
SIMPLE_TIMER_STATE_STOPPED,
SIMPLE_TIMER_STATE_STARTED
}simple_timer_states_t;
static app_simple_timer_mode_t m_mode; /**< Registered timer mode. */
static app_simple_timer_timeout_handler_t m_timeout_handler = NULL; /**< Registered time-out handler. */
static void * mp_timeout_handler_context = NULL; /**< Registered time-out handler context. */
static simple_timer_states_t m_simple_timer_state = SIMPLE_TIMER_STATE_IDLE; /**< State machine state. */
const nrf_drv_timer_t SIMPLE_TIMER = NRF_DRV_TIMER_INSTANCE(SIMPLE_TIMER_CONFIG_INSTANCE);
/**
* @brief Handler for timer events.
*/
static void app_simple_timer_event_handler(nrf_timer_event_t event_type, void * p_context)
{
switch (event_type)
{
case NRF_TIMER_EVENT_COMPARE0:
if (m_mode == APP_SIMPLE_TIMER_MODE_SINGLE_SHOT)
{
m_simple_timer_state = SIMPLE_TIMER_STATE_STOPPED;
}
//@note: No NULL check required as performed in timer_start(...).
m_timeout_handler(mp_timeout_handler_context);
break;
default:
//Do nothing.
break;
}
}
uint32_t app_simple_timer_init(void)
{
uint32_t err_code = NRF_SUCCESS;
nrf_drv_timer_config_t t_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
t_cfg.mode = NRF_TIMER_MODE_TIMER;
t_cfg.bit_width = NRF_TIMER_BIT_WIDTH_16;
t_cfg.frequency = (nrf_timer_frequency_t)SIMPLE_TIMER_CONFIG_FREQUENCY;
err_code = nrf_drv_timer_init(&SIMPLE_TIMER, &t_cfg, app_simple_timer_event_handler);
if (NRF_SUCCESS == err_code)
{
m_simple_timer_state = SIMPLE_TIMER_STATE_INITIALIZED;
}
return err_code;
}
uint32_t app_simple_timer_start(app_simple_timer_mode_t mode,
app_simple_timer_timeout_handler_t timeout_handler,
uint16_t timeout_ticks,
void * p_context)
{
uint32_t err_code = NRF_SUCCESS;
nrf_timer_short_mask_t timer_short;
VERIFY_PARAM_NOT_NULL(timeout_handler);
if (APP_SIMPLE_TIMER_MODE_REPEATED == mode)
{
timer_short = NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK;
}
else if (APP_SIMPLE_TIMER_MODE_SINGLE_SHOT == mode)
{
timer_short = NRF_TIMER_SHORT_COMPARE0_STOP_MASK;
}
else
{
return NRF_ERROR_INVALID_PARAM;
}
if (SIMPLE_TIMER_STATE_IDLE == m_simple_timer_state)
{
return NRF_ERROR_INVALID_STATE;
}
if (SIMPLE_TIMER_STATE_STARTED == m_simple_timer_state)
{
err_code = app_simple_timer_stop();
APP_ERROR_CHECK(err_code);
}
if (SIMPLE_TIMER_STATE_STOPPED == m_simple_timer_state)
{
nrf_drv_timer_clear(&SIMPLE_TIMER);
}
m_mode = mode;
m_timeout_handler = timeout_handler;
mp_timeout_handler_context = p_context;
nrf_drv_timer_extended_compare(
&SIMPLE_TIMER, NRF_TIMER_CC_CHANNEL0, (uint32_t)timeout_ticks, timer_short, true);
if (m_simple_timer_state == SIMPLE_TIMER_STATE_STOPPED)
{
nrf_drv_timer_resume(&SIMPLE_TIMER);
}
else
{
nrf_drv_timer_enable(&SIMPLE_TIMER);
}
m_simple_timer_state = SIMPLE_TIMER_STATE_STARTED;
return NRF_SUCCESS;
}
uint32_t app_simple_timer_stop(void)
{
if (SIMPLE_TIMER_STATE_STARTED == m_simple_timer_state)
{
nrf_drv_timer_pause(&SIMPLE_TIMER);
m_simple_timer_state = SIMPLE_TIMER_STATE_STOPPED;
}
return NRF_SUCCESS;
}
uint32_t app_simple_timer_uninit(void)
{
uint32_t err_code = NRF_SUCCESS;
if (SIMPLE_TIMER_STATE_IDLE != m_simple_timer_state)
{
nrf_drv_timer_uninit(&SIMPLE_TIMER);
m_simple_timer_state = SIMPLE_TIMER_STATE_IDLE;
}
return err_code;
}
#endif //NRF_MODULE_ENABLED(SIMPLE_TIMER)

View File

@@ -1,132 +0,0 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@file
*
* @defgroup app_simple_timer Simple Timer
* @{
* @ingroup app_common
*
* @brief Simple timer module.
*
* Supported features and limitations:
* - Two modes: single shot mode and repeated mode.
* - No more than one timer can run simultaneously.
* - The timer is hard-coded to use the TIMER1 peripheral and compare channel 0.
*/
#ifndef TIMER_H__
#define TIMER_H__
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**@brief Timer time-out handler type. */
typedef void (*app_simple_timer_timeout_handler_t)(void * p_context);
/**@brief Timer modes. */
typedef enum
{
APP_SIMPLE_TIMER_MODE_SINGLE_SHOT, /**< The timer will expire only once. */
APP_SIMPLE_TIMER_MODE_REPEATED /**< The timer will restart each time it expires. */
} app_simple_timer_mode_t;
/**@brief Function for configuring and setting up the timer hardware.
*
* @note Timer frequency is configured statically.
*
* @retval NRF_SUCCESS If the operation is successful.
* @retval NRF_ERROR_INVALID_STATE If the operation fails because the timer is already initialized.
* @retval NRF_ERROR_INVALID_PARAM If the operation fails because some configuration parameter is
* not valid.
*/
uint32_t app_simple_timer_init(void);
/**@brief Function for starting a timer.
*
* @note If this function is called for a timer that is already running, the currently running
* timer is stopped before starting the new one.
*
* @param[in] mode Timer mode (see @ref app_simple_timer_mode_t).
* @param[in] timeout_handler Function to be executed when the timer expires
* (see @ref app_simple_timer_timeout_handler_t).
* @param[in] timeout_ticks Number of timer ticks to time-out event.
* @param[in] p_context General purpose pointer. Will be passed to the time-out handler
* when the timer expires.
*
* @retval NRF_SUCCESS If the operation is successful.
* @retval NRF_ERROR_INVALID_STATE If the operation fails because @ref app_simple_timer_init has not
* been called and the operation is not allowed in this state.
* @retval NRF_ERROR_NULL If the operation fails because timeout_handler is NULL.
* @retval NRF_ERROR_INVALID_PARAM If the operation fails because "mode" parameter is not valid.
*/
uint32_t app_simple_timer_start(app_simple_timer_mode_t mode,
app_simple_timer_timeout_handler_t timeout_handler,
uint16_t timeout_ticks,
void * p_context);
/**@brief Function for stopping the timer.
*
* @retval NRF_SUCCESS If the operation is successful.
*/
uint32_t app_simple_timer_stop(void);
/**@brief Function for uninitializing the timer. Should be called also when the timer is not used
* anymore to reach lowest power consumption in system.
*
* @note The function switches off the internal core of the timer to reach lowest power consumption
* in system. The startup time from this state may be longer compared to starting the timer
* from the stopped state.
*
* @retval NRF_SUCCESS If the operation is successful.
*/
uint32_t app_simple_timer_uninit(void);
#ifdef __cplusplus
}
#endif
#endif // TIMER_H__
/** @} */

View File

@@ -1,150 +0,0 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sdk_common.h"
#if NRF_MODULE_ENABLED(SLIP)
#include "slip.h"
#include <string.h>
#define SLIP_BYTE_END 0300 /* indicates end of packet */
#define SLIP_BYTE_ESC 0333 /* indicates byte stuffing */
#define SLIP_BYTE_ESC_END 0334 /* ESC ESC_END means END data byte */
#define SLIP_BYTE_ESC_ESC 0335 /* ESC ESC_ESC means ESC data byte */
ret_code_t slip_encode(uint8_t * p_output, uint8_t * p_input, uint32_t input_length, uint32_t * p_output_buffer_length)
{
if (p_output == NULL || p_input == NULL || p_output_buffer_length == NULL)
{
return NRF_ERROR_NULL;
}
*p_output_buffer_length = 0;
uint32_t input_index;
for (input_index = 0; input_index < input_length; input_index++)
{
switch (p_input[input_index])
{
case SLIP_BYTE_END:
p_output[(*p_output_buffer_length)++] = SLIP_BYTE_ESC;
p_output[(*p_output_buffer_length)++] = SLIP_BYTE_ESC_END;
break;
case SLIP_BYTE_ESC:
p_output[(*p_output_buffer_length)++] = SLIP_BYTE_ESC;
p_output[(*p_output_buffer_length)++] = SLIP_BYTE_ESC_ESC;
break;
default:
p_output[(*p_output_buffer_length)++] = p_input[input_index];
}
}
p_output[(*p_output_buffer_length)++] = SLIP_BYTE_END;
return NRF_SUCCESS;
}
ret_code_t slip_decode_add_byte(slip_t * p_slip, uint8_t c)
{
if (p_slip == NULL)
{
return NRF_ERROR_NULL;
}
if (p_slip->current_index == p_slip->buffer_len)
{
return NRF_ERROR_NO_MEM;
}
switch (p_slip->state)
{
case SLIP_STATE_DECODING:
switch (c)
{
case SLIP_BYTE_END:
// finished reading packet
return NRF_SUCCESS;
case SLIP_BYTE_ESC:
// wait for
p_slip->state = SLIP_STATE_ESC_RECEIVED;
break;
default:
// add byte to buffer
p_slip->p_buffer[p_slip->current_index++] = c;
break;
}
break;
case SLIP_STATE_ESC_RECEIVED:
switch (c)
{
case SLIP_BYTE_ESC_END:
p_slip->p_buffer[p_slip->current_index++] = SLIP_BYTE_END;
p_slip->state = SLIP_STATE_DECODING;
break;
case SLIP_BYTE_ESC_ESC:
p_slip->p_buffer[p_slip->current_index++] = SLIP_BYTE_ESC;
p_slip->state = SLIP_STATE_DECODING;
break;
default:
// protocol violation
p_slip->state = SLIP_STATE_CLEARING_INVALID_PACKET;
return NRF_ERROR_INVALID_DATA;
}
break;
case SLIP_STATE_CLEARING_INVALID_PACKET:
if (c == SLIP_BYTE_END)
{
p_slip->state = SLIP_STATE_DECODING;
p_slip->current_index = 0;
}
break;
}
return NRF_ERROR_BUSY;
}
#endif //NRF_MODULE_ENABLED(SLIP)

View File

@@ -1,117 +0,0 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef SLIP_H__
#define SLIP_H__
#include <stdint.h>
#include "sdk_errors.h"
#ifdef __cplusplus
extern "C" {
#endif
/** @file
*
* @defgroup slip SLIP encoding and decoding
* @{
* @ingroup app_common
*
* @brief This module encodes and decodes SLIP packages.
*
* @details The SLIP protocol is described in @linkSLIP.
*/
/** @brief Status information that is used while receiving and decoding a packet. */
typedef enum
{
SLIP_STATE_DECODING, //!< Ready to receive the next byte.
SLIP_STATE_ESC_RECEIVED, //!< An ESC byte has been received and the next byte must be decoded differently.
SLIP_STATE_CLEARING_INVALID_PACKET //!< The received data is invalid and transfer must be restarted.
} slip_read_state_t;
/** @brief Representation of a SLIP packet. */
typedef struct
{
slip_read_state_t state; //!< Current state of the packet (see @ref slip_read_state_t).
uint8_t * p_buffer; //!< Decoded data.
uint32_t current_index; //!< Current length of the packet that has been received.
uint32_t buffer_len; //!< Size of the buffer that is available.
} slip_t;
/**@brief Function for encoding a SLIP packet.
*
* The maximum size of the output data is (2*input size + 1) bytes. Ensure that the provided buffer is large enough.
*
* @param[in,out] p_output The buffer where the encoded SLIP packet is stored. Ensure that it is large enough.
* @param[in,out] p_input The buffer to be encoded.
* @param[in,out] input_length The length of the input buffer.
* @param[out] p_output_buffer_length The length of the output buffer after the input has been encoded.
*
* @retval NRF_SUCCESS If the input was successfully encoded into output.
* @retval NRF_ERROR_NULL If one of the provided parameters is NULL.
*/
ret_code_t slip_encode(uint8_t * p_output, uint8_t * p_input, uint32_t input_length, uint32_t * p_output_buffer_length);
/**@brief Function for decoding a SLIP packet.
*
* The decoded packet is put into @p p_slip::p_buffer. The index and buffer state is updated.
*
* Ensure that @p p_slip is properly initialized. The initial state must be set to @ref SLIP_STATE_DECODING.
*
* @param[in,out] p_slip State of the decoding process.
* @param[in] c Byte to decode.
*
* @retval NRF_SUCCESS If a packet has been parsed. The received packet can be retrieved from @p p_slip.
* @retval NRF_ERROR_NULL If @p p_slip is NULL.
* @retval NRF_ERROR_NO_MEM If there is no more room in the buffer provided by @p p_slip.
* @retval NRF_ERROR_BUSY If the packet has not been parsed completely yet.
* @retval NRF_ERROR_INVALID_DATA If the packet is encoded wrong. In this case, @p p_slip::state is set to @ref SLIP_STATE_CLEARING_INVALID_PACKET,
* and decoding will stay in this state until the END byte is received.
*/
ret_code_t slip_decode_add_byte(slip_t * p_slip, uint8_t c);
#ifdef __cplusplus
}
#endif
#endif // SLIP_H__
/** @} */

View File

@@ -1,348 +0,0 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sdk_common.h"
#if NRF_MODULE_ENABLED(NRF_SPI_MNGR)
#include "nrf_spi_mngr.h"
#include "nrf_assert.h"
#include "app_util_platform.h"
typedef volatile struct
{
bool transaction_in_progress;
uint8_t transaction_result;
} nrf_spi_mngr_cb_data_t;
static ret_code_t start_transfer(nrf_spi_mngr_t const * p_nrf_spi_mngr)
{
ASSERT(p_nrf_spi_mngr != NULL);
// use a local variable to avoid using two volatile variables in one
// expression
uint8_t curr_transfer_idx = p_nrf_spi_mngr->p_nrf_spi_mngr_cb->current_transfer_idx;
nrf_spi_mngr_transfer_t const * p_transfer =
&p_nrf_spi_mngr->p_nrf_spi_mngr_cb->p_current_transaction->p_transfers[curr_transfer_idx];
return nrf_drv_spi_transfer(&p_nrf_spi_mngr->spi,
p_transfer->p_tx_data, p_transfer->tx_length,
p_transfer->p_rx_data, p_transfer->rx_length);
}
static void transaction_begin_signal(nrf_spi_mngr_t const * p_nrf_spi_mngr)
{
ASSERT(p_nrf_spi_mngr != NULL);
nrf_spi_mngr_transaction_t const * p_current_transaction =
p_nrf_spi_mngr->p_nrf_spi_mngr_cb->p_current_transaction;
if (p_current_transaction->begin_callback != NULL)
{
void * p_user_data = p_current_transaction->p_user_data;
p_current_transaction->begin_callback(p_user_data);
}
}
static void transaction_end_signal(nrf_spi_mngr_t const * p_nrf_spi_mngr,
ret_code_t result)
{
ASSERT(p_nrf_spi_mngr != NULL);
nrf_spi_mngr_transaction_t const * p_current_transaction =
p_nrf_spi_mngr->p_nrf_spi_mngr_cb->p_current_transaction;
if (p_current_transaction->end_callback != NULL)
{
void * p_user_data = p_current_transaction->p_user_data;
p_current_transaction->end_callback(result, p_user_data);
}
}
static void spi_event_handler(nrf_drv_spi_evt_t const * p_event,
void * p_context);
// This function starts pending transaction if there is no current one or
// when 'switch_transaction' parameter is set to true. It is important to
// switch to new transaction without setting 'p_nrf_spi_mngr->p_curr_transaction'
// to NULL in between, since this pointer is used to check idle status - see
// 'nrf_spi_mngr_is_idle()'.
static void start_pending_transaction(nrf_spi_mngr_t const * p_nrf_spi_mngr,
bool switch_transaction)
{
ASSERT(p_nrf_spi_mngr != NULL);
while (1)
{
bool start_transaction = false;
nrf_spi_mngr_cb_t * p_cb = p_nrf_spi_mngr->p_nrf_spi_mngr_cb;
CRITICAL_REGION_ENTER();
if (switch_transaction || nrf_spi_mngr_is_idle(p_nrf_spi_mngr))
{
if (nrf_queue_pop(p_nrf_spi_mngr->p_queue,
(void *)(&p_cb->p_current_transaction))
== NRF_SUCCESS)
{
start_transaction = true;
}
else
{
p_cb->p_current_transaction = NULL;
}
}
CRITICAL_REGION_EXIT();
if (!start_transaction)
{
return;
}
nrf_drv_spi_config_t const * p_instance_cfg;
if (p_cb->p_current_transaction->p_required_spi_cfg == NULL)
{
p_instance_cfg = &p_cb->default_configuration;
}
else
{
p_instance_cfg = p_cb->p_current_transaction->p_required_spi_cfg;
}
ret_code_t result;
if (memcmp(p_cb->p_current_configuration, p_instance_cfg, sizeof(*p_instance_cfg)) != 0)
{
nrf_drv_spi_uninit(&p_nrf_spi_mngr->spi);
result = nrf_drv_spi_init(&p_nrf_spi_mngr->spi,
p_instance_cfg,
spi_event_handler,
(void *)p_nrf_spi_mngr);
ASSERT(result == NRF_SUCCESS);
p_cb->p_current_configuration = p_instance_cfg;
}
// Try to start first transfer for this new transaction.
p_cb->current_transfer_idx = 0;
// Execute user code if available before starting transaction
transaction_begin_signal(p_nrf_spi_mngr);
result = start_transfer(p_nrf_spi_mngr);
// If transaction started successfully there is nothing more to do here now.
if (result == NRF_SUCCESS)
{
return;
}
// Transfer failed to start - notify user that this transaction
// cannot be started and try with next one (in next iteration of
// the loop).
transaction_end_signal(p_nrf_spi_mngr, result);
switch_transaction = true;
}
}
// This function shall be called to handle SPI events. It shall be mainly used by SPI IRQ for
// finished tranfer.
static void spi_event_handler(nrf_drv_spi_evt_t const * p_event,
void * p_context)
{
ASSERT(p_event != NULL);
ASSERT(p_context != NULL);
ret_code_t result;
nrf_spi_mngr_cb_t * p_cb = ((nrf_spi_mngr_t const *)p_context)->p_nrf_spi_mngr_cb;
// This callback should be called only during transaction.
ASSERT(p_cb->p_current_transaction != NULL);
if (p_event->type == NRF_DRV_SPI_EVENT_DONE)
{
result = NRF_SUCCESS;
// Transfer finished successfully. If there is another one to be
// performed in the current transaction, start it now.
// use a local variable to avoid using two volatile variables in one
// expression
uint8_t curr_transfer_idx = p_cb->current_transfer_idx;
++curr_transfer_idx;
if (curr_transfer_idx < p_cb->p_current_transaction->number_of_transfers)
{
p_cb->current_transfer_idx = curr_transfer_idx;
result = start_transfer(((nrf_spi_mngr_t const *)p_context));
if (result == NRF_SUCCESS)
{
// The current transaction is running and its next transfer
// has been successfully started. There is nothing more to do.
return;
}
// if the next transfer could not be started due to some error
// we finish the transaction with this error code as the result
}
}
else
{
result = NRF_ERROR_INTERNAL;
}
// The current transaction has been completed or interrupted by some error.
// Notify the user and start next one (if there is any).
transaction_end_signal(((nrf_spi_mngr_t const *)p_context), result);
// we switch transactions here ('p_nrf_spi_mngr->p_current_transaction' is set
// to NULL only if there is nothing more to do) in order to not generate
// spurious idle status (even for a moment)
start_pending_transaction(((nrf_spi_mngr_t const *)p_context), true);
}
ret_code_t nrf_spi_mngr_init(nrf_spi_mngr_t const * p_nrf_spi_mngr,
nrf_drv_spi_config_t const * p_default_spi_config)
{
ASSERT(p_nrf_spi_mngr != NULL);
ASSERT(p_nrf_spi_mngr->p_queue != NULL);
ASSERT(p_nrf_spi_mngr->p_queue->size > 0);
ASSERT(p_default_spi_config != NULL);
ret_code_t err_code;
err_code = nrf_drv_spi_init(&p_nrf_spi_mngr->spi,
p_default_spi_config,
spi_event_handler,
(void *)p_nrf_spi_mngr);
if (err_code == NRF_SUCCESS)
{
nrf_spi_mngr_cb_t * p_cb = p_nrf_spi_mngr->p_nrf_spi_mngr_cb;
p_cb->p_current_transaction = NULL;
p_cb->default_configuration = *p_default_spi_config;
p_cb->p_current_configuration = &p_cb->default_configuration;
}
return err_code;
}
void nrf_spi_mngr_uninit(nrf_spi_mngr_t const * p_nrf_spi_mngr)
{
ASSERT(p_nrf_spi_mngr != NULL);
nrf_drv_spi_uninit(&p_nrf_spi_mngr->spi);
p_nrf_spi_mngr->p_nrf_spi_mngr_cb->p_current_transaction = NULL;
}
ret_code_t nrf_spi_mngr_schedule(nrf_spi_mngr_t const * p_nrf_spi_mngr,
nrf_spi_mngr_transaction_t const * p_transaction)
{
ASSERT(p_nrf_spi_mngr != NULL);
ASSERT(p_transaction != NULL);
ASSERT(p_transaction->p_transfers != NULL);
ASSERT(p_transaction->number_of_transfers != 0);
ret_code_t result = nrf_queue_push(p_nrf_spi_mngr->p_queue, (void *)(&p_transaction));
if (result == NRF_SUCCESS)
{
// New transaction has been successfully added to queue,
// so if we are currently idle it's time to start the job.
start_pending_transaction(p_nrf_spi_mngr, false);
}
return result;
}
static void spi_internal_transaction_cb(ret_code_t result, void * p_user_data)
{
nrf_spi_mngr_cb_data_t * p_cb_data = (nrf_spi_mngr_cb_data_t *)p_user_data;
p_cb_data->transaction_result = result;
p_cb_data->transaction_in_progress = false;
}
ret_code_t nrf_spi_mngr_perform(nrf_spi_mngr_t const * p_nrf_spi_mngr,
nrf_drv_spi_config_t const * p_config,
nrf_spi_mngr_transfer_t const * p_transfers,
uint8_t number_of_transfers,
void (* user_function)(void))
{
ASSERT(p_nrf_spi_mngr != NULL);
ASSERT(p_transfers != NULL);
ASSERT(number_of_transfers != 0);
nrf_spi_mngr_cb_data_t cb_data =
{
.transaction_in_progress = true
};
nrf_spi_mngr_transaction_t internal_transaction =
{
.begin_callback = NULL,
.end_callback = spi_internal_transaction_cb,
.p_user_data = (void *)&cb_data,
.p_transfers = p_transfers,
.number_of_transfers = number_of_transfers,
.p_required_spi_cfg = p_config
};
ret_code_t result = nrf_spi_mngr_schedule(p_nrf_spi_mngr, &internal_transaction);
VERIFY_SUCCESS(result);
while (cb_data.transaction_in_progress)
{
if (user_function)
{
user_function();
}
}
return cb_data.transaction_result;
}
#endif //NRF_MODULE_ENABLED(NRF_SPI_MNGR)

View File

@@ -1,310 +0,0 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF_SPI_MNGR_H__
#define NRF_SPI_MNGR_H__
#include <stdint.h>
#include "nrf_drv_spi.h"
#include "sdk_errors.h"
#include "nrf_queue.h"
#ifdef __cplusplus
extern "C" {
#endif
/*lint -save -e491*/
#ifndef NRF_SPI_MNGR_BUFFERS_IN_RAM
#define NRF_SPI_MNGR_BUFFERS_IN_RAM defined(SPIM_PRESENT)
#endif
#if NRF_SPI_MNGR_BUFFERS_IN_RAM
#define NRF_SPI_MNGR_BUFFER_LOC_IND
#else
#define NRF_SPI_MNGR_BUFFER_LOC_IND const
#endif
/*lint -restore*/
/**
* @defgroup nrf_spi_mngr SPI transaction manager
* @{
* @ingroup app_common
*
* @brief Module for scheduling SPI transactions.
*/
/**
* @brief Macro for creating a simple SPI transfer.
*
* @param[in] _p_tx_data Pointer to the data to be sent.
* @param[in] _tx_length Number of bytes to send.
* @param[in] _p_rx_data Pointer to a buffer for received data.
* @param[in] _rx_length Number of bytes to receive.
*/
#define NRF_SPI_MNGR_TRANSFER(_p_tx_data, _tx_length, _p_rx_data, _rx_length) \
{ \
.p_tx_data = (uint8_t const *)_p_tx_data, \
.tx_length = (uint8_t) _tx_length, \
.p_rx_data = (uint8_t *) _p_rx_data, \
.rx_length = (uint8_t) _rx_length, \
}
/**
* @brief SPI transaction end callback prototype.
*
* @param result Result of operation (NRF_SUCCESS on success,
* otherwise a relevant error code).
* @param[in] p_user_data Pointer to user data defined in transaction
* descriptor.
*/
typedef void (* nrf_spi_mngr_callback_end_t)(ret_code_t result, void * p_user_data);
/**
* @brief SPI transaction begin callback prototype.
*
* @param[in] p_user_data Pointer to user data defined in transaction
* descriptor.
*/
typedef void (* nrf_spi_mngr_callback_begin_t)(void * p_user_data);
/**
* @brief SPI transfer descriptor.
*/
typedef struct
{
uint8_t const * p_tx_data; ///< Pointer to the data to be sent.
uint8_t tx_length; ///< Number of bytes to send.
uint8_t * p_rx_data; ///< Pointer to a buffer for received data.
uint8_t rx_length; ///< Number of bytes to receive.
} nrf_spi_mngr_transfer_t;
/**
* @brief SPI transaction descriptor.
*/
typedef struct
{
nrf_spi_mngr_callback_begin_t begin_callback;
///< User-specified function to be called before the transaction is started.
nrf_spi_mngr_callback_end_t end_callback;
///< User-specified function to be called after the transaction is finished.
void * p_user_data;
///< Pointer to user data to be passed to the end_callback.
nrf_spi_mngr_transfer_t const * p_transfers;
///< Pointer to the array of transfers that make up the transaction.
uint8_t number_of_transfers;
///< Number of transfers that make up the transaction.
nrf_drv_spi_config_t const * p_required_spi_cfg;
///< Pointer to instance hardware configuration.
} nrf_spi_mngr_transaction_t;
/**
* @brief SPI instance control block.
*/
typedef struct
{
nrf_spi_mngr_transaction_t const * volatile p_current_transaction;
///< Currently realized transaction.
nrf_drv_spi_config_t default_configuration;
///< Default hardware configuration.
nrf_drv_spi_config_t const * p_current_configuration;
///< Pointer to current hardware configuration.
uint8_t volatile current_transfer_idx;
///< Index of currently performed transfer (within current transaction).
} nrf_spi_mngr_cb_t;
/**
* @brief SPI transaction manager instance.
*/
typedef struct
{
nrf_spi_mngr_cb_t * p_nrf_spi_mngr_cb;
///< Control block of instance.
nrf_queue_t const * p_queue;
///< Transaction queue.
nrf_drv_spi_t spi;
///< Pointer to SPI master driver instance.
} nrf_spi_mngr_t;
/**
* @brief Macro for simplifying the defining of an SPI transaction manager
* instance.
*
* This macro allocates a static buffer for the transaction queue.
* Therefore, it should be used in only one place in the code for a given
* instance.
*
* @note The queue size is the maximum number of pending transactions
* not counting the one that is currently realized. This means that
* for an empty queue with size of for example 4 elements, it is
* possible to schedule up to 5 transactions.
*
* @param[in] _nrf_spi_mngr_name Name of instance to be created.
* @param[in] _queue_size Size of the transaction queue (maximum number
* of pending transactions).
* @param[in] _spi_idx Index of hardware SPI instance to be used.
*/
#define NRF_SPI_MNGR_DEF(_nrf_spi_mngr_name, _queue_size, _spi_idx) \
NRF_QUEUE_DEF(nrf_spi_mngr_transaction_t const *, \
_nrf_spi_mngr_name##_queue, \
(_queue_size), \
NRF_QUEUE_MODE_NO_OVERFLOW); \
static nrf_spi_mngr_cb_t CONCAT_2(_nrf_spi_mngr_name, _cb); \
static const nrf_spi_mngr_t _nrf_spi_mngr_name = \
{ \
.p_nrf_spi_mngr_cb = &CONCAT_2(_nrf_spi_mngr_name, _cb), \
.p_queue = &_nrf_spi_mngr_name##_queue, \
.spi = NRF_DRV_SPI_INSTANCE(_spi_idx) \
}
/**
* @brief Function for initializing an SPI transaction manager instance.
*
* @param[in] p_nrf_spi_mngr Pointer to the instance to be initialized.
* @param[in] p_default_spi_config Pointer to the SPI driver configuration. This configuration
* will be used whenever the scheduled transaction will have
* p_spi_config set to NULL value.
*
* @return Values returned by the @ref nrf_drv_spi_init function.
*/
ret_code_t nrf_spi_mngr_init(nrf_spi_mngr_t const * p_nrf_spi_mngr,
nrf_drv_spi_config_t const * p_default_spi_config);
/**
* @brief Function for uninitializing an SPI transaction manager instance.
*
* @param[in] p_nrf_spi_mngr Pointer to the instance to be uninitialized.
*/
void nrf_spi_mngr_uninit(nrf_spi_mngr_t const * p_nrf_spi_mngr);
/**
* @brief Function for scheduling an SPI transaction.
*
* The transaction is enqueued and started as soon as the SPI bus is
* available, thus when all previously scheduled transactions have been
* finished (possibly immediately).
*
* @note If @ref nrf_spi_mngr_transaction_t::p_required_spi_cfg
* is set to a non-NULL value the module will compare it with
* @ref nrf_spi_mngr_cb_t::p_current_configuration and reinitialize hardware
* SPI instance with new parameters if any differences are found.
* If @ref nrf_spi_mngr_transaction_t::p_required_spi_cfg is set to NULL then
* it will treat it as it would be set to @ref nrf_spi_mngr_cb_t::default_configuration.
*
* @param[in] p_nrf_spi_mngr Pointer to the SPI transaction manager instance.
* @param[in] p_transaction Pointer to the descriptor of the transaction to be
* scheduled.
*
* @retval NRF_SUCCESS If the transaction has been successfully scheduled.
* @retval NRF_ERROR_NO_MEM If the queue is full (Only if queue in
* @ref NRF_QUEUE_MODE_NO_OVERFLOW).
*/
ret_code_t nrf_spi_mngr_schedule(nrf_spi_mngr_t const * p_nrf_spi_mngr,
nrf_spi_mngr_transaction_t const * p_transaction);
/**
* @brief Function for scheduling a transaction and waiting until it is finished.
*
* This function schedules a transaction that consists of one or more transfers
* and waits until it is finished.
*
* @param[in] p_nrf_spi_mngr Pointer to the SPI transaction manager instance.
* @param[in] p_config Required SPI configuration.
* @param[in] p_transfers Pointer to an array of transfers to be performed.
* @param number_of_transfers Number of transfers to be performed.
* @param user_function User-specified function to be called while
* waiting. NULL if such functionality
* is not needed.
*
* @retval NRF_SUCCESS If the transfers have been successfully realized.
* @retval NRF_ERROR_BUSY If some transfers are already being performed.
* @retval - Other error codes mean that the transaction has failed
* with the error reported by @ref nrf_drv_spi_transfer().
*/
ret_code_t nrf_spi_mngr_perform(nrf_spi_mngr_t const * p_nrf_spi_mngr,
nrf_drv_spi_config_t const * p_config,
nrf_spi_mngr_transfer_t const * p_transfers,
uint8_t number_of_transfers,
void (* user_function)(void));
/**
* @brief Function for getting the current state of an SPI transaction manager
* instance.
*
* @param[in] p_nrf_spi_mngr Pointer to the SPI transaction manager instance.
*
* @retval true If all scheduled transactions have been finished.
* @retval false Otherwise.
*/
__STATIC_INLINE bool nrf_spi_mngr_is_idle(nrf_spi_mngr_t const * p_nrf_spi_mngr)
{
return (p_nrf_spi_mngr->p_nrf_spi_mngr_cb->p_current_transaction == NULL);
}
/**
*@}
**/
//typedef int p_current_transaction;
#ifdef __cplusplus
}
#endif
#endif // NRF_SPI_MNGR_H__

View File

@@ -1,93 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include <stdint.h>
#include "nrf.h"
#include "nrf_assert.h"
#include "nrf_mpu_lib.h"
#include "nrf_stack_guard.h"
#define NRF_LOG_MODULE_NAME stack_guard
#if NRF_STACK_GUARD_CONFIG_LOG_ENABLED
#define NRF_LOG_LEVEL NRF_STACK_GUARD_CONFIG_LOG_LEVEL
#define NRF_LOG_INFO_COLOR NRF_STACK_GUARD_CONFIG_INFO_COLOR
#define NRF_LOG_DEBUG_COLOR NRF_STACK_GUARD_CONFIG_DEBUG_COLOR
#endif
#include "nrf_log.h"
NRF_LOG_MODULE_REGISTER();
#if NRF_STACK_GUARD_ENABLED
STATIC_ASSERT(STACK_GUARD_SIZE >= 32);
ret_code_t nrf_stack_guard_init(void)
{
nrf_mpu_lib_region_t region;
uint32_t attributes;
ret_code_t status;
ASSERT((STACK_GUARD_BASE + STACK_GUARD_SIZE) < (uint32_t)((void *)(STACK_TOP)));
attributes = (0x05 << MPU_RASR_TEX_Pos) | (1 << MPU_RASR_B_Pos) | /* Normal memory, WBWA/WBWA */
(0x07 << MPU_RASR_AP_Pos) | (1 << MPU_RASR_XN_Pos); /* Access: RO/RO, XN */
status = nrf_mpu_lib_region_create(&region,
(void *)(STACK_GUARD_BASE),
STACK_GUARD_SIZE,
attributes);
if (status == NRF_SUCCESS)
{
NRF_LOG_INFO("Stack Guard (%u bytes): 0x%08X-0x%08X (total stack size: %u bytes, usable stack area: %u bytes)",
STACK_GUARD_SIZE,
STACK_GUARD_BASE,
STACK_GUARD_BASE + STACK_GUARD_SIZE - 1,
STACK_SIZE,
REAL_STACK_SIZE);
}
else
{
NRF_LOG_ERROR("Cannot create stack guard page! Error: %u [%s]", status, (uint32_t)NRF_LOG_ERROR_STRING_GET(status));
}
return status;
}
#endif /* NRF_STACK_GUARD_ENABLED */

View File

@@ -1,84 +0,0 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef __NRF_STACK_GUARD_H__
#define __NRF_STACK_GUARD_H__
/**
* @defgroup nrf_stack_guard Stack guard
* @{
* @ingroup app_common
* @brief Functions for enabling stack violation control.
*/
#include "sdk_config.h"
#include "app_util.h"
#ifdef __cplusplus
extern "C" {
#endif
#define STACK_SIZE (((int32_t)(STACK_TOP)) - (int32_t)((void *)(STACK_BASE)))
#if NRF_STACK_GUARD_ENABLED
#define STACK_GUARD_SIZE (1ul << NRF_STACK_GUARD_CONFIG_SIZE)
#define STACK_GUARD_BASE (((uint32_t)((void *)(STACK_BASE)) + STACK_GUARD_SIZE - 1) \
& ~(STACK_GUARD_SIZE - 1))
#define REAL_STACK_SIZE (STACK_SIZE - STACK_GUARD_SIZE)
#else /* !NRF_STACK_GUARD_ENABLED */
#define REAL_STACK_SIZE STACK_SIZE
#endif /* NRF_STACK_GUARD_ENABLED */
/**@brief Function for initializing the Stack Guard Page.
*
* @note When this module is enabled, the usable stack size is reduced by @ref NRF_STACK_GUARD_CONFIG_SIZE.
* */
ret_code_t nrf_stack_guard_init(void);
#if NRF_STACK_GUARD_ENABLED
#define NRF_STACK_GUARD_INIT() nrf_stack_guard_init()
#else
#define NRF_STACK_GUARD_INIT() NRF_SUCCESS
#endif
#ifdef __cplusplus
}
#endif
#endif //__NRF_STACK_GUARD_H__
/** @} */

View File

@@ -1,366 +0,0 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sdk_common.h"
#if NRF_MODULE_ENABLED(NRF_TWI_MNGR)
#include "nrf_twi_mngr.h"
#include "nrf_assert.h"
#include "app_util_platform.h"
typedef volatile struct
{
bool transaction_in_progress;
uint8_t transaction_result;
} nrf_twi_mngr_cb_data_t;
static ret_code_t start_transfer(nrf_twi_mngr_t const * p_nrf_twi_mngr)
{
ASSERT(p_nrf_twi_mngr != NULL);
// Pointer for cleaner code.
nrf_twi_mngr_cb_t * p_cb = p_nrf_twi_mngr->p_nrf_twi_mngr_cb;
// [use a local variable to avoid using two volatile variables in one
// expression]
uint8_t current_transfer_idx = p_cb->current_transfer_idx;
nrf_twi_mngr_transfer_t const * p_transfer =
&p_cb->p_current_transaction->p_transfers[current_transfer_idx];
uint8_t address = NRF_TWI_MNGR_OP_ADDRESS(p_transfer->operation);
nrf_drv_twi_xfer_desc_t xfer_desc;
uint32_t flags;
xfer_desc.address = address;
xfer_desc.p_primary_buf = p_transfer->p_data;
xfer_desc.primary_length = p_transfer->length;
/* If it is possible try to bind two transfers together. They can be combined if:
* - there is no stop condition after current transfer.
* - current transfer is TX.
* - there is at least one more transfer in the transaction.
* - address of next transfer is the same as current transfer.
*/
if ((p_transfer->flags & NRF_TWI_MNGR_NO_STOP) &&
!NRF_TWI_MNGR_IS_READ_OP(p_transfer->operation) &&
// Adding 1 to check if next transfer is from the same transaction.
((current_transfer_idx + 1) < p_cb->p_current_transaction->number_of_transfers) &&
(NRF_TWI_MNGR_OP_ADDRESS(p_transfer->operation) ==
NRF_TWI_MNGR_OP_ADDRESS(p_cb->p_current_transaction->
p_transfers[current_transfer_idx + 1].operation)))
{
nrf_twi_mngr_transfer_t const * p_second_transfer =
&p_cb->p_current_transaction->p_transfers[current_transfer_idx + 1];
xfer_desc.p_secondary_buf = p_second_transfer->p_data;
xfer_desc.secondary_length = p_second_transfer->length;
xfer_desc.type = NRF_TWI_MNGR_IS_READ_OP(p_second_transfer->operation) ?
NRF_DRV_TWI_XFER_TXRX : NRF_DRV_TWI_XFER_TXTX;
flags = (p_second_transfer->flags & NRF_TWI_MNGR_NO_STOP) ? NRF_DRV_TWI_FLAG_TX_NO_STOP : 0;
p_cb->current_transfer_idx++;
}
else
{
xfer_desc.type = NRF_TWI_MNGR_IS_READ_OP(p_transfer->operation) ? NRF_DRV_TWI_XFER_RX :
NRF_DRV_TWI_XFER_TX;
xfer_desc.p_secondary_buf = NULL;
xfer_desc.secondary_length = 0;
flags = (p_transfer->flags & NRF_TWI_MNGR_NO_STOP) ? NRF_DRV_TWI_FLAG_TX_NO_STOP : 0;
}
return nrf_drv_twi_xfer(&p_nrf_twi_mngr->twi, &xfer_desc, flags);
}
static void transaction_end_signal(nrf_twi_mngr_t const * p_nrf_twi_mngr,
ret_code_t result)
{
ASSERT(p_nrf_twi_mngr != NULL);
if (p_nrf_twi_mngr->p_nrf_twi_mngr_cb->p_current_transaction->callback)
{
// [use a local variable to avoid using two volatile variables in one
// expression]
void * p_user_data = p_nrf_twi_mngr->p_nrf_twi_mngr_cb->p_current_transaction->p_user_data;
p_nrf_twi_mngr->p_nrf_twi_mngr_cb->p_current_transaction->callback(result, p_user_data);
}
}
static void twi_event_handler(nrf_drv_twi_evt_t const * p_event,
void * p_context);
// This function starts pending transaction if there is no current one or
// when 'switch_transaction' parameter is set to true. It is important to
// switch to new transaction without setting 'p_nrf_twi_mngr->p_current_transaction'
// to NULL in between, since this pointer is used to check idle status - see
// 'nrf_twi_mngr_is_idle()'.
static void start_pending_transaction(nrf_twi_mngr_t const * p_nrf_twi_mngr,
bool switch_transaction)
{
ASSERT(p_nrf_twi_mngr != NULL);
// Pointer for cleaner code.
nrf_twi_mngr_cb_t * p_cb = p_nrf_twi_mngr->p_nrf_twi_mngr_cb;
for (;;)
{
bool start_transaction = false;
CRITICAL_REGION_ENTER();
if (switch_transaction || nrf_twi_mngr_is_idle(p_nrf_twi_mngr))
{
if (nrf_queue_pop(p_nrf_twi_mngr->p_queue, (void *)(&p_cb->p_current_transaction))
== NRF_SUCCESS)
{
start_transaction = true;
}
else
{
p_cb->p_current_transaction = NULL;
}
}
CRITICAL_REGION_EXIT();
if (!start_transaction)
{
return;
}
else
{
ret_code_t result;
nrf_drv_twi_config_t const * p_instance_cfg =
p_cb->p_current_transaction->p_required_twi_cfg == NULL ?
&p_cb->default_configuration :
p_cb->p_current_transaction->p_required_twi_cfg;
if (memcmp(p_cb->p_current_configuration, p_instance_cfg, sizeof(*p_instance_cfg)) != 0)
{
ret_code_t err_code;
nrf_drv_twi_uninit(&p_nrf_twi_mngr->twi);
err_code = nrf_drv_twi_init(&p_nrf_twi_mngr->twi,
p_instance_cfg,
twi_event_handler,
(void *)p_nrf_twi_mngr);
ASSERT(err_code == NRF_SUCCESS);
nrf_drv_twi_enable(&p_nrf_twi_mngr->twi);
UNUSED_VARIABLE(err_code);
p_cb->p_current_configuration = p_instance_cfg;
}
// Try to start first transfer for this new transaction.
p_cb->current_transfer_idx = 0;
result = start_transfer(p_nrf_twi_mngr);
// If transaction started successfully there is nothing more to do here now.
if (result == NRF_SUCCESS)
{
return;
}
// Transfer failed to start - notify user that this transaction
// cannot be started and try with next one (in next iteration of
// the loop).
transaction_end_signal(p_nrf_twi_mngr, result);
switch_transaction = true;
}
}
}
static void twi_event_handler(nrf_drv_twi_evt_t const * p_event,
void * p_context)
{
ASSERT(p_event != NULL);
nrf_twi_mngr_t * p_nrf_twi_mngr = (nrf_twi_mngr_t *)p_context;
ret_code_t result;
// This callback should be called only during transaction.
ASSERT(p_nrf_twi_mngr->p_nrf_twi_mngr_cb->p_current_transaction != NULL);
if (p_event->type == NRF_DRV_TWI_EVT_DONE)
{
result = NRF_SUCCESS;
// Transfer finished successfully. If there is another one to be
// performed in the current transaction, start it now.
// [use a local variable to avoid using two volatile variables in one
// expression]
uint8_t current_transfer_idx = p_nrf_twi_mngr->p_nrf_twi_mngr_cb->current_transfer_idx;
++current_transfer_idx;
if (current_transfer_idx <
p_nrf_twi_mngr->p_nrf_twi_mngr_cb->p_current_transaction->number_of_transfers)
{
p_nrf_twi_mngr->p_nrf_twi_mngr_cb->current_transfer_idx = current_transfer_idx;
result = start_transfer(p_nrf_twi_mngr);
if (result == NRF_SUCCESS)
{
// The current transaction goes on and we've successfully
// started its next transfer -> there is nothing more to do.
return;
}
// [if the next transfer could not be started due to some error
// we finish the transaction with this error code as the result]
}
}
else
{
result = NRF_ERROR_INTERNAL;
}
// The current transaction has been completed or interrupted by some error.
// Notify the user and start next one (if there is any).
transaction_end_signal(p_nrf_twi_mngr, result);
// [we switch transactions here ('p_nrf_twi_mngr->p_current_transaction' is set
// to NULL only if there is nothing more to do) in order to not generate
// spurious idle status (even for a moment)]
start_pending_transaction(p_nrf_twi_mngr, true);
}
ret_code_t nrf_twi_mngr_init(nrf_twi_mngr_t const * p_nrf_twi_mngr,
nrf_drv_twi_config_t const * p_default_twi_config)
{
ASSERT(p_nrf_twi_mngr != NULL);
ASSERT(p_nrf_twi_mngr->p_queue != NULL);
ASSERT(p_nrf_twi_mngr->p_queue->size > 0);
ASSERT(p_default_twi_config != NULL);
ret_code_t err_code;
err_code = nrf_drv_twi_init(&p_nrf_twi_mngr->twi,
p_default_twi_config,
twi_event_handler,
(void *)p_nrf_twi_mngr);
VERIFY_SUCCESS(err_code);
nrf_drv_twi_enable(&p_nrf_twi_mngr->twi);
p_nrf_twi_mngr->p_nrf_twi_mngr_cb->p_current_transaction = NULL;
p_nrf_twi_mngr->p_nrf_twi_mngr_cb->default_configuration = *p_default_twi_config;
p_nrf_twi_mngr->p_nrf_twi_mngr_cb->p_current_configuration =
&p_nrf_twi_mngr->p_nrf_twi_mngr_cb->default_configuration;
return NRF_SUCCESS;
}
void nrf_twi_mngr_uninit(nrf_twi_mngr_t const * p_nrf_twi_mngr)
{
ASSERT(p_nrf_twi_mngr != NULL);
nrf_drv_twi_uninit(&p_nrf_twi_mngr->twi);
p_nrf_twi_mngr->p_nrf_twi_mngr_cb->p_current_transaction = NULL;
}
ret_code_t nrf_twi_mngr_schedule(nrf_twi_mngr_t const * p_nrf_twi_mngr,
nrf_twi_mngr_transaction_t const * p_transaction)
{
ASSERT(p_nrf_twi_mngr != NULL);
ASSERT(p_transaction != NULL);
ASSERT(p_transaction->p_transfers != NULL);
ASSERT(p_transaction->number_of_transfers != 0);
ret_code_t result = NRF_SUCCESS;
result = nrf_queue_push(p_nrf_twi_mngr->p_queue, (void *)(&p_transaction));
if (result == NRF_SUCCESS)
{
// New transaction has been successfully added to queue,
// so if we are currently idle it's time to start the job.
start_pending_transaction(p_nrf_twi_mngr, false);
}
return result;
}
static void internal_transaction_cb(ret_code_t result, void * p_user_data)
{
nrf_twi_mngr_cb_data_t *p_cb_data = (nrf_twi_mngr_cb_data_t *)p_user_data;
p_cb_data->transaction_result = result;
p_cb_data->transaction_in_progress = false;
}
ret_code_t nrf_twi_mngr_perform(nrf_twi_mngr_t const * p_nrf_twi_mngr,
nrf_drv_twi_config_t const * p_config,
nrf_twi_mngr_transfer_t const * p_transfers,
uint8_t number_of_transfers,
void (* user_function)(void))
{
ASSERT(p_nrf_twi_mngr != NULL);
ASSERT(p_transfers != NULL);
ASSERT(number_of_transfers != 0);
nrf_twi_mngr_cb_data_t cb_data =
{
.transaction_in_progress = true
};
nrf_twi_mngr_transaction_t internal_transaction =
{
.callback = internal_transaction_cb,
.p_user_data = (void *)&cb_data,
.p_transfers = p_transfers,
.number_of_transfers = number_of_transfers,
.p_required_twi_cfg = p_config
};
ret_code_t result = nrf_twi_mngr_schedule(p_nrf_twi_mngr, &internal_transaction);
VERIFY_SUCCESS(result);
while (cb_data.transaction_in_progress)
{
if (user_function)
{
user_function();
}
}
return cb_data.transaction_result;
}
#endif //NRF_MODULE_ENABLED(NRF_TWI_MNGR)

View File

@@ -1,342 +0,0 @@
/**
* Copyright (c) 2015 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef NRF_TWI_MNGR_H__
#define NRF_TWI_MNGR_H__
#include <stdint.h>
#include "nrf_drv_twi.h"
#include "sdk_errors.h"
#include "nrf_queue.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup nrf_twi_mngr TWI transaction manager
* @{
* @ingroup app_common
*
* @brief Module for scheduling TWI transactions.
*/
//If TWIM is present buffers can only be in RAM
/*lint -save -e491*/
/**
* @brief Macro checking if buffers should be stored in RAM.
*/
#ifndef NRF_TWI_MNGR_BUFFERS_IN_RAM
#define NRF_TWI_MNGR_BUFFERS_IN_RAM defined(TWIM_PRESENT)
#endif
/**
* @brief Modifier used in array declaration for TWI Manager.
*
* @note For TWI peripheral array can be const, for TWIM array has to be located in RAM.
*/
#if NRF_TWI_MNGR_BUFFERS_IN_RAM
#define NRF_TWI_MNGR_BUFFER_LOC_IND
#else
#define NRF_TWI_MNGR_BUFFER_LOC_IND const
#endif
/*lint -restore*/
/**
* @brief Flag indicating that a given transfer should not be ended
* with a stop condition.
*
* Use this flag when a stop condition is undesirable between two transfers,
* for example, when the first transfer is a write that sets an address in the slave
* device and the second one is a read that fetches certain data using this
* address. In this case, the second transfer should follow directly after the
* first transfer, with a repeated start condition instead of a stop and then
* a new start condition.
*/
#define NRF_TWI_MNGR_NO_STOP 0x01
/**
* @brief Macro for creating a write transfer.
*
* @param[in] address Slave address.
* @param[in] p_data Pointer to the data to be sent.
* @param[in] length Number of bytes to transfer.
* @param[in] flags Transfer flags (see @ref NRF_TWI_MNGR_NO_STOP).
*/
#define NRF_TWI_MNGR_WRITE(address, p_data, length, flags) \
NRF_TWI_MNGR_TRANSFER(NRF_TWI_MNGR_WRITE_OP(address), p_data, length, flags)
/**
* @brief Macro for creating a read transfer.
*
* @param address Slave address.
* @param[in] p_data Pointer to the buffer where received data should be placed.
* @param length Number of bytes to transfer.
* @param flags Transfer flags (see @ref NRF_TWI_MNGR_NO_STOP).
*/
#define NRF_TWI_MNGR_READ(address, p_data, length, flags) \
NRF_TWI_MNGR_TRANSFER(NRF_TWI_MNGR_READ_OP(address), p_data, length, flags)
/**
* @brief Helper macro, should not be used directly.
*/
#define NRF_TWI_MNGR_TRANSFER(_operation, _p_data, _length, _flags) \
{ \
.p_data = (uint8_t *)(_p_data), \
.length = _length, \
.operation = _operation, \
.flags = _flags \
}
/**
* @brief Helper macro, should not be used directly.
*/
#define NRF_TWI_MNGR_WRITE_OP(address) (((address) << 1) | 0)
/**
* @brief Helper macro, should not be used directly.
*/
#define NRF_TWI_MNGR_READ_OP(address) (((address) << 1) | 1)
/**
* @brief Helper macro, should not be used directly.
*/
#define NRF_TWI_MNGR_IS_READ_OP(operation) ((operation) & 1)
/**
* @brief Helper macro, should not be used directly.
*/
#define NRF_TWI_MNGR_OP_ADDRESS(operation) ((operation) >> 1)
/**
* @brief TWI transaction callback prototype.
*
* @param result Result of operation (NRF_SUCCESS on success,
* otherwise a relevant error code).
* @param[in] p_user_data Pointer to user data defined in transaction
* descriptor.
*/
typedef void (* nrf_twi_mngr_callback_t)(ret_code_t result, void * p_user_data);
/**
* @brief TWI transfer descriptor.
*/
typedef struct {
uint8_t * p_data; ///< Pointer to the buffer holding the data.
uint8_t length; ///< Number of bytes to transfer.
uint8_t operation; ///< Device address combined with transfer direction.
uint8_t flags; ///< Transfer flags (see @ref NRF_TWI_MNGR_NO_STOP).
} nrf_twi_mngr_transfer_t;
/**
* @brief TWI transaction descriptor.
*/
typedef struct {
nrf_twi_mngr_callback_t callback;
///< User-specified function to be called after the transaction is finished.
void * p_user_data;
///< Pointer to user data to be passed to the callback.
nrf_twi_mngr_transfer_t const * p_transfers;
///< Pointer to the array of transfers that make up the transaction.
uint8_t number_of_transfers;
///< Number of transfers that make up the transaction.
nrf_drv_twi_config_t const * p_required_twi_cfg;
///< Pointer to instance hardware configuration.
} nrf_twi_mngr_transaction_t;
/**
* @brief TWI instance control block.
*/
typedef struct {
nrf_twi_mngr_transaction_t const * volatile p_current_transaction;
///< Currently realized transaction.
nrf_drv_twi_config_t default_configuration;
///< Default hardware configuration.
nrf_drv_twi_config_t const * p_current_configuration;
///< Pointer to current hardware configuration.
uint8_t volatile current_transfer_idx;
///< Index of currently performed transfer (within current transaction).
} nrf_twi_mngr_cb_t;
/**
* @brief TWI transaction manager instance.
*/
typedef struct {
nrf_twi_mngr_cb_t * p_nrf_twi_mngr_cb;
///< Control block of instance.
nrf_queue_t const * p_queue;
///< Transaction queue.
nrf_drv_twi_t twi;
///< Pointer to TWI master driver instance.
} nrf_twi_mngr_t;
/**
* @brief Macro that simplifies defining a TWI transaction manager
* instance.
*
* This macro allocates a static buffer for the transaction queue.
* Therefore, it should be used in only one place in the code for a given
* instance.
*
* @note The queue size is the maximum number of pending transactions
* not counting the one that is currently realized. This means that
* for an empty queue with size of, for example, 4 elements, it is
* possible to schedule up to 5 transactions.
*
* @param[in] _nrf_twi_mngr_name Name of instance to be created.
* @param[in] _queue_size Size of the transaction queue (maximum number
* of pending transactions).
* @param[in] _twi_idx Index of hardware TWI instance to be used.
*/
#define NRF_TWI_MNGR_DEF(_nrf_twi_mngr_name, _queue_size, _twi_idx) \
NRF_QUEUE_DEF(nrf_twi_mngr_transaction_t const *, \
_nrf_twi_mngr_name##_queue, \
(_queue_size), \
NRF_QUEUE_MODE_NO_OVERFLOW); \
static nrf_twi_mngr_cb_t CONCAT_2(_nrf_twi_mngr_name, _cb); \
static const nrf_twi_mngr_t _nrf_twi_mngr_name = \
{ \
.p_nrf_twi_mngr_cb = &CONCAT_2(_nrf_twi_mngr_name, _cb), \
.p_queue = &_nrf_twi_mngr_name##_queue, \
.twi = NRF_DRV_TWI_INSTANCE(_twi_idx) \
}
/**
* @brief Function for initializing a TWI transaction manager instance.
*
* @param[in] p_nrf_twi_mngr Pointer to the instance to be initialized.
* @param[in] p_default_twi_config Pointer to the TWI master driver configuration. This configuration
* will be used whenever the scheduled transaction will have
* p_twi_configuration set to NULL value.
*
* @return Values returned by the @ref nrf_drv_twi_init function.
*/
ret_code_t nrf_twi_mngr_init(nrf_twi_mngr_t const * p_nrf_twi_mngr,
nrf_drv_twi_config_t const * p_default_twi_config);
/**
* @brief Function for uninitializing a TWI transaction manager instance.
*
* @param[in] p_nrf_twi_mngr Pointer to the instance to be uninitialized.
*/
void nrf_twi_mngr_uninit(nrf_twi_mngr_t const * p_nrf_twi_mngr);
/**
* @brief Function for scheduling a TWI transaction.
*
* The transaction is enqueued and started as soon as the TWI bus is
* available, thus when all previously scheduled transactions have been
* finished (possibly immediately).
*
* @note If @ref nrf_twi_mngr_transaction_t::p_required_twi_cfg
* is set to a non-NULL value the module will compare it with
* @ref nrf_twi_mngr_cb_t::p_current_configuration and reinitialize hardware
* TWI instance with new parameters if any differences are found.
* If @ref nrf_twi_mngr_transaction_t::p_required_twi_cfg is set to NULL then
* it will treat it as it would be set to @ref nrf_twi_mngr_cb_t::default_configuration.
*
* @param[in] p_nrf_twi_mngr Pointer to the TWI transaction manager instance.
* @param[in] p_transaction Pointer to the descriptor of the transaction to be
* scheduled.
*
* @retval NRF_SUCCESS If the transaction has been successfully scheduled.
* @retval NRF_ERROR_NO_MEM If the queue is full (Only if queue in
* @ref NRF_QUEUE_MODE_NO_OVERFLOW).
*/
ret_code_t nrf_twi_mngr_schedule(nrf_twi_mngr_t const * p_nrf_twi_mngr,
nrf_twi_mngr_transaction_t const * p_transaction);
/**
* @brief Function for scheduling a transaction and waiting until it is finished.
*
* This function schedules a transaction that consists of one or more transfers
* and waits until it is finished.
*
* @param[in] p_nrf_twi_mngr Pointer to the TWI transaction manager instance.
* @param[in] p_config Required TWI configuration.
* @param[in] p_transfers Pointer to an array of transfers to be performed.
* @param number_of_transfers Number of transfers to be performed.
* @param user_function User-specified function to be called while
* waiting. NULL if such functionality
* is not needed.
*
* @retval NRF_SUCCESS If the transfers have been successfully realized.
* @retval NRF_ERROR_BUSY If some transfers are already being performed.
* @retval - Other error codes mean that the transaction has ended
* with the error that is specified in the error code.
*/
ret_code_t nrf_twi_mngr_perform(nrf_twi_mngr_t const * p_nrf_twi_mngr,
nrf_drv_twi_config_t const * p_config,
nrf_twi_mngr_transfer_t const * p_transfers,
uint8_t number_of_transfers,
void (* user_function)(void));
/**
* @brief Function for getting the current state of a TWI transaction manager
* instance.
*
* @param[in] p_nrf_twi_mngr Pointer to the TWI transaction manager instance.
*
* @retval true If all scheduled transactions have been finished.
* @retval false Otherwise.
*/
__STATIC_INLINE bool nrf_twi_mngr_is_idle(nrf_twi_mngr_t const * p_nrf_twi_mngr);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE bool nrf_twi_mngr_is_idle(nrf_twi_mngr_t const * p_nrf_twi_mngr)
{
return (p_nrf_twi_mngr->p_nrf_twi_mngr_cb->p_current_transaction == NULL);
}
#endif //SUPPRESS_INLINE_IMPLEMENTATION
/**
*@}
**/
#ifdef __cplusplus
}
#endif
#endif // NRF_TWI_MNGR_H__

View File

@@ -1,220 +0,0 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "nrf_twi_sensor.h"
#include <string.h>
#define NRF_LOG_MODULE_NAME twi_sensor
#if NRF_TWI_SENSOR_CONFIG_LOG_ENABLED
#define NRF_LOG_LEVEL NRF_TWI_SENSOR_CONFIG_LOG_LEVEL
#define NRF_LOG_INFO_COLOR NRF_TWI_SENSOR_CONFIG_INFO_COLOR
#define NRF_LOG_DEBUG_COLOR NRF_TWI_SENSOR_CONFIG_DEBUG_COLOR
#else
#define NRF_LOG_LEVEL 0
#endif // NRF_TWI_SENSOR_CONFIG_LOG_ENABLED
#include "nrf_log.h"
NRF_LOG_MODULE_REGISTER();
ret_code_t nrf_twi_sensor_init(nrf_twi_sensor_t * p_twi_sensor)
{
return nrf_balloc_init(p_twi_sensor->p_pool);
}
static void sensor_read_reg_cb(ret_code_t result, void * p_user_data)
{
nrf_twi_sensor_read_cmd_t * p_cmd = &((nrf_twi_sensor_cmd_t *) p_user_data)->read;
NRF_LOG_INFO("Read cb reg addr: 0x%02X, result %d", p_cmd->reg_address, result);
NRF_LOG_DEBUG("\r\nCallback pointer: %p\r\nData:", p_cmd->user_cb);
NRF_LOG_HEXDUMP_DEBUG(p_cmd->transfers[1].p_data, p_cmd->transfers[1].length);
if (p_cmd->user_cb != NULL)
{
p_cmd->user_cb(result, (void*)p_cmd->transfers[1].p_data);
}
nrf_balloc_free(p_cmd->p_instance->p_pool, p_user_data);
}
ret_code_t nrf_twi_sensor_reg_read(nrf_twi_sensor_t const * p_instance,
uint8_t sensor_addr,
uint8_t reg_address,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * p_data,
uint8_t length)
{
ASSERT(p_instance != NULL);
ASSERT(p_data != NULL);
NRF_LOG_INFO("Sensor addr: 0x%02X"
"\r\nRead reg addr: 0x%02X, bytes %d",
sensor_addr,
reg_address,
length);
nrf_twi_sensor_read_cmd_t * p_cmd =
(nrf_twi_sensor_read_cmd_t *) nrf_balloc_alloc(p_instance->p_pool);
if (p_cmd == NULL)
{
NRF_LOG_WARNING("Memory not allocated.");
return NRF_ERROR_NO_MEM;
}
p_cmd->p_instance = p_instance;
p_cmd->user_cb = user_cb;
p_cmd->reg_address = reg_address;
p_cmd->transfers[0] = (nrf_twi_mngr_transfer_t) NRF_TWI_MNGR_WRITE(sensor_addr,
&p_cmd->reg_address,
1,
NRF_TWI_MNGR_NO_STOP);
p_cmd->transfers[1] = (nrf_twi_mngr_transfer_t) NRF_TWI_MNGR_READ(sensor_addr,
p_data,
length,
NRF_TWI_MNGR_NO_STOP);
p_cmd->transaction = (nrf_twi_mngr_transaction_t) {
.callback = sensor_read_reg_cb,
.p_user_data = p_cmd,
.p_transfers = p_cmd->transfers,
.number_of_transfers = ARRAY_SIZE(p_cmd->transfers)
};
ret_code_t err_code = nrf_twi_mngr_schedule(p_instance->p_twi_mngr, &p_cmd->transaction);
if (err_code != NRF_SUCCESS)
{
NRF_LOG_WARNING("Transaction not scheduled.\r\nSensor addr: 0x%02X Error code: %d",
sensor_addr,
err_code);
nrf_balloc_free(p_instance->p_pool, p_cmd);
}
return err_code;
}
static void sensor_write_reg_cb(ret_code_t result, void * p_user_data)
{
nrf_twi_sensor_write_cmd_t * p_cmd = &((nrf_twi_sensor_cmd_t *) p_user_data)->write;
NRF_LOG_INFO("Write cb reg addr: 0x%02X, result %d", p_cmd->send_msg[0], result);
nrf_balloc_free(p_cmd->p_instance->p_pool, p_user_data);
}
ret_code_t nrf_twi_sensor_write(nrf_twi_sensor_t const * p_instance,
uint8_t sensor_addr,
uint8_t const * p_data,
uint8_t length,
bool copy_flag)
{
ASSERT(p_instance != NULL);
ASSERT(p_data != NULL);
NRF_LOG_INFO("Sensor addr: 0x%02X Write length %d", sensor_addr, length);
NRF_LOG_DEBUG("Data: ");
NRF_LOG_HEXDUMP_DEBUG(p_data, length);
nrf_twi_sensor_write_cmd_t * p_cmd =
(nrf_twi_sensor_write_cmd_t *) nrf_balloc_alloc(p_instance->p_pool);
if (p_cmd == NULL)
{
NRF_LOG_WARNING("Memory not allocated. Sensor addr: 0x%02X",
sensor_addr);
return NRF_ERROR_NO_MEM;
}
p_cmd->p_instance = p_instance;
p_cmd->transfer = (nrf_twi_mngr_transfer_t) NRF_TWI_MNGR_WRITE(sensor_addr,
p_data,
length,
0);
if (copy_flag == true)
{
if (length > NRF_TWI_SENSOR_SEND_BUF_SIZE)
{
NRF_LOG_ERROR("Data too long to copy. Sensor addr: 0x%02X"
"\r\nRequested write length: %d, max length: %d",
sensor_addr,
length,
NRF_TWI_SENSOR_SEND_BUF_SIZE);
nrf_balloc_free(p_instance->p_pool, p_cmd);
return NRF_ERROR_INVALID_LENGTH;
}
memcpy(p_cmd->send_msg, p_data, length);
p_cmd->transfer.p_data = p_cmd->send_msg;
}
p_cmd->transaction = (nrf_twi_mngr_transaction_t) {
.callback = sensor_write_reg_cb,
.p_user_data = p_cmd,
.p_transfers = &p_cmd->transfer,
.number_of_transfers = 1
};
ret_code_t err_code = nrf_twi_mngr_schedule(p_instance->p_twi_mngr, &p_cmd->transaction);
if (err_code != NRF_SUCCESS)
{
NRF_LOG_WARNING("Transaction not scheduled.\r\nSensor addr: 0x%02X Error code: %d",
sensor_addr,
err_code);
nrf_balloc_free(p_instance->p_pool, p_cmd);
}
return err_code;
}
ret_code_t nrf_twi_sensor_reg_write(nrf_twi_sensor_t const * p_instance,
uint8_t sensor_addr,
uint8_t reg_address,
uint8_t * p_data,
uint8_t length)
{
ASSERT(p_instance != NULL);
ASSERT(p_data != NULL);
NRF_LOG_INFO("Write register: 0x%02X", reg_address);
if (length > NRF_TWI_SENSOR_SEND_BUF_SIZE - 1) // Subtracting one byte for address
{
NRF_LOG_ERROR("Data too long to copy. Sensor addr: 0x%02X"
"\r\nRequested write length: %d, max length: %d",
sensor_addr,
length,
NRF_TWI_SENSOR_SEND_BUF_SIZE - 1);
return NRF_ERROR_INVALID_LENGTH;
}
uint8_t buf[NRF_TWI_SENSOR_SEND_BUF_SIZE];
buf[0] = reg_address;
memcpy(&buf[1], p_data, length);
return nrf_twi_sensor_write(p_instance, sensor_addr, buf, length + 1, true);
}

View File

@@ -1,314 +0,0 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/**@file
*
* @defgroup nrf_twi_sensor TWI Sensor module.
* @{
* @ingroup app_common
*/
#ifndef NRF_TWI_SENSOR_H
#define NRF_TWI_SENSOR_H
#include "nrf_twi_mngr.h"
#include "nrf_balloc.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Internal write operation buffer length.
*
* Defines how many bytes can be stored internally.
* 16 bytes were selected so that nrf_twi_sensor_write_cmd_t size
* matches nrf_twi_sensor_read_cmd_t size.
*/
#define NRF_TWI_SENSOR_SEND_BUF_SIZE 16
/**
* @brief Register read callback prototype.
*
* @param[in] result Return error code from TWI manager and underlying drivers.
* @param[in] p_register_data Pointer to register value.
*/
typedef void (* nrf_twi_sensor_reg_cb_t)(ret_code_t result, void * p_register_data);
/**
* @brief Structure holding sensor instance
*/
typedef struct
{
nrf_twi_mngr_t const * const p_twi_mngr;
nrf_balloc_t const * const p_pool;
} nrf_twi_sensor_t;
/**
* @brief Struct describing sensor read command.
*
* @note For internal use only.
*/
typedef struct
{
uint8_t reg_address;
nrf_twi_mngr_transfer_t transfers[2];
nrf_twi_mngr_transaction_t transaction;
nrf_twi_sensor_reg_cb_t user_cb;
nrf_twi_sensor_t const * p_instance;
} nrf_twi_sensor_read_cmd_t;
/**
* @brief Struct describing sensor write command.
*
* @note For internal use only.
*/
typedef struct
{
uint8_t send_msg[NRF_TWI_SENSOR_SEND_BUF_SIZE];
nrf_twi_mngr_transfer_t transfer;
nrf_twi_mngr_transaction_t transaction;
nrf_twi_sensor_t const * p_instance;
} nrf_twi_sensor_write_cmd_t;
/**
* @brief Union for sensor commands. Needed in buffer definition.
*
* @note For internal use only.
*/
typedef union
{
nrf_twi_sensor_read_cmd_t read;
nrf_twi_sensor_write_cmd_t write;
} nrf_twi_sensor_cmd_t;
/**
* @brief Macro creating common twi sensor instance.
*
* Data in structure is used for basic communication with sensors.
* THere should be one instance per TWI bus.
*
* @param[in] twi_sensor_name TWI common sensor instance name.
* @param[in] p_nrf_twi_mngr Pointer to TWI Manager instance. @ref NRF_TWI_MNGR_DEF
* @param[in] msg_buff_size Size of buffer used in communication
*
* @note Buffer size should be less or equal to TWI manager queue size.
* Minimum buffer size can be found after checking utilization of sensor buffer.
*/
#define NRF_TWI_SENSOR_DEF(twi_sensor_name, p_nrf_twi_mngr, msg_buff_size) \
NRF_BALLOC_DEF(CONCAT_2(twi_sensor_name,_pool), sizeof(nrf_twi_sensor_cmd_t), msg_buff_size);\
static nrf_twi_sensor_t twi_sensor_name = \
{ \
.p_twi_mngr = p_nrf_twi_mngr, \
.p_pool = &CONCAT_2(twi_sensor_name,_pool) \
}
/**
* @brief Macro for defining TWI manager read transfer.
*
* @note For internal use only.
*/
#define NRF_TWI_SENSOR_READ(p_reg_addr, p_buffer, byte_cnt) \
NRF_TWI_MNGR_WRITE(0x00, p_reg_addr, 1, NRF_TWI_MNGR_NO_STOP), \
NRF_TWI_MNGR_READ (0x00, p_buffer, byte_cnt, 0)
/**
* @brief Macro for defining TWI manager write transfer.
*
* @note For internal use only.
*/
#define NRF_TWI_SENSOR_WRITE(p_buffer, byte_cnt) \
NRF_TWI_MNGR_WRITE(0x00, p_buffer, byte_cnt, 0)
/**
* @brief Macro for assigning sensor address to transfers.
*
* @param[in] _transfers Transfers array.
* @param[in] _sensor_addr Desired sensor address.
*
* @note For internal use only.
*/
#define NRF_TWI_SENSOR_ADDRESS_SET(_transfers, _sensor_addr) \
for (uint8_t i = 0; i < ARRAY_SIZE(_transfers); i++) \
{ \
if (i % 2 == 0) \
{ \
transfers[i].operation = NRF_TWI_MNGR_WRITE_OP(_sensor_addr); \
} \
else \
{ \
transfers[i].operation = NRF_TWI_MNGR_READ_OP(_sensor_addr); \
} \
}
/**
* @brief Macro for setting parameters in sensor register.
*
* @param[in,out] _register Register to be altered.
* @param[in] _msk Parameter mask.
* @param[in] _pos Parameter position.
* @param[in] _val Parameter value to be set.
*/
#define NRF_TWI_SENSOR_REG_SET(_register, _msk, _pos, _val) \
_register &= ~(_msk); \
_register |= ((_msk) & ((_val) << (_pos)))
/**
* @brief Macro for getting parameters from sensor register.
*
* @param[in] _register Register to be processed.
* @param[in] _msk Parameter mask.
* @param[in] _pos Parameter position.
*
* @note For usage with registers read using nrf_twi_sensor_register_read function.
*
* @return Parameter value
*/
#define NRF_TWI_SENSOR_REG_VAL_GET(_register, _msk, _pos) \
(((_register) & (_msk)) >> (_pos))
/**
* @brief Function for initialization of sensor common instance.
*
* @note TWI Manager should be initialized before @ref nrf_twi_mngr_init
* @param[in] p_twi_sensor Pointer to sensor common instance.
*
* @return Error code from nrf_balloc @ref nrf_balloc_init
*/
ret_code_t nrf_twi_sensor_init(nrf_twi_sensor_t * p_twi_sensor);
/**
* @brief Function for reading sensor register.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] sensor_addr Sensor address.
* @param[in] reg_address Register address.
* @param[in] user_cb User callback.
* @param[out] p_data Pointer to data save location.
* @param[in] length Number of bytes to read.
*
* @retval NRF_ERROR_NO_MEM If there is no memory in sensor buffer
* @retval NRF_SUCCESS If the operation was successful.
* @retval other Error code from TWI manager @ref nrf_twi_mngr_schedule.
*/
ret_code_t nrf_twi_sensor_reg_read(nrf_twi_sensor_t const * p_instance,
uint8_t sensor_addr,
uint8_t reg_address,
nrf_twi_sensor_reg_cb_t user_cb,
uint8_t * p_data,
uint8_t length);
/**
* @brief Function for writing to sensor.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] sensor_addr Sensor address.
* @param[in] p_data Pointer to data to be written.
* @param[in] length Number of bytes to write.
* @param[in] copy_flag If true, p_data is copied into internal static buffer.
*
* @note Most of the time, to write to sensors register, first byte in p_data has to be
* register address.
*
* @retval NRF_ERROR_NO_MEM If there is no memory in sensor buffer
* @retval NRF_ERROR_INVALID_LENGTH If trying to copy more bytes than
* NRF_TWI_SENSOR_SEND_BUF_SIZE.
* @retval NRF_SUCCESS If the operation was successful.
* @retval other Error code from TWI manager @ref nrf_twi_mngr_schedule.
*/
ret_code_t nrf_twi_sensor_write(nrf_twi_sensor_t const * p_instance,
uint8_t sensor_addr,
uint8_t const * p_data,
uint8_t length,
bool copy_flag);
/**
* @brief Function for writing to sensor register.
*
* @param[in] p_instance Pointer to sensor instance.
* @param[in] sensor_addr Sensor address.
* @param[in] reg_address Register address.
* @param[in] p_data Pointer to data to be written.
* @param[in] length Number of bytes to write.
*
* @note Data is copied into internal buffer.
* Length has to be less than NRF_TWI_SENSOR_SEND_BUF_SIZE.
*
* @retval NRF_ERROR_NO_MEM If there is no memory in sensor buffer
* @retval NRF_ERROR_INVALID_LENGTH If trying to copy more bytes than
* NRF_TWI_SENSOR_SEND_BUF_SIZE - 1.
* One byte reserved for register address.
* @retval NRF_SUCCESS If the operation was successful.
* @retval other Error code from TWI manager @ref nrf_twi_mngr_schedule.
*/
ret_code_t nrf_twi_sensor_reg_write(nrf_twi_sensor_t const * p_instance,
uint8_t sensor_addr,
uint8_t reg_address,
uint8_t * p_data,
uint8_t length);
/**
* @brief Function for getting maximum utilization of sensor buffer.
*
* @param[in] p_twi_sensor Pointer to sensor buffer.
*
* @return Maximum utilization.
*/
__STATIC_INLINE uint8_t nrf_twi_sensor_max_util_get(nrf_twi_sensor_t const * p_twi_sensor);
#ifndef SUPPRESS_INLINE_IMPLEMENTATION
__STATIC_INLINE uint8_t nrf_twi_sensor_max_util_get(nrf_twi_sensor_t const * p_twi_sensor)
{
return nrf_balloc_max_utilization_get(p_twi_sensor->p_pool);
}
#endif //SUPPRESS_INLINE_IMPLEMENTATION
#ifdef __cplusplus
}
#endif
#endif // NRF_SENSOR_COMMON_H
/** @} */

File diff suppressed because it is too large Load Diff

View File

@@ -1,816 +0,0 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef APP_USBD_H__
#define APP_USBD_H__
#include "nrf_drv_usbd.h"
#include "app_usbd_types.h"
#include "app_usbd_class_base.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup app_usbd USB Device high level library
* @ingroup app_common
*
* @brief @tagAPI52840 Module for easy support for any USB device configuration.
*
* This module manages class instances that would create the USB device,
* manages endpoints and interfaces transactions.
* @{
*/
/**
* @brief Highest value of Frame Number in SOF packets.
*/
#define APP_USBD_SOF_MAX 2047
/**
* @brief True if SOF timestamping is really provided.
*
* SOF timestamping is really provided if it was requested and if the logger is enabled.
*/
#if ((APP_USBD_CONFIG_SOF_TIMESTAMP_PROVIDE) && (NRF_LOG_ENABLED))
#define APP_USBD_PROVIDE_SOF_TIMESTAMP 1
#else
#define APP_USBD_PROVIDE_SOF_TIMESTAMP 0
#endif
/**
* @brief SOF event handling modes.
*/
#define APP_USBD_SOF_HANDLING_NORMAL_QUEUE 0 //!< Push SOF events into event queue.
#define APP_USBD_SOF_HANDLING_COMPRESS_QUEUE 1 //!< Compress SOF events.
#define APP_USBD_SOF_HANDLING_INTERRUPT 2 //!< Handle SOF events in interrupt.
/**
* @brief Configuration passed to @ref app_usbd_init.
*/
typedef struct {
#if (!(APP_USBD_CONFIG_EVENT_QUEUE_ENABLE)) || defined(__SDK_DOXYGEN__)
/**
* @brief User defined event handler.
*
* This function is called on every event from the interrupt.
* It is prepared for external user function that would queue events to be processed
* from the main context.
* It should be used with operating systems with its own implementation of the queue.
*
* @param p_event The event structure pointer.
*
* @note This field is available only when USB internal queue is disabled
* (see @ref APP_USBD_CONFIG_EVENT_QUEUE_ENABLE).
*/
void (*ev_handler)(app_usbd_internal_evt_t const * const p_event);
#endif
#if (APP_USBD_CONFIG_EVENT_QUEUE_ENABLE) || defined(__SDK_DOXYGEN__)
/**
* @brief User defined event handler.
*
* This function is called on every event from the interrupt.
*
* @param p_event The event structure pointer.
* @param queued The event is visible in the queue.
* If queue conflict is detected the event might not be accessible inside queue
* until all write operations finish.
* See @ref nrf_atfifo for more details.
*
* @note This field is available only when USBD internal queue is configured
* (see @ref APP_USBD_CONFIG_EVENT_QUEUE_ENABLE).
*
* @note If is set to NULL no event would be called from interrupt.
* @note This function is called before event is processed.
* It means that if the event type is @ref APP_USBD_EVT_DRV_SETUP,
* there would not be setup field present in the event structure.
*/
void (*ev_isr_handler)(app_usbd_internal_evt_t const * const p_event, bool queued);
#endif
/**
* @brief User defined event processor
*
* This function is called while state event is processed.
*
* * @note This field is available only when USBD internal queue is configured
* (see @ref APP_USBD_CONFIG_EVENT_QUEUE_ENABLE).
*
* @param event Event type.
* Only following events are sent into this function:
* - APP_USBD_EVT_DRV_SOF
* - APP_USBD_EVT_DRV_RESET - Note that it also exits suspend
* - APP_USBD_EVT_DRV_SUSPEND
* - APP_USBD_EVT_DRV_RESUME - It is also generated when remote wakeup is generated
* - APP_USBD_EVT_START
* - APP_USBD_EVT_STOP
* - APP_USBD_EVT_STATE_CHANGED
* - APP_USBD_EVT_POWER_DETECTED
* - APP_USBD_EVT_POWER_REMOVED
* - APP_USBD_EVT_POWER_READY
*/
void (*ev_state_proc)(app_usbd_event_type_t event);
/**
* @brief SOF processing required by the user event processing.
*
* This flag would enable SOF processing for the user events regardless of the fact if any
* of the implemented class requires SOF event.
*
* @note SOF event would be enabled anyway if any of the appended class requires SOF processing.
*/
bool enable_sof;
} app_usbd_config_t;
#if (APP_USBD_PROVIDE_SOF_TIMESTAMP) || defined(__SDK_DOXYGEN__)
/**
* @brief Timestamp function for the logger.
*
* @return Current frame number taken directly from the last processed SOF.
*/
uint32_t app_usbd_sof_timestamp_get(void);
#endif
/**
* @brief USB library initialization.
*
* Call this function before any configuration or class attachment.
* USBD peripheral would be ready to accept commands, and library would be ready,
* but it would not be connected to the bus.
* Call @ref app_usbd_enable to enable USBD communication with the host.
*
* @param p_config Configuration. NULL pointer might be passed here and default
* configuration will be applied then.
*/
ret_code_t app_usbd_init(app_usbd_config_t const * p_config);
/**
* @brief USB library un-initialization.
*
* @note Currently not supported.
*/
ret_code_t app_usbd_uninit(void);
#if (APP_USBD_CONFIG_POWER_EVENTS_PROCESS) || defined(__SDK_DOXYGEN__)
/**
* @brief Function to start USB related power events processing.
*
* This function should be called after @ref app_usbd_init and after all the
* required classes were appended (@ref app_usbd_class_append).
*
* @retval NRF_SUCCESS Power events successfully initialized.
* @retval NRF_ERROR_INVALID_STATE The state of the driver does not allow to enable
* the power events processing.
*/
ret_code_t app_usbd_power_events_enable(void);
#endif
/**
* @brief Enable USBD.
*
* USBD is enabled.
* Since now the high frequency clock may be requested when USB RESET would be detected.
*/
void app_usbd_enable(void);
/**
* @brief Disable USBD.
*
* Disabled USDB peripheral cannot be accessed but also stops requesting
* High Frequency clock and releases power regulator.
*
* @note This function cannot be called when USB is started. Stop it first.
*/
void app_usbd_disable(void);
/**
* @brief Request USBD to start.
*
* The function sends start request to the event queue.
* If the queue is enabled (@ref APP_USBD_CONFIG_EVENT_QUEUE_ENABLE) it would be processed
* when the queue is processed.
* If queue is disabled it would be processed immediately inside this function.
* It means that if queue is disabled this function cannot be called from interrupt with priority
* higher than USB interrupt.
*
* When start is processed it would:
* 1. Start library.
* 2. Enable interrupts.
* 3. Enable USB pull-ups.
*
* @note
* In some specific circumstances the library can be left not started and this function would
* silently exit.
* This may happen if some glitches appears on USB power line or if the plug was disconnected before
* whole starting process finishes.
* User would get the event from POWER peripheral then.
* Also no @ref APP_USBD_EVT_STARTED event would be generated to the classes and user event handler.
* For the safe code it is recommended to wait for @ref APP_USBD_EVT_STARTED event if anything
* has to be initialized after USB driver is started (just before enabling the interrupts).
* If library is properly started the @ref APP_USBD_EVT_STARTED event passed to the user handler
* from this function body.
*/
void app_usbd_start(void);
/**
* @brief Stop USB.
*
* The function sends stop request to the event queue.
* If the queue is enabled (@ref APP_USBD_CONFIG_EVENT_QUEUE_ENABLE) it would be processed
* when the queue is processed.
* If queue is disabled it would be processed immediately inside this function.
* It means that if queue is disabled this function cannot be called from interrupt with priority
* higher than USB interrupt.
*
* When the event is processed interrupts and USB pull-ups are disabled.
* The peripheral itself is left enabled so it can be programmed,
* but a HOST sees it as a peripheral disconnection.
*
* @note
* If the library is not started when this function is called it exits silently - also
* no @ref APP_USBD_EVT_STOPPED is generated.
*/
void app_usbd_stop(void);
/**
* @brief Request library to suspend.
*
* This function send suspend request to the event queue.
*
* @note This function should only be called after @ref APP_USBD_EVT_DRV_SUSPEND os received.
* Internal suspend request processing would give no effect if the bus is not in suspend state.
*/
void app_usbd_suspend_req(void);
/**
* @brief Request library to wake-up.
*
* This function send wakeup request to the event queue.
*
* @note Calling this function does not mean that peripheral is active - the wakeup request is sent
* into message queue and needs to be processed.
*
* @retval true Wakeup generation has been started.
* @retval false No wakeup would be generated becouse it is disabled by the host.
*/
bool app_usbd_wakeup_req(void);
/**
* @brief Get information whether there is an active connection.
*
* Function to check if the communication with the bus is possible.
*
* @retval true The bus is active.
* @retval false There is no connection or bus is suspended.
*/
bool app_usbd_active_check(void);
/**
* @brief USBD event processor.
*
* Function to be called on each event to be processed by the library.
*/
void app_usbd_event_execute(app_usbd_internal_evt_t const * const p_event);
#if (APP_USBD_CONFIG_EVENT_QUEUE_ENABLE) || defined(__SDK_DOXYGEN__)
/**
* @brief Function that process events from the queue.
*
* @note This function calls @ref app_usbd_event_execute internally.
*
* @retval true Event was processed.
* @retval false The event queue is empty.
*/
bool app_usbd_event_queue_process(void);
#endif
/**
* @brief Add class instance.
*
* This function connects given instance into internal class instance chain and
* into all required endpoints.
* The instance event handler would be connected into endpoint by default,
* but this can be overwritten by @ref app_usbd_ep_handler_set.
*
* After successful attachment @ref APP_USBD_EVT_INST_APPEND would be passed to class instance.
*
* @note This function can only be called after USBD library is initialized but still disabled.
* Assertion would be generated otherwise.
*
* @param[in,out] p_cinst Instance to connect. Chain data would be written into writable instance data.
*
* @retval NRF_SUCCESS Instance successfully added.
* @retval NRF_ERROR_BUSY Endpoint(s) not available.
*/
ret_code_t app_usbd_class_append(app_usbd_class_inst_t const * p_cinst);
/**
* @brief Remove class instance.
*
* Instance is removed from instance chain.
* Instance and event handlers are removed also from endpoints.
* Endpoints used by by the class instance are left disabled.
*
* @note This function can only be called after USBD library is initialized but still disabled.
* Assertion would be generated otherwise.
*
* @param p_cinst Instance pointer to remove.
*
* @retval NRF_SUCCESS Instance successfully removed.
* @retval NRF_ERROR_NOT_FOUND Instance not found in the instance chain.
*/
ret_code_t app_usbd_class_remove(app_usbd_class_inst_t const * p_cinst);
/**
* @brief Remove all class instances.
*
* This function basically calls @ref app_usbd_class_remove
* on instances chain as long as there is any element left.
*
* @note This function can only be called after USBD library is initialized but still disabled.
* Assertion would be generated otherwise.
*
* @sa app_usbd_class_remove
*
* @return Is should always return @ref NRF_SUCCESS.
* Any error value returned would mean there is an error inside the library.
*/
ret_code_t app_usbd_class_remove_all(void);
/**
* @brief Change endpoint handler.
*
* This function may be called for the endpoint only if the class instance is
* already properly attached by the @ref app_usbd_class_append function.
*
* The endpoint event handler function can be only overwritten by the class instance
* that was connected into the endpoint.
*
* @note This function can only be called after USBD library is initialized but still disabled.
* Assertion would be generated otherwise.
*
* @param[in] p_cinst Instance of a class that wish to set new event handler.
* It has to match currently configured instance for the selected endpoint.
* In other situation error would be returned.
* @param[in] ep Endpoint address to configure.
* @param[in] handler Event handler function to set.
*
* @retval NRF_SUCCESS New handler successfully set
* @retval NRF_ERROR_INVALID_PARAM p_cinst is not the same as currently set for the endpoint
*/
ret_code_t app_usbd_ep_handler_set(app_usbd_class_inst_t const * p_cinst,
nrf_drv_usbd_ep_t ep,
app_usbd_ep_event_handler_t handler);
/**
* @brief Register class instance as the one that requires SOF events.
*
* This function should be called in reaction on APP_USBD_EVT_INST_APPEND event.
* Connect the class instance to the list of instances that requires SOF processing.
* If none of the appended instances requires SOF event - it is disabled.
*
* @param p_cinst Instance that requires SOF event.
*
* @retval NRF_SUCCESS Instance linked into SOF processing list.
*
* @sa app_usbd_class_sof_unregister
*/
ret_code_t app_usbd_class_sof_register(app_usbd_class_inst_t const * p_cinst);
/**
* @brief Unregister class instance from SOF processing instances list.
*
* Every class that calls @ref app_usbd_class_sof_register have to call also unregistering function
* in reaction to @ref APP_USBD_EVT_INST_REMOVE event.
*
* @param p_cinst Instance to be unregistered from SOF event processing list.
*
* @retval NRF_SUCCESS Instance linked into SOF processing list.
* @retval NRF_ERROR_NOT_FOUND Instance not found in the SOF processing list.
*
* @sa app_usbd_class_sof_register
*/
ret_code_t app_usbd_class_sof_unregister(app_usbd_class_inst_t const * p_cinst);
/**
* @brief Register class instance as the one that requires SOF events in interrupt.
*
* This function should be called in reaction on APP_USBD_EVT_INST_APPEND event.
* Connect the class instance to the list of instances that requires SOF processing.
* If none of the appended instances requires SOF event - it is disabled.
*
* @param p_cinst Instance that requires SOF event.
* @param handler Handler to SOF event
*
* @retval NRF_SUCCESS Instance linked into SOF processing list.
*
* @sa app_usbd_class_sof_interrupt_unregister
*/
ret_code_t app_usbd_class_sof_interrupt_register(app_usbd_class_inst_t const * p_cinst,
app_usbd_sof_interrupt_handler_t handler);
/**
* @brief Unregister class instance from SOF processing in interrupt instances list.
*
* Every class that calls @ref app_usbd_class_sof_interrupt_register have to call
* also unregistering function in reaction to @ref APP_USBD_EVT_INST_REMOVE event.
*
* @param p_cinst Instance to be unregistered from SOF processing in interrupt list.
*
* @retval NRF_SUCCESS Instance linked into SOF processing in interrupt list.
* @retval NRF_ERROR_NOT_FOUND Instance not found in the SOF processing in interrupt list.
*
* @sa app_usbd_class_sof_interrupt_register
*/
ret_code_t app_usbd_class_sof_interrupt_unregister(app_usbd_class_inst_t const * p_cinst);
/**
* @brief Register class on remote wake-up feature.
*
* @param[in] p_inst Instance of the class.
*
* @retval NRF_SUCCESS Instance that requires remote wake-up registered.
*/
ret_code_t app_usbd_class_rwu_register(app_usbd_class_inst_t const * const p_inst);
/**
* @brief Unregister class from remote wake-up feature.
*
* @param[in] p_inst Instance of the class.
*
* @retval NRF_SUCCESS Instance that requires remote wake-up removed.
*/
ret_code_t app_usbd_class_rwu_unregister(app_usbd_class_inst_t const * const p_inst);
/**
* @brief Check if there is any class with remote wakeup.
*
* The function checks internal registered class with remote wakeup counter.
*
* @sa app_usbd_class_rwu_register, app_usbd_class_rwu_unregister
*
* @retval true The remote wakeup functionality is required by some class instance.
* @retval false There is no class instance that requires wakeup functionality.
*/
bool app_usbd_class_rwu_enabled_check(void);
/**
* @brief Find a specified descriptor.
*
* @param[in] p_cinst Class instance.
* @param[in] desc_type Descriptor type @ref app_usbd_descriptor_t
* @param[in] desc_index Descriptor index.
* @param[out] p_desc Pointer to escriptor.
* @param[out] p_desc_len Length of descriptor.
*
* @return Standard error code @ref ret_code_t
* @retval NRF_SUCCESS Descriptor successfully found.
* @retval NRF_ERROR_NOT_FOUND Descriptor not found.
* */
ret_code_t app_usbd_class_descriptor_find(app_usbd_class_inst_t const * const p_cinst,
uint8_t desc_type,
uint8_t desc_index,
uint8_t * p_desc,
size_t * p_desc_len);
/**
* @brief Standard set interface request handle.
*
* This function should be called when processing SET_INTERFACE request.
*
* @param[in] p_cinst Instance of a class.
* @param[in] iface Interface number.
*
* @return Standard error code.
*
* @note Selected interface to reset has to be part of given class.
* */
ret_code_t app_usbd_interface_ep_reset(app_usbd_class_inst_t const * const p_cinst,
uint8_t iface);
/**
* @brief Enable selected endpoint.
*
* Selected endpoint is enabled and cleared.
*
* @param ep Endpoint number.
*/
void app_usbd_ep_enable(nrf_drv_usbd_ep_t ep);
/**
* @brief Disable selected endpoint.
*
* @param ep Endpoint number.
*/
void app_usbd_ep_disable(nrf_drv_usbd_ep_t ep);
/**
* @name Iterate through classes lists
*
* Functions that helps to iterate through internally chained classes.
* @{
*/
/**
* @brief Get first class instance in the list.
*
* Get first instance from the list of active class instances.
* That instance may be used then in @ref app_usbd_class_next_get function.
*
* @return First instance in the list or NULL if there are no instances available.
*/
app_usbd_class_inst_t const * app_usbd_class_first_get(void);
/**
* @brief Get next instance in the list.
*
* Get the next instance from the list of active instances.
* Used to iterate through all instances.
*
* @param[in] p_cinst The current instance from with next one is required.
*
* @return Next instance to the given one or NULL if there is no more instances in the list.
*/
static inline app_usbd_class_inst_t const * app_usbd_class_next_get(
app_usbd_class_inst_t const * const p_cinst)
{
ASSERT(NULL != p_cinst);
return app_usbd_class_data_access(p_cinst)->p_next;
}
/**
* @brief Get first instance in SOF list.
*
* Start iteration through the list of instances that require SOF event processing.
*
* @return First instance in the list or NULL if the list is empty.
*
* @sa app_usbd_class_first_get
*/
app_usbd_class_inst_t const * app_usbd_class_sof_first_get(void);
/**
* @brief Get next instance in the SOF list.
*
* Get the next instance from the list of instances requiring SOF event processing.
* Used to iterate through all SOF instances.
*
* @param p_cinst The current instance from with next one is required.
*
* @return Next instance to the given one or NULL if there is no more instances in the list.
*/
static inline app_usbd_class_inst_t const * app_usbd_class_sof_next_get(
app_usbd_class_inst_t const * const p_cinst)
{
ASSERT(NULL != p_cinst);
return app_usbd_class_data_access(p_cinst)->p_sof_next;
}
/**
* @brief Get first instance in SOF interrupt list.
*
* Start iteration through the list of instances that require SOF processing in interrupt.
*
* @return First instance in the list or NULL if the list is empty.
*
* @sa app_usbd_class_first_get
*/
app_usbd_class_inst_t const * app_usbd_class_sof_interrupt_first_get(void);
/**
* @brief Get next instance in the SOF interrupt list.
*
* Get the next instance from the list of instances requiring SOF processing in interrupt.
* Used to iterate through all SOF instances that have SOF handlers.
*
* @param p_cinst The current instance from with next one is required.
*
* @return Next instance to the given one or NULL if there is no more instances in the list.
*/
static inline app_usbd_class_inst_t const * app_usbd_class_sof_interrupt_next_get(
app_usbd_class_inst_t const * const p_cinst)
{
ASSERT(NULL != p_cinst);
return app_usbd_class_data_access(p_cinst)->p_sof_next;
}
/** @} */
/**
* @brief Search for selected interface.
*
* Function searches for the given interface number and returns the class that contains it.
* Optionally it can return interface index inside class instance.
*
* @param[in] iface Interface number.
* @param[out] p_iface_idx Pointer to a variable that would hold interface index inside returned
* class instance.
*
* @return Pointer to the class structure that cointain given interface or NULL if not found.
*/
app_usbd_class_inst_t const * app_usbd_iface_find(uint8_t iface, uint8_t * p_iface_idx);
/**
* @name Communicate with interfaces, endpoints and instances inside usbd library
*
* @{
*/
/**
* @brief Call interface event handler.
*
* Call event handler for selected interface.
* @param[in,out] p_class_inst Class instance that holds selected interface.
* @param[in] iface_idx Index of the interface in class structure.
* @param[in] p_event Event structure to be processed.
*
* @return Operation status.
*/
ret_code_t app_usbd_iface_call(
app_usbd_class_inst_t const * const p_class_inst,
uint8_t iface_idx,
app_usbd_complex_evt_t const * const p_event);
/**
* @brief Call endpoint event handler.
*
* Call event handler for the selected endpoint.
* @param[in] ep Endpoint number.
* @param[in] p_event Event structure to send.
*
* @return Operation status.
*/
ret_code_t app_usbd_ep_call(nrf_drv_usbd_ep_t ep, app_usbd_complex_evt_t const * const p_event);
/**
* @brief Auxiliary function that process event by every instance in the list.
*
* This function ignores the result of called handler.
*
* @param p_event Event to pass to every instance.
*/
void app_usbd_all_call(app_usbd_complex_evt_t const * const p_event);
/**
* @brief Call interface event handlers and stop when served.
*
* Call event handlers from instances as long as we get result different than @ref NRF_ERROR_NOT_SUPPORTED
* @param[in] p_event Event structure to send.
*
* @return Operation status or @ref NRF_ERROR_NOT_SUPPORTED if none of instances in the list can support given event.
*/
ret_code_t app_usbd_all_until_served_call(app_usbd_complex_evt_t const * const p_event);
/** @} */
/**
* @brief Endpoint transfer.
*
* @param ep Endpoint number.
* @param p_transfer Description of the transfer to be performed.
* The direction of the transfer is determined by the
* endpoint number.
*
* @retval NRF_ERROR_INVALID_STATE The state of the USB device does not allow
* data transfer on the endpoint.
* @return Values returned by @ref nrf_drv_usbd_ep_transfer.
*
* @sa app_usbd_ep_handled_transfer
*/
ret_code_t app_usbd_ep_transfer(
nrf_drv_usbd_ep_t ep,
nrf_drv_usbd_transfer_t const * const p_transfer);
/**
* @brief Set up an endpoint handled transfer.
*
* Configures a transfer handled by the feedback function.
*
* @param ep Endpoint number.
* @param p_handler Function called when the next chunk of data is requested.
*
* @retval NRF_ERROR_INVALID_STATE The state of the USB device does not allow
* data transfer on the endpoint.
* @return Values returned by @ref nrf_drv_usbd_ep_handled_transfer.
*/
ret_code_t app_usbd_ep_handled_transfer(
nrf_drv_usbd_ep_t ep,
nrf_drv_usbd_handler_desc_t const * const p_handler);
/**
* @brief Select interface
*
* Select the given interface.
* This function calls class interface selection function or default
* interface selection function.
*
* After calling this function interface should be functional.
*
* @param[in,out] p_inst Instance of the class.
* @param[in] iface_idx Index of the interface inside class structure.
* @param[in] alternate Alternate setting that should be selected.
*
* @return Standard error code.
*/
ret_code_t app_usbd_iface_select(
app_usbd_class_inst_t const * const p_inst,
uint8_t iface_idx,
uint8_t alternate);
/**
* @brief Deselect interface.
*
* Disable the given interface.
* This function calls class interface deselection function or
* default interface selection function.
*
* After calling this function all the endpoints from the interface
* have to be disabled.
*
* @param[in,out] p_inst Instance of the class.
* @param[in] iface_idx Index of the interface inside class structure.
*/
void app_usbd_iface_deselect(
app_usbd_class_inst_t const * const p_inst,
uint8_t iface_idx);
/**
* @brief Get selected interface.
*
* Function retieves currently selected interface.
* If the class contains @ref app_usbd_class_methods_t::iface_selection_get it is called.
* It it does not contain this function this function would return default, 0 value.
*
* @param[in] p_inst Instance of the class.
* @param[in] iface_idx Index of the interface inside class structure.
*
* @return Selected alternate interface setting.
*/
uint8_t app_usbd_iface_selection_get(
app_usbd_class_inst_t const * const p_inst,
uint8_t iface_idx);
/**
* @brief Select alternate configuration 0 for all interfaces.
*
* Auxiliary function that clears settings for all interfaces leaving them enabled.
*/
void app_usbd_all_iface_select_0(void);
/**
* @brief Deselect all interfaces.
*
* Auxiliary function to disable all interfaces.
*/
void app_usbd_all_iface_deselect(void);
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* APP_USBD_H__ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,222 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef APP_USBD_CORE_H__
#define APP_USBD_CORE_H__
#include <stdint.h>
#include "sdk_common.h"
#include "nrf_drv_usbd.h"
#include "app_usbd_types.h"
#include "app_usbd_class_base.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup app_usbd_core USB Device high level library core module
* @ingroup app_usbd
*
* @brief @tagAPI52840 Core module that manages current USB state and process device requests.
* @{
*/
/**
* @brief Core interface configuration.
*
* Core instance would have 2 endpoints (IN0 and OUT0).
* The interface number does not matter because it is not used.
*/
#define APP_USBD_CORE_CLASS_CONFIGURATION ((0, NRF_DRV_USBD_EPOUT0, NRF_DRV_USBD_EPIN0))
/**
* @brief USB Device state.
*
* Possible USB Device states according to specification.
*/
typedef enum
{
APP_USBD_STATE_Disabled , /**< The whole USBD library is disabled */
APP_USBD_STATE_Unattached, /**< Device is currently not connected to the host */
APP_USBD_STATE_Powered , /**< Device is connected to the host but has not been enumerated */
APP_USBD_STATE_Default , /**< USB Reset condition detected, waiting for the address */
APP_USBD_STATE_Addressed , /**< Device has been addressed but has not been configured */
APP_USBD_STATE_Configured, /**< Device is addressed and configured */
}app_usbd_state_t;
/**
* @brief EP0 handler function pointer.
*
* Type of the variable that would hold the pointer to the handler for
* endpoint 0 messages processing.
*
* @param p_contex Context variable configured with the transmission request.
*/
typedef ret_code_t (*app_usbd_core_setup_data_handler_t)(nrf_drv_usbd_ep_status_t status,
void * p_context);
/**
* @brief Variable type used to register EP0 transfer handler.
*
* EP0 messages are processed by core instance.
* Another class can register itself to receive messages from EP0 when requesting
* for Setup data transfer.
*/
typedef struct
{
app_usbd_core_setup_data_handler_t handler; //!< Event handler to be called when transmission is ready
void * p_context; //!< Context pointer to be send to every called event.
} app_usbd_core_setup_data_handler_desc_t;
/*lint -save -e10 -e26 -e93 -e123 -e505 */
/**
* @brief Declare Core instance type.
*
* USBD core instance type definition.
*/
APP_USBD_CLASS_TYPEDEF(app_usbd_core,
APP_USBD_CORE_CLASS_CONFIGURATION,
APP_USBD_CLASS_INSTANCE_SPECIFIC_DEC_NONE,
APP_USBD_CLASS_DATA_SPECIFIC_DEC_NONE);
/*lint -restore*/
/**
* @brief Access to core instance.
*
* Function that returns pointer to the USBD core instance.
*
* @return pointer to the core instance.
*/
static inline app_usbd_class_inst_t const * app_usbd_core_instance_access(void)
{
extern const APP_USBD_CLASS_INSTANCE_TYPE(app_usbd_core) app_usbd_core_inst;
return (app_usbd_class_inst_t const *)&app_usbd_core_inst;
}
/**
* @brief Enable endpoint 0
*
* Function enables endpoint OUT0 and IN0.
* This makes the USB respond to SETUP transfers.
*/
void app_usbd_core_ep0_enable(void);
/**
* @brief Disable endpoint 0
*
* Function disables endpoint OUT0 and IN0.
* This makes the USB ignore SETUP transfers.
*/
void app_usbd_core_ep0_disable(void);
/**
* @brief Default simple response to setup command.
*
* This function generates default simple response.
* It sends ZLP when required and on takes care on allowing status stage when
* transfer is finished.
*
* @param p_setup Pointer to original setup message.
* @param p_data Pointer to the response. This has to be globaly aviable data.
* @param size Total size of the answer - The function takes care about
* limiting the size of transfered data to the size required
* by setup command.
*/
ret_code_t app_usbd_core_setup_rsp(app_usbd_setup_t const * p_setup,
void const * p_data,
size_t size);
/**
* @brief Configure the handler for the nearest setup data endpoint transfer.
*
* This function would be called on incomming setup data.
* The correct place to set the handler for a data is when SETUP command
* was received.
*
* @param ep Endpoint number (only IN0 and OUT0 are supported).
* @param p_handler_desc Descriptor of the handler to be called.
*
* @retval NRF_SUCCESS Successfully configured.
* @retval NRF_ERROR_INVALID_ADDR Last received setup direction does not match
* configured endpoint.
*/
ret_code_t app_usbd_core_setup_data_handler_set(
nrf_drv_usbd_ep_t ep,
app_usbd_core_setup_data_handler_desc_t const * const p_handler_desc);
/**
* @brief Set up a data transfer buffer.
*
* Returns special internal buffer that can be used in setup transfer.
* @return Internal buffer pointer.
*/
void * app_usbd_core_setup_transfer_buff_get(size_t * p_size);
/**@brief Return internal USBD core state.
*
* @return Check @ref app_usbd_state_t to find possible USBD core states.
*/
app_usbd_state_t app_usbd_core_state_get(void);
/**
* @brief Check current feature state.
*
* Function checks the state of the selected feature that was configured by the host.
*
* @param feature Feature to check. @ref app_usbd_setup_stdfeature_t
* Only features related to the device should be checked by this function.
*
* @retval true Selected feature is set.
* @retval false Selected feature is cleared.
*/
bool app_usbd_core_feature_state_get(app_usbd_setup_stdfeature_t feature);
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* APP_USBD_CORE_H__ */

View File

@@ -1,337 +0,0 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef APP_USBD_DESCRIPTOR_H__
#define APP_USBD_DESCRIPTOR_H__
#include "nrf.h"
#include "nrf_drv_usbd.h"
#include "app_usbd_langid.h"
#include "app_util_platform.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Compiler support for anonymous unions */
ANON_UNIONS_ENABLE;
/**
* @defgroup app_usbd_descriptor USB standard descriptors
* @ingroup app_usbd
*
* @brief @tagAPI52840 Module with types definitions used for standard descriptors.
* @{
*/
/**
* @brief Helper macro for translating unsigned 24 bit value to 2 byte raw descriptor.
* */
#define APP_USBD_U16_TO_RAW_DSC(val) (uint8_t)(val), \
(uint8_t)(((val) / (256)))
/**
* @brief Helper macro for translating unsigned 24 bit value to 3 byte raw descriptor.
* */
#define APP_USBD_U24_TO_RAW_DSC(val) (uint8_t)(val), \
(uint8_t)(((val) / (256))), \
(uint8_t)(((val) / (256 * 256)))
/**
* @brief Helper macro for translating unsigned 32 bit value to 4 byte raw descriptor.
* */
#define APP_USBD_U32_TO_RAW_DSC(val) (uint8_t)(val), \
(uint8_t)(((val) / (256))), \
(uint8_t)(((val) / (256 * 256))) \
(uint8_t)(((val) / (256 * 256 * 256)))
/**
* @brief Descriptor types.
*
* Descriptor types used in two situations:
* - When processing @ref APP_USBD_SETUP_STDREQ_GET_DESCRIPTOR SETUP request,
* the required descriptor type may be placed in wValue in HighByte.
* - As a descriptor identifier itself inside descriptor stream.
*
* According to chapter 9.6 of USB 2.0 specification, following descriptors may
* be requested directly by GetDescriptor method:
* - @ref APP_USBD_DESCRIPTOR_DEVICE
* - @ref APP_USBD_DESCRIPTOR_DEVICE_QUALIFIER (not used for FullSpeed only device)
* - @ref APP_USBD_DESCRIPTOR_CONFIGURATION
* - @ref APP_USBD_DESCRIPTOR_STRING
*/
typedef enum
{
APP_USBD_DESCRIPTOR_DEVICE = 1, /**< Device descriptor. */
APP_USBD_DESCRIPTOR_CONFIGURATION = 2, /**<
* Specific configuration descriptor.
* Configuration descriptor is always followed by all the related interface
* and endpoints descriptors.
*/
APP_USBD_DESCRIPTOR_STRING = 3, /**< String descriptor. */
APP_USBD_DESCRIPTOR_INTERFACE = 4, /**<
* Interface descriptor followed by all the related endpoints descriptors.
*
* @note It is returned together with @ref APP_USBD_DESCRIPTOR_CONFIGURATION.
* Cannot be accessed by GetDescriptor or SetDescriptor
*/
APP_USBD_DESCRIPTOR_ENDPOINT = 5, /**<
* Endpoint descriptor.
*
* @note It is returned together with @ref APP_USBD_DESCRIPTOR_CONFIGURATION.
* Cannot be accessed by GetDescriptor or SetDescriptor
*/
APP_USBD_DESCRIPTOR_DEVICE_QUALIFIER = 6, /**< @note Not supported - used only in HighSpeed capable devices. */
APP_USBD_DESCRIPTOR_OTHER_SPEED_CONFIGURATION = 7, /**< @note Not supported - USB library supports only one speed. */
APP_USBD_DESCRIPTOR_INTERFACE_POWER = 8, /**< @note Not supported */
APP_USBD_DESCRIPTOR_OTG = 9, /**< @note Not supported - USB library does not have OTG functionality */
APP_USBD_DESCRIPTOR_DEBUG = 10, /**< Debug channel descriptor if available, can be only reached by GetDescriptor */
APP_USBD_DESCRIPTOR_INTERFACE_ASSOCIATION = 11, /**<
* Descriptor used to describe that two or more interfaces are associated to the same function.
*
* @note It is returned together with @ref APP_USBD_DESCRIPTOR_CONFIGURATION.
* Cannot be accessed by GetDescriptor or SetDescriptor
*/
APP_USBD_DESCRIPTOR_REPORT = 34, /**< HID Report descriptor. */
APP_USBD_DESCRIPTOR_PHYSICAL = 35 /**< HID Physical descriptor. */
} app_usbd_descriptor_t;
/* Make all descriptors packed */
#pragma pack(push, 1)
/**
* @brief Common descriptor header.
*
* The header that we can find on the beginning of all descriptors that contains
* the descriptor length and type.
*/
typedef struct
{
uint8_t bLength; //!< Size of the descriptor in bytes.
uint8_t bDescriptorType; //!< Should equal one of @ref app_usbd_descriptor_t.
/** Class specific descriptors values are defined inside classes. */
} app_usbd_descriptor_header_t;
/**
* @brief Device descriptor.
*
* Descriptor used for the whole device.
*/
typedef struct
{
uint8_t bLength; //!< Size of the descriptor in bytes.
uint8_t bDescriptorType; //!< Should equal to @ref APP_USBD_DESCRIPTOR_DEVICE.
uint16_t bcdUSB; //!< USB Specification Release Number in Binary-Coded Decimal
uint8_t bDeviceClass; //!< Device class code.
/**< If 0, each interface specifies its own class information.
* 0xFF for vendor-specific.
*/
uint8_t bDeviceSubClass; //!< Subclass code.
/**< If bDevice Class is set to value other than 0xFF,
* all values here are reserved for assignment by USB-IF.
*/
uint8_t bDeviceProtocol; //!< Subclass code.
/**< If 0, no specific protocol is defined on device basis.
* Each interface may define its own protocol then.
* If set to 0xFF, vendor-specific protocol is used.
*/
uint8_t bMaxPacketSize0; //!< Maximum packet size for endpoint zero.
uint16_t idVendor; //!< Vendor ID (Assigned by the USB-IF).
uint16_t idProduct; //!< Product ID (assigned by manufacturer).
uint16_t bcdDevice; //!< Device release number in binary-coded decimal.
uint8_t iManufacturer; //!< Index of string descriptor in describing manufacturer.
uint8_t iProduct; //!< Index of string descriptor in describing product.
uint8_t iSerialNumber; //!< Index of string descriptor in describing the device's serial number.
uint8_t bNumConfigurations; //!< Number of possible configurations.
} app_usbd_descriptor_device_t;
/**
* @brief Attributes masks.
*
* Masks used for attributes in configuration.
*/
typedef enum
{
/** This is reserved descriptor that has always to be set */
APP_USBD_DESCRIPTOR_CONFIGURATION_ATTRIBUTE_ALWAYS_SET_MASK = 1U << 7,
/** Attribute that informs that device is self powered */
APP_USBD_DESCRIPTOR_CONFIGURATION_ATTRIBUTE_SELF_POWERED_MASK = 1U << 6,
/** Attribute that informs that device has Remove Wakeup functionality */
APP_USBD_DESCRIPTOR_CONFIGURATION_ATTRIBUTE_REMOTE_WAKEUP_MASK = 1U << 5
} app_usbd_descriptor_configuration_attributes_t;
/**
* @brief Configuration descriptor.
*
* Descriptor used at the beginning of configuration response.
*/
typedef struct
{
uint8_t bLength; //!< Size of the descriptor in bytes.
uint8_t bDescriptorType; //!< Should equal to @ref APP_USBD_DESCRIPTOR_DEVICE.
uint16_t wTotalLength; //!< Total length of configuration data, including all descriptors returned after configuration itself.
uint8_t bNumInterfaces; //!< Number of interfaces supportedf by this configuration
uint8_t bConfigurationValue; //!< Value to use as an argument to the SetConfiguration request.
uint8_t iConfiguration; //!< Index of string descriptor describing this configuration.
uint8_t bmAttributes; //!< Configuration characteristics.
uint8_t bMaxPower; //!< Maximum power consumption. Expressed in 2&nbsp;mA units.
} app_usbd_descriptor_configuration_t;
/**
* @brief Raw descriptor - String descriptor zero.
*
* String descriptor sent only as a response for GetDescriptor.
*/
typedef struct
{
uint8_t bLength; //!< Size of the descriptor in bytes.
uint8_t bDescriptorType; //!< Should equal to @ref APP_USBD_DESCRIPTOR_STRING.
uint16_t wLANGID[]; //!< The array of LANGID codes supported by the device.
} app_usbd_descriptor_string0_t;
/**
* @brief Raw descriptor - Any normal string.
*
* String descriptor sent only as a response for GetDescriptor.
*/
typedef struct
{
uint8_t bLength; //!< Size of the descriptor in bytes.
uint8_t bDescriptorType; //!< Should equal to @ref APP_USBD_DESCRIPTOR_STRING.
uint16_t bString[]; //!< UNICODE encoded string.
} app_usbd_descriptor_string_t;
/**
* @brief Interface descriptor.
*
* Interface descriptor, returned as a part of configuration descriptor.
*/
typedef struct
{
uint8_t bLength; //!< Size of the descriptor in bytes.
uint8_t bDescriptorType; //!< Should equal to @ref APP_USBD_DESCRIPTOR_INTERFACE.
uint8_t bInterfaceNumber; //!< Number of this interface.
uint8_t bAlternateSetting; //!< Value used to select this alternate setting.
uint8_t bNumEndpoints; //!< Number of endpoints used by this interface.
uint8_t bInterfaceClass; //!< Class code (assigned by the USB-IF). 0xff for vendor specific.
uint8_t bInterfaceSubClass; //!< Subclass code (assigned by the USB-IF).
uint8_t bInterfaceProtocol; //!< Protocol code (assigned by the USB-IF). 0xff for vendor specific.
uint8_t iInterface; //!< Index of string descriptor describing this interface.
} app_usbd_descriptor_iface_t;
/** Offset of endpoint type attribute bits */
#define APP_USBD_DESCRIPTOR_EP_ATTR_TYPE_OFFSET 0
/** Mask of endpoint type attribute bits */
#define APP_USBD_DESCRIPTOR_EP_ATTR_TYPE_MASK BF_MASK(2, APP_USBD_DESCRIPTOR_EP_ATTR_TYPE_OFFSET)
/** Offset of endpoint synchronization type attribute bits */
#define APP_USBD_DESCRIPTOR_EP_ATTR_SYNC_OFFSET 2
/** Mask of endpoint synchronization type attribute bits */
#define APP_USBD_DESCRIPTOR_EP_ATTR_SYNC_MASK BF_MASK(2, APP_USBD_DESCRIPTOR_EP_ATTR_SYNC_OFFSET)
/** Offset of endpoint usage type attribute bits */
#define APP_USBD_DESCRIPTOR_EP_ATTR_USAGE_OFFSET 4
/** Mask of endpoint usage type attribute bits */
#define APP_USBD_DESCRIPTOR_EP_ATTR_USAGE_MASK BF_MASK(2, APP_USBD_DESCRIPTOR_EP_ATTR_USAGE_OFFSET)
/**
* @brief Endpoint attributes mnemonics.
*
* @sa APP_USBD_DESCRIPTOR_EP_ATTR_TYPE_OFFSET APP_USBD_DESCRIPTOR_EP_ATTR_TYPE_MASK
* @sa APP_USBD_DESCRIPTOR_EP_ATTR_SYNC_OFFSET APP_USBD_DESCRIPTOR_EP_ATTR_SYNC_MASK
* @sa APP_USBD_DESCRIPTOR_EP_ATTR_USAGE_OFFSET APP_USBD_DESCRIPTOR_EP_ATTR_USAGE_MASK
*/
typedef enum
{
APP_USBD_DESCRIPTOR_EP_ATTR_TYPE_CONTROL = 0 << APP_USBD_DESCRIPTOR_EP_ATTR_TYPE_OFFSET,
APP_USBD_DESCRIPTOR_EP_ATTR_TYPE_ISOCHRONOUS = 1 << APP_USBD_DESCRIPTOR_EP_ATTR_TYPE_OFFSET,
APP_USBD_DESCRIPTOR_EP_ATTR_TYPE_BULK = 2 << APP_USBD_DESCRIPTOR_EP_ATTR_TYPE_OFFSET,
APP_USBD_DESCRIPTOR_EP_ATTR_TYPE_INTERRUPT = 3 << APP_USBD_DESCRIPTOR_EP_ATTR_TYPE_OFFSET,
APP_USBD_DESCRIPTOR_EP_ATTR_SYNC_NONE = 0 << APP_USBD_DESCRIPTOR_EP_ATTR_SYNC_OFFSET,
APP_USBD_DESCRIPTOR_EP_ATTR_SYNC_ASYNCHRONOUS = 1 << APP_USBD_DESCRIPTOR_EP_ATTR_SYNC_OFFSET,
APP_USBD_DESCRIPTOR_EP_ATTR_SYNC_ADAPTIVE = 2 << APP_USBD_DESCRIPTOR_EP_ATTR_SYNC_OFFSET,
APP_USBD_DESCRIPTOR_EP_ATTR_SYNC_SYNCHRONOUS = 3 << APP_USBD_DESCRIPTOR_EP_ATTR_SYNC_OFFSET,
APP_USBD_DESCRIPTOR_EP_ATTR_USAGE_DATA = 0 << APP_USBD_DESCRIPTOR_EP_ATTR_USAGE_OFFSET,
APP_USBD_DESCRIPTOR_EP_ATTR_USAGE_FEEDBACK = 1 << APP_USBD_DESCRIPTOR_EP_ATTR_USAGE_OFFSET,
APP_USBD_DESCRIPTOR_EP_ATTR_USAGE_IMPLICIT = 2 << APP_USBD_DESCRIPTOR_EP_ATTR_USAGE_OFFSET
} app_usbd_descriptor_ep_attr_bitmap_t;
/**
* @brief Endpoint descriptor.
*
* Endpoint descriptor, returned as a part of configuration descriptor.
*/
typedef struct
{
uint8_t bLength; //!< Size of the descriptor in bytes.
uint8_t bDescriptorType; //!< Should equal to @ref APP_USBD_DESCRIPTOR_ENDPOINT.
uint8_t bEndpointAddress; //!< Endpoint address
uint8_t bmAttributes; //!< Endpoint attributes
uint16_t wMaxPacketSize; //!< Maximum packet size this endpoint is capable of handling.
uint8_t bInterval; //!< Interval for pooling endpoint for data transfers.
} app_usbd_descriptor_ep_t;
/**
* @brief Interface association descriptor.
*/
typedef struct
{
uint8_t bLength; //!< size of this descriptor in bytes
uint8_t bDescriptorType; //!< INTERFACE descriptor type
uint8_t bFirstInterface; //!< Number of interface
uint8_t bInterfaceCount; //!< value to select alternate setting
uint8_t bFunctionClass; //!< Class code assigned by the USB
uint8_t bFunctionSubClass;//!< Sub-class code assigned by the USB
uint8_t bFunctionProtocol;//!< Protocol code assigned by the USB
uint8_t iFunction; //!< Index of string descriptor
} app_usbd_descriptor_iad_t;
#pragma pack(pop)
ANON_UNIONS_DISABLE;
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* APP_USBD_DESCRIPTOR_H__ */

View File

@@ -1,300 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef APP_USBD_LANGID_H__
#define APP_USBD_LANGID_H__
#ifdef __cplusplus
extern "C" {
#endif
/**
* @file
* @brief This file contains LANGID variable type with all defined values.
*
* This file was created using Language Identifiers (LANGIDs) 3/29/00 Version 1.0,
* available on USB web page:
* http://www.usb.org/developers/docs/USB_LANGIDs.pdf
*
* @note
* Do not include this file directly to the project.
* It is included by @file app_usbd_request.h.
*/
/**
* Offset of the lowest bit of primary language identifier.
* @sa app_usbd_langid_t
*/
#define APP_USB_LANG_OFFSET 0
/**
* Bitmask for a primary language identifier.
* @sa app_usbd_langid_t
*/
#define APP_USB_LANG_MASK BF_MASK(10, APP_USB_LANG_OFFSET)
/**
* Macro for defining language identifier.
*
* @param x Language identifier value.
*/
#define APP_USB_LANG_DEF(x) ((x) << (APP_USB_LANG_OFFSET))
/**
* Offset of the lowest bit of sublanguage identifier.
* @sa app_usbd_langid_t
*/
#define APP_USB_SUBLANG_OFFSET 10
/**
* Bitmask for a sublanguage identifier.
* @sa app_usbd_langid_t
*/
#define APP_USB_SUBLANG_MASK BF_MASK(6, APP_USB_SUBLANG_OFFSET)
/**
* Macro for defining language identifier.
*
* @param x Language identifier value.
*/
#define APP_USB_SUBLANG_DEF(x) ((x) << (APP_USB_SUBLANG_OFFSET))
/**
* @brief Primary language identifiers.
*
* Mnemonics for primary language identifiers.
* This mnemonics can be combined using the logical OR operator with @ref app_usbd_langid_sub_t.
*/
typedef enum
{
APP_USBD_LANG_ARABIC = APP_USB_LANG_DEF(0x01U), /**< Arabic */
APP_USBD_LANG_BULGARIAN = APP_USB_LANG_DEF(0x02U), /**< Bulgarian */
APP_USBD_LANG_CATALAN = APP_USB_LANG_DEF(0x03U), /**< Catalan */
APP_USBD_LANG_CHINESE = APP_USB_LANG_DEF(0x04U), /**< Chinese */
APP_USBD_LANG_CZECH = APP_USB_LANG_DEF(0x05U), /**< Czech */
APP_USBD_LANG_DANISH = APP_USB_LANG_DEF(0x06U), /**< Danish */
APP_USBD_LANG_GERMAN = APP_USB_LANG_DEF(0x07U), /**< German */
APP_USBD_LANG_GREEK = APP_USB_LANG_DEF(0x08U), /**< Greek */
APP_USBD_LANG_ENGLISH = APP_USB_LANG_DEF(0x09U), /**< English */
APP_USBD_LANG_SPANISH = APP_USB_LANG_DEF(0x0aU), /**< Spanish */
APP_USBD_LANG_FINNISH = APP_USB_LANG_DEF(0x0bU), /**< Finnish */
APP_USBD_LANG_FRENCH = APP_USB_LANG_DEF(0x0cU), /**< French */
APP_USBD_LANG_HEBREW = APP_USB_LANG_DEF(0x0dU), /**< Hebrew */
APP_USBD_LANG_HUNGARIAN = APP_USB_LANG_DEF(0x0eU), /**< Hungarian */
APP_USBD_LANG_ICELANDIC = APP_USB_LANG_DEF(0x0fU), /**< Icelandic */
APP_USBD_LANG_ITALIAN = APP_USB_LANG_DEF(0x10U), /**< Italian */
APP_USBD_LANG_JAPANESE = APP_USB_LANG_DEF(0x11U), /**< Japanese */
APP_USBD_LANG_KOREAN = APP_USB_LANG_DEF(0x12U), /**< Korean */
APP_USBD_LANG_DUTCH = APP_USB_LANG_DEF(0x13U), /**< Dutch */
APP_USBD_LANG_NORWEGIAN = APP_USB_LANG_DEF(0x14U), /**< Norwegian */
APP_USBD_LANG_POLISH = APP_USB_LANG_DEF(0x15U), /**< Polish */
APP_USBD_LANG_PORTUGUESE = APP_USB_LANG_DEF(0x16U), /**< Portuguese */
APP_USBD_LANG_ROMANIAN = APP_USB_LANG_DEF(0x18U), /**< Romanian */
APP_USBD_LANG_RUSSIAN = APP_USB_LANG_DEF(0x19U), /**< Russian */
APP_USBD_LANG_CROATIAN = APP_USB_LANG_DEF(0x1aU), /**< Croatian */
APP_USBD_LANG_SERBIAN = APP_USB_LANG_DEF(0x1aU), /**< Serbian */
APP_USBD_LANG_SLOVAK = APP_USB_LANG_DEF(0x1bU), /**< Slovak */
APP_USBD_LANG_ALBANIAN = APP_USB_LANG_DEF(0x1cU), /**< Albanian */
APP_USBD_LANG_SWEDISH = APP_USB_LANG_DEF(0x1dU), /**< Swedish */
APP_USBD_LANG_THAI = APP_USB_LANG_DEF(0x1eU), /**< Thai */
APP_USBD_LANG_TURKISH = APP_USB_LANG_DEF(0x1fU), /**< Turkish */
APP_USBD_LANG_URDU = APP_USB_LANG_DEF(0x20U), /**< Urdu */
APP_USBD_LANG_INDONESIAN = APP_USB_LANG_DEF(0x21U), /**< Indonesian */
APP_USBD_LANG_UKRANIAN = APP_USB_LANG_DEF(0x22U), /**< Ukrainian */
APP_USBD_LANG_BELARUSIAN = APP_USB_LANG_DEF(0x23U), /**< Belarusian */
APP_USBD_LANG_SLOVENIAN = APP_USB_LANG_DEF(0x24U), /**< Slovenian */
APP_USBD_LANG_ESTONIAN = APP_USB_LANG_DEF(0x25U), /**< Estonian */
APP_USBD_LANG_LATVIAN = APP_USB_LANG_DEF(0x26U), /**< Latvian */
APP_USBD_LANG_LITHUANIAN = APP_USB_LANG_DEF(0x27U), /**< Lithuanian */
APP_USBD_LANG_FARSI = APP_USB_LANG_DEF(0x29U), /**< Farsi */
APP_USBD_LANG_VIETNAMESE = APP_USB_LANG_DEF(0x2aU), /**< Vietnamese */
APP_USBD_LANG_ARMENIAN = APP_USB_LANG_DEF(0x2bU), /**< Armenian */
APP_USBD_LANG_AZERI = APP_USB_LANG_DEF(0x2cU), /**< Azeri */
APP_USBD_LANG_BASQUE = APP_USB_LANG_DEF(0x2dU), /**< Basque */
APP_USBD_LANG_MACEDONIAN = APP_USB_LANG_DEF(0x2fU), /**< Macedonian */
APP_USBD_LANG_AFRIKAANS = APP_USB_LANG_DEF(0x36U), /**< Afrikaans */
APP_USBD_LANG_GEORGIAN = APP_USB_LANG_DEF(0x37U), /**< Georgian */
APP_USBD_LANG_FAEROESE = APP_USB_LANG_DEF(0x38U), /**< Faeroese */
APP_USBD_LANG_HINDI = APP_USB_LANG_DEF(0x39U), /**< Hindi */
APP_USBD_LANG_MALAY = APP_USB_LANG_DEF(0x3eU), /**< Malay */
APP_USBD_LANG_KAZAK = APP_USB_LANG_DEF(0x3fU), /**< Kazak */
APP_USBD_LANG_SWAHILI = APP_USB_LANG_DEF(0x41U), /**< Swahili */
APP_USBD_LANG_UZBEK = APP_USB_LANG_DEF(0x43U), /**< Uzbek */
APP_USBD_LANG_TATAR = APP_USB_LANG_DEF(0x44U), /**< Tatar */
APP_USBD_LANG_BENGALI = APP_USB_LANG_DEF(0x45U), /**< Bengali */
APP_USBD_LANG_PUNJABI = APP_USB_LANG_DEF(0x46U), /**< Punjabi */
APP_USBD_LANG_GUJARATI = APP_USB_LANG_DEF(0x47U), /**< Gujarati */
APP_USBD_LANG_ORIYA = APP_USB_LANG_DEF(0x48U), /**< Oriya */
APP_USBD_LANG_TAMIL = APP_USB_LANG_DEF(0x49U), /**< Tamil */
APP_USBD_LANG_TELUGU = APP_USB_LANG_DEF(0x4aU), /**< Telugu */
APP_USBD_LANG_KANNADA = APP_USB_LANG_DEF(0x4bU), /**< Kannada */
APP_USBD_LANG_MALAYALAM = APP_USB_LANG_DEF(0x4cU), /**< Malayalam */
APP_USBD_LANG_ASSAMESE = APP_USB_LANG_DEF(0x4dU), /**< Assamese */
APP_USBD_LANG_MARATHI = APP_USB_LANG_DEF(0x4eU), /**< Marathi */
APP_USBD_LANG_SANSKRIT = APP_USB_LANG_DEF(0x4fU), /**< Sanskrit */
APP_USBD_LANG_KONKANI = APP_USB_LANG_DEF(0x57U), /**< Konkani */
APP_USBD_LANG_MANIPURI = APP_USB_LANG_DEF(0x58U), /**< Manipuri */
APP_USBD_LANG_SINDHI = APP_USB_LANG_DEF(0x59U), /**< Sindhi */
APP_USBD_LANG_KASHMIRI = APP_USB_LANG_DEF(0x60U), /**< Kashmiri */
APP_USBD_LANG_NEPALI = APP_USB_LANG_DEF(0x61U), /**< Nepali */
APP_USBD_LANG_HID = APP_USB_LANG_DEF(0xffU), /**< Reserved for USB HID Class use. */
} app_usbd_langid_primary_t;
/**
* @brief Sublanguage identifiers.
*
* Mnemonics with sublanguage values.
* Use them in combination with @ref app_usbd_langid_primary_t.
*/
typedef enum
{
APP_USBD_SUBLANG_ARABIC_SAUDI_ARABIA = APP_USB_SUBLANG_DEF(0x01U), /**< Arabic (Saudi Arabia) */
APP_USBD_SUBLANG_ARABIC_IRAQ = APP_USB_SUBLANG_DEF(0x02U), /**< Arabic (Iraq) */
APP_USBD_SUBLANG_ARABIC_EGYPT = APP_USB_SUBLANG_DEF(0x03U), /**< Arabic (Egypt) */
APP_USBD_SUBLANG_ARABIC_LIBYA = APP_USB_SUBLANG_DEF(0x04U), /**< Arabic (Libya) */
APP_USBD_SUBLANG_ARABIC_ALGERIA = APP_USB_SUBLANG_DEF(0x05U), /**< Arabic (Algeria) */
APP_USBD_SUBLANG_ARABIC_MOROCCO = APP_USB_SUBLANG_DEF(0x06U), /**< Arabic (Morocco) */
APP_USBD_SUBLANG_ARABIC_TUNISIA = APP_USB_SUBLANG_DEF(0x07U), /**< Arabic (Tunisia) */
APP_USBD_SUBLANG_ARABIC_OMAN = APP_USB_SUBLANG_DEF(0x08U), /**< Arabic (Oman) */
APP_USBD_SUBLANG_ARABIC_YEMEN = APP_USB_SUBLANG_DEF(0x09U), /**< Arabic (Yemen) */
APP_USBD_SUBLANG_ARABIC_SYRIA = APP_USB_SUBLANG_DEF(0x10U), /**< Arabic (Syria) */
APP_USBD_SUBLANG_ARABIC_JORDAN = APP_USB_SUBLANG_DEF(0x11U), /**< Arabic (Jordan) */
APP_USBD_SUBLANG_ARABIC_LEBANON = APP_USB_SUBLANG_DEF(0x12U), /**< Arabic (Lebanon) */
APP_USBD_SUBLANG_ARABIC_KUWAIT = APP_USB_SUBLANG_DEF(0x13U), /**< Arabic (Kuwait) */
APP_USBD_SUBLANG_ARABIC_UAE = APP_USB_SUBLANG_DEF(0x14U), /**< Arabic (U.A.E.) */
APP_USBD_SUBLANG_ARABIC_BAHRAIN = APP_USB_SUBLANG_DEF(0x15U), /**< Arabic (Bahrain) */
APP_USBD_SUBLANG_ARABIC_QATAR = APP_USB_SUBLANG_DEF(0x16U), /**< Arabic (Qatar) */
APP_USBD_SUBLANG_AZERI_CYRILLIC = APP_USB_SUBLANG_DEF(0x01U), /**< Azeri (Cyrillic) */
APP_USBD_SUBLANG_AZERI_LATIN = APP_USB_SUBLANG_DEF(0x02U), /**< Azeri (Latin) */
APP_USBD_SUBLANG_CHINESE_TRADITIONAL = APP_USB_SUBLANG_DEF(0x01U), /**< Chinese (Traditional) */
APP_USBD_SUBLANG_CHINESE_SIMPLIFIED = APP_USB_SUBLANG_DEF(0x02U), /**< Chinese (Simplified) */
APP_USBD_SUBLANG_CHINESE_HONGKONG = APP_USB_SUBLANG_DEF(0x03U), /**< Chinese (Hong Kong SAR, PRC) */
APP_USBD_SUBLANG_CHINESE_SINGAPORE = APP_USB_SUBLANG_DEF(0x04U), /**< Chinese (Singapore) */
APP_USBD_SUBLANG_CHINESE_MACAU = APP_USB_SUBLANG_DEF(0x05U), /**< Chinese (Macau SAR) */
APP_USBD_SUBLANG_DUTCH = APP_USB_SUBLANG_DEF(0x01U), /**< Dutch */
APP_USBD_SUBLANG_DUTCH_BELGIAN = APP_USB_SUBLANG_DEF(0x02U), /**< Dutch (Belgian) */
APP_USBD_SUBLANG_ENGLISH_US = APP_USB_SUBLANG_DEF(0x01U), /**< English (US) */
APP_USBD_SUBLANG_ENGLISH_UK = APP_USB_SUBLANG_DEF(0x02U), /**< English (UK) */
APP_USBD_SUBLANG_ENGLISH_AUS = APP_USB_SUBLANG_DEF(0x03U), /**< English (Australian) */
APP_USBD_SUBLANG_ENGLISH_CAN = APP_USB_SUBLANG_DEF(0x04U), /**< English (Canadian) */
APP_USBD_SUBLANG_ENGLISH_NZ = APP_USB_SUBLANG_DEF(0x05U), /**< English (New Zealand) */
APP_USBD_SUBLANG_ENGLISH_EIRE = APP_USB_SUBLANG_DEF(0x06U), /**< English (Ireland) */
APP_USBD_SUBLANG_ENGLISH_SOUTH_AFRICA = APP_USB_SUBLANG_DEF(0x07U), /**< English (South Africa) */
APP_USBD_SUBLANG_ENGLISH_JAMAICA = APP_USB_SUBLANG_DEF(0x08U), /**< English (Jamaica) */
APP_USBD_SUBLANG_ENGLISH_CARIBBEAN = APP_USB_SUBLANG_DEF(0x09U), /**< English (Caribbean) */
APP_USBD_SUBLANG_ENGLISH_BELIZE = APP_USB_SUBLANG_DEF(0x0aU), /**< English (Belize) */
APP_USBD_SUBLANG_ENGLISH_TRINIDAD = APP_USB_SUBLANG_DEF(0x0bU), /**< English (Trinidad) */
APP_USBD_SUBLANG_ENGLISH_PHILIPPINES = APP_USB_SUBLANG_DEF(0x0cU), /**< English (Zimbabwe) */
APP_USBD_SUBLANG_ENGLISH_ZIMBABWE = APP_USB_SUBLANG_DEF(0x0dU), /**< English (Philippines) */
APP_USBD_SUBLANG_FRENCH = APP_USB_SUBLANG_DEF(0x01U), /**< French */
APP_USBD_SUBLANG_FRENCH_BELGIAN = APP_USB_SUBLANG_DEF(0x02U), /**< French (Belgian) */
APP_USBD_SUBLANG_FRENCH_CANADIAN = APP_USB_SUBLANG_DEF(0x03U), /**< French (Canadian) */
APP_USBD_SUBLANG_FRENCH_SWISS = APP_USB_SUBLANG_DEF(0x04U), /**< French (Switzerland) */
APP_USBD_SUBLANG_FRENCH_LUXEMBOURG = APP_USB_SUBLANG_DEF(0x05U), /**< French (Luxembourg) */
APP_USBD_SUBLANG_FRENCH_MONACO = APP_USB_SUBLANG_DEF(0x06U), /**< French (Monaco) */
APP_USBD_SUBLANG_GERMAN = APP_USB_SUBLANG_DEF(0x01U), /**< German */
APP_USBD_SUBLANG_GERMAN_SWISS = APP_USB_SUBLANG_DEF(0x02U), /**< German (Switzerland) */
APP_USBD_SUBLANG_GERMAN_AUSTRIAN = APP_USB_SUBLANG_DEF(0x03U), /**< German (Austria) */
APP_USBD_SUBLANG_GERMAN_LUXEMBOURG = APP_USB_SUBLANG_DEF(0x04U), /**< German (Luxembourg) */
APP_USBD_SUBLANG_GERMAN_LIECHTENSTEIN = APP_USB_SUBLANG_DEF(0x05U), /**< German (Liechtenstein) */
APP_USBD_SUBLANG_ITALIAN = APP_USB_SUBLANG_DEF(0x01U), /**< Italian */
APP_USBD_SUBLANG_ITALIAN_SWISS = APP_USB_SUBLANG_DEF(0x02U), /**< Italian (Switzerland) */
APP_USBD_SUBLANG_KASHMIRI_INDIA = APP_USB_SUBLANG_DEF(0x02U), /**< Kashmiri (India) */
APP_USBD_SUBLANG_KOREAN = APP_USB_SUBLANG_DEF(0x01U), /**< Korean */
APP_USBD_SUBLANG_LITHUANIAN = APP_USB_SUBLANG_DEF(0x01U), /**< Lithuanian */
APP_USBD_SUBLANG_MALAY_MALAYSIA = APP_USB_SUBLANG_DEF(0x01U), /**< Malay (Malaysia) */
APP_USBD_SUBLANG_MALAY_BRUNEI_DARUSSALAM = APP_USB_SUBLANG_DEF(0x02U), /**< Malay (Brunei Darassalam) */
APP_USBD_SUBLANG_NEPALI_INDIA = APP_USB_SUBLANG_DEF(0x02U), /**< Nepali (India) */
APP_USBD_SUBLANG_NORWEGIAN_BOKMAL = APP_USB_SUBLANG_DEF(0x01U), /**< Norwegian (Bokmal) */
APP_USBD_SUBLANG_NORWEGIAN_NYNORSK = APP_USB_SUBLANG_DEF(0x02U), /**< Norwegian (Nynorsk) */
APP_USBD_SUBLANG_PORTUGUESE = APP_USB_SUBLANG_DEF(0x01U), /**< Portuguese */
APP_USBD_SUBLANG_PORTUGUESE_BRAZILIAN = APP_USB_SUBLANG_DEF(0x02U), /**< Portuguese (Brazil) */
APP_USBD_SUBLANG_SERBIAN_LATIN = APP_USB_SUBLANG_DEF(0x02U), /**< Serbian (Latin) */
APP_USBD_SUBLANG_SERBIAN_CYRILLIC = APP_USB_SUBLANG_DEF(0x03U), /**< Serbian (Cyrillic) */
APP_USBD_SUBLANG_SPANISH = APP_USB_SUBLANG_DEF(0x01U), /**< Spanish (Traditional) */
APP_USBD_SUBLANG_SPANISH_MEXICAN = APP_USB_SUBLANG_DEF(0x02U), /**< Spanish (Mexican) */
APP_USBD_SUBLANG_SPANISH_MODERN = APP_USB_SUBLANG_DEF(0x03U), /**< Spanish (Modern) */
APP_USBD_SUBLANG_SPANISH_GUATEMALA = APP_USB_SUBLANG_DEF(0x04U), /**< Spanish (Guatemala) */
APP_USBD_SUBLANG_SPANISH_COSTA_RICA = APP_USB_SUBLANG_DEF(0x05U), /**< Spanish (Costa Rica) */
APP_USBD_SUBLANG_SPANISH_PANAMA = APP_USB_SUBLANG_DEF(0x06U), /**< Spanish (Panama) */
APP_USBD_SUBLANG_SPANISH_DOMINICAN_REPUBLIC = APP_USB_SUBLANG_DEF(0x07U), /**< Spanish (Dominican Republic) */
APP_USBD_SUBLANG_SPANISH_VENEZUELA = APP_USB_SUBLANG_DEF(0x08U), /**< Spanish (Venezuela) */
APP_USBD_SUBLANG_SPANISH_COLOMBIA = APP_USB_SUBLANG_DEF(0x09U), /**< Spanish (Colombia) */
APP_USBD_SUBLANG_SPANISH_PERU = APP_USB_SUBLANG_DEF(0x0aU), /**< Spanish (Peru) */
APP_USBD_SUBLANG_SPANISH_ARGENTINA = APP_USB_SUBLANG_DEF(0x0bU), /**< Spanish (Argentina) */
APP_USBD_SUBLANG_SPANISH_ECUADOR = APP_USB_SUBLANG_DEF(0x0cU), /**< Spanish (Ecuador) */
APP_USBD_SUBLANG_SPANISH_CHILE = APP_USB_SUBLANG_DEF(0x0dU), /**< Spanish (Chile) */
APP_USBD_SUBLANG_SPANISH_URUGUAY = APP_USB_SUBLANG_DEF(0x0eU), /**< Spanish (Uruguay) */
APP_USBD_SUBLANG_SPANISH_PARAGUAY = APP_USB_SUBLANG_DEF(0x0fU), /**< Spanish (Paraguay) */
APP_USBD_SUBLANG_SPANISH_BOLIVIA = APP_USB_SUBLANG_DEF(0x10U), /**< Spanish (Bolivia) */
APP_USBD_SUBLANG_SPANISH_EL_SALVADOR = APP_USB_SUBLANG_DEF(0x11U), /**< Spanish (El Salvador) */
APP_USBD_SUBLANG_SPANISH_HONDURAS = APP_USB_SUBLANG_DEF(0x12U), /**< Spanish (Honduras) */
APP_USBD_SUBLANG_SPANISH_NICARAGUA = APP_USB_SUBLANG_DEF(0x13U), /**< Spanish (Nicaragua) */
APP_USBD_SUBLANG_SPANISH_PUERTO_RICO = APP_USB_SUBLANG_DEF(0x14U), /**< Spanish (Puerto Rico) */
APP_USBD_SUBLANG_SWEDISH = APP_USB_SUBLANG_DEF(0x01U), /**< Swedish */
APP_USBD_SUBLANG_SWEDISH_FINLAND = APP_USB_SUBLANG_DEF(0x02U), /**< Swedish (Finland) */
APP_USBD_SUBLANG_URDU_PAKISTAN = APP_USB_SUBLANG_DEF(0x01U), /**< Urdu (Pakistan) */
APP_USBD_SUBLANG_URDU_INDIA = APP_USB_SUBLANG_DEF(0x02U), /**< Urdu (India) */
APP_USBD_SUBLANG_UZBEK_LATIN = APP_USB_SUBLANG_DEF(0x01U), /**< Uzbek (Latin) */
APP_USBD_SUBLANG_UZBEK_CYRILLIC = APP_USB_SUBLANG_DEF(0x02U), /**< Uzbek (Cyrillic) */
APP_USBD_SUBLANG_HID_USAGE_DATA_DESCRIPTOR = APP_USB_SUBLANG_DEF(0x01U), /**< HID (Usage Data Descriptor) */
APP_USBD_SUBLANG_HID_VENDOR_DEFINED_1 = APP_USB_SUBLANG_DEF(0x3cU), /**< HID (Vendor Defined 1) */
APP_USBD_SUBLANG_HID_VENDOR_DEFINED_2 = APP_USB_SUBLANG_DEF(0x3dU), /**< HID (Vendor Defined 2) */
APP_USBD_SUBLANG_HID_VENDOR_DEFINED_3 = APP_USB_SUBLANG_DEF(0x3eU), /**< HID (Vendor Defined 3) */
APP_USBD_SUBLANG_HID_VENDOR_DEFINED_4 = APP_USB_SUBLANG_DEF(0x3fU), /**< HID (Vendor Defined 4) */
} app_usbd_langid_sub_t;
/**
* @brief LANGID variable.
*
* The LANGID value is composed of:
* - 10 bits (9-0) of Primary Language Identifier,
* - 6 bits (15-10) of Sublanguage Identifier.
*
* @sa app_usbd_langid_primary_t
* @sa app_usbd_langid_sub_t
*/
typedef uint16_t app_usbd_langid_t;
#ifdef __cplusplus
}
#endif
#endif /* APP_USBD_LANGID_H__ */

View File

@@ -1,356 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef APP_USBD_REQUEST_H__
#define APP_USBD_REQUEST_H__
#include "sdk_common.h"
#include "nrf.h"
#include "nrf_drv_usbd.h"
#include "app_usbd_descriptor.h"
#include "app_util_platform.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Compiler support for anonymous unions */
ANON_UNIONS_ENABLE;
#pragma pack(push, 1)
/**
* @defgroup app_usbd_request USB standard requests
* @ingroup app_usbd
*
* @brief @tagAPI52840 Module with types definitions used for standard requests processing.
* @{
*/
/**
* @brief Recipient bit-field in request type.
*
* Bits 4...0
*/
#define APP_USBD_SETUP_REQ_BF_REC BF_CX(5, 0)
/**
* @brief Type bit-field in request type.
*
* Bits 6...5
*/
#define APP_USBD_SETUP_REQ_BF_TYP BF_CX(2, 5)
/**
* @brief Direction bit-field in request type.
*
* Bit 7
*/
#define APP_USBD_SETUP_REQ_BF_DIR BF_CX(1, 7)
/**
* @brief Recipient enumerator.
*
* @note It is part of @ref app_usbd_setup_reqtype_t variable type.
*/
typedef enum {
APP_USBD_SETUP_REQREC_DEVICE = 0x0, /**< The whole device is a request target */
APP_USBD_SETUP_REQREC_INTERFACE = 0x1, /**< Selected interface is a request target */
APP_USBD_SETUP_REQREC_ENDPOINT = 0x2, /**< Selected endpoint is a request target */
APP_USBD_SETUP_REQREC_OTHER = 0x3 /**< Other element is a request target */
} app_usbd_setup_reqrec_t;
/**
* @brief Request type enumerator.
*
* @note It is part of @ref app_usbd_setup_reqtype_t variable type.
*/
typedef enum {
APP_USBD_SETUP_REQTYPE_STD = 0x0, /**< Standard request */
APP_USBD_SETUP_REQTYPE_CLASS = 0x1, /**< Class specific request */
APP_USBD_SETUP_REQTYPE_VENDOR = 0x2 /**< Vendor specific request */
} app_usbd_setup_reqtype_t;
/**
* @brief Direction of setup command.
*
* @note It is part of @ref app_usbd_setup_reqtype_t variable type.
*/
typedef enum {
APP_USBD_SETUP_REQDIR_OUT = 0x0, /**< Host to device */
APP_USBD_SETUP_REQDIR_IN = 0x1, /**< Device to host */
} app_usbd_setup_reqdir_t;
/**
* @brief Standard requests.
*
* Enumerator for standard requests values.
*/
typedef enum {
APP_USBD_SETUP_STDREQ_GET_STATUS = 0x00, /**<
* Targets: Device, Interface, Endpoint
* Expected SETUP frame format:
* - wValue: Zero
* - wIndex: Zero, (lb): Interface or Endpoint
* - wLength: 2
* - Data:2 bytes of data, depending on targets
* - Device:
* - D15..D2: Reserved (Reset to zero)
* - D1: Remove Wakeup
* - D0: Self Powered
* - Interface:
* - D15..D0: Reserved (Reset to zero)
* - Endpoint:
* - D15..D1: Reserved (Reset to zero)
* - D0: Halt
*/
APP_USBD_SETUP_STDREQ_CLEAR_FEATURE = 0x01, /**<
* Targets: Device, Interface, Endpoint
* Expected SETUP frame format:
* - wValue: Feature selector (@ref app_usbd_setup_stdfeature_t)
* - wIndex: Zero, Interface or Endpoint
* - wLength: 0
* - Data: None
*/
APP_USBD_SETUP_STDREQ_SET_FEATURE = 0x03, /**<
* Targets: Device, Interface, Endpoint
* Expected SETUP frame format:
* - wValue: Feature selector (@ref app_usbd_setup_stdfeature_t)
* - wIndex: Zero, Interface or Endpoint
* - wLength: 0
* - Data: None
*/
APP_USBD_SETUP_STDREQ_SET_ADDRESS = 0x05, /**<
* @note This SETUP request is processed in hardware.
* Use it only to mark current USB state.
*
* Targets: Device
* Expected SETUP frame format:
* - wValue: New device address
* - wIndex: 0
* - wLength: 0
* - Data: None
*/
APP_USBD_SETUP_STDREQ_GET_DESCRIPTOR = 0x06, /**<
* Targets: Device
* - wValue: (hb): Descriptor Type and (lb): Descriptor Index
* - wIndex: Zero of Language ID
* - wLength: Descriptor Length
* - Data: Descriptor
*/
APP_USBD_SETUP_STDREQ_SET_DESCRIPTOR = 0x07, /**<
* Not supported - Stall when called.
*/
APP_USBD_SETUP_STDREQ_GET_CONFIGURATION = 0x08, /**<
* Target: Device
* Expected SETUP frame format:
* - wValue: 0
* - wIndex: 0
* - wLength: 1
* - Data: Configuration value
*/
APP_USBD_SETUP_STDREQ_SET_CONFIGURATION = 0x09, /**<
* Target: Device
* Expected SETUP frame format:
* - wValue: (lb): Configuration value
* - wIndex: 0
* - wLength: 0
* - Data: None
*/
APP_USBD_SETUP_STDREQ_GET_INTERFACE = 0x0A, /**<
* Target: Interface
* Expected SETUP frame format:
* - wValue: 0
* - wIndex: Interface
* - wLength: 1
* - Data: Alternate setting
*/
APP_USBD_SETUP_STDREQ_SET_INTERFACE = 0x0B, /**<
* Target: Interface
* Expected SETUP frame format:
* - wValue: Alternate setting
* - wIndex: Interface
* - wLength: 0
* - Data: None
*/
APP_USBD_SETUP_STDREQ_SYNCH_FRAME = 0x0C /**<
* Target: Endpoint
* Expected SETUP frame format:
* - wValue: 0
* - wIndex: Endpoint
* - wLength: 2
* - Data: Frame Number
*
* @note
* This request is used only in connection with isochronous endpoints.
* This is rarely used and probably we would not need to support it.
*/
} app_usbd_setup_stdrequest_t;
/**
* @brief Standard feature selectors.
*
* Standard features that may be disabled or enabled by
* @ref APP_USBD_SETUP_STDREQ_CLEAR_FEATURE or @ref APP_USBD_SETUP_STDREQ_SET_FEATURE
*/
typedef enum {
APP_USBD_SETUP_STDFEATURE_DEVICE_REMOTE_WAKEUP = 1, /**<
* Remote wakeup feature.
* Target: Device only
*/
APP_USBD_SETUP_STDFEATURE_ENDPOINT_HALT = 0, /**<
* Stall or clear the endpoint.
* Target: Endpoint different than default (0)
*/
APP_USBD_SETUP_STDFEATURE_TEST_MODE = 2 /**<
* Upstream port test mode.
* Power has to be cycled to exit test mode.
* This feature cannot be cleared.
*
* Target: Device only
*
* @note
* It should only be supported by HighSpeed capable devices.
* Not supported in this library.
*/
} app_usbd_setup_stdfeature_t;
/**
* @brief Universal way to access 16 bit values and its parts.
*/
typedef union {
uint16_t w; //!< 16 bit access
struct
{
uint8_t lb; //!< Low byte access
uint8_t hb; //!< High byte access
};
} app_usbd_setup_w_t;
/**
* @brief Internal redefinition of setup structure.
*
* Redefinition of the structure to simplify changes in the future
* if required - app_usbd API would present setup data using app_usbd_setup_t.
*
* The structure layout is always the same like @ref nrf_drv_usbd_setup_t
*/
typedef struct {
uint8_t bmRequestType; //!< Setup type bitfield
uint8_t bRequest; //!< One of @ref app_usbd_setup_stdrequest_t values or class dependent one.
app_usbd_setup_w_t wValue; //!< byte 2, 3
app_usbd_setup_w_t wIndex; //!< byte 4, 5
app_usbd_setup_w_t wLength; //!< byte 6, 7
} app_usbd_setup_t;
#pragma pack(pop)
/**
* @brief Extract recipient from request type.
*
* @param[in] bmRequestType
*
* @return Extracted recipient field from request type value.
*/
static inline app_usbd_setup_reqrec_t app_usbd_setup_req_rec(uint8_t bmRequestType)
{
return (app_usbd_setup_reqrec_t)BF_CX_GET(bmRequestType, APP_USBD_SETUP_REQ_BF_REC);
}
/**
* @brief Extract type from request type.
*
* @param[in] bmRequestType
*
* @return Extracted type field from request type value.
*/
static inline app_usbd_setup_reqtype_t app_usbd_setup_req_typ(uint8_t bmRequestType)
{
return (app_usbd_setup_reqtype_t)BF_CX_GET(bmRequestType, APP_USBD_SETUP_REQ_BF_TYP);
}
/**
* @brief Extract direction from request type.
*
* @param[in] bmRequestType
*
* @return Extracted direction field from request type value.
*/
static inline app_usbd_setup_reqdir_t app_usbd_setup_req_dir(uint8_t bmRequestType)
{
return (app_usbd_setup_reqdir_t)BF_CX_GET(bmRequestType, APP_USBD_SETUP_REQ_BF_DIR);
}
/**
* @brief Make request type value.
*
* @param[in] rec Recipient.
* @param[in] typ Request type.
* @param[in] dir Direction.
*
* @return Assembled request type value.
*/
static inline uint8_t app_usbd_setup_req_val(app_usbd_setup_reqrec_t rec,
app_usbd_setup_reqtype_t typ,
app_usbd_setup_reqdir_t dir)
{
uint32_t bmRequestType = (
BF_CX_VAL(rec, APP_USBD_SETUP_REQ_BF_REC) |
BF_CX_VAL(typ, APP_USBD_SETUP_REQ_BF_TYP) |
BF_CX_VAL(dir, APP_USBD_SETUP_REQ_BF_DIR)
);
ASSERT(bmRequestType < 256U);
return (uint8_t)bmRequestType;
}
ANON_UNIONS_DISABLE;
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* APP_USBD_REQUEST_H__ */

View File

@@ -1,84 +0,0 @@
/**
* Copyright (c) 2018 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "app_usbd_serial_num.h"
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "app_usbd.h"
#define SERIAL_NUMBER_STRING_SIZE (12)
/**@brief Serial number generated.
*
* Serial number generated by the @ref serial_number_string_create function.
*/
uint8_t g_extern_serial_number[SERIAL_NUMBER_STRING_SIZE + 1];
/**@brief Function for creating the serial number string from a regular C string.
*
* @param[in] p_serial_number_string The serial number string. Must be terminated with \0.
*/
static void string_create(char * p_serial_number_string)
{
for (uint32_t i = 0; i < strlen(p_serial_number_string); i++)
{
g_extern_serial_number[i] = (uint8_t)p_serial_number_string[i];
}
}
void app_usbd_serial_num_generate(void)
{
char serial_number_string[SERIAL_NUMBER_STRING_SIZE + 1];
const uint16_t serial_num_high_bytes = (uint16_t)NRF_FICR->DEVICEADDR[1] | 0xC000; // The masking makes the address match the Random Static BLE address.
const uint32_t serial_num_low_bytes = NRF_FICR->DEVICEADDR[0];
(void)snprintf(serial_number_string,
SERIAL_NUMBER_STRING_SIZE + 1,
"%04"PRIX16"%08"PRIX32,
serial_num_high_bytes,
serial_num_low_bytes);
string_create(serial_number_string);
}

View File

@@ -1,75 +0,0 @@
/**
* Copyright (c) 2018 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef APP_USBD_SERIAL_NUM_H__
#define APP_USBD_SERIAL_NUM_H__
#include <stdint.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup app_usbd_serial_num USBD serial number generator
* @ingroup app_usbd
*
* @brief @tagAPI52840 Generate a standard USB serial number that is unique for each device.
* @{
*/
/**@brief Function for generating a default serial number string based on FIRC->DEVICEADDR.
*
* After calling this function, the serial number is ready for the USB driver.
*
* The generated serial number shows up as a 12-hexidecimal-digit string with no delimiters
* (e.g 123456ABCDEF). The byte string is also printed on the PCA10059 dongle. It is also used as
* the default advertising address in the SoftDevice.
*/
void app_usbd_serial_num_generate(void);
/** @} */
#ifdef __cplusplus
}
#endif
#endif // APP_USBD_SERIAL_NUM_H__

View File

@@ -1,321 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sdk_config.h"
#if APP_USBD_ENABLED
#include "app_usbd_string_desc.h"
#include "app_usbd_langid.h"
#include "app_usbd_core.h"
#include "nordic_common.h"
#include "utf.h"
/**
* @defgroup app_usbd_string_desc
* @ingroup app_usbd
*
* USBD string descriptor management
* @{
*/
/**
* @brief Array with language identifiers.
*
* This array is used to search the proper string for the selected language.
*/
static uint16_t const m_langids[] = { APP_USBD_STRINGS_LANGIDS };
/**
* @brief Language ID descriptor.
*
* Language.
*/
/**
* @brief Mnemonics for the string positions in the array.
*
* The mnemonics for the indexes of the strings inside the string array.
*/
enum {
APP_USBD_STRING_ID_LANGIDS_ARRAY_POS = 0, /**< Supported language identifiers. */
#if (APP_USBD_STRING_ID_MANUFACTURER != 0)
APP_USBD_STRING_ID_MANUFACTURER_ARRAY_POS, /**< Manufacturer name. */
#endif // (APP_USBD_STRING_ID_MANUFACTURER != 0)
#if (APP_USBD_STRING_ID_PRODUCT != 0)
APP_USBD_STRING_ID_PRODUCT_ARRAY_POS, /**< Product name. */
#endif // (APP_USBD_STRING_ID_PRODUCT != 0)
#if (APP_USBD_STRING_ID_SERIAL != 0)
APP_USBD_STRING_ID_SERIAL_ARRAY_POS, /**< Serial number. */
#endif // (APP_USBD_STRING_ID_SERIAL != 0)
#if (APP_USBD_STRING_ID_CONFIGURATION != 0)
APP_USBD_STRING_ID_CONFIGURATION_ARRAY_POS, /**< Configuration string. */
#endif // (APP_USBD_STRING_ID_CONFIGURATION != 0)
#define X(mnemonic, str_idx, ...) CONCAT_2(mnemonic, _ARRAY_POS),
APP_USBD_STRINGS_USER
#undef X
};
/**
* @brief String index into internal array index conversion table.
*
* The array that transforms the USB string indexes into internal array position.
* @note Value 0 is used to mark non-existing string.
*/
#define X(mnemonic, str_idx, ...) 1 +
static app_usbd_strings_convert_t const m_string_translation[APP_USBD_STRINGS_NUM] =
#undef X
{
{
.identifier = APP_USBD_STRING_ID_LANGIDS,
.array_pos = APP_USBD_STRING_ID_LANGIDS_ARRAY_POS,
},
#if (APP_USBD_STRING_ID_MANUFACTURER != 0)
{
.identifier = APP_USBD_STRING_ID_MANUFACTURER,
.array_pos = APP_USBD_STRING_ID_MANUFACTURER_ARRAY_POS,
},
#endif // (APP_USBD_STRING_ID_MANUFACTURER != 0)
#if (APP_USBD_STRING_ID_PRODUCT != 0)
{
.identifier = APP_USBD_STRING_ID_PRODUCT,
.array_pos = APP_USBD_STRING_ID_PRODUCT_ARRAY_POS,
},
#endif // (APP_USBD_STRING_ID_PRODUCT != 0)
#if (APP_USBD_STRING_ID_SERIAL != 0)
{
.identifier = APP_USBD_STRING_ID_SERIAL,
.array_pos = APP_USBD_STRING_ID_SERIAL_ARRAY_POS,
},
#endif // (APP_USBD_STRING_ID_SERIAL != 0)
#if (APP_USBD_STRING_ID_CONFIGURATION != 0)
{
.identifier = APP_USBD_STRING_ID_CONFIGURATION,
.array_pos = APP_USBD_STRING_ID_CONFIGURATION_ARRAY_POS,
},
#endif // (APP_USBD_STRING_ID_CONFIGURATION != 0)
#define X(mnemonic, ...) \
{ \
.identifier = mnemonic, \
.array_pos = CONCAT_2(mnemonic, _ARRAY_POS), \
},
APP_USBD_STRINGS_USER
#undef X
};
#ifndef APP_USBD_STRINGS_MANUFACTURER_EXTERN
#define APP_USBD_STRINGS_MANUFACTURER_EXTERN 0
#endif
#if APP_USBD_STRINGS_MANUFACTURER_EXTERN
extern uint8_t APP_USBD_STRINGS_MANUFACTURER[];
#endif
#ifndef APP_USBD_STRINGS_PRODUCT_EXTERN
#define APP_USBD_STRINGS_PRODUCT_EXTERN 0
#endif
#if APP_USBD_STRINGS_PRODUCT_EXTERN
extern uint8_t APP_USBD_STRINGS_PRODUCT[];
#endif
#ifndef APP_USBD_STRING_SERIAL_EXTERN
#define APP_USBD_STRING_SERIAL_EXTERN 0
#endif
#if APP_USBD_STRING_SERIAL_EXTERN
extern uint8_t APP_USBD_STRING_SERIAL[];
#endif
#ifndef APP_USBD_STRING_CONFIGURATION_EXTERN
#define APP_USBD_STRING_CONFIGURATION_EXTERN 0
#endif
#if APP_USBD_STRING_CONFIGURATION_EXTERN
extern uint8_t APP_USBD_STRING_CONFIGURATION[];
#endif
/**
* @brief String descriptor table.
* */
#define X(mnemonic, str_idx, ...) 1 +
static uint8_t const * m_string_dsc[APP_USBD_STRINGS_NUM][ARRAY_SIZE(m_langids)] =
#undef X
{
[APP_USBD_STRING_ID_LANGIDS_ARRAY_POS] = {APP_USBD_STRING_RAW16_DESC(APP_USBD_STRINGS_LANGIDS)},
#if (APP_USBD_STRING_ID_MANUFACTURER != 0)
[APP_USBD_STRING_ID_MANUFACTURER_ARRAY_POS] = { APP_USBD_STRINGS_MANUFACTURER },
#endif // (APP_USBD_STRING_ID_MANUFACTURER != 0)
#if (APP_USBD_STRING_ID_PRODUCT != 0)
[APP_USBD_STRING_ID_PRODUCT_ARRAY_POS] = { APP_USBD_STRINGS_PRODUCT },
#endif // (APP_USBD_STRING_ID_PRODUCT != 0)
#if (APP_USBD_STRING_ID_SERIAL != 0)
[APP_USBD_STRING_ID_SERIAL_ARRAY_POS] = { APP_USBD_STRING_SERIAL },
#endif // (APP_USBD_STRING_ID_SERIAL != 0)
#if (APP_USBD_STRING_ID_CONFIGURATION != 0)
[APP_USBD_STRING_ID_CONFIGURATION_ARRAY_POS] = { APP_USBD_STRINGS_CONFIGURATION },
#endif // (APP_USBD_STRING_ID_CONFIGURATION != 0)
#define X(mnemonic, str_idx, ...) [CONCAT_2(mnemonic, _ARRAY_POS)] = {__VA_ARGS__},
APP_USBD_STRINGS_USER
#undef X
};
/**
* @brief Function for preparing UTF16 string descriptor.
*
* @param idx String descriptor ID.
* @param langid Language ID.
*
* @return Pointer to the string descriptor.
*/
static uint16_t * app_usbd_prepare_string(uint8_t idx, uint16_t langid)
{
if (m_string_dsc[idx][langid][0] == 0x00)
{
return (uint16_t *) &(m_string_dsc[idx][langid][2]);
}
#if ((APP_USBD_CONFIG_DESC_STRING_SIZE * 2) + 2) <= NRF_DRV_USBD_EPSIZE
uint16_t * string_buffer = app_usbd_core_setup_transfer_buff_get(NULL);
#else
static uint16_t string_buffer[APP_USBD_CONFIG_DESC_STRING_SIZE + 1];
// + 1 element for string descriptor type and size
#endif
uint8_t size = 0;
const uint8_t * p_pos = m_string_dsc[idx][langid];
#if APP_USBD_CONFIG_DESC_STRING_UTF_ENABLED
size = utf8UTF16Count((char *) p_pos, 0);
ASSERT(size <= APP_USBD_CONFIG_DESC_STRING_SIZE);
uint16_t * p_out = &(string_buffer[1]);
uint32_t rune;
while (*p_pos != 0)
{
p_pos = (uint8_t *) utf8DecodeRune((char *) p_pos, 0, &rune);
p_out += utf16EncodeRune(rune, p_out);
}
#else
while(*p_pos != 0)
{
ASSERT(size < APP_USBD_CONFIG_DESC_STRING_SIZE);
++size;
string_buffer[size] = *p_pos;
++p_pos;
}
#endif
// Descriptor size is length of the string times 2 bytes per character + 2 bytes for
// descriptor type and size.
string_buffer[0] = (0xff & (size * 2 + 2)) | ((uint16_t)APP_USBD_DESCRIPTOR_STRING) << 8;
return string_buffer;
}
uint16_t const * app_usbd_string_desc_get(uint8_t idx, uint16_t langid)
{
/* LANGID string. */
if (APP_USBD_STRING_ID_LANGIDS == idx)
{
return app_usbd_prepare_string(APP_USBD_STRING_ID_LANGIDS_ARRAY_POS, 0);
}
/* Searching for the language. */
uint8_t lang_idx = 0;
if (ARRAY_SIZE(m_langids) > 1)
{
while (m_langids[lang_idx] != langid)
{
++lang_idx;
if (lang_idx >= ARRAY_SIZE(m_langids))
{
return NULL;
}
}
}
uint8_t str_pos = 0;
for (uint8_t i = 0; i < ARRAY_SIZE(m_string_translation); i++)
{
if (m_string_translation[i].identifier == idx)
{
str_pos = m_string_translation[i].array_pos;
break;
}
}
if (str_pos == 0)
{
return NULL;
}
if ((ARRAY_SIZE(m_langids) > 1) && (lang_idx != 0))
{
if (m_string_dsc[str_pos][lang_idx] == NULL)
{
lang_idx = 0;
}
}
if (m_string_dsc[str_pos][lang_idx] == NULL)
{
return NULL;
}
return app_usbd_prepare_string(str_pos, lang_idx);
}
/** @} */
#endif // APP_USBD_ENABLED

View File

@@ -1,212 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef APP_USBD_STRING_DESC_H__
#define APP_USBD_STRING_DESC_H__
#include <stdint.h>
#include "sdk_common.h"
#include "app_usbd.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup app_usbd_string_desc USBD string descriptors
* @ingroup app_usbd
*
* @brief @tagAPI52840 USBD string descriptor management.
* @{
*/
/**
* @brief USB Language identifier initialization.
*
* @param[in] lang Language identifier.
*/
#define APP_USBD_LANG(lang) \
((app_usbd_langid_t) lang)
/**
* @brief USB Language identifier with sublanguage initialization.
*
* @param[in] lang Language identifier.
* @param[in] sublang Sublanguage identifier.
*/
#define APP_USBD_LANG_AND_SUBLANG(lang, sublang) \
((app_usbd_langid_t) lang | (app_usbd_langid_t) sublang)
/**
* @brief USB string initialization.
*
* Macro that creates initialization values for the USB string.
* The string must be declared as a NULL-terminated string.
*
* @param[in] str NULL-terminated string.
*
* @return String descriptor initialization data.
*/
#define APP_USBD_STRING_DESC(str) (const uint8_t *)(const char[]){str}
/**
* @brief USB raw 8-bit string initialization.
*
* Macro that creates header for raw values passed into descriptor.
* Values must be of the uint8_t type and separated by commas.
*
* @param[in] ... comma-separated values.
*
* @return String descriptor initialization data.
*/
#define APP_USBD_STRING_RAW8_DESC(...) (const uint8_t[]){ \
0x00, 0x00, /* NULL character at start to differentiate from normal string */ \
(0xff & (sizeof((uint8_t[]){__VA_ARGS__}) + 2)), \
(APP_USBD_DESCRIPTOR_STRING), \
__VA_ARGS__ }
/**
* @brief USB raw 16-bit string initialization.
*
* Macro that creates header for raw values passed into descriptor.
* Values must be of the uint16_t type and separated by commas.
*
* @param[in] ... comma-separated values.
*
* @return String descriptor initialization data.
*/
#define APP_USBD_STRING_RAW16_DESC(...) (const uint8_t *) ((const uint16_t[]){ \
0x00, /* NULL character at start to differentiate from normal string */ \
(0xff & (sizeof((uint16_t[]){__VA_ARGS__}) + 2)) | \
((uint16_t)APP_USBD_DESCRIPTOR_STRING) << 8, \
__VA_ARGS__ })
#if (APP_USBD_STRING_ID_MANUFACTURER != 0)
#define APP_USBD_STRING_ID_MANUFACTURER_LEN 1
#else
#define APP_USBD_STRING_ID_MANUFACTURER_LEN 0
#endif
#if (APP_USBD_STRING_ID_PRODUCT != 0)
#define APP_USBD_STRING_ID_PRODUCT_LEN 1
#else
#define APP_USBD_STRING_ID_PRODUCT_LEN 0
#endif
#if (APP_USBD_STRING_ID_SERIAL != 0)
#define APP_USBD_STRING_ID_SERIAL_LEN 1
#else
#define APP_USBD_STRING_ID_SERIAL_LEN 0
#endif
#if (APP_USBD_STRING_ID_CONFIGURATION != 0)
#define APP_USBD_STRING_ID_CONFIGURATION_LEN 1
#else
#define APP_USBD_STRING_ID_CONFIGURATION_LEN 0
#endif
/** @brief Total number of USB strings */
#define APP_USBD_STRINGS_NUM \
((APP_USBD_STRINGS_USER 0) + 1 + APP_USBD_STRING_ID_MANUFACTURER_LEN + APP_USBD_STRING_ID_PRODUCT_LEN + APP_USBD_STRING_ID_SERIAL_LEN + APP_USBD_STRING_ID_CONFIGURATION_LEN)
/**
* @brief USB string descriptors IDs
*/
typedef enum {
APP_USBD_STRING_ID_LANGIDS = 0, /**< Supported language identifiers */
/// Placeholders used only for alignement of user strings. Do not use or modify them.
#if (APP_USBD_STRING_ID_MANUFACTURER != 0)
APP_USBD_STRING_ID_MANUFACTURER_PLACEHOLDER = APP_USBD_STRING_ID_MANUFACTURER,
#endif // (APP_USBD_STRING_ID_MANUFACTURER != 0)
#if (APP_USBD_STRING_ID_PRODUCT != 0)
APP_USBD_STRING_ID_PRODUCT_PLACEHOLDER = APP_USBD_STRING_ID_PRODUCT,
#endif // (APP_USBD_STRING_ID_PRODUCT != 0)
#if (APP_USBD_STRING_ID_SERIAL != 0)
APP_USBD_STRING_ID_SERIAL_PLACEHOLDER = APP_USBD_STRING_ID_SERIAL,
#endif // (APP_USBD_STRING_ID_SERIAL != 0)
#if (APP_USBD_STRING_ID_CONFIGURATION != 0)
APP_USBD_STRING_ID_CONFIGURATION_PLACEHOLDER = APP_USBD_STRING_ID_CONFIGURATION,
#endif // (APP_USBD_STRING_ID_CONFIGURATION != 0)
#define X(mnemonic, str_idx, ...) mnemonic str_idx,
APP_USBD_STRINGS_USER
#undef X
} app_usbd_string_desc_idx_t;
/** @brief String ID conversion struct */
typedef struct {
uint8_t const identifier;
uint8_t const array_pos;
} app_usbd_strings_convert_t;
/**
* @brief Get string descriptor.
*
* @param[in] idx String descriptor index.
* @param[in] langid Selected language for the string.
* @return String descriptor, or NULL if it does not exist.
* */
uint16_t const * app_usbd_string_desc_get(uint8_t idx, uint16_t langid);
/**
* @brief Get string length.
*
* Function for getting string length from descriptor (descriptor returned by @ref app_usbd_string_desc_get).
*
* @param[in] p_str String descriptor pointer.
* @return Total descriptor length in bytes.
*/
static inline size_t app_usbd_string_desc_length(uint16_t const * p_str)
{
return ((const app_usbd_descriptor_string_t *)p_str)->bLength;
}
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* APP_USBD_STRING_DESC_H__ */

View File

@@ -1,279 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef APP_USBD_TYPES_H__
#define APP_USBD_TYPES_H__
#include <stdint.h>
#include "sdk_errors.h"
#include "nrf_drv_usbd.h"
#include "app_usbd_request.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup app_usbd_types USB Device high level library variable types definition
* @ingroup app_usbd
*
* @brief @tagAPI52840 All types used by @ref app_usbd are defined here.
* This helps to avoid cross referencing into types in different files.
* @{
*/
/**
* @brief Change given value to 2 digits in BCD notation.
*
* @param[in] val The decimal value to be converted in the range from 0 to 99.
* @return Calculated BCD value.
*/
#define APP_USBD_BCD_2_MAKE(val) ( \
((((val) % 100) / 10) * 0x10) + \
((((val) % 10) / 1) * 0x1) \
)
/**
* @brief Change given decimal version values to 4 digits in BCD notation.
*
* USB specification uses 4 digits BCD version notation in many descriptors.
* This macro changes 3 values to 4 BCD digits (one 16 bit value)
* that describes version in USB standard.
*
* @param[in] major Major version.
* @param[in] minor Minor version.
* @param[in] sub Sub-minor version.
*
* @return Calculated 16 bit value with BCD representation of the version.
*/
#define APP_USBD_BCD_VER_MAKE(major, minor, sub) \
((APP_USBD_BCD_2_MAKE(major) << 8) | (minor) << 4 | (sub))
/**
* @brief Combine endpoint address and its interval.
*
* @param[in] address Endpoint address
* @param[in] interval Endpoint interval
* @return Combined address and interval.
*/
#define APP_USBD_EP_WITH_INTERVAL(address, interval) \
((1UL << 16) | ((interval) << 8) | (address))
#define APP_USBD_EXTRACT_INTERVAL_VALUE(combined) \
(((combined) & 0xFF00) >> 8)
#define APP_USBD_EXTRACT_INTERVAL_FLAG(combined) \
(((combined) >> 16) & 0x01)
/**
* @brief Events codes.
*
* Redefined application event codes.
*/
typedef enum
{
APP_USBD_EVT_DRV_SOF = NRF_DRV_USBD_EVT_SOF, /**< See documentation for @ref NRF_DRV_USBD_EVT_SOF */
APP_USBD_EVT_DRV_RESET = NRF_DRV_USBD_EVT_RESET, /**< See documentation for @ref NRF_DRV_USBD_EVT_RESET */
APP_USBD_EVT_DRV_SUSPEND = NRF_DRV_USBD_EVT_SUSPEND, /**< See documentation for @ref NRF_DRV_USBD_EVT_SUSPEND */
APP_USBD_EVT_DRV_RESUME = NRF_DRV_USBD_EVT_RESUME, /**< See documentation for @ref NRF_DRV_USBD_EVT_RESUME */
APP_USBD_EVT_DRV_WUREQ = NRF_DRV_USBD_EVT_WUREQ, /**< See documentation for @ref NRF_DRV_USBD_EVT_WUREQ */
APP_USBD_EVT_DRV_SETUP = NRF_DRV_USBD_EVT_SETUP, /**< This event type has special structure. See @ref app_usbd_setup_evt_t */
APP_USBD_EVT_DRV_EPTRANSFER = NRF_DRV_USBD_EVT_EPTRANSFER, /**< See documentation for @ref NRF_DRV_USBD_EVT_EPTRANSFER */
APP_USBD_EVT_FIRST_POWER, /**< First power event code - for internal static assert checking */
APP_USBD_EVT_POWER_DETECTED, /**< See documentation for @ref NRF_DRV_POWER_USB_EVT_DETECTED */
APP_USBD_EVT_POWER_REMOVED, /**< See documentation for @ref NRF_DRV_POWER_USB_EVT_REMOVED */
APP_USBD_EVT_POWER_READY, /**< See documentation for @ref NRF_DRV_POWER_USB_EVT_READY */
APP_USBD_EVT_FIRST_APP, /**< First application event code - for internal static assert checking */
APP_USBD_EVT_INST_APPEND = APP_USBD_EVT_FIRST_APP, /**< The instance was attached to the library, any configuration action can be done now */
APP_USBD_EVT_INST_REMOVE, /**<
* The instance is going to be removed, this event is called just before removing the instance.
* This removing cannot be stopped.
*/
APP_USBD_EVT_STARTED, /**< USBD library has just been started and functional - event passed to all instances, before USBD interrupts have been enabled */
APP_USBD_EVT_STOPPED, /**< USBD library has just been stopped and is not functional - event passed to all instances, after USBD interrupts have been disabled*/
APP_USBD_EVT_STATE_CHANGED, /**<
* Informs all the classes that base state has been changed.
* This event is processed before setup stage that caused the state change finishes (before acknowledging it).
*/
APP_USBD_EVT_FIRST_INTERNAL = 0x80, /**< First internal event, used by the APP library internally. */
APP_USBD_EVT_HFCLK_READY = APP_USBD_EVT_FIRST_INTERNAL, /**< High frequency clock started */
APP_USBD_EVT_START_REQ, /**< Start requested */
APP_USBD_EVT_STOP_REQ, /**< Stop requested */
APP_USBD_EVT_SUSPEND_REQ, /**< Suspend request - HFCLK would be released and USBD peripheral clock would be disconnected */
APP_USBD_EVT_WAKEUP_REQ, /**< Wakeup request - start the whole wakeup generation. */
APP_USBD_EVT_SETUP_SETADDRESS, /**<
* Setup request to set address, separated from
* regular EVT_SETUP because this request is
* fully handled by hardware and for the software
* it is only a notification about what happened
*/
} app_usbd_event_type_t;
/**
* @brief Specific application event structure.
*
* All the data required by the events that comes from the application level.
*/
typedef struct
{
app_usbd_event_type_t type; //!< Event type
} app_usbd_evt_t;
/**
* @brief Specific application event structure with setup structure included.
*
* This event structure would be used when @ref APP_USBD_EVT_DRV_SETUP
* is passed to instance event handler.
*/
typedef struct
{
app_usbd_event_type_t type; //!< Event type
app_usbd_setup_t setup; //!< Setup structure
} app_usbd_setup_evt_t;
/**
* @brief Complex event variable type.
*
* A variable that can store any kind of event.
*/
typedef union
{
app_usbd_event_type_t type; //!< Event type
nrf_drv_usbd_evt_t drv_evt; //!< Events that comes directly from the driver.
/**< Use this event structure only for event
* type < @ref APP_USBD_EVT_FIRST_APP
*/
app_usbd_setup_evt_t setup_evt; //!< Event structure with SETUP structure included.
/**< This structure is used in connection with
* @ref APP_USBD_EVT_DRV_SETUP
*/
app_usbd_evt_t app_evt; //!< Events that comes from the application driver.
/**< Use this event structure only for event
* type >= @ref APP_USBD_EVT_FIRST_APP
*/
} app_usbd_complex_evt_t;
/**
* @brief Internal event variable type.
*
* The variable type used for internal event processing.
* This kind of event is the one that goes into the event queue.
*
* @note There is no setup event structure.
* This structure would be created when setup event is processed.
* The reason for that is the fact that setup event structure has high memory printout.
*/
typedef union
{
app_usbd_event_type_t type; //!< Event type
nrf_drv_usbd_evt_t drv_evt; //!< Events that comes directly from the driver.
/**< Use this event structure only for event
* type < @ref APP_USBD_EVT_FIRST_APP
*/
app_usbd_evt_t app_evt; //!< Events that comes from the application driver.
/**< Use this event structure only for event
* type >= @ref APP_USBD_EVT_FIRST_APP
*/
} app_usbd_internal_evt_t;
#ifdef DOXYGEN
/**
* @brief Base instance of a USBD class.
*
* Any USBD class instance have to begin with this instance.
* This may then be followed by any implementation dependent data.
*
* For an instance it should be possible to put whole structure into FLASH.
*
* @note This type is early defined as incomplete type.
* This is required for function declaration that takes the pointer
* to this structure but in second hand - it is also placed inside
* the instance structure.
* @note The structure is defined in @file app_usbd_class_base.h.
*/
typedef struct {} app_usbd_class_inst_t;
#else
typedef struct app_usbd_class_inst_s app_usbd_class_inst_t;
#endif
/**
* @brief Endpoint callback function.
*
* The function used by every class instance.
* @param[in,out] p_inst Instance of the class.
* @param[in] p_event Event to process.
*
* @note If given event is not supported by class, return @ref NRF_ERROR_NOT_SUPPORTED
*/
typedef ret_code_t (*app_usbd_ep_event_handler_t)(
app_usbd_class_inst_t const * const p_inst,
app_usbd_complex_evt_t const * const p_event
);
/**
* @brief SOF interrupt callback function.
*
* @param[in] framecnt Number of current SOF frame.
*
* @sa app_usbd_class_sof_register
*/
typedef void (*app_usbd_sof_interrupt_handler_t)(uint16_t framecnt);
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* APP_USBD_TYPES_H__ */

View File

@@ -1,861 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sdk_common.h"
#if NRF_MODULE_ENABLED(APP_USBD_AUDIO)
#include "app_usbd_audio.h"
#include "app_util_platform.h"
/**
* @defgroup app_usbd_audio_internals USBD Audio internals
* @{
* @ingroup app_usbd_audio
* @internal
*/
STATIC_ASSERT(sizeof(app_usbd_audio_ac_iface_header_desc_t) == 8);
STATIC_ASSERT(sizeof(app_usbd_audio_input_terminal_desc_t) == 12);
STATIC_ASSERT(sizeof(app_usbd_audio_output_terminal_desc_t) == 9);
STATIC_ASSERT(sizeof(app_usbd_audio_feature_unit_desc_t) == 6);
STATIC_ASSERT(sizeof(app_usbd_audio_as_iface_desc_t) == 7);
STATIC_ASSERT(sizeof(app_usbd_audio_as_format_type_one_desc_t) == 8);
STATIC_ASSERT(sizeof(app_usbd_audio_as_format_type_two_desc_t) == 9);
STATIC_ASSERT(sizeof(app_usbd_audio_as_format_type_three_desc_t) == 8);
STATIC_ASSERT(sizeof(app_usbd_audio_as_endpoint_desc_t) == 7);
#define APP_USBD_AUDIO_CONTROL_IFACE_IDX 0 /**< Audio class control interface index */
#define APP_USBD_AUDIO_STREAMING_IFACE_IDX 1 /**< Audio class streaming interface index */
#define APP_USBD_CDC_AUDIO_STREAMING_EP_IDX 0 /**< Audio streaming isochronous endpoint index */
/**
* @brief Auxiliary function to access audio class instance data.
*
* @param[in] p_inst Class instance data.
* @return Audio class instance data @ref app_usbd_audio_t
*/
static inline app_usbd_audio_t const * audio_get(app_usbd_class_inst_t const * p_inst)
{
ASSERT(p_inst != NULL);
return (app_usbd_audio_t const *)p_inst;
}
/**
* @brief Auxiliary function to access audio class context data.
*
* @param[in] p_audio Audio class instance data.
* @return Audio class context data @ref app_usbd_audio_ctx_t
*/
static inline app_usbd_audio_ctx_t * audio_ctx_get(app_usbd_audio_t const * p_audio)
{
ASSERT(p_audio != NULL);
ASSERT(p_audio->specific.p_data != NULL);
return &p_audio->specific.p_data->ctx;
}
/**
* @brief User event handler.
*
* @param[in] p_inst Class instance.
* @param[in] event user Event type @ref app_usbd_audio_user_event_t
*/
static inline void user_event_handler(
app_usbd_class_inst_t const * p_inst,
app_usbd_audio_user_event_t event)
{
app_usbd_audio_t const * p_audio = audio_get(p_inst);
if (p_audio->specific.inst.user_ev_handler != NULL)
{
p_audio->specific.inst.user_ev_handler(p_inst, event);
}
}
/**
* @brief Select interface.
*
* @param[in,out] p_inst Instance of the class.
* @param[in] iface_idx Index of the interface inside class structure.
* @param[in] alternate Alternate setting that should be selected.
*/
static ret_code_t iface_select(
app_usbd_class_inst_t const * const p_inst,
uint8_t iface_idx,
uint8_t alternate)
{
app_usbd_class_iface_conf_t const * p_iface = app_usbd_class_iface_get(p_inst, iface_idx);
/* Simple check if this is data interface */
uint8_t const ep_count = app_usbd_class_iface_ep_count_get(p_iface);
if (ep_count > 0)
{
if (alternate > 1)
{
return NRF_ERROR_INVALID_PARAM;
}
app_usbd_audio_t const * p_audio = audio_get(p_inst);
app_usbd_audio_ctx_t * p_audio_ctx = audio_ctx_get(p_audio);
p_audio_ctx->streaming = (alternate != 0);
uint8_t i;
for (i = 0; i < ep_count; ++i)
{
nrf_drv_usbd_ep_t ep_addr =
app_usbd_class_ep_address_get(app_usbd_class_iface_ep_get(p_iface, i));
if (alternate)
{
app_usbd_ep_enable(ep_addr);
}
else
{
app_usbd_ep_disable(ep_addr);
}
}
return NRF_SUCCESS;
}
return NRF_ERROR_NOT_SUPPORTED;
}
static void iface_deselect(
app_usbd_class_inst_t const * const p_inst,
uint8_t iface_idx)
{
app_usbd_class_iface_conf_t const * p_iface = app_usbd_class_iface_get(p_inst, iface_idx);
/* Simple check if this is data interface */
if (p_iface->ep_cnt > 0)
{
app_usbd_audio_t const * p_audio = audio_get(p_inst);
app_usbd_audio_ctx_t * p_audio_ctx = audio_ctx_get(p_audio);
p_audio_ctx->streaming = false;
}
/* Note that all the interface endpoints would be disabled automatically after this function */
}
static uint8_t iface_selection_get(
app_usbd_class_inst_t const * const p_inst,
uint8_t iface_idx)
{
app_usbd_class_iface_conf_t const * p_iface = app_usbd_class_iface_get(p_inst, iface_idx);
/* Simple check if this is data interface */
uint8_t const ep_count = app_usbd_class_iface_ep_count_get(p_iface);
if (ep_count > 0)
{
app_usbd_audio_t const * p_audio = audio_get(p_inst);
app_usbd_audio_ctx_t * p_audio_ctx = audio_ctx_get(p_audio);
return (p_audio_ctx->streaming) ? 1 : 0;
}
return 0;
}
/**
* @brief Internal SETUP standard IN request handler.
*
* @param[in] p_inst Generic class instance.
* @param[in] p_setup_ev Setup event.
*
* @return Standard error code.
* @retval NRF_SUCCESS Request handled correctly.
* @retval NRF_ERROR_NOT_SUPPORTED Request is not supported.
*/
static ret_code_t setup_req_std_in(app_usbd_class_inst_t const * p_inst,
app_usbd_setup_evt_t const * p_setup_ev)
{
/* Only Get Descriptor standard IN request is supported by Audio class */
if ((app_usbd_setup_req_rec(p_setup_ev->setup.bmRequestType) == APP_USBD_SETUP_REQREC_INTERFACE)
&&
(p_setup_ev->setup.bRequest == APP_USBD_SETUP_STDREQ_GET_DESCRIPTOR))
{
size_t dsc_len = 0;
size_t max_size;
uint8_t * p_trans_buff = app_usbd_core_setup_transfer_buff_get(&max_size);
/* Try to find descriptor in class internals*/
ret_code_t ret = app_usbd_class_descriptor_find(
p_inst,
p_setup_ev->setup.wValue.hb,
p_setup_ev->setup.wValue.lb,
p_trans_buff,
&dsc_len);
if (ret != NRF_ERROR_NOT_FOUND)
{
ASSERT(dsc_len < NRF_DRV_USBD_EPSIZE);
return app_usbd_core_setup_rsp(&(p_setup_ev->setup), p_trans_buff, dsc_len);
}
}
return NRF_ERROR_NOT_SUPPORTED;
}
/**
* @brief Internal SETUP class IN request handler.
*
* @param[in] p_inst Generic class instance.
* @param[in] p_setup_ev Setup event.
*
* @return Standard error code.
* @retval NRF_SUCCESS Request handled correctly.
* @retval NRF_ERROR_NOT_SUPPORTED Request is not supported.
*/
static ret_code_t setup_req_class_in(
app_usbd_class_inst_t const * p_inst,
app_usbd_setup_evt_t const * p_setup_ev)
{
switch (p_setup_ev->setup.bRequest)
{
case APP_USBD_AUDIO_REQ_GET_CUR:
case APP_USBD_AUDIO_REQ_GET_MIN:
case APP_USBD_AUDIO_REQ_GET_MAX:
case APP_USBD_AUDIO_REQ_SET_RES:
case APP_USBD_AUDIO_REQ_GET_MEM:
{
app_usbd_audio_t const * p_audio = audio_get(p_inst);
app_usbd_audio_ctx_t * p_audio_ctx = audio_ctx_get(p_audio);
p_audio_ctx->request.req_type = (app_usbd_audio_req_type_t)p_setup_ev->setup.bRequest;
p_audio_ctx->request.control = p_setup_ev->setup.wValue.hb;
p_audio_ctx->request.channel = p_setup_ev->setup.wValue.lb;
p_audio_ctx->request.interface = p_setup_ev->setup.wIndex.hb;
p_audio_ctx->request.entity = p_setup_ev->setup.wIndex.lb;
p_audio_ctx->request.length = p_setup_ev->setup.wLength.w;
p_audio_ctx->request.req_target = APP_USBD_AUDIO_CLASS_REQ_IN;
app_usbd_setup_reqrec_t rec = app_usbd_setup_req_rec(p_setup_ev->setup.bmRequestType);
if (rec == APP_USBD_SETUP_REQREC_ENDPOINT)
{
p_audio_ctx->request.req_target = APP_USBD_AUDIO_EP_REQ_IN;
}
user_event_handler((app_usbd_class_inst_t const *)p_audio,
APP_USBD_AUDIO_USER_EVT_CLASS_REQ);
return app_usbd_core_setup_rsp(&p_setup_ev->setup,
p_audio_ctx->request.payload,
p_audio_ctx->request.length);
}
default:
break;
}
return NRF_ERROR_NOT_SUPPORTED;
}
static ret_code_t audio_req_out_data_cb(nrf_drv_usbd_ep_status_t status, void * p_context)
{
if (status == NRF_USBD_EP_OK)
{
app_usbd_audio_t const * p_audio = p_context;
user_event_handler((app_usbd_class_inst_t const *)p_audio,
APP_USBD_AUDIO_USER_EVT_CLASS_REQ);
}
return NRF_SUCCESS;
}
static ret_code_t audio_req_out(
app_usbd_class_inst_t const * p_inst,
app_usbd_setup_evt_t const * p_setup_ev)
{
app_usbd_audio_t const * p_audio = audio_get(p_inst);
app_usbd_audio_ctx_t * p_audio_ctx = audio_ctx_get(p_audio);
p_audio_ctx->request.req_type = (app_usbd_audio_req_type_t)p_setup_ev->setup.bRequest;
p_audio_ctx->request.control = p_setup_ev->setup.wValue.hb;
p_audio_ctx->request.channel = p_setup_ev->setup.wValue.lb;
p_audio_ctx->request.interface = p_setup_ev->setup.wIndex.hb;
p_audio_ctx->request.entity = p_setup_ev->setup.wIndex.lb;
p_audio_ctx->request.length = p_setup_ev->setup.wLength.w;
p_audio_ctx->request.req_target = APP_USBD_AUDIO_CLASS_REQ_OUT;
if (app_usbd_setup_req_rec(p_setup_ev->setup.bmRequestType) == APP_USBD_SETUP_REQREC_ENDPOINT)
{
p_audio_ctx->request.req_target = APP_USBD_AUDIO_EP_REQ_OUT;
}
/*Request setup data*/
NRF_DRV_USBD_TRANSFER_OUT(transfer, p_audio_ctx->request.payload, p_audio_ctx->request.length);
ret_code_t ret;
CRITICAL_REGION_ENTER();
ret = app_usbd_ep_transfer(NRF_DRV_USBD_EPOUT0, &transfer);
if (ret == NRF_SUCCESS)
{
app_usbd_core_setup_data_handler_desc_t desc = {
.handler = audio_req_out_data_cb,
.p_context = (void *)p_audio
};
ret = app_usbd_core_setup_data_handler_set(NRF_DRV_USBD_EPOUT0, &desc);
}
CRITICAL_REGION_EXIT();
return ret;
}
/**
* @brief Internal SETUP class OUT request handler.
*
* @param[in] p_inst Generic class instance.
* @param[in] p_setup_ev Setup event.
*
* @return Standard error code
* @retval NRF_SUCCESS Request handled correctly.
* @retval NRF_ERROR_NOT_SUPPORTED Request is not supported.
*/
static ret_code_t setup_req_class_out(
app_usbd_class_inst_t const * p_inst,
app_usbd_setup_evt_t const * p_setup_ev)
{
switch (p_setup_ev->setup.bRequest)
{
case APP_USBD_AUDIO_REQ_SET_CUR:
case APP_USBD_AUDIO_REQ_SET_MIN:
case APP_USBD_AUDIO_REQ_SET_MAX:
case APP_USBD_AUDIO_REQ_SET_RES:
case APP_USBD_AUDIO_REQ_SET_MEM:
return audio_req_out(p_inst, p_setup_ev);
default:
break;
}
return NRF_ERROR_NOT_SUPPORTED;
}
/**
* @brief Control endpoint handle.
*
* @param[in] p_inst Generic class instance.
* @param[in] p_setup_ev Setup event.
*
* @return Standard error code.
* @retval NRF_SUCCESS Request handled correctly.
* @retval NRF_ERROR_NOT_SUPPORTED Request is not supported.
*/
static ret_code_t setup_event_handler(
app_usbd_class_inst_t const * p_inst,
app_usbd_setup_evt_t const * p_setup_ev)
{
ASSERT(p_inst != NULL);
ASSERT(p_setup_ev != NULL);
if (app_usbd_setup_req_dir(p_setup_ev->setup.bmRequestType) == APP_USBD_SETUP_REQDIR_IN)
{
switch (app_usbd_setup_req_typ(p_setup_ev->setup.bmRequestType))
{
case APP_USBD_SETUP_REQTYPE_STD:
return setup_req_std_in(p_inst, p_setup_ev);
case APP_USBD_SETUP_REQTYPE_CLASS:
return setup_req_class_in(p_inst, p_setup_ev);
default:
break;
}
}
else /*APP_USBD_SETUP_REQDIR_OUT*/
{
switch (app_usbd_setup_req_typ(p_setup_ev->setup.bmRequestType))
{
case APP_USBD_SETUP_REQTYPE_CLASS:
return setup_req_class_out(p_inst, p_setup_ev);
default:
break;
}
}
return NRF_ERROR_NOT_SUPPORTED;
}
/**
* @brief Endpoint IN event handler.
*
* @param[in] p_inst Generic class instance.
*
* @return Standard error code.
* @retval NRF_SUCCESS Request handled correctly.
* @retval NRF_ERROR_NOT_SUPPORTED Request is not supported.
*/
static ret_code_t endpoint_in_event_handler(app_usbd_class_inst_t const * p_inst)
{
user_event_handler(p_inst, APP_USBD_AUDIO_USER_EVT_TX_DONE);
return NRF_SUCCESS;
}
/**
* @brief Endpoint OUT event handler.
*
* @param[in] p_inst Generic class instance.
*
* @return Standard error code.
* @retval NRF_SUCCESS Request handled correctly.
* @retval NRF_ERROR_NOT_SUPPORTED Request is not supported.
*/
static ret_code_t endpoint_out_event_handler(app_usbd_class_inst_t const * p_inst)
{
user_event_handler(p_inst, APP_USBD_AUDIO_USER_EVT_RX_DONE);
return NRF_SUCCESS;
}
/**
* @brief Auxiliary function to access isochronous endpoint address.
*
* @param[in] p_inst Class instance data.
*
* @return ISO endpoint address.
*/
static inline nrf_drv_usbd_ep_t ep_iso_addr_get(app_usbd_class_inst_t const * p_inst)
{
app_usbd_class_iface_conf_t const * class_iface;
class_iface = app_usbd_class_iface_get(p_inst, APP_USBD_AUDIO_STREAMING_IFACE_IDX);
app_usbd_class_ep_conf_t const * ep_cfg;
ep_cfg = app_usbd_class_iface_ep_get(class_iface, APP_USBD_CDC_AUDIO_STREAMING_EP_IDX);
return app_usbd_class_ep_address_get(ep_cfg);
}
/**
* @brief @ref app_usbd_class_methods_t::event_handler
*/
static ret_code_t audio_event_handler(
app_usbd_class_inst_t const * p_inst,
app_usbd_complex_evt_t const * p_event)
{
ASSERT(p_inst != NULL);
ASSERT(p_event != NULL);
ret_code_t ret = NRF_SUCCESS;
switch (p_event->app_evt.type)
{
case APP_USBD_EVT_DRV_RESET:
break;
case APP_USBD_EVT_DRV_SETUP:
ret = setup_event_handler(p_inst, (app_usbd_setup_evt_t const *)p_event);
break;
case APP_USBD_EVT_DRV_EPTRANSFER:
if (NRF_USBD_EPIN_CHECK(p_event->drv_evt.data.eptransfer.ep))
{
ret = endpoint_in_event_handler(p_inst);
}
else
{
ret = endpoint_out_event_handler(p_inst);
}
break;
case APP_USBD_EVT_DRV_SUSPEND:
break;
case APP_USBD_EVT_DRV_RESUME:
break;
case APP_USBD_EVT_INST_APPEND:
{
app_usbd_audio_t const * p_audio = audio_get(p_inst);
app_usbd_audio_ctx_t * p_audio_ctx = audio_ctx_get(p_audio);
if(p_audio_ctx->sof_handler != NULL)
{
ret = app_usbd_class_sof_interrupt_register(p_inst, p_audio_ctx->sof_handler);
APP_ERROR_CHECK(ret);
}
break;
}
case APP_USBD_EVT_INST_REMOVE:
{
app_usbd_audio_t const * p_audio = audio_get(p_inst);
app_usbd_audio_ctx_t * p_audio_ctx = audio_ctx_get(p_audio);
if(p_audio_ctx->sof_handler != NULL)
{
ret = app_usbd_class_sof_interrupt_unregister(p_inst);
APP_ERROR_CHECK(ret);
}
break;
}
case APP_USBD_EVT_STARTED:
break;
case APP_USBD_EVT_STOPPED:
break;
default:
ret = NRF_ERROR_NOT_SUPPORTED;
break;
}
return ret;
}
static size_t audio_get_format_descriptor_size(app_usbd_class_inst_t const * p_inst)
{
app_usbd_audio_t const * p_audio = audio_get(p_inst);
if (p_audio->specific.inst.p_format_dsc == NULL)
{
return 0;
}
return p_audio->specific.inst.p_format_dsc->size;
}
static size_t audio_get_format_descriptor_data(app_usbd_class_inst_t const * p_inst,
uint32_t cur_byte)
{
app_usbd_audio_t const * p_audio = audio_get(p_inst);
return p_audio->specific.inst.p_format_dsc->p_data[cur_byte];
}
static size_t audio_get_input_descriptor_size(app_usbd_class_inst_t const * p_inst)
{
app_usbd_audio_t const * p_audio = audio_get(p_inst);
if (p_audio->specific.inst.p_input_dsc == NULL)
{
return 0;
}
return p_audio->specific.inst.p_input_dsc->size;
}
static size_t audio_get_input_descriptor_data(app_usbd_class_inst_t const * p_inst,
uint32_t cur_byte)
{
app_usbd_audio_t const * p_audio = audio_get(p_inst);
return p_audio->specific.inst.p_input_dsc->p_data[cur_byte];
}
static size_t audio_get_output_descriptor_size(app_usbd_class_inst_t const * p_inst)
{
app_usbd_audio_t const * p_audio = audio_get(p_inst);
if (p_audio->specific.inst.p_output_dsc == NULL)
{
return 0;
}
return p_audio->specific.inst.p_output_dsc->size;
}
static size_t audio_get_output_descriptor_data(app_usbd_class_inst_t const * p_inst,
uint32_t cur_byte)
{
app_usbd_audio_t const * p_audio = audio_get(p_inst);
return p_audio->specific.inst.p_output_dsc->p_data[cur_byte];
}
static size_t audio_get_feature_descriptor_size(app_usbd_class_inst_t const * p_inst)
{
app_usbd_audio_t const * p_audio = audio_get(p_inst);
if (p_audio->specific.inst.p_feature_dsc == NULL)
{
return 0;
}
return p_audio->specific.inst.p_feature_dsc->size;
}
static size_t audio_get_feature_descriptor_data(app_usbd_class_inst_t const * p_inst,
uint32_t cur_byte)
{
app_usbd_audio_t const * p_audio = audio_get(p_inst);
return p_audio->specific.inst.p_feature_dsc->p_data[cur_byte];
}
static uint8_t audio_get_control_interface_number(app_usbd_class_inst_t const * p_inst)
{
app_usbd_class_iface_conf_t const * ifce = 0;
ifce = app_usbd_class_iface_get(p_inst, 0);
return app_usbd_class_iface_number_get(ifce);
}
/**
* @brief @ref app_usbd_class_methods_t::feed_descriptors
*/
static bool audio_feed_descriptors(app_usbd_class_descriptor_ctx_t * p_ctx,
app_usbd_class_inst_t const * p_inst,
uint8_t * p_buff,
size_t max_size)
{
static uint8_t ifaces = 0;
ifaces = app_usbd_class_iface_count_get(p_inst);
ASSERT(ifaces == 2);
app_usbd_audio_t const * p_audio = audio_get(p_inst);
APP_USBD_CLASS_DESCRIPTOR_BEGIN(p_ctx, p_buff, max_size);
/* CONTROL INTERFACE DESCRIPTOR */
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x09); // bLength
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_DESCRIPTOR_INTERFACE); // bDescriptorType = Interface
static app_usbd_class_iface_conf_t const * p_cur_iface = NULL;
p_cur_iface = app_usbd_class_iface_get(p_inst, 0);
APP_USBD_CLASS_DESCRIPTOR_WRITE(app_usbd_class_iface_number_get(p_cur_iface)); // bInterfaceNumber
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x00); // bAlternateSetting
APP_USBD_CLASS_DESCRIPTOR_WRITE(app_usbd_class_iface_ep_count_get(p_cur_iface)); // bNumEndpoints
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_AUDIO_CLASS); // bInterfaceClass = Audio
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_AUDIO_SUBCLASS_AUDIOCONTROL); // bInterfaceSubclass (Audio Control)
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_AUDIO_CLASS_PROTOCOL_UNDEFINED); // bInterfaceProtocol
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x00); // iInterface
/* HEADER INTERFACE */
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x09); // bLength
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_AUDIO_DESCRIPTOR_INTERFACE); // bDescriptorType = Audio Interfaces
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_AUDIO_AC_IFACE_SUBTYPE_HEADER); // bDescriptorSubtype = Header
APP_USBD_CLASS_DESCRIPTOR_WRITE(LSB_16(0x0100)); // bcdADC LSB
APP_USBD_CLASS_DESCRIPTOR_WRITE(MSB_16(0x0100)); // bcdADC MSB
static uint16_t header_desc_len = 0;
header_desc_len = 9 + audio_get_feature_descriptor_size(p_inst) +
audio_get_input_descriptor_size(p_inst) + audio_get_output_descriptor_size(
p_inst);
APP_USBD_CLASS_DESCRIPTOR_WRITE(LSB_16(header_desc_len)); // wTotalLength LSB
APP_USBD_CLASS_DESCRIPTOR_WRITE(MSB_16(header_desc_len)); // wTotalLength MSB
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x01); // bInCollection
APP_USBD_CLASS_DESCRIPTOR_WRITE(audio_get_control_interface_number(p_inst) + 1); // baInterfaceNr(1)
/* INPUT TERMINAL DESCRIPTOR */
static uint32_t cur_byte = 0;
static size_t input_desc_size = 0;
input_desc_size = audio_get_input_descriptor_size(p_inst);
for (cur_byte = 0; cur_byte < input_desc_size; cur_byte++)
{
APP_USBD_CLASS_DESCRIPTOR_WRITE(audio_get_input_descriptor_data(p_inst, cur_byte));
}
/* FEATURE UNIT DESCRIPTOR */
static size_t feature_desc_size = 0;
feature_desc_size = audio_get_feature_descriptor_size(p_inst);
for (cur_byte = 0; cur_byte < feature_desc_size; cur_byte++)
{
APP_USBD_CLASS_DESCRIPTOR_WRITE(audio_get_feature_descriptor_data(p_inst, cur_byte));
}
/* OUTPUT TERMINAL DESCRIPTOR */
static size_t output_desc_size = 0;
output_desc_size = audio_get_output_descriptor_size(p_inst);
for (cur_byte = 0; cur_byte < output_desc_size; cur_byte++)
{
APP_USBD_CLASS_DESCRIPTOR_WRITE(audio_get_output_descriptor_data(p_inst, cur_byte));
}
p_cur_iface++;
/* STREAM INTERFACE DESCRIPTOR ALT 0 */
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x09); // bLength
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_DESCRIPTOR_INTERFACE); // bDescriptorType = Interface
APP_USBD_CLASS_DESCRIPTOR_WRITE(audio_get_control_interface_number(p_inst) + 1); // bInterfaceNumber
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x00); // bAlternateSetting
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x00); // bNumEndpoints
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_AUDIO_CLASS); // bInterfaceClass = Audio
APP_USBD_CLASS_DESCRIPTOR_WRITE(p_audio->specific.inst.type_streaming); // bInterfaceSubclass (Audio Control)
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_AUDIO_CLASS_PROTOCOL_UNDEFINED); // bInterfaceProtocol
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x00); // iInterface
/* STREAM INTERFACE DESCRIPTOR ALT 1 */
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x09); // bLength
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_DESCRIPTOR_INTERFACE); // bDescriptorType = Interface
APP_USBD_CLASS_DESCRIPTOR_WRITE(audio_get_control_interface_number(p_inst) + 1); // bInterfaceNumber
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x01); // bAlternateSetting
APP_USBD_CLASS_DESCRIPTOR_WRITE(app_usbd_class_iface_ep_count_get(p_cur_iface)); // bNumEndpoints
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_AUDIO_CLASS); // bInterfaceClass = Audio
APP_USBD_CLASS_DESCRIPTOR_WRITE(p_audio->specific.inst.type_streaming); // bInterfaceSubclass (Audio Control)
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_AUDIO_CLASS_PROTOCOL_UNDEFINED); // bInterfaceProtocol
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x00); // iInterface
/* AudioStreaming GENERAL DESCRIPTOR */
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x07); // bLength
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_AUDIO_DESCRIPTOR_INTERFACE); // bDescriptorType = Audio Interface
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_AUDIO_AS_IFACE_SUBTYPE_GENERAL); // bDescriptorSubtype = General
APP_USBD_CLASS_DESCRIPTOR_WRITE(p_audio->specific.inst.terminal_link); // bTerminalLink
APP_USBD_CLASS_DESCRIPTOR_WRITE(p_audio->specific.inst.delay); // bDelay
APP_USBD_CLASS_DESCRIPTOR_WRITE(LSB_16(p_audio->specific.inst.format)); // wFormatTag LSB
APP_USBD_CLASS_DESCRIPTOR_WRITE(MSB_16(p_audio->specific.inst.format)); // wFormatTag MSB
/* FORMAT DESCRIPTOR */
static size_t format_desc_size = 0;
format_desc_size = audio_get_format_descriptor_size(p_inst);
for (cur_byte = 0; cur_byte < format_desc_size; cur_byte++)
{
APP_USBD_CLASS_DESCRIPTOR_WRITE(audio_get_format_descriptor_data(p_inst, cur_byte));
}
/* ENDPOINT GENERAL DESCRIPTOR */
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x07); // bLength
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_AUDIO_DESCRIPTOR_ENDPOINT); // bDescriptorType = Audio Descriptor
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_AUDIO_EP_SUBTYPE_GENERAL); // bDescriptorSubtype = EP General
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x00); // bmAttributes
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x00); // bLockDelayUnits
APP_USBD_CLASS_DESCRIPTOR_WRITE(LSB_16(0x0000)); // wLockDelay LSB
APP_USBD_CLASS_DESCRIPTOR_WRITE(MSB_16(0x0000)); // wLockDelay MSB
/* ENDPOINT ISO DESCRIPTOR */
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x09); // bLength
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_DESCRIPTOR_ENDPOINT); // bDescriptorType = Endpoint
static app_usbd_class_ep_conf_t const * p_cur_ep = NULL;
p_cur_ep = app_usbd_class_iface_ep_get(p_cur_iface, 0);
APP_USBD_CLASS_DESCRIPTOR_WRITE(app_usbd_class_ep_address_get(p_cur_ep)); // bEndpointAddress
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_DESCRIPTOR_EP_ATTR_TYPE_ISOCHRONOUS); // bmAttributes
APP_USBD_CLASS_DESCRIPTOR_WRITE(LSB_16(p_audio->specific.inst.ep_size)); // wMaxPacketSize LSB
APP_USBD_CLASS_DESCRIPTOR_WRITE(MSB_16(p_audio->specific.inst.ep_size)); // wMaxPacketSize MSB
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x01); // bInterval
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x00); // bRefresh
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x00); // bSynchAddress
APP_USBD_CLASS_DESCRIPTOR_END();
}
/** @} */
const app_usbd_class_methods_t app_usbd_audio_class_methods = {
.event_handler = audio_event_handler,
.feed_descriptors = audio_feed_descriptors,
.iface_select = iface_select,
.iface_deselect = iface_deselect,
.iface_selection_get = iface_selection_get,
};
size_t app_usbd_audio_class_rx_size_get(app_usbd_class_inst_t const * p_inst)
{
nrf_drv_usbd_ep_t ep_addr;
ep_addr = ep_iso_addr_get(p_inst);
ASSERT(NRF_USBD_EPISO_CHECK(ep_addr));
return (size_t)nrf_drv_usbd_epout_size_get(ep_addr);
}
ret_code_t app_usbd_audio_class_rx_start(
app_usbd_class_inst_t const * p_inst,
void * p_buff,
size_t size)
{
nrf_drv_usbd_ep_t ep_addr;
ep_addr = ep_iso_addr_get(p_inst);
ASSERT(NRF_USBD_EPISO_CHECK(ep_addr));
NRF_DRV_USBD_TRANSFER_OUT(transfer, p_buff, size);
return app_usbd_ep_transfer(ep_addr, &transfer);
}
ret_code_t app_usbd_audio_class_tx_start(
app_usbd_class_inst_t const * p_inst,
const void * p_buff,
size_t size)
{
nrf_drv_usbd_ep_t ep_addr;
ep_addr = ep_iso_addr_get(p_inst);
ASSERT(NRF_USBD_EPISO_CHECK(ep_addr));
NRF_DRV_USBD_TRANSFER_IN(transfer, p_buff, size);
return app_usbd_ep_transfer(ep_addr, &transfer);
}
ret_code_t app_usbd_audio_sof_interrupt_register(app_usbd_class_inst_t const * p_inst,
app_usbd_sof_interrupt_handler_t handler)
{
app_usbd_audio_t const * p_audio = audio_get(p_inst);
app_usbd_audio_ctx_t * p_audio_ctx = audio_ctx_get(p_audio);
p_audio_ctx->sof_handler = handler;
return NRF_SUCCESS;
}
#endif //NRF_MODULE_ENABLED(APP_USBD_AUDIO)

View File

@@ -1,346 +0,0 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef APP_USBD_AUDIO_H__
#define APP_USBD_AUDIO_H__
#include <stdint.h>
#include <stdbool.h>
#include "nrf_drv_usbd.h"
#include "app_usbd.h"
#include "app_usbd_core.h"
#include "app_usbd_class_base.h"
#include "app_usbd_descriptor.h"
#include "app_usbd_audio_types.h"
#include "app_usbd_audio_desc.h"
#include "app_usbd_audio_internal.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup app_usbd_audio USB AUDIO class
* @ingroup app_usbd
*
* @brief @tagAPI52840 Module with types, definitions, and API used by USB Audio class.
*
* @details Reference specifications:
* - "Universal Serial Bus Device Class Definition for Audio Devices"
* Release 1.0, March 18, 1998.
* - "Universal Serial Bus Device Class Definition for Audio Data Formats"
* Release 1.0, March 18, 1998.
* - "Universal Serial Bus Device Class Definition for Terminal Types"
* Release 1.0, March 18, 1998.
*
* @{
*/
#ifdef DOXYGEN
/**
* @brief Audio class instance type
*
* @ref APP_USBD_CLASS_TYPEDEF
*/
typedef struct { } app_usbd_audio_t;
#else
/*lint -save -e10 -e26 -e123 -e505 */
APP_USBD_CLASS_TYPEDEF(app_usbd_audio, \
APP_USBD_AUDIO_CONFIG(0, 1), \
APP_USBD_AUDIO_INSTANCE_SPECIFIC_DEC, \
APP_USBD_AUDIO_DATA_SPECIFIC_DEC \
);
/*lint -restore*/
#endif
/*lint -save -e407 */
/**
* @brief Events passed to user event handler
*
* @note Example prototype of user event handler:
*
* @code
void audio_user_ev_handler(app_usbd_class_inst_t const * p_inst,
app_usbd_audio_user_event_t event);
* @endcode
*/
typedef enum app_usbd_audio_user_event_e {
APP_USBD_AUDIO_USER_EVT_CLASS_REQ, /**< User event CLASS_REQ */
APP_USBD_AUDIO_USER_EVT_RX_DONE, /**< User event RX_DONE */
APP_USBD_AUDIO_USER_EVT_TX_DONE, /**< User event TX_DONE */
} app_usbd_audio_user_event_t;
/*lint -restore*/
/**
* @brief Global definition of app_usbd_audio_t class instance.
*
* @param instance_name Name of global instance.
* @param interfaces_configs Interfaces configurations.
* @param user_ev_handler User event handler.
* @param format_descriptor Audio class Format descriptor.
* @param input_descriptor Audio class Input Terminal descriptor.
* @param output_descriptor Audio class Output Terminal descriptor.
* @param feature_descriptor Audio class Feature Unit descriptor.
* @param delay Streaming delay.
* @param format FormatTag (@ref app_usbd_audio_as_iface_format_tag_t).
* @param ep_size Endpoint size.
* @param type_str Streaming type MIDISTREAMING/AUDIOSTREAMING.
* @param terminal_link Terminal link in AS Interface Descriptor.
*
* @note This macro is just simplified version of @ref APP_USBD_AUDIO_GLOBAL_DEF_INTERNAL
*
*/
#define APP_USBD_AUDIO_GLOBAL_DEF(instance_name, \
interfaces_configs, \
user_ev_handler, \
format_descriptor, \
input_descriptor, \
output_descriptor, \
feature_descriptor, \
delay, \
format, \
ep_size, \
type_str, \
terminal_link) \
APP_USBD_AUDIO_GLOBAL_DEF_INTERNAL(instance_name, \
interfaces_configs, \
user_ev_handler, \
format_descriptor, \
input_descriptor, \
output_descriptor, \
feature_descriptor, \
delay, \
format, \
ep_size, \
type_str, \
terminal_link)
/**
* @brief Initializer of Audio Format descriptor.
*
* @param name Format descriptor name.
* @param ... Format descriptor data.
*/
#define APP_USBD_AUDIO_FORMAT_DESCRIPTOR(name, ...) \
static uint8_t const CONCAT_2(name, _data)[] = \
{ \
__VA_ARGS__ \
}; \
static const app_usbd_audio_subclass_desc_t name = \
{ \
sizeof(CONCAT_2(name, _data)), \
APP_USBD_AUDIO_AS_IFACE_SUBTYPE_FORMAT_TYPE, \
CONCAT_2(name,_data) \
}
/**
* @brief Initializer of Audio Input descriptor.
*
* @param name Input descriptor name.
* @param ... Input descriptor data.
*/
#define APP_USBD_AUDIO_INPUT_DESCRIPTOR(name, ...) \
static uint8_t const CONCAT_2(name, _data)[] = \
{ \
__VA_ARGS__ \
}; \
static const app_usbd_audio_subclass_desc_t name = \
{ \
sizeof(CONCAT_2(name, _data)), \
APP_USBD_AUDIO_AC_IFACE_SUBTYPE_INPUT_TERMINAL, \
CONCAT_2(name,_data) \
}
/**
* @brief Initializer of Audio Output descriptor.
*
* @param name Output descriptor name.
* @param ... Output descriptor data.
*/
#define APP_USBD_AUDIO_OUTPUT_DESCRIPTOR(name, ...) \
static uint8_t const CONCAT_2(name, _data)[] = \
{ \
__VA_ARGS__ \
}; \
static const app_usbd_audio_subclass_desc_t name = \
{ \
sizeof(CONCAT_2(name, _data)), \
APP_USBD_AUDIO_AC_IFACE_SUBTYPE_OUTPUT_TERMINAL, \
CONCAT_2(name,_data) \
}
/**
* @brief Initializer of Feture Output descriptor.
*
* @param name Feture descriptor name.
* @param ... Feture descriptor data.
*/
#define APP_USBD_AUDIO_FEATURE_DESCRIPTOR(name, ...) \
static uint8_t const CONCAT_2(name, _data)[] = \
{ \
__VA_ARGS__ \
}; \
static const app_usbd_audio_subclass_desc_t name = \
{ \
sizeof(CONCAT_2(name, _data)), \
APP_USBD_AUDIO_AC_IFACE_SUBTYPE_FEATURE_UNIT, \
CONCAT_2(name,_data) \
}
/**
* @@brief Helper function to get class instance from Audio class.
*
* @param[in] p_audio Audio class instance (declared by @ref APP_USBD_AUDIO_GLOBAL_DEF).
* @return Base class instance.
*/
static inline app_usbd_class_inst_t const *
app_usbd_audio_class_inst_get(app_usbd_audio_t const * p_audio)
{
return &p_audio->base;
}
/**
* @brief Helper function to get audio specific request from audio class.
*
* @param[in] p_audio Audio class instance (declared by @ref APP_USBD_AUDIO_GLOBAL_DEF).
* @return Audio class specific request.
*/
static inline app_usbd_audio_req_t *
app_usbd_audio_class_request_get(app_usbd_audio_t const * p_audio)
{
return &p_audio->specific.p_data->ctx.request;
}
/**
* @brief Helper function to get audio from base class instance.
*
* @param[in] p_inst Base class instance.
* @return Audio class handle.
*/
static inline app_usbd_audio_t const *
app_usbd_audio_class_get(app_usbd_class_inst_t const * p_inst)
{
return (app_usbd_audio_t const *)p_inst;
}
/**
* @brief Get the size of last received transfer.
*
* @note Call this function in reaction to a SOF event to check if there is any data to process.
*
* @param p_inst Base class instance.
*
* @return Number of bytes received in the last transmission.
*/
size_t app_usbd_audio_class_rx_size_get(app_usbd_class_inst_t const * p_inst);
/**
* @brief Start audio data copying from the endpoint buffer.
*
* Function to be used to copy data from an audio OUT endpoint to a given buffer.
* When it finishes, an @ref APP_USBD_AUDIO_USER_EVT_RX_DONE event is generated.
*
* @param p_inst Base class instance.
* @param p_buff Target buffer.
* @param size Size of the requested data.
*
* @return Result of the endpoint transmission start.
*
* @sa app_usbd_audio_class_rx_size_get
*
* @note This function should be called in reaction to a SOF event.
* Isochronous endpoints are double buffered and they are automatically switched at every SOF.
*/
ret_code_t app_usbd_audio_class_rx_start(
app_usbd_class_inst_t const * p_inst,
void * p_buff,
size_t size);
/**
* @brief Start copying audio data to the endpoint buffer.
*
* Function to be used to copy data to an audio IN endpoint from a given buffer.
* When it finishes, an @ref APP_USBD_AUDIO_USER_EVT_TX_DONE event is generated.
*
* @param p_inst Base class instance.
* @param p_buff Source buffer.
* @param size Size of the data to be sent.
*
* @return Result of the endpoint transsmision start.
*
* @note This function should be called in reaction to a SOF event.
* Isochronous endpoints are double buffered and they are automatically switched at every SOF.
*/
ret_code_t app_usbd_audio_class_tx_start(
app_usbd_class_inst_t const * p_inst,
const void * p_buff,
size_t size);
/**
* @brief Register audio instance as the one that requires SOF events in interrupt.
*
* This function should be called before appending the instance.
*
* @param p_inst Audio instance that requires SOF event.
* @param handler Handler to SOF event
*
* @retval NRF_SUCCESS Instance linked into SOF processing list.
*
* @sa app_usbd_class_sof_interrupt_register
*/
ret_code_t app_usbd_audio_sof_interrupt_register(app_usbd_class_inst_t const * p_inst,
app_usbd_sof_interrupt_handler_t handler);
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* APP_USBD_AUDIO_H__ */

View File

@@ -1,318 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef APP_USBD_AUDIO_DESC_H__
#define APP_USBD_AUDIO_DESC_H__
#include "app_usbd_descriptor.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup app_usbd_audio_dsc USB Audio descriptors
* @brief @tagAPI52840 Descriptors used in the USB Audio class.
* @ingroup app_usbd_audio
* @{
*/
/**
* @brief Initializer of interface descriptor for AUDIO class.
*
* @param interface_number Interface number.
* @param alt_setting Interface alternate setting.
* @param ep_num Number of endpoints.
* @param subclass Audio subclass @ref app_usbd_audio_subclass_t
* */
#define APP_USBD_AUDIO_INTERFACE_DSC(interface_number, alt_setting, ep_num, subclass) \
/*.bLength = */ sizeof(app_usbd_descriptor_iface_t), \
/*.bDescriptorType = */ APP_USBD_DESCRIPTOR_INTERFACE, \
/*.bInterfaceNumber = */ (interface_number), \
/*.bAlternateSetting = */ (alt_setting), \
/*.bNumEndpoints = */ (ep_num), \
/*.bInterfaceClass = */ APP_USBD_AUDIO_CLASS, \
/*.bInterfaceSubClass = */ (subclass), \
/*.bInterfaceProtocol = */ APP_USBD_AUDIO_CLASS_PROTOCOL_UNDEFINED, \
/*.iInterface = 0, */ 0x00, \
/**
* @brief Initializer of isochronous endpoint descriptors for audio class.
*
* @param ep ISO endpoint id: @ref NRF_DRV_USBD_EPIN8, @ref NRF_DRV_USBD_EPOUT8
* @param ep_size Endpoint size (bytes).
* @param interval Endpoint interval (milliseconds).
* @param refresh Refresh value (usually 0).
* @param synch_addr Synch address (usually 0).
* */
#define APP_USBD_AUDIO_ISO_EP_DSC(ep, ep_size, interval, refresh, synch_addr) \
/*.bLength = */ sizeof(app_usbd_descriptor_ep_t) + 2, \
/*.bDescriptorType = */ APP_USBD_DESCRIPTOR_ENDPOINT, \
/*.bEndpointAddress = */ ep, \
/*.bmAttributes = */ APP_USBD_DESCRIPTOR_EP_ATTR_TYPE_ISOCHRONOUS, \
/*.wMaxPacketSize = */ APP_USBD_U16_TO_RAW_DSC(ep_size), \
/*.bInterval = */ (interval), \
/*.bRefresh = */ (refresh), \
/*.bInterval = */ (synch_addr), \
/**
* @brief Simplified version of @ref APP_USBD_AUDIO_ISO_EP_DSC for ISO IN endpoint
*/
#define APP_USBD_AUDIO_ISO_EP_IN_DSC(ep_size) \
APP_USBD_AUDIO_ISO_EP_DSC(NRF_DRV_USBD_EPIN8, ep_size, 1, 0, 0)
/**
* @brief Simplified version of @ref APP_USBD_AUDIO_ISO_EP_DSC for ISO OUT endpoint
*/
#define APP_USBD_AUDIO_ISO_EP_OUT_DSC(ep_size) \
APP_USBD_AUDIO_ISO_EP_DSC(NRF_DRV_USBD_EPOUT8, ep_size, 1, 0, 0)
/**
* @brief Initializer of @ref app_usbd_audio_ac_iface_header_desc_t
*
* @param descriptor_list Descriptor list following audio interface header descriptor.
* @param ... List of interfaces following audio control interface.
* */
#define APP_USBD_AUDIO_AC_IFACE_HEADER_DSC(descriptor_list, ...) \
/*.bLength = */ sizeof(app_usbd_audio_ac_iface_header_desc_t) + \
(NUM_VA_ARGS(__VA_ARGS__)), \
/*.bDescriptorType = */ APP_USBD_AUDIO_DESCRIPTOR_INTERFACE, \
/*.bDescriptorSubtype = */ APP_USBD_AUDIO_AC_IFACE_SUBTYPE_HEADER, \
/*.bcdADC = */ APP_USBD_U16_TO_RAW_DSC(0x0100), \
/*.wTotalLength = */ APP_USBD_U16_TO_RAW_DSC( \
sizeof((uint8_t[]){BRACKET_EXTRACT(descriptor_list)}) + \
sizeof(app_usbd_audio_ac_iface_header_desc_t) + \
(NUM_VA_ARGS(__VA_ARGS__))), \
/*.bInCollection = */ (NUM_VA_ARGS(__VA_ARGS__)), \
/*.baInterfaceNr[] = */ __VA_ARGS__, \
/**
* @brief Initializer of @ref app_usbd_audio_input_terminal_desc_t
*
* @param terminal_id Terminal ID.
* @param terminal_type Terminal type @ref app_usbd_audio_terminal_type_t
* @param nr_channels Number of channels.
* @param ch_config Channel config bitmask.
* */
#define APP_USBD_AUDIO_INPUT_TERMINAL_DSC(terminal_id, terminal_type, nr_channels, ch_config) \
/*.bLength = */ sizeof(app_usbd_audio_input_terminal_desc_t), \
/*.bDescriptorType = */ APP_USBD_AUDIO_DESCRIPTOR_INTERFACE, \
/*.bDescriptorSubtype = */ APP_USBD_AUDIO_AC_IFACE_SUBTYPE_INPUT_TERMINAL, \
/*.bTerminalID = */ (terminal_id), \
/*.wTerminalType = */ APP_USBD_U16_TO_RAW_DSC(terminal_type), \
/*.bAssocTerminal = */ 0, \
/*.bNrChannels = */ (nr_channels), \
/*.wChannelConfig = */ APP_USBD_U16_TO_RAW_DSC(ch_config), \
/*.iChannelNames = */ 0, \
/*.iTerminal = */ 0, \
/**
* @brief Initializer of @ref app_usbd_audio_output_terminal_desc_t
*
* @param terminal_id Terminal ID.
* @param terminal_type Terminal type @ref app_usbd_audio_terminal_type_t
* @param source_id Source ID.
* */
#define APP_USBD_AUDIO_OUTPUT_TERMINAL_DSC(terminal_id, terminal_type, source_id) \
/*.bLength = */ sizeof(app_usbd_audio_output_terminal_desc_t), \
/*.bDescriptorType = */ APP_USBD_AUDIO_DESCRIPTOR_INTERFACE, \
/*.bDescriptorSubtype = */ APP_USBD_AUDIO_AC_IFACE_SUBTYPE_OUTPUT_TERMINAL, \
/*.bTerminalID = */ (terminal_id), \
/*.wTerminalType = */ APP_USBD_U16_TO_RAW_DSC(terminal_type), \
/*.bAssocTerminal = */ 0, \
/*.bSourceID = */ (source_id), \
/*.iTerminal = */ 0, \
/**
* @brief Initializer of @ref app_usbd_audio_feature_unit_desc_t
*
* @param unit_id Unit ID.
* @param source_id Source ID.
* @param ... List of controls.
* */
#define APP_USBD_AUDIO_FEATURE_UNIT_DSC(unit_id, source_id, ...) \
/*.bLength = */ sizeof(app_usbd_audio_feature_unit_desc_t) + \
1 + (NUM_VA_ARGS(__VA_ARGS__)), \
/*.bDescriptorType = */ APP_USBD_AUDIO_DESCRIPTOR_INTERFACE, \
/*.bDescriptorSubtype = */ APP_USBD_AUDIO_AC_IFACE_SUBTYPE_FEATURE_UNIT, \
/*.bUnitID = */ (unit_id), \
/*.bSourceID = */ (source_id), \
/*.bControlSize = */ sizeof(uint16_t), \
/*.bmaControls[] = */ __VA_ARGS__, \
/*.iFeature = */ 0, \
/**
* @brief Initializer of @ref app_usbd_audio_as_iface_desc_t
*
* @param terminal_link Terminal link.
* @param delay Delay.
* @param format_tag Format TAG.
* */
#define APP_USBD_AUDIO_AS_IFACE_DSC(terminal_link, delay, format_tag) \
/*.bLength = */ sizeof(app_usbd_audio_as_iface_desc_t), \
/*.bDescriptorType = */ APP_USBD_AUDIO_DESCRIPTOR_INTERFACE, \
/*.bDescriptorSubtype = */ APP_USBD_AUDIO_AS_IFACE_SUBTYPE_GENERAL, \
/*.bTerminalLink = */ (terminal_link), \
/*.bDelay = */ (delay), \
/*.wFormatTag = */ APP_USBD_U16_TO_RAW_DSC(format_tag), \
/**
* @brief Initializer of @ref app_usbd_audio_as_format_type_one_desc_t
*
* @param nr_channels Number of channels.
* @param subframe_size Subframe size.
* @param resolution Bit resolution.
* @param freq_type Frequency type.
* @param ... List of frequencies.
* */
#define APP_USBD_AUDIO_AS_FORMAT_I_DSC(nr_channels, subframe_size, resolution, freq_type, ...) \
/*.bLength = */ sizeof(app_usbd_audio_as_format_type_one_desc_t) + \
(NUM_VA_ARGS(__VA_ARGS__)), \
/*.bDescriptorType = */ APP_USBD_AUDIO_DESCRIPTOR_INTERFACE, \
/*.bDescriptorSubtype = */ APP_USBD_AUDIO_AS_IFACE_SUBTYPE_FORMAT_TYPE, \
/*.bFormatType = */ (1), \
/*.bNrChannels = */ (nr_channels), \
/*.bSubFrameSize = */ (subframe_size), \
/*.bBitResolution = */ (resolution), \
/*.bSamFreqType = */ (freq_type), \
/*.tSamFreq = */ __VA_ARGS__, \
/**
* @brief Initializer of @ref app_usbd_audio_as_format_type_two_desc_t
*
* @param max_bitrate Maximum bitrate.
* @param samples_per_frame Samples per frame.
* @param freq_type Frequency type.
* @param ... List of frequencies.
* */
#define APP_USBD_AUDIO_AS_FORMAT_II_DSC(max_bitrate, samples_per_frame, freq_type, ...) \
/*.bLength = */ sizeof(app_usbd_audio_as_format_type_two_desc_t) + \
(NUM_VA_ARGS(__VA_ARGS__)), \
/*.bDescriptorType = */ APP_USBD_AUDIO_DESCRIPTOR_INTERFACE, \
/*.bDescriptorSubtype = */ APP_USBD_AUDIO_AS_IFACE_SUBTYPE_FORMAT_TYPE, \
/*.bFormatType = */ (2), \
/*.wMaxBitRate = */ APP_USBD_U16_TO_RAW_DSC(max_bitrate), \
/*.wSamplesPerFrame = */ APP_USBD_U16_TO_RAW_DSC(samples_per_frame), \
/*.bSamFreqType = */ (freq_type), \
/*.tSamFreq = */ __VA_ARGS__, \
/**
* @brief Initializer of @ref app_usbd_audio_as_format_type_three_desc_t
*
* @param nr_channels Number of channels.
* @param subframe_size Subframe size.
* @param resolution Bit resolution.
* @param freq_type Frequency type.
* @param ... List of frequencies.
* */
#define APP_USBD_AUDIO_AS_FORMAT_III_DSC(nr_channels, subframe_size, resolution, freq_type, ...) \
/*.bLength = */ sizeof(app_usbd_audio_as_format_type_three_desc_t) + \
(NUM_VA_ARGS(__VA_ARGS__)), \
/*.bDescriptorType = */ APP_USBD_AUDIO_DESCRIPTOR_INTERFACE, \
/*.bDescriptorSubtype = */ APP_USBD_AUDIO_AS_IFACE_SUBTYPE_FORMAT_TYPE, \
/*.bFormatType = */ (3), \
/*.bNrChannels = */ (nr_channels), \
/*.bSubFrameSize = */ (subframe_size), \
/*.bBitResolution = */ (resolution), \
/*.bSamFreqType = */ (freq_type), \
/*.tSamFreq = */ __VA_ARGS__, \
/**
* @brief Initializer of @ref app_usbd_audio_as_endpoint_desc_t
*
* @param attributes Endpoint attributes.
* @param lock_delay_units Lock delay units.
* @param lock_delay Lock delay.
* */
#define APP_USBD_AUDIO_EP_GENERAL_DSC(attributes, lock_delay_units, lock_delay) \
/*.bLength = */ sizeof(app_usbd_audio_as_endpoint_desc_t), \
/*.bDescriptorType = */ APP_USBD_AUDIO_DESCRIPTOR_ENDPOINT, \
/*.bDescriptorSubtype = */ APP_USBD_AUDIO_EP_SUBTYPE_GENERAL, \
/*.bmAttributes = */ (attributes), \
/*.bLockDelayUnits = */ (lock_delay_units), \
/*.wLockDelay = */ APP_USBD_U16_TO_RAW_DSC(lock_delay), \
/**
* @brief Macro to configure Audio Class control descriptor.
*
* @param interface_number Interface number.
* @param descriptor_list List of descriptors after Audio interface header descriptor.
* @param interface_list List of interfaces passed to @ref APP_USBD_AUDIO_AC_IFACE_HEADER_DSC
* */
#define APP_USBD_AUDIO_CONTROL_DSC(interface_number, descriptor_list, interface_list) \
APP_USBD_AUDIO_INTERFACE_DSC(interface_number, 0, 0, APP_USBD_AUDIO_SUBCLASS_AUDIOCONTROL) \
APP_USBD_AUDIO_AC_IFACE_HEADER_DSC(descriptor_list, BRACKET_EXTRACT(interface_list)) \
BRACKET_EXTRACT(descriptor_list)
/**
* @brief Macro to configure Audio Class streaming descriptor.
*
* @param interface_number Interface number.
* @param alt_setting Alternate interface setting.
* @param ep_num Number of endpoints.
*/
#define APP_USBD_AUDIO_STREAMING_DSC(interface_number, alt_setting, ep_num) \
APP_USBD_AUDIO_INTERFACE_DSC(interface_number, alt_setting, ep_num, \
APP_USBD_AUDIO_SUBCLASS_AUDIOSTREAMING)
/**
* @brief Macro to configure Audio Class MIDI streaming descriptor.
*
* @param interface_number Interface number.
* @param alt_setting Alternate interface setting.
* @param ep_num Number of endpoints.
*/
#define APP_USBD_AUDIO_MIDI_STREAMING_DSC(interface_number, alt_setting, ep_num) \
APP_USBD_AUDIO_INTERFACE_DSC(interface_number, alt_setting, ep_num, \
APP_USBD_AUDIO_SUBCLASS_MIDISTREAMING)
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* APP_USBD_AUDIO_DESC_H__ */

View File

@@ -1,291 +0,0 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef APP_USBD_AUDIO_INTERNAL_H__
#define APP_USBD_AUDIO_INTERNAL_H__
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup app_usbd_audio_internal USB Audio internals
* @brief @tagAPI52840 USB Audio class internals.
* @ingroup app_usbd_audio
* @{
*/
/**
* @brief Forward declaration of type defined by @ref APP_USBD_CLASS_TYPEDEF in audio class.
*
*/
APP_USBD_CLASS_FORWARD(app_usbd_audio);
/*lint -save -e165*/
/**
* @brief Forward declaration of @ref app_usbd_audio_user_event_e
*
*/
enum app_usbd_audio_user_event_e;
/*lint -restore*/
/**
* @brief User event handler.
*
* @param[in] p_inst Class instance.
* @param[in] event User event.
*
*/
typedef void (*app_usbd_audio_user_ev_handler_t)(app_usbd_class_inst_t const * p_inst,
enum app_usbd_audio_user_event_e event);
/**
* @brief Audio subclass descriptor.
*/
typedef struct {
size_t size;
uint8_t type;
uint8_t const * const p_data;
} app_usbd_audio_subclass_desc_t;
/**
* @brief Audio class part of class instance data.
*/
typedef struct {
app_usbd_audio_subclass_desc_t const * const p_format_dsc; //!< Audio class Format descriptor
app_usbd_audio_subclass_desc_t const * const p_input_dsc; //!< Audio class Input Terminal descriptor
app_usbd_audio_subclass_desc_t const * const p_output_dsc; //!< Audio class Output Terminal descriptor
app_usbd_audio_subclass_desc_t const * const p_feature_dsc; //!< Audio class Feature Unit descriptor
uint8_t delay; //!< Streaming delay
uint16_t format; //!< FormatTag (@ref app_usbd_audio_as_iface_format_tag_t)
uint16_t ep_size; //!< Endpoint size
uint8_t terminal_link; //!< Terminal link in AS Interface Descriptor
app_usbd_audio_subclass_t type_streaming; //!< Streaming type MIDISTREAMING/AUDIOSTREAMING (@ref app_usbd_audio_subclass_t)
app_usbd_audio_user_ev_handler_t user_ev_handler; //!< User event handler
} app_usbd_audio_inst_t;
/**
* @brief Audio class request target.
*/
typedef enum {
APP_USBD_AUDIO_CLASS_REQ_IN, /**< Audio class request IN */
APP_USBD_AUDIO_CLASS_REQ_OUT, /**< Audio class request OUT */
APP_USBD_AUDIO_EP_REQ_IN, /**< Audio class endpoint request IN */
APP_USBD_AUDIO_EP_REQ_OUT, /**< Audio class endpoint request OUT */
} app_usbd_audio_class_req_target_t;
/**
* @brief Audio class specific request handled via control endpoint.
*/
typedef struct {
app_usbd_audio_class_req_target_t req_target; //!< Request target
app_usbd_audio_req_type_t req_type; //!< Request type
uint8_t control; //!< Request control field
uint8_t channel; //!< Channel ID
uint8_t interface; //!< Interface ID
uint8_t entity; //!< Entity ID
uint16_t length; //!< Request payload length
uint8_t payload[64]; //!< Request payload
} app_usbd_audio_req_t;
/**
* @brief Audio class context.
*
*/
typedef struct {
app_usbd_audio_req_t request; //!< Audio class request
bool streaming; //!< Streaming flag
app_usbd_sof_interrupt_handler_t sof_handler; //!< SOF event handler
} app_usbd_audio_ctx_t;
/**
* @brief Audio class configuration macro.
*
* Used by @ref APP_USBD_AUDIO_GLOBAL_DEF
*
* @param iface_control Interface number of audio control.
* @param iface_stream Interface number of audio stream.
*/
#define APP_USBD_AUDIO_CONFIG(iface_control, iface_stream) \
((iface_control), \
(iface_stream, 0))
/**
* @brief Only IN audio stream configuration.
*
* @param iface_control Interface number of audio control.
* @param iface_stream_in Interface number of audio stream on IN endpoint.
*/
#define APP_USBD_AUDIO_CONFIG_IN(iface_control, iface_stream_in) \
((iface_control), (iface_stream_in, NRF_DRV_USBD_EPIN8))
/**
* @brief Only OUT audio stream configuration.
*
* @param iface_control Interface number of audio control.
* @param iface_stream_out Interface number of audio stream on OUT endpoint.
*/
#define APP_USBD_AUDIO_CONFIG_OUT(iface_control, iface_stream_out) \
((iface_control), (iface_stream_out, NRF_DRV_USBD_EPOUT8))
/**
* @brief Specific class constant data for audio class.
*
* @ref app_usbd_audio_inst_t
*/
#define APP_USBD_AUDIO_INSTANCE_SPECIFIC_DEC app_usbd_audio_inst_t inst;
/**
* @brief Configures audio class instance.
*
* @param user_event_handler User event handler.
* @param format_descriptor Audio class Format descriptor.
* @param input_descriptor Audio class Input Terminal descriptor.
* @param output_descriptor Audio class Output Terminal descriptor.
* @param feature_descriptor Audio class Feature Unit descriptor.
* @param dlay Streaming delay.
* @param frmat FormatTag (@ref app_usbd_audio_as_iface_format_tag_t).
* @param ep_siz Endpoint size.
* @param type_str Streaming type MIDISTREAMING/AUDIOSTREAMING.
* @param terminal Terminal link in AS Interface Descriptor.
*/
#define APP_USBD_AUDIO_INST_CONFIG(user_event_handler, \
format_descriptor, \
input_descriptor, \
output_descriptor, \
feature_descriptor, \
dlay, \
frmat, \
ep_siz, \
type_str, \
terminal) \
.inst = { \
.user_ev_handler = user_event_handler, \
.p_format_dsc = format_descriptor, \
.p_input_dsc = input_descriptor, \
.p_output_dsc = output_descriptor, \
.p_feature_dsc = feature_descriptor, \
.delay = dlay, \
.format = frmat, \
.ep_size = ep_siz, \
.type_streaming = type_str, \
.terminal_link = terminal \
}
/**
* @brief Specific class data for audio class.
*
* @ref app_usbd_audio_ctx_t
*/
#define APP_USBD_AUDIO_DATA_SPECIFIC_DEC app_usbd_audio_ctx_t ctx;
/**
* @brief Audio class descriptors config macro.
*
* @param interface_number Interface number.
* @param ... Extracted endpoint list.
*/
#define APP_USBD_AUDIO_DSC_CONFIG(interface_number, ...) { \
APP_USBD_AUDIO_INTERFACE_DSC(interface_number, \
0, \
0, \
APP_USBD_AUDIO_SUBCLASS_AUDIOCONTROL) \
}
/**
* @brief Public audio class interface.
*
*/
extern const app_usbd_class_methods_t app_usbd_audio_class_methods;
/**
* @brief Global definition of @ref app_usbd_audio_t class
*
*/
#define APP_USBD_AUDIO_GLOBAL_DEF_INTERNAL(instance_name, \
interfaces_configs, \
user_ev_handler, \
format_descriptor, \
input_descriptor, \
output_descriptor, \
feature_descriptor, \
delay, \
format, \
ep_size, \
type_str, \
terminal_link) \
APP_USBD_CLASS_INST_GLOBAL_DEF( \
instance_name, \
app_usbd_audio, \
&app_usbd_audio_class_methods, \
interfaces_configs, \
(APP_USBD_AUDIO_INST_CONFIG(user_ev_handler, \
format_descriptor, \
input_descriptor, \
output_descriptor, \
feature_descriptor, \
delay, \
format, \
ep_size, \
type_str, \
terminal_link)) \
)
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* APP_USBD_AUDIO_INTERNAL_H__ */

View File

@@ -1,382 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef APP_USBD_AUDIO_TYPES_H__
#define APP_USBD_AUDIO_TYPES_H__
#include "app_util.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup app_usbd_audio_types USB Audio types
* @brief @tagAPI52840 Type definitions for the USB Audio class.
* @ingroup app_usbd_audio
* @{
*/
/** @brief Audio class definition in interface descriptor.
*
* Fixed value, @ref app_usbd_descriptor_iface_t::bInterfaceClass
* */
#define APP_USBD_AUDIO_CLASS 0x01
/** @brief Audio class protocol definition in interface descriptor.
*
* Fixed value, @ref app_usbd_descriptor_iface_t::bInterfaceProtocol
* */
#define APP_USBD_AUDIO_CLASS_PROTOCOL_UNDEFINED 0x00
/**
* @brief Audio subclass possible values.
*
* @ref app_usbd_descriptor_iface_t::bInterfaceSubClass
*/
typedef enum {
APP_USBD_AUDIO_SUBCLASS_UNDEFINED = 0x00, /**< UNDEFINED subclass */
APP_USBD_AUDIO_SUBCLASS_AUDIOCONTROL, /**< AUDIOCONTROL subclass */
APP_USBD_AUDIO_SUBCLASS_AUDIOSTREAMING, /**< AUDIOSTREAMING subclass */
APP_USBD_AUDIO_SUBCLASS_MIDISTREAMING /**< MIDISTREAMING subclass */
} app_usbd_audio_subclass_t;
/**
* @brief Audio class specific descriptor types
*/
typedef enum {
APP_USBD_AUDIO_DESCRIPTOR_UNDEFINED = 0x20, /**< UNDEFINED descriptor type */
APP_USBD_AUDIO_DESCRIPTOR_DEVICE = 0x21, /**< DEVICE descriptor type */
APP_USBD_AUDIO_DESCRIPTOR_CONFIGURATION = 0x22, /**< CONFIGURATION descriptor type */
APP_USBD_AUDIO_DESCRIPTOR_STRING = 0x23, /**< STRING descriptor type */
APP_USBD_AUDIO_DESCRIPTOR_INTERFACE = 0x24, /**< INTERFACE descriptor type */
APP_USBD_AUDIO_DESCRIPTOR_ENDPOINT = 0x25, /**< ENDPOINT descriptor type */
} app_usbd_audio_descriptor_type_t;
/**
* @brief Audio control interface subtype
*/
typedef enum {
APP_USBD_AUDIO_AC_IFACE_SUBTYPE_UNDEFINED = 0x00, /**< Audio control interface subtype UNDEFINED */
APP_USBD_AUDIO_AC_IFACE_SUBTYPE_HEADER, /**< Audio control interface subtype HEADER */
APP_USBD_AUDIO_AC_IFACE_SUBTYPE_INPUT_TERMINAL, /**< Audio control interface subtype INPUT_TERMINAL */
APP_USBD_AUDIO_AC_IFACE_SUBTYPE_OUTPUT_TERMINAL, /**< Audio control interface subtype OUTPUT_TERMINAL */
APP_USBD_AUDIO_AC_IFACE_SUBTYPE_MIXER_UNIT, /**< Audio control interface subtype MIXER_UNIT */
APP_USBD_AUDIO_AC_IFACE_SUBTYPE_SELECTOR_UNIT, /**< Audio control interface subtype SELECTOR_UNIT */
APP_USBD_AUDIO_AC_IFACE_SUBTYPE_FEATURE_UNIT, /**< Audio control interface subtype FEATURE_UNIT */
APP_USBD_AUDIO_AC_IFACE_SUBTYPE_PROCESSING_UNIT, /**< Audio control interface subtype PROCESSING_UNIT */
APP_USBD_AUDIO_AC_IFACE_SUBTYPE_EXTENSION_UNIT, /**< Audio control interface subtype EXTENSION_UNIT */
} app_usbd_audio_ac_iface_subtype_t;
/**
* @brief Audio streaming interface subtype
*/
typedef enum {
APP_USBD_AUDIO_AS_IFACE_SUBTYPE_UNDEFINED = 0x00, /**< Audio streaming interface subtype UNDEFINED */
APP_USBD_AUDIO_AS_IFACE_SUBTYPE_GENERAL, /**< Audio streaming interface subtype GENERAL */
APP_USBD_AUDIO_AS_IFACE_SUBTYPE_FORMAT_TYPE, /**< Audio streaming interface subtype FORMAT_TYPE */
APP_USBD_AUDIO_AS_IFACE_SUBTYPE_FORMAT_SPECIFIC, /**< Audio streaming interface subtype FORMAT_SPECIFIC*/
} app_usbd_audio_as_iface_subtype_t;
/**
* @brief Audio class specific endpoint subtypes
*/
typedef enum {
APP_USBD_AUDIO_EP_SUBTYPE_UNDEFINED = 0x00, /**< APP_USBD_AUDIO_EP_SUBTYPE_UNDEFINED */
APP_USBD_AUDIO_EP_SUBTYPE_GENERAL, /**< APP_USBD_AUDIO_EP_SUBTYPE_GENERAL */
} app_usbd_audio_ep_subtype_t;
/**
* @brief Audio class specific requests.
*
* @ref nrf_drv_usbd_setup_t::bmRequestType
*/
typedef enum {
APP_USBD_AUDIO_REQ_UNDEFINED = 0x00, /**< UNDEFINED request*/
APP_USBD_AUDIO_REQ_SET_CUR = 0x01, /**< SET_CUR request */
APP_USBD_AUDIO_REQ_SET_MIN = 0x02, /**< SET_MIN request */
APP_USBD_AUDIO_REQ_SET_MAX = 0x03, /**< SET_MAX request */
APP_USBD_AUDIO_REQ_SET_RES = 0x04, /**< SET_RES request */
APP_USBD_AUDIO_REQ_SET_MEM = 0x05, /**< SET_MEM request */
APP_USBD_AUDIO_REQ_GET_CUR = 0x81, /**< GET_CUR request */
APP_USBD_AUDIO_REQ_GET_MIN = 0x82, /**< GET_MIN request */
APP_USBD_AUDIO_REQ_GET_MAX = 0x83, /**< GET_MAX request */
APP_USBD_AUDIO_REQ_GET_RES = 0x84, /**< GET_RES request */
APP_USBD_AUDIO_REQ_GET_MEM = 0x85, /**< GET_MEM request */
APP_USBD_AUDIO_REQ_GET_STAT = 0xFF, /**< GET_STAT request */
} app_usbd_audio_req_type_t;
/**
* @brief Audio class terminal types.
* */
typedef enum {
/*USB terminals*/
APP_USBD_AUDIO_TERMINAL_USB_UNDEFINED = 0x0100, /**< USB_UNDEFINED*/
APP_USBD_AUDIO_TERMINAL_USB_STREAMING = 0x0101, /**< USB_STREAMING */
APP_USBD_AUDIO_TERMINAL_USB_VENDOR_SPEC = 0x01FF, /**< USB_VENDOR_SPEC*/
/*Input terminals*/
APP_USBD_AUDIO_TERMINAL_IN_UNDEFINED = 0x0200, /**< UNDEFINED */
APP_USBD_AUDIO_TERMINAL_IN_MICROPHONE = 0x0201, /**< MICROPHONE */
APP_USBD_AUDIO_TERMINAL_IN_DESKTOP_MIC = 0x0202, /**< DESKTOP_MIC */
APP_USBD_AUDIO_TERMINAL_IN_PERSONAL_MIC = 0x0203, /**< PERSONAL_MIC */
APP_USBD_AUDIO_TERMINAL_IN_OM_DIR_MIC = 0x0204, /**< OM_DIR_MIC */
APP_USBD_AUDIO_TERMINAL_IN_MIC_ARRAY = 0x0205, /**< MIC_ARRAY */
APP_USBD_AUDIO_TERMINAL_IN_PROC_MIC_ARRAY = 0x0205, /**< PROC_MIC_ARRAY */
/*Output terminals*/
APP_USBD_AUDIO_TERMINAL_OUT_UNDEFINED = 0x0300, /**< UNDEFINED */
APP_USBD_AUDIO_TERMINAL_OUT_SPEAKER = 0x0301, /**< SPEAKER */
APP_USBD_AUDIO_TERMINAL_OUT_HEADPHONES = 0x0302, /**< HEADPHONES */
APP_USBD_AUDIO_TERMINAL_OUT_HEAD_AUDIO = 0x0303, /**< HEAD_AUDIO */
APP_USBD_AUDIO_TERMINAL_OUT_DESKTOP_SPEAKER = 0x0304, /**< DESKTOP_SPEAKER */
APP_USBD_AUDIO_TERMINAL_OUT_ROOM_SPEAKER = 0x0305, /**< ROOM_SPEAKER */
APP_USBD_AUDIO_TERMINAL_OUT_COMM_SPEAKER = 0x0306, /**< COMM_SPEAKER */
APP_USBD_AUDIO_TERMINAL_OUT_LOW_FREQ_SPEAKER = 0x0307, /**< LOW_FREQ_SPEAKER */
/*Input/Output terminals*/
APP_USBD_AUDIO_TERMINAL_IO_UNDEFINED = 0x0400, /**< UNDEFINED */
APP_USBD_AUDIO_TERMINAL_IO_HANDSET = 0x0401, /**< HANDSET */
APP_USBD_AUDIO_TERMINAL_IO_HEADSET = 0x0402, /**< HEADSET */
APP_USBD_AUDIO_TERMINAL_IO_SPEAKERPHONE_ECHO_NONE = 0x0403, /**< SPEAKERPHONE_ECHO_NONE */
APP_USBD_AUDIO_TERMINAL_IO_SPEAKERPHONE_ECHO_SUP = 0x0404, /**< SPEAKERPHONE_ECHO_SUP */
APP_USBD_AUDIO_TERMINAL_IO_SPEAKERPHONE_ECHO_CAN = 0x0405, /**< SPEAKERPHONE_ECHO_CAN */
} app_usbd_audio_terminal_type_t;
/**
* @brief Audio class control interface header descriptor.
*/
typedef struct {
uint8_t bLength; //!< Length of the descriptor
uint8_t bDescriptorType; //!< Descriptor type @ref APP_USBD_AUDIO_DESCRIPTOR_INTERFACE
uint8_t bDescriptorSubtype; //!< Descriptor subtype @ref APP_USBD_AUDIO_AC_IFACE_SUBTYPE_HEADER
uint8_t bcdADC[2]; //!< BCD ADC
uint8_t wTotalLength[2]; //!< Total interfaces length
uint8_t bInCollection; //!< Input collection
uint8_t baInterfaceNr[]; //!< Interface number list
} app_usbd_audio_ac_iface_header_desc_t;
/**
* @brief Possible values of input terminal channel config.
*
* @ref app_usbd_audio_input_terminal_desc_t::wChannelConfig
* */
typedef enum {
APP_USBD_AUDIO_IN_TERM_CH_CONFIG_LEFT_FRONT = (1u << 0), /**< Channel config bit LEFT_FRONT */
APP_USBD_AUDIO_IN_TERM_CH_CONFIG_RIGHT_FRONT = (1u << 1), /**< Channel config bit RIGHT_FRONT */
APP_USBD_AUDIO_IN_TERM_CH_CONFIG_CENTER_FRONT = (1u << 2), /**< Channel config bit CENTER_FRONT */
APP_USBD_AUDIO_IN_TERM_CH_CONFIG_LOW_FREQ_ENH = (1u << 3), /**< Channel config bit LOW_FREQ_ENH */
APP_USBD_AUDIO_IN_TERM_CH_CONFIG_LEFT_SURROUND = (1u << 4), /**< Channel config bit LEFT_SURROUND */
APP_USBD_AUDIO_IN_TERM_CH_CONFIG_RIGHT_SURROUND = (1u << 5), /**< Channel config bit RIGHT_SURROUND */
APP_USBD_AUDIO_IN_TERM_CH_CONFIG_LEFT_OF_CENTER = (1u << 6), /**< Channel config bit LEFT_OF_CENTER */
APP_USBD_AUDIO_IN_TERM_CH_CONFIG_RIGHT_OF_CENTER = (1u << 7), /**< Channel config bit RIGHT_OF_CENTER */
APP_USBD_AUDIO_IN_TERM_CH_CONFIG_SURROUND = (1u << 8), /**< Channel config bit SURROUND */
APP_USBD_AUDIO_IN_TERM_CH_CONFIG_SIDE_LEFT = (1u << 9), /**< Channel config bit SIDE_LEFT */
APP_USBD_AUDIO_IN_TERM_CH_CONFIG_SIDE_RIGHT = (1u << 10), /**< Channel config bit SIDE_RIGHT */
APP_USBD_AUDIO_IN_TERM_CH_CONFIG_TOP = (1u << 11), /**< Channel config bit TOP */
} app_usbd_audio_in_term_ch_config_t;
/**
* @brief Audio class input terminal descriptor.
*/
typedef struct {
uint8_t bLength; //!< Length of the descriptor
uint8_t bDescriptorType; //!< Descriptor type @ref APP_USBD_AUDIO_DESCRIPTOR_INTERFACE
uint8_t bDescriptorSubtype; //!< Descriptor subtype @ref APP_USBD_AUDIO_AC_IFACE_SUBTYPE_INPUT_TERMINAL
uint8_t bTerminalID; //!< Terminal ID
uint8_t wTerminalType[2]; //!< Terminal type
uint8_t bAssocTerminal; //!< Association terminal
uint8_t bNrChannels; //!< Number of channels
uint8_t wChannelConfig[2]; //!< Channel config
uint8_t iChannelNames; //!< Channel names
uint8_t iTerminal; //!< Terminal string ID
} app_usbd_audio_input_terminal_desc_t;
/**
* @brief Audio class output terminal descriptor.
*/
typedef struct {
uint8_t bLength; //!< Length of the descriptor
uint8_t bDescriptorType; //!< Descriptor type @ref APP_USBD_AUDIO_DESCRIPTOR_INTERFACE
uint8_t bDescriptorSubtype; //!< Descriptor subtype @ref APP_USBD_AUDIO_AC_IFACE_SUBTYPE_OUTPUT_TERMINAL
uint8_t bTerminalID; //!< Terminal ID
uint8_t wTerminalType[2]; //!< Terminal type
uint8_t bAssocTerminal; //!< Association terminal
uint8_t bSourceID; //!< Source ID
uint8_t iTerminal; //!< Terminal string ID
} app_usbd_audio_output_terminal_desc_t;
/**
* @brief Possible values of feature unit control field.
*/
typedef enum {
APP_USBD_AUDIO_FEATURE_UNIT_CONTROL_MUTE = (1u << 0), /**< Feature unit control bit MUTE */
APP_USBD_AUDIO_FEATURE_UNIT_CONTROL_VOLUME = (1u << 1), /**< Feature unit control bit VOLUME */
APP_USBD_AUDIO_FEATURE_UNIT_CONTROL_BASS = (1u << 2), /**< Feature unit control bit BASS */
APP_USBD_AUDIO_FEATURE_UNIT_CONTROL_MID = (1u << 3), /**< Feature unit control bit MID */
APP_USBD_AUDIO_FEATURE_UNIT_CONTROL_TREBLE = (1u << 4), /**< Feature unit control bit TREBLE */
APP_USBD_AUDIO_FEATURE_UNIT_CONTROL_GRAPH_EQ = (1u << 5), /**< Feature unit control bit GRAPH_EQ */
APP_USBD_AUDIO_FEATURE_UNIT_CONTROL_AUTO_GAIN = (1u << 6), /**< Feature unit control bit AUTO_GAIN */
APP_USBD_AUDIO_FEATURE_UNIT_CONTROL_DELAY = (1u << 7), /**< Feature unit control bit DELAY */
APP_USBD_AUDIO_FEATURE_UNIT_CONTROL_BASS_BOOST = (1u << 8), /**< Feature unit control bit BASS_BOOST*/
APP_USBD_AUDIO_FEATURE_UNIT_CONTROL_LOUDNESS = (1u << 9), /**< Feature unit control bit LOUDNESS */
} app_usbd_audio_feature_unit_control_t;
/**
* @brief Audio class feature unit descriptor.
*/
typedef struct {
uint8_t bLength; //!< Length of the descriptor
uint8_t bDescriptorType; //!< Descriptor type @ref APP_USBD_AUDIO_DESCRIPTOR_INTERFACE
uint8_t bDescriptorSubtype; //!< Descriptor subtype @ref APP_USBD_AUDIO_AC_IFACE_SUBTYPE_FEATURE_UNIT
uint8_t bUnitID; //!< Unit ID
uint8_t bSourceID; //!< Source ID
uint8_t bControlSize; //!< Control size
uint8_t bmaControls[]; //!< Controls array
} app_usbd_audio_feature_unit_desc_t;
/**
* @brief Format tag in audio streaming interface descriptor.
*
* @ref app_usbd_audio_as_iface_desc_t::wFormatTag
* */
typedef enum {
APP_USBD_AUDIO_AS_IFACE_FORMAT_TYPE_I_UNDEFINED = 0x0000, /**< AS format TYPE_I_UNDEFINED */
APP_USBD_AUDIO_AS_IFACE_FORMAT_PCM = 0x0001, /**< AS format PCM */
APP_USBD_AUDIO_AS_IFACE_FORMAT_PCM8 = 0x0002, /**< AS format PCM8 */
APP_USBD_AUDIO_AS_IFACE_FORMAT_IEEE_FLOAT = 0x0003, /**< AS format IEEE_FLOAT */
APP_USBD_AUDIO_AS_IFACE_FORMAT_ALAW = 0x0004, /**< AS format ALAW */
APP_USBD_AUDIO_AS_IFACE_FORMAT_MULAW = 0x0005, /**< AS format MULAW */
APP_USBD_AUDIO_AS_IFACE_FORMAT_TYPE_II_UNDEFINED = 0x1000, /**< AS format TYPE_II_UNDEFINED */
APP_USBD_AUDIO_AS_IFACE_FORMAT_MPEG = 0x1001, /**< AS format MPEG */
APP_USBD_AUDIO_AS_IFACE_FORMAT_AC3 = 0x1002, /**< AS format AC3 */
APP_USBD_AUDIO_AS_IFACE_FORMAT_TYPE_III_UNDEFINED = 0x2000, /**< AS format TYPE_III_UNDEFINED */
APP_USBD_AUDIO_AS_IFACE_FORMAT_IEC1937_AC_3 = 0x2001, /**< AS format IEC1937_AC_3 */
APP_USBD_AUDIO_AS_IFACE_FORMAT_IEC1937_MPEG_1_LAYER1 = 0x2002, /**< AS format IEC1937_MPEG_1_LAYER1 */
APP_USBD_AUDIO_AS_IFACE_FORMAT_IEC1937_MPEG_2_NOEXT = 0x2003, /**< AS format IEC1937_MPEG_2_NOEXT */
APP_USBD_AUDIO_AS_IFACE_FORMAT_IEC1937_MPEG_2_EXT = 0x2004, /**< AS format IEC1937_MPEG_2_EXT */
APP_USBD_AUDIO_AS_IFACE_FORMAT_IEC1937_MPEG_2_LAYER1_LS = 0x2005, /**< AS format IEC1937_MPEG_2_LAYER1_LS */
APP_USBD_AUDIO_AS_IFACE_FORMAT_IEC1937_MPEG_2_LAYER23_LS = 0x2005, /**< AS format IEC1937_MPEG_2_LAYER23_LS */
} app_usbd_audio_as_iface_format_tag_t;
/**
* @brief Audio class audio streaming interface descriptor.
*/
typedef struct {
uint8_t bLength; //!< Length of the descriptor
uint8_t bDescriptorType; //!< Descriptor type @ref APP_USBD_AUDIO_DESCRIPTOR_INTERFACE
uint8_t bDescriptorSubtype; //!< Descriptor subtype @ref app_usbd_audio_ac_iface_subtype_t
uint8_t bTerminalLink; //!< Terminal link
uint8_t bDelay; //!< Delay
uint8_t wFormatTag[2]; //!< Format TAG
} app_usbd_audio_as_iface_desc_t;
/**
* @brief Audio class audio streaming format type I descriptor.
*/
typedef struct {
uint8_t bLength; //!< Length of the descriptor
uint8_t bDescriptorType; //!< Descriptor type @ref APP_USBD_AUDIO_DESCRIPTOR_INTERFACE
uint8_t bDescriptorSubtype; //!< Descriptor subtype @ref app_usbd_audio_as_iface_subtype_t
uint8_t bFormatType; //!< Format type: fixed value 1
uint8_t bNrChannels; //!< Number of channels
uint8_t bSubframeSize; //!< Subframe size
uint8_t bBitResolution; //!< Bit resolution
uint8_t bSamFreqType; //!< Number of supported sampling frequencies
uint8_t tSamFreq[]; //!< Number of supported sampling frequencies table (24 bit entries)
} app_usbd_audio_as_format_type_one_desc_t;
/**
* @brief Audio class audio streaming format type II descriptor.
*/
typedef struct {
uint8_t bLength; //!< Length of the descriptor
uint8_t bDescriptorType; //!< Descriptor type @ref APP_USBD_AUDIO_DESCRIPTOR_INTERFACE
uint8_t bDescriptorSubtype; //!< Descriptor subtype @ref app_usbd_audio_as_iface_subtype_t
uint8_t bFormatType; //!< Format type: fixed value 2
uint8_t wMaxBitRate[2]; //!< Maximum bitrate
uint8_t wSamplesPerFrame[2]; //!< Samples per frame
uint8_t bSamFreqType; //!< Number of supported sampling frequencies
uint8_t tSamFreq[]; //!< Number of supported sampling frequencies table (24 bit entries)
} app_usbd_audio_as_format_type_two_desc_t;
/**
* @brief Audio class audio streaming format type III descriptor.
*/
typedef struct {
uint8_t bLength; //!< Length of the descriptor
uint8_t bDescriptorType; //!< Descriptor type @ref APP_USBD_AUDIO_DESCRIPTOR_INTERFACE
uint8_t bDescriptorSubtype; //!< Descriptor subtype @ref app_usbd_audio_as_iface_subtype_t
uint8_t bFormatType; //!< Format type: fixed value 1
uint8_t bNrChannels; //!< Number of channels
uint8_t bSubframeSize; //!< Subframe size
uint8_t bBitResolution; //!< Bit resolution
uint8_t bSamFreqType; //!< Number of supported sampling frequencies
uint8_t tSamFreq[]; //!< Number of supported sampling frequencies table (24 bit entries)
} app_usbd_audio_as_format_type_three_desc_t;
/**
* @brief Audio class audio endpoint descriptor.
*/
typedef struct {
uint8_t bLength; //!< Length of the descriptor
uint8_t bDescriptorType; //!< Descriptor type @ref APP_USBD_AUDIO_DESCRIPTOR_ENDPOINT
uint8_t bDescriptorSubtype; //!< Descriptor subtype @ref APP_USBD_AUDIO_EP_SUBTYPE_GENERAL
uint8_t bmAttributes; //!< Audio endpoint attributes
uint8_t bLockDelayUnits; //!< Lock delay units
uint8_t wLockDelay[2]; //!< Lock delay value
} app_usbd_audio_as_endpoint_desc_t;
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* APP_USBD_AUDIO_TYPES_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -1,362 +0,0 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef APP_USBD_CDC_ACM_H__
#define APP_USBD_CDC_ACM_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "nrf_drv_usbd.h"
#include "app_usbd_class_base.h"
#include "app_usbd.h"
#include "app_usbd_core.h"
#include "app_usbd_descriptor.h"
#include "app_usbd_cdc_desc.h"
#include "app_usbd_cdc_types.h"
#include "app_usbd_cdc_acm_internal.h"
/**
* @defgroup app_usbd_cdc_acm USB CDC ACM class
* @ingroup app_usbd
*
* @brief @tagAPI52840 Module with types, definitions and API used by CDC ACM class.
*
* @details References:
* - "Universal Serial Bus Class Definitions for Communications Devices"
* Revision 1.2, November 3, 2010
* - "Universal Serial Bus Communications Class Subclass Specification for PSTN Devices"
* Revision 1.2, February 9, 2007
*
* @{
*/
#ifdef DOXYGEN
/**
* @brief CDC ACM class instance type.
*
* @ref APP_USBD_CLASS_TYPEDEF
*/
typedef struct { } app_usbd_cdc_acm_t;
#else
/*lint -save -e10 -e26 -e123 -e505 */
APP_USBD_CLASS_TYPEDEF(app_usbd_cdc_acm, \
APP_USBD_CDC_ACM_CONFIG(0, 0, 0, 0, 0), \
APP_USBD_CDC_ACM_INSTANCE_SPECIFIC_DEC, \
APP_USBD_CDC_ACM_DATA_SPECIFIC_DEC \
);
/*lint -restore*/
#endif
/*lint -save -e407 */
/**
* @brief Events passed to user event handler.
*
* @note Example prototype of user event handler:
*
* @code
void cdc_acm_user_ev_handler(app_usbd_class_inst_t const * p_inst,
app_usbd_cdc_acm_user_event_t event);
* @endcode
*/
typedef enum app_usbd_cdc_acm_user_event_e {
APP_USBD_CDC_ACM_USER_EVT_RX_DONE, /**< User event RX_DONE. */
APP_USBD_CDC_ACM_USER_EVT_TX_DONE, /**< User event TX_DONE. */
APP_USBD_CDC_ACM_USER_EVT_PORT_OPEN, /**< User event PORT_OPEN. */
APP_USBD_CDC_ACM_USER_EVT_PORT_CLOSE, /**< User event PORT_CLOSE. */
} app_usbd_cdc_acm_user_event_t;
/*lint -restore*/
/**
* @brief Default CDC ACM descriptors.
*
* @param comm_interface COMM interface number.
* @param comm_epin COMM interface IN endpoint.
* @param data_interface DATA interface number.
* @param data_epin DATA interface IN endpoint.
* @param data_epout DATA interface OUT endpoint.
*/
#define APP_USBD_CDC_ACM_DEFAULT_DESC(comm_interface, \
comm_epin, \
data_interface, \
data_epin, \
data_epout) \
APP_USBD_CDC_IAD_DSC(comm_interface, \
APP_USBD_CDC_SUBCLASS_ACM, \
APP_USBD_CDC_COMM_PROTOCOL_AT_V250) \
APP_USBD_CDC_COMM_INTERFACE_DSC(comm_interface, \
APP_USBD_CDC_SUBCLASS_ACM, \
APP_USBD_CDC_COMM_PROTOCOL_AT_V250) \
APP_USBD_CDC_HEADER_DSC(0x0110) \
APP_USBD_CDC_CALL_MGMT_DSC(0x03, data_interface) \
APP_USBD_CDC_ACM_DSC(0x02) \
APP_USBD_CDC_UNION_DSC(comm_interface, data_interface) \
APP_USBD_CDC_COM_EP_DSC(comm_epin, NRF_DRV_USBD_EPSIZE) \
APP_USBD_CDC_DATA_INTERFACE_DSC(data_interface, 0, 0) \
APP_USBD_CDC_DATA_EP_DSC(data_epin, data_epout, NRF_DRV_USBD_EPSIZE)
/**
* @brief Global definition of app_usbd_cdc_acm_t class instance.
*
* @param instance_name Name of global instance.
* @param user_ev_handler User event handler (optional).
* @param comm_ifc Interface number of cdc_acm control.
* @param data_ifc Interface number of cdc_acm DATA.
* @param comm_ein COMM subclass IN endpoint.
* @param data_ein DATA subclass IN endpoint.
* @param data_eout DATA subclass OUT endpoint.
* @param cdc_protocol CDC protocol @ref app_usbd_cdc_comm_protocol_t
*
* @note This macro is just simplified version of @ref APP_USBD_CDC_ACM_GLOBAL_DEF_INTERNAL.
*
*/
#define APP_USBD_CDC_ACM_GLOBAL_DEF(instance_name, \
user_ev_handler, \
comm_ifc, \
data_ifc, \
comm_ein, \
data_ein, \
data_eout, \
cdc_protocol) \
APP_USBD_CDC_ACM_GLOBAL_DEF_INTERNAL(instance_name, \
user_ev_handler, \
comm_ifc, \
data_ifc, \
comm_ein, \
data_ein, \
data_eout, \
cdc_protocol) \
/**
* @brief Helper function to get class instance from CDC ACM class.
*
* @param[in] p_cdc_acm CDC ACM class instance (defined by @ref APP_USBD_CDC_ACM_GLOBAL_DEF).
*
* @return Base class instance.
*/
static inline app_usbd_class_inst_t const *
app_usbd_cdc_acm_class_inst_get(app_usbd_cdc_acm_t const * p_cdc_acm)
{
return &p_cdc_acm->base;
}
/**
* @brief Helper function to get cdc_acm specific request from cdc_acm class.
*
* @param[in] p_cdc_acm CDC ACM class instance (defined by @ref APP_USBD_CDC_ACM_GLOBAL_DEF).
*
* @return CDC ACM class specific request.
*/
static inline app_usbd_cdc_acm_req_t *
app_usbd_cdc_acm_class_request_get(app_usbd_cdc_acm_t const * p_cdc_acm)
{
return &p_cdc_acm->specific.p_data->ctx.request;
}
/**
* @brief Helper function to get cdc_acm from base class instance.
*
* @param[in] p_inst Base class instance.
*
* @return CDC ACM class handle.
*/
static inline app_usbd_cdc_acm_t const *
app_usbd_cdc_acm_class_get(app_usbd_class_inst_t const * p_inst)
{
return (app_usbd_cdc_acm_t const *)p_inst;
}
/**
* @brief Writes data to CDC ACM serial port.
*
* This is asynchronous call. User should wait for @ref APP_USBD_CDC_ACM_USER_EVT_TX_DONE event
* to be sure that all data has been sent and input buffer could be accessed again.
*
* @param[in] p_cdc_acm CDC ACM class instance (defined by @ref APP_USBD_CDC_ACM_GLOBAL_DEF).
* @param[in] p_buf Input buffer.
* @param[in] length Input buffer length.
*
* @return Standard error code.
*/
ret_code_t app_usbd_cdc_acm_write(app_usbd_cdc_acm_t const * p_cdc_acm,
const void * p_buf,
size_t length);
/**
* @brief Returns the amount of data that was read.
*
* This function should be used on @ref APP_USBD_CDC_ACM_USER_EVT_RX_DONE event to get
* information how many bytes have been transfered into user buffer.
*
* @param[in] p_cdc_acm CDC ACM class instance (defined by @ref APP_USBD_CDC_ACM_GLOBAL_DEF).
*
* @return Amount of data transfered.
*/
size_t app_usbd_cdc_acm_rx_size(app_usbd_cdc_acm_t const * p_cdc_acm);
/**
* @brief Returns the amount of data that was stored into internal buffer
*
* This function should be used on @ref APP_USBD_CDC_ACM_USER_EVT_RX_DONE event to get
* information how many bytes are waiting in internal buffer.
*
* @param[in] p_cdc_acm CDC ACM class instance (defined by @ref APP_USBD_CDC_ACM_GLOBAL_DEF).
*
* @return Amount of data waiting.
*/
size_t app_usbd_cdc_acm_bytes_stored(app_usbd_cdc_acm_t const * p_cdc_acm);
/**
* @brief Reads data from CDC ACM serial port.
*
* This function uses internal buffer and double buffering for continuous transmission.
*
* If there is enough data in internal buffer to fill user buffer, NRF_SUCCESS is
* returned and data is immediately available in the user buffer.
*
* If not, up to two user buffers can be scheduled, function returns NRF_ERROR_IO_PENDING
* when first buffer is filled and @ref APP_USBD_CDC_ACM_USER_EVT_RX_DONE event is generated.
*
* @sa app_usbd_cdc_acm_read_any
* @sa app_usbd_cdc_acm_rx_size
*
* @param[in] p_cdc_acm CDC ACM class instance (defined by @ref APP_USBD_CDC_ACM_GLOBAL_DEF).
* @param[out] p_buf Output buffer.
* @param[in] length Number of bytes to read.
*
* @retval NRF_SUCCESS Data is stored into user buffer.
* @retval NRF_ERROR_IO_PENDING Awaiting transmission, when data is stored into user buffer,
* @ref APP_USBD_CDC_ACM_USER_EVT_RX_DONE event will be raised.
* @retval NRF_ERROR_BUSY There are already 2 buffers queued for transfers.
* @retval other Standard error code.
*/
ret_code_t app_usbd_cdc_acm_read(app_usbd_cdc_acm_t const * p_cdc_acm,
void * p_buf,
size_t length);
/**
* @brief Read any data from CDC ACM port up to given buffer size
*
* This function is very similar to the @ref app_usbd_cdc_acm_read but it returns
* data as quick as any data is available, even if the given buffer was not totally full.
*
* @note This function cannot use double buffering.
* @note To check the number of bytes really read use @ref app_usbd_cdc_acm_rx_size
* function.
*
* @sa app_usbd_cdc_acm_read
* @sa app_usbd_cdc_acm_rx_size
*
* @param p_cdc_acm CDC ACM class instance (defined by @ref APP_USBD_CDC_ACM_GLOBAL_DEF).
* @param[out] p_buf Output buffer.
* @param[in] length Maximum number of bytes to read.
*
* @retval NRF_SUCCESS Data is stored into user buffer.
* @retval NRF_ERROR_IO_PENDING Awaiting transmission, when data is stored into user buffer,
* @ref APP_USBD_CDC_ACM_USER_EVT_RX_DONE event will be raised.
* @retval NRF_ERROR_BUSY There is already buffer set for a transfer.
* @retval other Standard error code.
*/
ret_code_t app_usbd_cdc_acm_read_any(app_usbd_cdc_acm_t const * p_cdc_acm,
void * p_buf,
size_t length);
/**
* @brief Serial state notifications.
* */
typedef enum {
APP_USBD_CDC_ACM_SERIAL_STATE_DCD = (1u << 0), /**< Notification bit DCD. */
APP_USBD_CDC_ACM_SERIAL_STATE_DSR = (1u << 1), /**< Notification bit DSR. */
APP_USBD_CDC_ACM_SERIAL_STATE_BREAK = (1u << 2), /**< Notification bit BREAK. */
APP_USBD_CDC_ACM_SERIAL_STATE_RING = (1u << 3), /**< Notification bit RING. */
APP_USBD_CDC_ACM_SERIAL_STATE_FRAMING = (1u << 4), /**< Notification bit FRAMING.*/
APP_USBD_CDC_ACM_SERIAL_STATE_PARITY = (1u << 5), /**< Notification bit PARITY. */
APP_USBD_CDC_ACM_SERIAL_STATE_OVERRUN = (1u << 6), /**< Notification bit OVERRUN.*/
} app_usbd_cdc_acm_serial_state_t;
/**
* @brief Serial line state.
*/
typedef enum {
APP_USBD_CDC_ACM_LINE_STATE_DTR = (1u << 0), /**< Line state bit DTR.*/
APP_USBD_CDC_ACM_LINE_STATE_RTS = (1u << 1), /**< Line state bit RTS.*/
} app_usbd_cdc_acm_line_state_t;
/**
* @brief Serial state notification via IN interrupt endpoint.
*
* @param[in] p_cdc_acm CDC ACM class instance (defined by @ref APP_USBD_CDC_ACM_GLOBAL_DEF).
* @param[in] serial_state Serial state notification type.
* @param[in] value Serial state value.
*
* @return Standard error code.
*/
ret_code_t app_usbd_cdc_acm_serial_state_notify(app_usbd_cdc_acm_t const * p_cdc_acm,
app_usbd_cdc_acm_serial_state_t serial_state,
bool value);
/**
* @brief Control line value get.
*
* @param[in] p_cdc_acm CDC ACM class instance (defined by @ref APP_USBD_CDC_ACM_GLOBAL_DEF).
* @param[in] line_state Line control value type.
* @param[out] value Line control value.
*
* @return Standard error code.
*/
ret_code_t app_usbd_cdc_acm_line_state_get(app_usbd_cdc_acm_t const * p_cdc_acm,
app_usbd_cdc_acm_line_state_t line_state,
uint32_t * value);
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* APP_USBD_CDC_ACM_H__ */

View File

@@ -1,287 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef APP_USBD_CDC_ACM_INTERNAL_H__
#define APP_USBD_CDC_ACM_INTERNAL_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "app_util.h"
/**
* @defgroup app_usbd_cdc_acm_internal USB CDC ACM internals
* @ingroup app_usbd_cdc_acm
* @brief @tagAPI52840 Internals of the USB ACM class implementation.
* @{
*/
/**
* @brief Forward declaration of type defined by @ref APP_USBD_CLASS_TYPEDEF in cdc_acm class.
*
*/
APP_USBD_CLASS_FORWARD(app_usbd_cdc_acm);
/*lint -save -e165*/
/**
* @brief Forward declaration of @ref app_usbd_cdc_acm_user_event_e.
*
*/
enum app_usbd_cdc_acm_user_event_e;
/*lint -restore*/
/**
* @brief User event handler.
*
* @param[in] p_inst Class instance.
* @param[in] event User event.
*
*/
typedef void (*app_usbd_cdc_acm_user_ev_handler_t)(app_usbd_class_inst_t const * p_inst,
enum app_usbd_cdc_acm_user_event_e event);
/**
* @brief CDC ACM class part of class instance data.
*/
typedef struct {
uint8_t comm_interface; //!< Interface number of cdc_acm control.
uint8_t comm_epin; //!< COMM subclass IN endpoint.
uint8_t data_interface; //!< Interface number of cdc_acm DATA.
uint8_t data_epout; //!< DATA subclass OUT endpoint.
uint8_t data_epin; //!< DATA subclass IN endpoint.
app_usbd_cdc_comm_protocol_t protocol; //!< User specified CDC protocol.
app_usbd_cdc_acm_user_ev_handler_t user_ev_handler; //!< User event handler.
uint8_t * p_ep_interval; //!< Endpoint intervals.
} app_usbd_cdc_acm_inst_t;
/**
* @brief CDC ACM serial state class notify.
*/
typedef struct {
app_usbd_cdc_notify_t cdc_notify; //!< CDC notify.
uint16_t serial_state; //!< Serial port state.
} app_usbd_cdc_acm_notify_t;
/**
* @brief CDC ACM class specific request handled via control endpoint.
*/
typedef struct {
uint8_t type; //!< Request type.
uint8_t len; //!< Request length.
union {
app_usbd_cdc_line_coding_t line_coding; //!< CDC ACM current line coding.
app_usbd_cdc_acm_notify_t notify; //!< CDC ACM class notify.
} payload;
} app_usbd_cdc_acm_req_t;
/**
* @brief CDC ACM rx transfer buffer.
*/
typedef struct {
uint8_t * p_buf; //!< User buffer pointer.
size_t read_left; //!< Bytes left to read into buffer.
} cdc_rx_buffer_t;
/**
* @brief CDC ACM class context.
*/
typedef struct {
app_usbd_cdc_acm_req_t request; //!< CDC ACM class request.
app_usbd_cdc_line_coding_t line_coding; //!< CDC ACM current line coding.
uint16_t line_state; //!< CDC ACM line state bitmap, DTE side.
uint16_t serial_state; //!< CDC ACM serial state bitmap, DCE side.
cdc_rx_buffer_t rx_transfer[2]; //!< User receive transfers.
uint8_t internal_rx_buf[NRF_DRV_USBD_EPSIZE]; //!< Internal receive buffer.
uint8_t * p_copy_pos; //!< Current copy position from internal buffer.
size_t bytes_left; //!< Bytes left in internal buffer to copy.
size_t bytes_read; //!< Bytes currently written to user buffer.
size_t last_read; //!< Bytes read in last transfer.
size_t cur_read; //!< Bytes currently read to internal buffer.
} app_usbd_cdc_acm_ctx_t;
/**
* @brief Default interval value for comm endpoint IN
*
*/
#define APP_USBD_CDC_ACM_DEFAULT_INTERVAL 0x10
/**
* @brief CDC ACM class configuration macro.
*
* Used by @ref APP_USBD_CDC_ACM_GLOBAL_DEF
*
* @param iface_comm Interface number of cdc_acm control.
* @param epin_comm COMM subclass IN endpoint.
* @param iface_data Interface number of cdc_acm DATA.
* @param epin_data DATA subclass IN endpoint.
* @param epout_data DATA subclass OUT endpoint.
*
*/
#define APP_USBD_CDC_ACM_CONFIG(iface_comm, epin_comm, iface_data, epin_data, epout_data) \
((iface_comm, epin_comm), \
(iface_data, epin_data, epout_data))
/**
* @brief Specific class constant data for cdc_acm class.
*
* @ref app_usbd_cdc_acm_inst_t
*/
#define APP_USBD_CDC_ACM_INSTANCE_SPECIFIC_DEC app_usbd_cdc_acm_inst_t inst;
/**
* @brief Configures cdc_acm class instance.
*
* @param user_event_handler User event handler.
* @param comm_ifc Interface number of cdc_acm control.
* @param comm_ein COMM subclass IN endpoint.
* @param data_ifc Interface number of cdc_acm DATA.
* @param data_ein DATA subclass IN endpoint.
* @param data_eout DATA subclass OUT endpoint.
* @param cdc_protocol CDC protocol.
* @param ep_list List of endpoints and intervals
*/
#define APP_USBD_CDC_ACM_INST_CONFIG(user_event_handler, \
comm_ifc, \
comm_ein, \
data_ifc, \
data_ein, \
data_eout, \
cdc_protocol, \
ep_list) \
.inst = { \
.user_ev_handler = user_event_handler, \
.comm_interface = comm_ifc, \
.comm_epin = comm_ifc, \
.data_interface = data_ifc, \
.data_epin = data_ein, \
.data_epout = data_eout, \
.protocol = cdc_protocol, \
.p_ep_interval = ep_list \
}
/**
* @brief Specific class data for cdc_acm class.
*
* @ref app_usbd_cdc_acm_ctx_t
*/
#define APP_USBD_CDC_ACM_DATA_SPECIFIC_DEC app_usbd_cdc_acm_ctx_t ctx;
/**
* @brief CDC ACM class descriptors config macro.
*
* @param interface_number Interface number.
* @param ... Extracted endpoint list.
*/
#define APP_USBD_CDC_ACM_DSC_CONFIG(interface_number, ...) { \
APP_USBD_CDC_ACM_INTERFACE_DSC(interface_number, \
0, \
0, \
APP_USBD_CDC_ACM_SUBCLASS_CDC_ACMCONTROL) \
}
/**
* @brief Public cdc_acm class interface.
*
*/
extern const app_usbd_class_methods_t app_usbd_cdc_acm_class_methods;
/**
* @brief Global definition of @ref app_usbd_cdc_acm_t class.
*
* @param instance_name Name of global instance.
* @param user_ev_handler User event handler.
* @param comm_ifc Interface number of cdc_acm control.
* @param data_ifc Interface number of cdc_acm DATA.
* @param comm_ein COMM subclass IN endpoint.
* @param data_ein DATA subclass IN endpoint.
* @param data_eout DATA subclass OUT endpoint.
* @param cdc_protocol CDC protocol @ref app_usbd_cdc_comm_protocol_t
*/
/*lint -save -emacro(26 64 123 505 572 651, APP_USBD_CDC_ACM_GLOBAL_DEF_INTERNAL)*/
#define APP_USBD_CDC_ACM_GLOBAL_DEF_INTERNAL(instance_name, \
user_ev_handler, \
comm_ifc, \
data_ifc, \
comm_ein, \
data_ein, \
data_eout, \
cdc_protocol) \
static uint8_t CONCAT_2(instance_name, _ep) = { \
(APP_USBD_EXTRACT_INTERVAL_FLAG(comm_ein) ? APP_USBD_EXTRACT_INTERVAL_VALUE(comm_ein) \
: APP_USBD_CDC_ACM_DEFAULT_INTERVAL)}; \
APP_USBD_CLASS_INST_GLOBAL_DEF( \
instance_name, \
app_usbd_cdc_acm, \
&app_usbd_cdc_acm_class_methods, \
APP_USBD_CDC_ACM_CONFIG(comm_ifc, comm_ein, data_ifc, data_ein, data_eout), \
(APP_USBD_CDC_ACM_INST_CONFIG(user_ev_handler, \
comm_ifc, \
comm_ein, \
data_ifc, \
data_ein, \
data_eout, \
cdc_protocol, \
&CONCAT_2(instance_name, _ep))) \
)
/*lint -restore*/
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* APP_USBD_CDC_ACM_INTERNAL_H__ */

View File

@@ -1,208 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef APP_USBD_CDC_DESC_H__
#define APP_USBD_CDC_DESC_H__
#include <stdint.h>
#include <stdbool.h>
#include "app_usbd_descriptor.h"
#include "app_usbd_cdc_types.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup app_usbd_cdc_desc CDC class descriptors
* @brief @tagAPI52840 Descriptors used in the USB CDC class implementation.
* @ingroup app_usbd_cdc_acm
*
* A group of macros used to initialize CDC descriptors
* @{
*/
/**
* @brief Initializer of IAD descriptor for CDC class.
*
* @param interface_number Interface number.
* @param subclass Subclass, @ref app_usbd_cdc_subclass_t.
* @param protocol Protocol, @ref app_usbd_cdc_comm_protocol_t.
*/
#define APP_USBD_CDC_IAD_DSC(interface_number, subclass, protocol) \
/*.bLength = */ sizeof(app_usbd_descriptor_iad_t), \
/*.bDescriptorType = */ APP_USBD_DESCRIPTOR_INTERFACE_ASSOCIATION, \
/*.bFirstInterface = */ interface_number, \
/*.bInterfaceCount = */ 2, \
/*.bFunctionClass = */ APP_USBD_CDC_COMM_CLASS, \
/*.bFunctionSubClass = */ subclass, \
/*.bFunctionProtocol = */ protocol, \
/*.iFunction = */ 0, \
/**
* @brief Initializer of interface descriptor for CDC COMM class.
*
* @param interface_number Interface number.
* @param subclass Subclass, @ref app_usbd_cdc_subclass_t.
* @param protocol Protocol, @ref app_usbd_cdc_comm_protocol_t.
*/
#define APP_USBD_CDC_COMM_INTERFACE_DSC(interface_number, subclass, protocol) \
/*.bLength = */ sizeof(app_usbd_descriptor_iface_t), \
/*.bDescriptorType = */ APP_USBD_DESCRIPTOR_INTERFACE, \
/*.bInterfaceNumber = */ interface_number, \
/*.bAlternateSetting = */ 0x00, \
/*.bNumEndpoints = */ 1, \
/*.bInterfaceClass = */ APP_USBD_CDC_COMM_CLASS, \
/*.bInterfaceSubClass = */ subclass, \
/*.bInterfaceProtocol = */ protocol, \
/*.iInterface = 0, */ 0x00, \
/**
* @brief Initializer of interface descriptor for CDC DATA class.
*
* @param interface_number Interface number.
* @param subclass Subclass, @ref app_usbd_cdc_subclass_t.
* @param protocol Protocol, @ref app_usbd_cdc_data_protocol_t.
*/
#define APP_USBD_CDC_DATA_INTERFACE_DSC(interface_number, subclass, protocol) \
/*.bLength = */ sizeof(app_usbd_descriptor_iface_t), \
/*.bDescriptorType = */ APP_USBD_DESCRIPTOR_INTERFACE, \
/*.bInterfaceNumber = */ interface_number, \
/*.bAlternateSetting = */ 0x00, \
/*.bNumEndpoints = */ 2, \
/*.bInterfaceClass = */ APP_USBD_CDC_DATA_CLASS, \
/*.bInterfaceSubClass = */ subclass, \
/*.bInterfaceProtocol = */ protocol, \
/*.iInterface = 0, */ 0x00, \
/**
* @brief Initializer of endpoint descriptor for CDC COM class.
*
* @param endpoint_in IN endpoint.
* @param ep_size Endpoint size.
*/
#define APP_USBD_CDC_COM_EP_DSC(endpoint_in, ep_size) \
/*.bLength = */ sizeof(app_usbd_descriptor_ep_t), \
/*.bDescriptorType = */ APP_USBD_DESCRIPTOR_ENDPOINT, \
/*.bEndpointAddress = */ endpoint_in, \
/*.bmAttributes = */ APP_USBD_DESCRIPTOR_EP_ATTR_TYPE_INTERRUPT, \
/*.wMaxPacketSize = */ APP_USBD_U16_TO_RAW_DSC(ep_size), \
/*.bInterval = */ 16, \
/**
* @brief Initializer of endpoint descriptors for CDC DATA class.
*
* @param endpoint_in IN endpoint.
* @param endpoint_out OUT endpoint.
* @param ep_size Endpoint size.
*/
#define APP_USBD_CDC_DATA_EP_DSC(endpoint_in, endpoint_out, ep_size) \
/*.bLength = */ sizeof(app_usbd_descriptor_ep_t), \
/*.bDescriptorType = */ APP_USBD_DESCRIPTOR_ENDPOINT, \
/*.bEndpointAddress = */ endpoint_in, \
/*.bmAttributes = */ APP_USBD_DESCRIPTOR_EP_ATTR_TYPE_BULK, \
/*.wMaxPacketSize = */ APP_USBD_U16_TO_RAW_DSC(ep_size), \
/*.bInterval = */ 0, \
/*.bLength = */ sizeof(app_usbd_descriptor_ep_t), \
/*.bDescriptorType = */ APP_USBD_DESCRIPTOR_ENDPOINT, \
/*.bEndpointAddress = */ endpoint_out, \
/*.bmAttributes = */ APP_USBD_DESCRIPTOR_EP_ATTR_TYPE_BULK, \
/*.wMaxPacketSize = */ APP_USBD_U16_TO_RAW_DSC(ep_size), \
/*.bInterval = */ 0, \
/**
* @brief Initializer of endpoint descriptors for CDC header descriptor.
*
* @param bcd_cdc BCD CDC version.
*/
#define APP_USBD_CDC_HEADER_DSC(bcd_cdc) \
/*.bLength = */ sizeof(app_usbd_cdc_desc_header_t), \
/*.bDescriptorType = */ APP_USBD_CDC_CS_INTERFACE, \
/*.bDescriptorSubtype = */ APP_USBD_CDC_SCS_HEADER, \
/*.bcdCDC = */ APP_USBD_U16_TO_RAW_DSC(bcd_cdc), \
/**
* @brief Initializer of endpoint descriptors for CDC call management descriptor.
*
* @param capabilities Capabilities.
* @param data_interface Data interface.
*/
#define APP_USBD_CDC_CALL_MGMT_DSC(capabilities, data_interface) \
/*.bLength = */ sizeof(app_usbd_cdc_desc_call_mgmt_t), \
/*.bDescriptorType = */ APP_USBD_CDC_CS_INTERFACE, \
/*.bDescriptorSubtype = */ APP_USBD_CDC_SCS_CALL_MGMT, \
/*.bmCapabilities = */ capabilities, \
/*.bDataInterface = */ data_interface, \
/**
* @brief Initializer of endpoint descriptors for CDC DATA class.
*
* @param capabilities Capabilities.
*/
#define APP_USBD_CDC_ACM_DSC(capabilities) \
/*.bLength = */ sizeof(app_usbd_cdc_desc_acm_t), \
/*.bDescriptorType = */ APP_USBD_CDC_CS_INTERFACE, \
/*.bDescriptorSubtype = */ APP_USBD_CDC_SCS_ACM, \
/*.bmCapabilities = */ capabilities, \
/**
* @brief Initializer of endpoint descriptors for CDC DATA class.
*
* @param control_interface Control interface.
* @param ... Subordinate interfaces list.
*/
#define APP_USBD_CDC_UNION_DSC(control_interface, ...) \
/*.bLength = */ sizeof(app_usbd_cdc_desc_union_t) + (NUM_VA_ARGS(__VA_ARGS__)), \
/*.bDescriptorType = */ APP_USBD_CDC_CS_INTERFACE, \
/*.bDescriptorSubtype = */ APP_USBD_CDC_SCS_UNION, \
/*.bControlInterface = */ control_interface, \
/*.bSubordinateInterface = */ __VA_ARGS__, \
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* APP_USBD_CDC_H__ */

View File

@@ -1,360 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef APP_USBD_CDC_TYPES_H__
#define APP_USBD_CDC_TYPES_H__
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup app_usbd_cdc_types CDC class types
* @ingroup app_usbd_cdc_acm
*
* @brief @tagAPI52840 Variable types used by the CDC class implementation.
* @{
*/
/**
* @brief Communications Interface Class code.
*
* Used for control interface in communication class.
* @ref app_usbd_descriptor_iface_t::bInterfaceClass
*/
#define APP_USBD_CDC_COMM_CLASS 0x02
/**
* @brief Data Class Interface code.
*
* Used for data interface in communication class.
* @ref app_usbd_descriptor_iface_t::bInterfaceClass
*/
#define APP_USBD_CDC_DATA_CLASS 0x0A
/**
* @brief CDC subclass possible values.
*
* @ref app_usbd_descriptor_iface_t::bInterfaceSubClass
*/
typedef enum {
APP_USBD_CDC_SUBCLASS_RESERVED = 0x00, /**< Reserved in documentation. */
APP_USBD_CDC_SUBCLASS_DLCM = 0x01, /**< Direct Line Control Model. */
APP_USBD_CDC_SUBCLASS_ACM = 0x02, /**< Abstract Control Model. */
APP_USBD_CDC_SUBCLASS_TCM = 0x03, /**< Telephone Control Model. */
APP_USBD_CDC_SUBCLASS_MCCM = 0x04, /**< Multi-Channel Control Model. */
APP_USBD_CDC_SUBCLASS_CAPI = 0x05, /**< CAPI Control Model. */
APP_USBD_CDC_SUBCLASS_ENCM = 0x06, /**< Ethernet Networking Control Model. */
APP_USBD_CDC_SUBCLASS_ATM = 0x07, /**< ATM Networking Control Model. */
APP_USBD_CDC_SUBCLASS_WHCM = 0x08, /**< Wireless Handset Control Model. */
APP_USBD_CDC_SUBCLASS_DM = 0x09, /**< Device Management. */
APP_USBD_CDC_SUBCLASS_MDLM = 0x0A, /**< Mobile Direct Line Model. */
APP_USBD_CDC_SUBCLASS_OBEX = 0x0B, /**< OBEX. */
APP_USBD_CDC_SUBCLASS_EEM = 0x0C, /**< Ethernet Emulation Model. */
APP_USBD_CDC_SUBCLASS_NCM = 0x0D /**< Network Control Model. */
} app_usbd_cdc_subclass_t;
/**
* @brief CDC protocol possible values.
*
* @ref app_usbd_descriptor_iface_t::bInterfaceProtocol
*/
typedef enum {
APP_USBD_CDC_COMM_PROTOCOL_NONE = 0x00, /**< No class specific protocol required. */
APP_USBD_CDC_COMM_PROTOCOL_AT_V250 = 0x01, /**< AT Commands: V.250 etc. */
APP_USBD_CDC_COMM_PROTOCOL_AT_PCCA101 = 0x02, /**< AT Commands defined by PCCA-101. */
APP_USBD_CDC_COMM_PROTOCOL_AT_PCCA101_ANNEXO = 0x03, /**< AT Commands defined by PCCA-101 & Annex O. */
APP_USBD_CDC_COMM_PROTOCOL_AT_GSM707 = 0x04, /**< AT Commands defined by GSM 07.07. */
APP_USBD_CDC_COMM_PROTOCOL_AT_3GPP_27007 = 0x05, /**< AT Commands defined by 3GPP 27.007. */
APP_USBD_CDC_COMM_PROTOCOL_AT_CDMA = 0x06, /**< AT Commands defined by TIA for CDMA. */
APP_USBD_CDC_COMM_PROTOCOL_EEM = 0x07, /**< Ethernet Emulation Model. */
APP_USBD_CDC_COMM_PROTOCOL_EXTERNAL = 0xFE, /**< External Protocol: Commands defined by Command Set Functional Descriptor. */
APP_USBD_CDC_COMM_PROTOCOL_VENDOR = 0xFF /**< Vendor-specific. */
} app_usbd_cdc_comm_protocol_t;
/**
* @brief CDC data interface protocols possible values.
*/
typedef enum {
APP_USBD_CDC_DATA_PROTOCOL_NONE = 0x00, /**< No class specific protocol required. */
APP_USBD_CDC_DATA_PROTOCOL_NTB = 0x01, /**< Network Transfer Block. */
APP_USBD_CDC_DATA_PROTOCOL_ISDN_BRI = 0x30, /**< Physical interface protocol for ISDN BRI. */
APP_USBD_CDC_DATA_PROTOCOL_HDLC = 0x31, /**< HDLC. */
APP_USBD_CDC_DATA_PROTOCOL_TRANSPARENT = 0x32, /**< Transparent. */
APP_USBD_CDC_DATA_PROTOCOL_Q921M = 0x50, /**< Management protocol for Q.921 data link protocol. */
APP_USBD_CDC_DATA_PROTOCOL_Q921 = 0x51, /**< Data link protocol for Q.921. */
APP_USBD_CDC_DATA_PROTOCOL_Q921TM = 0x52, /**< TEI-multiplexor for Q.921 data link protocol. */
APP_USBD_CDC_DATA_PROTOCOL_V42BIS = 0x90, /**< Data compression procedures. */
APP_USBD_CDC_DATA_PROTOCOL_Q931 = 0x91, /**< Euro-ISDN protocol control. */
APP_USBD_CDC_DATA_PROTOCOL_V120 = 0x92, /**< V.24 rate adaptation to ISDN. */
APP_USBD_CDC_DATA_PROTOCOL_CAPI20 = 0x93, /**< CAPI Commands. */
APP_USBD_CDC_DATA_PROTOCOL_HOST = 0xFD, /**< Host based driver.
* @note This protocol code should only be used in messages
* between host and device to identify the host driver portion
* of a protocol stack.
*/
APP_USBD_CDC_DATA_PROTOCOL_EXTERNAL = 0xFE, /**< The protocol(s) are described using a Protocol Unit Functional
* Descriptors on Communications Class Interface.
*/
APP_USBD_CDC_DATA_PROTOCOL_VENDOR = 0xFF /**< Vendor-specific. */
} app_usbd_cdc_data_protocol_t;
/**
* @brief CDC Functional Descriptor types.
*/
typedef enum {
APP_USBD_CDC_CS_INTERFACE = 0x24, /**< Class specific interface descriptor type.*/
APP_USBD_CDC_CS_ENDPOINT = 0x25 /**< Class specific endpoint descriptor type.*/
} app_usbd_cdc_func_type_t;
/**
* @brief CDC Functional Descriptor subtypes.
*/
typedef enum {
APP_USBD_CDC_SCS_HEADER = 0x00, /**< Header Functional Descriptor, which marks the beginning of the concatenated set of functional descriptors for the interface. */
APP_USBD_CDC_SCS_CALL_MGMT = 0x01, /**< Call Management Functional Descriptor. */
APP_USBD_CDC_SCS_ACM = 0x02, /**< Abstract Control Management Functional Descriptor. */
APP_USBD_CDC_SCS_DLM = 0x03, /**< Direct Line Management Functional Descriptor. */
APP_USBD_CDC_SCS_TEL_R = 0x04, /**< Telephone Ringer Functional Descriptor. */
APP_USBD_CDC_SCS_TEL_CAP = 0x05, /**< Telephone Call and Line State Reporting Capabilities Functional Descriptor. */
APP_USBD_CDC_SCS_UNION = 0x06, /**< Union Functional Descriptor. */
APP_USBD_CDC_SCS_COUNTRY_SEL = 0x07, /**< Country Selection Functional Descriptor. */
APP_USBD_CDC_SCS_TEL_OM = 0x08, /**< Telephone Operational Modes Functional Descriptor. */
APP_USBD_CDC_SCS_USB_TERM = 0x09, /**< USB Terminal Functional Descriptor. */
APP_USBD_CDC_SCS_NCT = 0x0A, /**< Network Channel Terminal Descriptor. */
APP_USBD_CDC_SCS_PU = 0x0B, /**< Protocol Unit Functional Descriptor. */
APP_USBD_CDC_SCS_EU = 0x0C, /**< Extension Unit Functional Descriptor. */
APP_USBD_CDC_SCS_MCM = 0x0D, /**< Multi-Channel Management Functional Descriptor. */
APP_USBD_CDC_SCS_CAPI = 0x0E, /**< CAPI Control Management Functional Descriptor. */
APP_USBD_CDC_SCS_ETH = 0x0F, /**< Ethernet Networking Functional Descriptor. */
APP_USBD_CDC_SCS_ATM = 0x10, /**< ATM Networking Functional Descriptor. */
APP_USBD_CDC_SCS_WHCM = 0x11, /**< Wireless Handset Control Model Functional Descriptor. */
APP_USBD_CDC_SCS_MDLM = 0x12, /**< Mobile Direct Line Model Functional Descriptor. */
APP_USBD_CDC_SCS_MDLM_DET = 0x13, /**< MDLM Detail Functional Descriptor. */
APP_USBD_CDC_SCS_DMM = 0x14, /**< Device Management Model Functional Descriptor. */
APP_USBD_CDC_SCS_OBEX = 0x15, /**< OBEX Functional Descriptor. */
APP_USBD_CDC_SCS_CS = 0x16, /**< Command Set Functional Descriptor. */
APP_USBD_CDC_SCS_CS_DET = 0x17, /**< Command Set Detail Functional Descriptor. */
APP_USBD_CDC_SCS_TEL_CM = 0x18, /**< Telephone Control Model Functional Descriptor. */
APP_USBD_CDC_SCS_OBEX_SI = 0x19, /**< OBEX Service Identifier Functional Descriptor. */
APP_USBD_CDC_SCS_NCM = 0x1A /**< NCM Functional Descriptor. */
} app_usbd_cdc_func_subtype_t;
/* Make all descriptors packed */
#pragma pack(push, 1)
/**
* @brief Header Functional Descriptor.
*/
typedef struct {
uint8_t bFunctionLength; //!< Size of this descriptor in bytes.
uint8_t bDescriptorType; //!< @ref APP_USBD_CDC_CS_INTERFACE descriptor type.
uint8_t bDescriptorSubtype; //!< Descriptor subtype @ref APP_USBD_CDC_SCS_HEADER.
uint8_t bcdCDC[2]; //!< USB Class Definitions for Communications Devices Specification release number in binary-coded decimal.
} app_usbd_cdc_desc_header_t;
/**
* @brief Call management capabilities.
*
* @ref app_usbd_cdc_desc_call_mgmt_t::bmCapabilities bit.
* */
typedef enum {
APP_USBD_CDC_CALL_MGMT_SUPPORTED = (1 << 0), /**< Call management capability bit 0.*/
APP_USBD_CDC_CALL_MGMT_OVER_DCI = (1 << 1), /**< Call management capability bit 1.*/
} app_subd_cdc_call_mgmt_cap_t;
/**
* @brief CDC Call Management Functional Descriptor.
*/
typedef struct {
uint8_t bFunctionLength; //!< Size of this functional descriptor, in bytes.
uint8_t bDescriptorType; //!< Descriptor type @ref APP_USBD_CDC_CS_INTERFACE.
uint8_t bDescriptorSubtype; //!< Descriptor subtype @ref APP_USBD_CDC_SCS_CALL_MGMT.
uint8_t bmCapabilities; //!< Capabilities @ref app_subd_cdc_call_mgmt_cap_t.
uint8_t bDataInterface; //!< Data interface number.
} app_usbd_cdc_desc_call_mgmt_t;
/**
* @brief ACM capabilities.
*
* @ref app_usbd_cdc_desc_acm_t::bmCapabilities bit.
* */
typedef enum {
APP_USBD_CDC_ACM_FEATURE_REQUESTS = (1 << 0), /**< ACM capability bit FEATURE_REQUESTS. */
APP_USBD_CDC_ACM_LINE_REQUESTS = (1 << 1), /**< ACM capability bit LINE_REQUESTS. */
APP_USBD_CDC_ACM_SENDBREAK_REQUESTS = (1 << 2), /**< ACM capability bit SENDBREAK_REQUESTS.*/
APP_USBD_CDC_ACM_NOTIFY_REQUESTS = (1 << 3), /**< ACM capability bit NOTIFY_REQUESTS. */
} app_subd_cdc_acm_cap_t;
/**
* @brief CDC ACM Functional Descriptor.
*/
typedef struct {
uint8_t bFunctionLength; //!< Size of this functional descriptor, in bytes.
uint8_t bDescriptorType; //!< Descriptor type @ref APP_USBD_CDC_CS_INTERFACE.
uint8_t bDescriptorSubtype; //!< Descriptor subtype @ref APP_USBD_CDC_SCS_ACM.
uint8_t bmCapabilities; //!< Capabilities @ref app_subd_cdc_acm_cap_t.
} app_usbd_cdc_desc_acm_t;
/**
* @brief Union Functional Descriptor.
*/
typedef struct {
uint8_t bFunctionLength; //!< Size of this functional descriptor, in bytes.
uint8_t bDescriptorType; //!< Descriptor type @ref APP_USBD_CDC_CS_INTERFACE.
uint8_t bDescriptorSubtype; //!< Descriptor subtype @ref APP_USBD_CDC_SCS_UNION.
uint8_t bControlInterface; //!< The interface number of the Communications or Data Class interface, designated as the controlling interface for the union.
uint8_t bSubordinateInterface[]; //!< Interface number of subordinate interfaces in the union. Number of interfaced depends on descriptor size.
} app_usbd_cdc_desc_union_t;
/**
* @brief Country Selection Functional Descriptor.
*/
typedef struct {
uint8_t bFunctionLength; //!< Size of this functional descriptor, in bytes.
uint8_t bDescriptorType; //!< Descriptor type @ref APP_USBD_CDC_CS_INTERFACE.
uint8_t bDescriptorSubtype; //!< Descriptor subtype @ref APP_USBD_CDC_SCS_COUNTRY_SEL.
uint8_t iCountryCodeRelDate; //!< Index of a string giving the release date for the implemented ISO 3166 Country Codes.
} app_usbd_cdc_desc_country_sel_t;
/**
* @brief CDC Requests
*
*/
typedef enum {
/* CDC General */
APP_USBD_CDC_REQ_SEND_ENCAPSULATED_COMMAND = 0x00, /**< This request is used to issue a command in the format of the supported control protocol of the Communications Class interface. */
APP_USBD_CDC_REQ_GET_ENCAPSULATED_RESPONSE = 0x01, /**< This request is used to request a response in the format of the supported control protocol of the Communications Class interface. */
/* CDC PSTN */
APP_USBD_CDC_REQ_SET_COMM_FEATURE = 0x02, /**< This request controls the settings for a particular communications feature of a particular target. */
APP_USBD_CDC_REQ_GET_COMM_FEATURE = 0x03, /**< This request returns the current settings for the communications feature as selected. */
APP_USBD_CDC_REQ_CLEAR_COMM_FEATURE = 0x04, /**< This request controls the settings for a particular communications feature of a particular target, setting the selected feature to its default state. */
APP_USBD_CDC_REQ_SET_AUX_LINE_STATE = 0x10, /**< This request is used to connect or disconnect a secondary jack to POTS circuit or CODEC, depending on hook state. */
APP_USBD_CDC_REQ_SET_HOOK_STATE = 0x11, /**< This request is used to set the necessary PSTN line relay code for on-hook, off-hook, and caller ID states. */
APP_USBD_CDC_REQ_PULSE_SETUP = 0x12, /**< This request is used to prepare for a pulse-dialing cycle. */
APP_USBD_CDC_REQ_SEND_PULSE = 0x13, /**< This request is used to generate a specified number of make/break pulse cycles. */
APP_USBD_CDC_REQ_SET_PULSE_TIME = 0x14, /**< This request sets the timing of the make and break periods for pulse dialing. */
APP_USBD_CDC_REQ_RING_AUX_JACK = 0x15, /**< This request is used to generate a ring signal on a secondary phone jack. */
APP_USBD_CDC_REQ_SET_LINE_CODING = 0x20, /**< This request allows the host to specify typical asynchronous line-character formatting properties. */
APP_USBD_CDC_REQ_GET_LINE_CODING = 0x21, /**< This request allows the host to find out the currently configured line coding. */
APP_USBD_CDC_REQ_SET_CONTROL_LINE_STATE = 0x22, /**< This request generates RS-232/V.24 style control signals. */
APP_USBD_CDC_REQ_SEND_BREAK = 0x23, /**< This request sends special carrier modulation that generates an RS-232 style break. */
APP_USBD_CDC_REQ_SET_RINGER_PARMS = 0x30, /**< This request configures the ringer for the communications device. */
APP_USBD_CDC_REQ_GET_RINGER_PARMS = 0x31, /**< This request returns the ringer capabilities of the device and the current status of the devices ringer. */
APP_USBD_CDC_REQ_SET_OPERATION_PARMS = 0x32, /**< Sets the operational mode for the device, between a simple mode, standalone mode and a host centric mode. */
APP_USBD_CDC_REQ_GET_OPERATION_PARMS = 0x33, /**< This request gets the current operational mode for the device. */
APP_USBD_CDC_REQ_SET_LINE_PARMS = 0x34, /**< This request is used to change the state of the line, corresponding to the interface or master interface of a union to which the command was sent. */
APP_USBD_CDC_REQ_GET_LINE_PARMS = 0x35, /**< This request is used to report the state of the line that corresponds to the interface or master interface of a union to which the command was sent. */
APP_USBD_CDC_REQ_DIAL_DIGITS = 0x36, /**< This request dials the DTMF digits over the specified line. */
} app_usbd_cdc_req_id_t;
/**
* @brief CDC Notifications.
*/
typedef enum {
/* CDC General */
APP_USBD_CDC_NOTIF_NETWORK_CONNECTION = 0x00, /**< This notification allows the device to notify the host about network connection status. */
APP_USBD_CDC_NOTIF_RESPONSE_AVAILABLE = 0x01, /**< This notification allows the device to notify the host that a response is available.
* This response can be retrieved with a subsequent GetEncapsulatedResponse request.
_ */
APP_USBD_CDC_NOTIF_CONNECTION_SPEED_CHANGE = 0x2A, /**< This notification allows the device to inform the host-networking driver
* that a change in either the up-link or the down-link bit rate of the connection has occurred.
*/
/* CDC PSTN */
APP_USBD_CDC_NOTIF_AUX_JACK_HOOK_STATE = 0x08, /**< (DLM) This notification indicates the loop has changed on the auxiliary phone interface of the USB device. */
APP_USBD_CDC_NOTIF_RING_DETECT = 0x09, /**< (DLM) This notification indicates ring voltage on the POTS line interface of the USB device. */
APP_USBD_CDC_NOTIF_SERIAL_STATE = 0x20, /**< (ACM) This notification sends asynchronous notification of UART status. */
APP_USBD_CDC_NOTIF_CALL_STATE_CHANGE = 0x28, /**< (TCM) This notification identifies that a change has occurred to the state of a call on the line corresponding to the interface or union for the line. */
APP_USBD_CDC_NOTIF_LINE_STATE_CHANGE = 0x29 /**< (TCM) This notification identifies that a change has occurred to the state of the line corresponding to the interface or master interface of a union sending the notification message. */
} app_usbd_cdc_notify_id_t;
/**
* @brief Notification sent via CDC COMM endpoint.
* */
typedef struct {
uint8_t bmRequestType; //!< Request type.
uint8_t bRequest; //!< Request ID @ref app_usbd_cdc_req_id_t.
uint16_t wValue; //!< Value field.
uint16_t wIndex; //!< Index field.
uint16_t wLength; //!< Length of payload following.
} app_usbd_cdc_notify_t;
/**
* @brief CDC line coding structure.
*/
typedef struct {
uint8_t dwDTERate[4]; //!< Line baudrate.
uint8_t bCharFormat; //!< Character format @ref app_usbd_cdc_line_stopbit_t.
uint8_t bParityType; //!< Parity bits @ref app_usbd_cdc_line_parity_t.
uint8_t bDataBits; //!< Number of data bits.
} app_usbd_cdc_line_coding_t;
/**
* @brief Possible values of @ref app_usbd_cdc_line_coding_t::bCharFormat.
*/
typedef enum {
APP_USBD_CDC_LINE_STOPBIT_1 = 0, /**< 1 stop bit. */
APP_USBD_CDC_LINE_STOPBIT_1_5 = 1, /**< 1.5 stop bits. */
APP_USBD_CDC_LINE_STOPBIT_2 = 2, /**< 2 stop bits. */
} app_usbd_cdc_line_stopbit_t;
/**
* @brief Possible values of @ref app_usbd_cdc_line_coding_t::bParityType.
*/
typedef enum {
APP_USBD_CDC_LINE_PARITY_NONE = 0, /**< No parity. */
APP_USBD_CDC_LINE_PARITY_ODD = 1, /**< Odd parity. */
APP_USBD_CDC_LINE_PARITY_EVEN = 2, /**< Even parity. */
APP_USBD_CDC_LINE_PARITY_MARK = 3, /**< Parity forced to 0 (mark). */
APP_USBD_CDC_LINE_PARITY_SPACE = 4, /**< Parity forced to 1 (space). */
} app_usbd_cdc_line_parity_t;
#pragma pack(pop)
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* APP_USBD_TYPES_H__ */

View File

@@ -1,115 +0,0 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sdk_common.h"
#if NRF_MODULE_ENABLED(APP_USBD_DUMMY)
#include <string.h>
#include <ctype.h>
#include "app_usbd.h"
#include "app_usbd_dummy.h"
#include "app_usbd_string_desc.h"
#include "nrf_gpio.h"
/**
* @defgroup app_usbd_dummy_internal USBD Dummy internals
* @{
* @ingroup app_usbd_dummy
* @internal
*/
#define NRF_LOG_MODULE_NAME usbd_dummy
#if APP_USBD_DUMMY_CONFIG_LOG_ENABLED
#define NRF_LOG_LEVEL APP_USBD_DUMMY_CONFIG_LOG_LEVEL
#define NRF_LOG_INFO_COLOR APP_USBD_DUMMY_CONFIG_INFO_COLOR
#define NRF_LOG_DEBUG_COLOR APP_USBD_DUMMY_CONFIG_DEBUG_COLOR
#else //APP_USBD_DUMMY_CONFIG_LOG_ENABLED
#define NRF_LOG_LEVEL 0
#endif //APP_USBD_DUMMY_CONFIG_LOG_ENABLED
#include "nrf_log.h"
NRF_LOG_MODULE_REGISTER();
/** @brief @ref app_usbd_class_methods_t::event_handler */
static ret_code_t dummy_class_event_handler(app_usbd_class_inst_t const * p_inst,
app_usbd_complex_evt_t const * p_event)
{
if((p_event->app_evt.type == APP_USBD_EVT_INST_APPEND) ||
(p_event->app_evt.type == APP_USBD_EVT_INST_REMOVE))
{
return NRF_SUCCESS;
}
else
{
return NRF_ERROR_NOT_SUPPORTED;
}
}
/** @brief @ref app_usbd_class_methods_t::feed_descriptors */
static bool dummy_class_feed_descriptors(app_usbd_class_descriptor_ctx_t * p_ctx,
app_usbd_class_inst_t const * p_inst,
uint8_t * p_buff,
size_t max_size)
{
static app_usbd_class_iface_conf_t const * p_cur_iface = 0;
p_cur_iface = app_usbd_class_iface_get(p_inst, 0);
APP_USBD_CLASS_DESCRIPTOR_BEGIN(p_ctx, p_buff, max_size)
/* INTERFACE DESCRIPTOR */
APP_USBD_CLASS_DESCRIPTOR_WRITE(sizeof(app_usbd_descriptor_iface_t)); // bLength
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_DESCRIPTOR_INTERFACE); // bDescriptorType
APP_USBD_CLASS_DESCRIPTOR_WRITE(app_usbd_class_iface_number_get(p_cur_iface)); // bInterfaceNumber
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x00); // bAlternateSetting
APP_USBD_CLASS_DESCRIPTOR_WRITE(0); // bNumEndpoints
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_DUMMY_CLASS); // bInterfaceClass
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_DUMMY_SUBCLASS); // bInterfaceSubClass
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_DUMMY_PROTOCOL); // bInterfaceProtocol
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x00); // iInterface
APP_USBD_CLASS_DESCRIPTOR_END();
}
const app_usbd_class_methods_t app_usbd_dummy_class_methods = {
.event_handler = dummy_class_event_handler,
.feed_descriptors = dummy_class_feed_descriptors,
};
#endif //NRF_MODULE_ENABLED(APP_USBD_DUMMY)

View File

@@ -1,138 +0,0 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef APP_USBD_DUMMY_H__
#define APP_USBD_DUMMY_H__
#include <stdint.h>
#include <stdbool.h>
#include "nrf_drv_usbd.h"
#include "nrf_block_dev.h"
#include "app_usbd_class_base.h"
#include "app_usbd.h"
#include "app_usbd_core.h"
#include "app_usbd_descriptor.h"
#include "app_usbd_dummy_types.h"
#include "app_usbd_dummy_internal.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup app_usbd_dummy USB Dummy class
* @ingroup app_usbd
*
* @brief @tagAPI52840 Module with types, definitions,
* and API used by the USB Dummy class.
*
* @note Class is used as a filler to provide correct alignement of interfaces.
*
* @{
*/
#ifdef DOXYGEN
/**
* @brief Dummy class instance type.
*
* @ref APP_USBD_CLASS_TYPEDEF
*/
typedef struct { } app_usbd_dummy_t;
#else
/*lint -save -e10 -e26 -e123 -e505 */
APP_USBD_CLASS_NO_EP_TYPEDEF(app_usbd_dummy, \
APP_USBD_DUMMY_CONFIG(0), \
APP_USBD_DUMMY_INSTANCE_SPECIFIC_DEC, \
APP_USBD_DUMMY_DATA_SPECIFIC_DEC \
);
#endif
/*lint -restore*/
/**
* @brief Global definition of app_usbd_dummy_t class.
*
* @param instance_name Name of global instance.
* @param interface_number Unique interface number.
*
* @note This macro is just simplified version of @ref APP_USBD_DUMMY_GLOBAL_DEF_INTERNAL
*
*/
/*lint -save -emacro(26 64 123 505 651, APP_USBD_DUMMY_GLOBAL_DEF)*/
#define APP_USBD_DUMMY_GLOBAL_DEF(instance_name, interface_number) \
APP_USBD_DUMMY_GLOBAL_DEF_INTERNAL(instance_name, interface_number)
/*lint -restore*/
/**
* @@brief Helper function to get class instance from dummy.
*
* @param[in] p_dummy Dummy instance
* (declared by @ref APP_USBD_DUMMY_GLOBAL_DEF).
*
* @return Base class instance.
*/
static inline app_usbd_class_inst_t const *
app_usbd_dummy_class_inst_get(app_usbd_dummy_t const * p_dummy)
{
return &p_dummy->base;
}
/**
* @brief Helper function to get dummy from base class instance.
*
* @param[in] p_inst Base class instance.
*
* @return Dummy class handle.
*/
static inline app_usbd_dummy_t const *
app_usbd_dummy_class_get( app_usbd_class_inst_t const * p_inst)
{
return (app_usbd_dummy_t const *)p_inst;
}
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* APP_USBD_DUMMY_H__ */

View File

@@ -1,115 +0,0 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef APP_USBD_DUMMY_INTERNAL_H__
#define APP_USBD_DUMMY_INTERNAL_H__
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup app_usbd_dummy_internals USB Dummy internals
* @ingroup app_usbd_dummy
*
* @brief @tagAPI52840 Internals of the USB Dummy class.
* @{
*/
/** @brief Forward declaration of Dummy Class type */
APP_USBD_CLASS_FORWARD(app_usbd_dummy);
/** @brief Dummy part of class instance data */
typedef struct {
uint8_t none;
} app_usbd_dummy_inst_t;
/** @brief Dummy context */
typedef struct {
uint8_t none;
} app_usbd_dummy_ctx_t;
/**
* @brief Dummy configuration macro.
*
* Used by @ref APP_USBD_DUMMY_GLOBAL_DEF
*
* @param iface Interface number.
* */
#define APP_USBD_DUMMY_CONFIG(iface) (iface)
/**
* @brief Specific class constant data for Dummy.
*
* @ref app_usbd_dummy_inst_t
*/
#define APP_USBD_DUMMY_INSTANCE_SPECIFIC_DEC app_usbd_dummy_inst_t inst;
/**
* @brief Specific class data for Dummy.
*
* @ref app_usbd_dummy_ctx_t
* */
#define APP_USBD_DUMMY_DATA_SPECIFIC_DEC app_usbd_dummy_ctx_t ctx;
/** @brief Public Dummy class interface */
extern const app_usbd_class_methods_t app_usbd_dummy_class_methods;
/** @brief Global definition of Dummy instance */
#define APP_USBD_DUMMY_GLOBAL_DEF_INTERNAL(instance_name, interface_number) \
APP_USBD_CLASS_INST_NO_EP_GLOBAL_DEF( \
instance_name, \
app_usbd_dummy, \
&app_usbd_dummy_class_methods, \
APP_USBD_DUMMY_CONFIG((interface_number)), \
() \
)
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* APP_USBD_DUMMY_INTERNAL_H__ */

View File

@@ -1,75 +0,0 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef APP_USBD_DUMMY_TYPES_H__
#define APP_USBD_DUMMY_TYPES_H__
#include "app_util.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup app_usbd_dummy_types USB Dummy types
* @ingroup app_usbd_dummy
*
* @brief @tagAPI52840 Types used in the USB Dummy class.
* @{
*/
/** @brief Dummy class definition in interface descriptor.
*
* @ref app_usbd_descriptor_iface_t::bInterfaceClass
* */
#define APP_USBD_DUMMY_CLASS 0xFF
/** @brief Dummy subclass value. */
#define APP_USBD_DUMMY_SUBCLASS 0x00
/** @brief Dummy protocol value. */
#define APP_USBD_DUMMY_PROTOCOL 0x00
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* APP_USBD_DUMMY_TYPES_H__ */

View File

@@ -1,637 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sdk_common.h"
#if NRF_MODULE_ENABLED(APP_USBD_HID)
#include "app_usbd.h"
#include "app_usbd_core.h"
#include "app_usbd_hid.h"
#include "nrf_log.h"
/**
* @ingroup app_usbd_hid_internals USBD HID internals
* @{
* @ingroup app_usbd_hid
* @internal
*/
#define APP_USBD_HID_SOF_NOT_REQ_FLAG 0xFFFF
/**
* @brief Test whether SOF HID transfer is required.
*
* This function handles idle period IN transfer.
*
* @param[in,out] p_hid_ctx Internal HID context.
* @param[in] framecnt SOF event frame counter.
*
* @retval report_id If transfer with ID required
* @retval APP_USBD_HID_SOF_NOT_REQ_FLAG If no transfer required
*/
static uint16_t hid_sof_required(app_usbd_hid_ctx_t * p_hid_ctx, uint16_t framecnt)
{
if (!p_hid_ctx->idle_on)
{
/* Infinite idle rate */
return APP_USBD_HID_SOF_NOT_REQ_FLAG;
}
uint8_t i = 0;
uint16_t rate_ms[APP_USBD_HID_REPORT_IDLE_TABLE_SIZE] = {0};
for(i = 0; i < APP_USBD_HID_REPORT_IDLE_TABLE_SIZE; i++)
{
rate_ms[i] = p_hid_ctx->idle_rate[i] * 4;
if((framecnt == APP_USBD_SOF_MAX) && (p_hid_ctx->first_idle[i] != (APP_USBD_SOF_MAX + 1)))
{
/* SOF has only 2047 frame count maximum - adjust m_first_idle */
p_hid_ctx->first_idle[i] = ((p_hid_ctx->first_idle[i] + APP_USBD_SOF_MAX) % rate_ms[i]) + 1;
}
if (p_hid_ctx->access_lock)
{
/* Access to internal data locked. Buffer is BUSY.
* Don't send anything. Clear transfer flag. Next transfer will be triggered
* from API context.*/
app_usbd_hid_state_flag_clr(p_hid_ctx, APP_USBD_HID_STATE_FLAG_TRANS_IN_PROGRESS);
return APP_USBD_HID_SOF_NOT_REQ_FLAG;
}
/* Idle transfer required if SOF is correct with an accuracy of +/-10% + 2ms*/
if (((framecnt + p_hid_ctx->first_idle[i]) % rate_ms[i]) < (2 + (rate_ms[i] / 10)))
{
return i;
}
/* Only 0 id has set idle rate. No need to check whole table. */
if(!p_hid_ctx->idle_id_report)
{
return APP_USBD_HID_SOF_NOT_REQ_FLAG;
}
}
return APP_USBD_HID_SOF_NOT_REQ_FLAG;
}
/**
* @brief User event handler.
*
* @param[in] p_inst Class instance.
* @param[in] p_hinst HID class instance.
* @param[in] event user Event type.
*/
static inline void user_event_handler(app_usbd_class_inst_t const * p_inst,
app_usbd_hid_inst_t const * p_hinst,
app_usbd_hid_user_event_t event)
{
if (p_hinst->user_event_handler != NULL)
{
p_hinst->user_event_handler(p_inst, event);
}
}
/**
* @brief Internal SETUP standard IN request handler.
*
* @param[in] p_inst Generic class instance.
* @param[in] p_hinst HID class instance.
* @param[in,out] p_hid_ctx HID context.
* @param[in] p_setup_ev Setup event.
*
* @return Standard error code.
*/
static ret_code_t setup_req_std_in(app_usbd_class_inst_t const * p_inst,
app_usbd_hid_inst_t const * p_hinst,
app_usbd_hid_ctx_t * p_hid_ctx,
app_usbd_setup_evt_t const * p_setup_ev)
{
/* Only Get Descriptor standard IN request is supported by HID class */
if ((app_usbd_setup_req_rec(p_setup_ev->setup.bmRequestType) == APP_USBD_SETUP_REQREC_INTERFACE)
&&
(p_setup_ev->setup.bRequest == APP_USBD_SETUP_STDREQ_GET_DESCRIPTOR))
{
size_t dsc_len = 0;
size_t max_size;
uint8_t descr_type = p_setup_ev->setup.wValue.hb;
uint8_t descr_idx = p_setup_ev->setup.wValue.lb;
uint8_t * p_trans_buff = app_usbd_core_setup_transfer_buff_get(&max_size);
/* Validation for Class Descriptors. Only HID and REPORT are supported */
if ((descr_type < APP_USBD_HID_DESCRIPTOR_HID) || (descr_type >= APP_USBD_HID_DESCRIPTOR_PHYSICAL))
{
return NRF_ERROR_NOT_SUPPORTED;
}
/* Try to find descriptor in class internals*/
ret_code_t ret = app_usbd_class_descriptor_find(
p_inst,
descr_type,
descr_idx,
p_trans_buff,
&dsc_len);
if (ret == NRF_SUCCESS)
{
ASSERT(dsc_len < NRF_DRV_USBD_EPSIZE);
return app_usbd_core_setup_rsp(&(p_setup_ev->setup), p_trans_buff, dsc_len);
}
/* If not found try HID specific descriptors*/
if (descr_idx >= p_hinst->p_hid_methods->subclass_count(p_inst) )
{
/* requested index out of range */
return NRF_ERROR_NOT_SUPPORTED;
}
else
{
uint32_t report_size =
p_hinst->p_hid_methods->subclass_length(p_inst, descr_idx);
const uint8_t * p_first_byte =
p_hinst->p_hid_methods->subclass_data(p_inst, descr_idx, 0);
return app_usbd_core_setup_rsp(&p_setup_ev->setup, p_first_byte, report_size);
}
}
return NRF_ERROR_NOT_SUPPORTED;
}
/**
* @brief Internal SETUP standard OUT request handler.
*
* @param[in] p_inst Generic class instance.
* @param[in] p_hinst HID class instance.
* @param[in,out] p_hid_ctx HID context.
* @param[in] p_setup_ev Setup event.
*
* @return Standard error code.
*/
static ret_code_t setup_req_std_out(app_usbd_class_inst_t const * p_inst,
app_usbd_hid_inst_t const * p_hinst,
app_usbd_hid_ctx_t * p_hid_ctx,
app_usbd_setup_evt_t const * p_setup_ev)
{
/*Only Set Descriptor standard OUT request is supported by HID class. However, it is optional
* and useless in HID cases.*/
return NRF_ERROR_NOT_SUPPORTED;
}
/**
* @brief Internal SETUP class IN request handler.
*
* @param[in] p_inst Generic class instance.
* @param[in] p_hinst HID class instance.
* @param[in,out] p_hid_ctx HID context.
* @param[in] p_setup_ev Setup event.
*
* @return Standard error code.
*/
static ret_code_t setup_req_class_in(app_usbd_class_inst_t const * p_inst,
app_usbd_hid_inst_t const * p_hinst,
app_usbd_hid_ctx_t * p_hid_ctx,
app_usbd_setup_evt_t const * p_setup_ev)
{
switch (p_setup_ev->setup.bRequest)
{
case APP_USBD_HID_REQ_GET_REPORT:
{
if ((p_setup_ev->setup.wValue.hb == APP_USBD_HID_REPORT_TYPE_INPUT) ||
(p_setup_ev->setup.wValue.hb == APP_USBD_HID_REPORT_TYPE_OUTPUT) ||
(p_setup_ev->setup.wValue.hb == APP_USBD_HID_REPORT_TYPE_FEATURE))
{
return p_hinst->p_hid_methods->on_get_report(p_inst, p_setup_ev);
}
else
{
break;
}
}
case APP_USBD_HID_REQ_GET_IDLE:
{
return app_usbd_core_setup_rsp(&p_setup_ev->setup,
&p_hid_ctx->idle_rate[p_setup_ev->setup.wValue.lb],
sizeof(p_hid_ctx->idle_rate[p_setup_ev->setup.wValue.lb]));
}
case APP_USBD_HID_REQ_GET_PROTOCOL:
{
return app_usbd_core_setup_rsp(&p_setup_ev->setup,
&p_hid_ctx->selected_protocol,
sizeof(p_hid_ctx->selected_protocol));
}
default:
break;
}
return NRF_ERROR_NOT_SUPPORTED;
}
/**
* @brief Internal SETUP class OUT request handler.
*
* @param[in] p_inst Generic class instance.
* @param[in] p_hinst HID class instance.
* @param[in,out] p_hid_ctx HID context.
* @param[in] p_setup_ev Setup event.
*
* @return Standard error code.
*/
static ret_code_t setup_req_class_out(app_usbd_class_inst_t const * p_inst,
app_usbd_hid_inst_t const * p_hinst,
app_usbd_hid_ctx_t * p_hid_ctx,
app_usbd_setup_evt_t const * p_setup_ev)
{
switch (p_setup_ev->setup.bRequest)
{
case APP_USBD_HID_REQ_SET_REPORT:
if (((p_setup_ev->setup.wValue.hb != APP_USBD_HID_REPORT_TYPE_OUTPUT) &&
(p_setup_ev->setup.wValue.hb != APP_USBD_HID_REPORT_TYPE_FEATURE)) ||
p_hinst->p_hid_methods->on_set_report == NULL)
{
break;
}
return p_hinst->p_hid_methods->on_set_report(p_inst, p_setup_ev);
case APP_USBD_HID_REQ_SET_IDLE:
{
p_hid_ctx->idle_rate[p_setup_ev->setup.wValue.lb] = p_setup_ev->setup.wValue.hb;
p_hid_ctx->first_idle[p_setup_ev->setup.wValue.lb] = APP_USBD_SOF_MAX + 1;
/* Clear idle, high byte is interval. */
if(p_setup_ev->setup.wValue.hb == 0)
{
/* Set global idle flags according to values in channels.
If only idle rate with id 0 is non 0 set idle_id_report to false. */
bool clear = true;
uint8_t i = 0;
/* Loop starts at 1 to skip the "global" channel 0. */
for(i=1; i < APP_USBD_HID_REPORT_IDLE_TABLE_SIZE; i++)
{
if(p_hid_ctx->idle_rate[i] != 0)
{
clear = false;
break;
}
}
/* If all channels 1..N have frequency 0 then switch off global handling of idle. */
if(clear)
{
/* Distinguish between "report-specific" reports and "global" flag. */
p_hid_ctx->idle_id_report = false;
if(p_hid_ctx->idle_rate[0] == 0)
{
/* If all are 0 set m_idle_on to false. */
p_hid_ctx->idle_on = false;
}
}
}
/* Set idle because Interval was != 0 */
else
{
/* If any idle rate is not 0 set m_idle_on to true. */
p_hid_ctx->idle_on = true;
/* If any idle rate with id != 0 is non 0 set idle_id_report to true. */
if(p_setup_ev->setup.wValue.lb != 0)
{
/* Separate handling when only a single report is used. */
p_hid_ctx->idle_id_report = true;
}
}
return NRF_SUCCESS;
}
case APP_USBD_HID_REQ_SET_PROTOCOL:
{
app_usbd_hid_user_event_t ev = (p_setup_ev->setup.wValue.w == APP_USBD_HID_PROTO_BOOT) ?
APP_USBD_HID_USER_EVT_SET_BOOT_PROTO :
APP_USBD_HID_USER_EVT_SET_REPORT_PROTO;
if (ev == APP_USBD_HID_USER_EVT_SET_BOOT_PROTO)
{
p_hid_ctx->selected_protocol = APP_USBD_HID_PROTO_BOOT;
}
else if (ev == APP_USBD_HID_USER_EVT_SET_REPORT_PROTO)
{
p_hid_ctx->selected_protocol = APP_USBD_HID_PROTO_REPORT;
}
else
{
return NRF_ERROR_INVALID_PARAM;
}
user_event_handler(p_inst, p_hinst, ev);
}
return NRF_SUCCESS;
default:
break;
}
return NRF_ERROR_NOT_SUPPORTED;
}
/**
* @brief Internal SETUP event handler.
*
* @param[in] p_inst Generic class instance.
* @param[in] p_hinst HID class instance.
* @param[in,out] p_hid_ctx HID context.
* @param[in] p_setup_ev Setup event.
*
* @return Standard error code.
*/
static ret_code_t setup_event_handler(app_usbd_class_inst_t const * p_inst,
app_usbd_hid_inst_t const * p_hinst,
app_usbd_hid_ctx_t * p_hid_ctx,
app_usbd_setup_evt_t const * p_setup_ev)
{
ASSERT(p_hinst != NULL);
ASSERT(p_hid_ctx != NULL);
ASSERT(p_setup_ev != NULL);
if (app_usbd_setup_req_dir(p_setup_ev->setup.bmRequestType) == APP_USBD_SETUP_REQDIR_IN)
{
switch (app_usbd_setup_req_typ(p_setup_ev->setup.bmRequestType))
{
case APP_USBD_SETUP_REQTYPE_STD:
return setup_req_std_in(p_inst, p_hinst, p_hid_ctx, p_setup_ev);
case APP_USBD_SETUP_REQTYPE_CLASS:
return setup_req_class_in(p_inst, p_hinst, p_hid_ctx, p_setup_ev);
default:
break;
}
}
else /*APP_USBD_SETUP_REQDIR_OUT*/
{
switch (app_usbd_setup_req_typ(p_setup_ev->setup.bmRequestType))
{
case APP_USBD_SETUP_REQTYPE_STD:
return setup_req_std_out(p_inst, p_hinst, p_hid_ctx, p_setup_ev);
case APP_USBD_SETUP_REQTYPE_CLASS:
return setup_req_class_out(p_inst, p_hinst, p_hid_ctx, p_setup_ev);
default:
break;
}
}
return NRF_ERROR_NOT_SUPPORTED;
}
/**
* @brief Endpoint IN event handler.
*
* @param[in] p_inst Generic class instance.
* @param[in] p_hinst HID class instance.
* @param[in,out] p_hid_ctx HID context.
* @param[in] p_setup_ev Setup event.
*
* @return Standard error code.
*/
static ret_code_t endpoint_in_event_handler(app_usbd_class_inst_t const * p_inst,
app_usbd_hid_inst_t const * p_hinst,
app_usbd_hid_ctx_t * p_hid_ctx,
app_usbd_complex_evt_t const * p_event)
{
if (p_event->drv_evt.data.eptransfer.status == NRF_USBD_EP_OK)
{
/* Notify user about last successful transfer. */
user_event_handler(p_inst, p_hinst, APP_USBD_HID_USER_EVT_IN_REPORT_DONE);
}
if (app_usbd_hid_access_lock_test(p_hid_ctx))
{
/* Access to internal data locked. Buffer is BUSY.
* Don't send anything. Clear transfer flag. Next transfer will be triggered
* from main loop context. */
app_usbd_hid_state_flag_clr(p_hid_ctx, APP_USBD_HID_STATE_FLAG_TRANS_IN_PROGRESS);
return NRF_SUCCESS;
}
{
uint8_t i = 0;
for(i=0; i < APP_USBD_HID_REPORT_IDLE_TABLE_SIZE; i++)
{
if (p_hid_ctx->first_idle[i] == (APP_USBD_SOF_MAX + 1))
{
p_hid_ctx->lock_idle[i] = true;
}
/* Only 0 id has set idle rate. No need to check whole table. */
if(!p_hid_ctx->idle_id_report)
{
break;
}
}
}
/* HID 1.11 specification states that in case the report has changed,
it should be transfered immediately even when idle is enabled. */
return p_hinst->p_hid_methods->ep_transfer_in(p_inst);
}
/**
* @brief Endpoint OUT event handler.
*
* @param[in] p_inst Generic class instance.
* @param[in] p_hinst HID class instance.
* @param[in,out] p_hid_ctx HID context.
* @param[in] p_setup_ev Setup event.
*
* @return Standard error code.
*/
static ret_code_t endpoint_out_event_handler(app_usbd_class_inst_t const * p_inst,
app_usbd_hid_inst_t const * p_hinst,
app_usbd_hid_ctx_t * p_hid_ctx,
app_usbd_complex_evt_t const * p_event)
{
if (p_hinst->p_hid_methods->ep_transfer_out == NULL)
{
return NRF_ERROR_NOT_SUPPORTED;
}
if (p_event->drv_evt.data.eptransfer.status == NRF_USBD_EP_OK)
{
/* Notify user about last successful transfer. */
user_event_handler(p_inst, p_hinst, APP_USBD_HID_USER_EVT_OUT_REPORT_READY);
}
ASSERT(p_hinst->p_rep_buffer_out->size <= NRF_DRV_USBD_EPSIZE);
return p_hinst->p_hid_methods->ep_transfer_out(p_inst);
}
static void app_usbd_clear_idle_ctx(app_usbd_hid_ctx_t * p_hid_ctx)
{
uint8_t i = 0;
for(i=0; i < APP_USBD_HID_REPORT_IDLE_TABLE_SIZE; i++)
{
p_hid_ctx->idle_rate[i] = APP_USBD_HID_DEFAULT_IDLE_RATE;
p_hid_ctx->first_idle[i] = APP_USBD_SOF_MAX + 1;
}
p_hid_ctx->idle_id_report = false;
p_hid_ctx->idle_on = false;
}
/** @} */
ret_code_t app_usbd_hid_event_handler(app_usbd_class_inst_t const * p_inst,
app_usbd_hid_inst_t const * p_hinst,
app_usbd_hid_ctx_t * p_hid_ctx,
app_usbd_complex_evt_t const * p_event)
{
ret_code_t ret = NRF_SUCCESS;
switch (p_event->app_evt.type)
{
case APP_USBD_EVT_DRV_SOF:
{
uint16_t sof_req = hid_sof_required(p_hid_ctx, p_event->drv_evt.data.sof.framecnt);
if (sof_req != APP_USBD_HID_SOF_NOT_REQ_FLAG)
{
uint8_t i = 0;
for(i=0; i < APP_USBD_HID_REPORT_IDLE_TABLE_SIZE; i++)
{
if(p_hid_ctx->lock_idle[i])
{
p_hid_ctx->first_idle[i] = p_event->drv_evt.data.sof.framecnt;
p_hid_ctx->lock_idle[i] = false;
}
/* Only 0 id has set idle rate. No need to check whole table. */
if(!p_hid_ctx->idle_id_report)
{
break;
}
}
ret = p_hinst->p_hid_methods->on_idle(p_inst, sof_req);
}
break;
}
case APP_USBD_EVT_DRV_RESET:
{
app_usbd_hid_state_flag_clr(p_hid_ctx, APP_USBD_HID_STATE_FLAG_TRANS_IN_PROGRESS);
p_hid_ctx->selected_protocol = APP_USBD_HID_PROTO_REPORT;
app_usbd_clear_idle_ctx(p_hid_ctx);
break;
}
case APP_USBD_EVT_DRV_SETUP:
ret = setup_event_handler(p_inst, p_hinst, p_hid_ctx, &p_event->setup_evt);
break;
case APP_USBD_EVT_DRV_EPTRANSFER:
if (NRF_USBD_EPIN_CHECK(p_event->drv_evt.data.eptransfer.ep))
{
ret = endpoint_in_event_handler(p_inst, p_hinst, p_hid_ctx, p_event);
}
else
{
ret = endpoint_out_event_handler(p_inst, p_hinst, p_hid_ctx, p_event);
}
break;
case APP_USBD_EVT_DRV_SUSPEND:
app_usbd_hid_state_flag_set(p_hid_ctx, APP_USBD_HID_STATE_FLAG_SUSPENDED);
break;
case APP_USBD_EVT_DRV_RESUME:
app_usbd_hid_state_flag_clr(p_hid_ctx, APP_USBD_HID_STATE_FLAG_SUSPENDED);
/* Always try to trigger transfer on resume event*/
ret = p_hinst->p_hid_methods->ep_transfer_in(p_inst);
break;
case APP_USBD_EVT_INST_APPEND:
/*SOF register: GetIdle/SetIdle support*/
ret = app_usbd_class_sof_register(p_inst);
if (ret != NRF_SUCCESS)
{
break;
}
ret = app_usbd_class_rwu_register(p_inst);
if (ret != NRF_SUCCESS)
{
break;
}
app_usbd_clear_idle_ctx(p_hid_ctx);
app_usbd_hid_state_flag_set(p_hid_ctx, APP_USBD_HID_STATE_FLAG_APPENDED);
break;
case APP_USBD_EVT_INST_REMOVE:
/*SOF unregister: GetIdle/SetIdle support*/
ret = app_usbd_class_sof_unregister(p_inst);
if (ret != NRF_SUCCESS)
{
break;
}
ret = app_usbd_class_rwu_unregister(p_inst);
if (ret != NRF_SUCCESS)
{
break;
}
app_usbd_hid_state_flag_clr(p_hid_ctx, APP_USBD_HID_STATE_FLAG_APPENDED);
break;
case APP_USBD_EVT_STARTED:
app_usbd_hid_state_flag_set(p_hid_ctx, APP_USBD_HID_STATE_FLAG_STARTED);
break;
case APP_USBD_EVT_STOPPED:
app_usbd_hid_state_flag_clr(p_hid_ctx, APP_USBD_HID_STATE_FLAG_STARTED);
break;
default:
ret = NRF_ERROR_NOT_SUPPORTED;
break;
}
return ret;
}
app_usbd_hid_report_buffer_t * app_usbd_hid_rep_buff_in_get(app_usbd_hid_inst_t const * p_hinst)
{
ASSERT(p_hinst);
return p_hinst->p_rep_buffer_in;
}
app_usbd_hid_report_buffer_t const * app_usbd_hid_rep_buff_feature_get(app_usbd_hid_inst_t const * p_hinst)
{
ASSERT(p_hinst);
return p_hinst->p_rep_buffer_feature;
}
#endif //NRF_MODULE_ENABLED(APP_USBD_HID)

View File

@@ -1,607 +0,0 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef APP_USBD_HID_H__
#define APP_USBD_HID_H__
#include <stdint.h>
#include <stdbool.h>
#include "sdk_common.h"
#include "nrf_atomic.h"
#include "app_usbd_hid_types.h"
#include "app_usbd.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup app_usbd_hid USB HID class
* @ingroup app_usbd
*
* @brief @tagAPI52840 Module with generic HID event data processing.
* @{
*/
#define APP_USBD_HID_IFACE_IDX 0 /**< @brief HID instance interface index. */
#define APP_USBD_HID_EPIN_IDX 0 /**< @brief HID instance endpoint IN index. */
#define APP_USBD_HID_EPOUT_IDX 1 /**< @brief HID instance endpoint OUT index.*/
/**
* @brief HID context state flags.
*
* Bit numbers in @ref app_usbd_hid_ctx_t::state_flags.
*/
typedef enum {
APP_USBD_HID_STATE_FLAG_APPENDED = 0, /**< State flag APPENDED. */
APP_USBD_HID_STATE_FLAG_STARTED = 1, /**< State flag STARTED. */
APP_USBD_HID_STATE_FLAG_SUSPENDED = 2, /**< State flag SUSPENDED. */
APP_USBD_HID_STATE_FLAG_TRANS_IN_PROGRESS = 3, /**< State flag TRANS_IN_PROGRESS. */
} app_usbd_hid_state_flag_t;
/**
* @brief Events passed to user event handler.
*
* @note Example prototype of user event handler:
@code
void hid_user_ev_handler(app_usbd_class_inst_t const * p_inst,
app_usbd_hid_mouse_user_event_t event);
@endcode
*/
typedef enum {
APP_USBD_HID_USER_EVT_SET_BOOT_PROTO, /**< Event SET_BOOT_PROTOCOL. */
APP_USBD_HID_USER_EVT_SET_REPORT_PROTO, /**< Event SET_REPORT_PROTOCOL. */
APP_USBD_HID_USER_EVT_OUT_REPORT_READY, /**< Event OUT_REPORT_READY. */
APP_USBD_HID_USER_EVT_IN_REPORT_DONE, /**< Event IN_REPORT_DONE. */
APP_USBD_HID_USER_EVT_FEATURE_REPORT_READY, /**< Event FEATURE_REPORT_READY. */
} app_usbd_hid_user_event_t;
/**
* @brief User event handler.
*
* @param[in] p_inst Class instance.
* @param[in] event User event.
*/
typedef void (*app_usbd_hid_user_ev_handler_t)(app_usbd_class_inst_t const * p_inst,
app_usbd_hid_user_event_t event);
/**
* @brief Idle report handler.
*
* @param[in] p_inst Class instance.
* @param[in] report_id Number of report ID that needs idle transfer.
*/
typedef ret_code_t (*app_usbd_hid_idle_handler_t)(app_usbd_class_inst_t const * p_inst,
uint8_t report_id);
/**
* @brief HID unified interface
* */
typedef struct {
/**
* @brief Function called on HID specific, GetReport request.
*
* This function should trigger data write to control pipe.
*
* @param[in] p_inst Class instance.
* @param[in] p_setup_ev Setup event.
*
* @return Standard error code.
*/
ret_code_t (*on_get_report)(app_usbd_class_inst_t const * p_inst,
app_usbd_setup_evt_t const * p_setup_ev);
/**
* @brief Function called on HID specific, SetReport request.
*
* This function should trigger data read from control pipe. This function is not required and
* NULL could be pinned to this handler when output report is not defined in report descriptor.
*
* @param[in] p_inst Class instance.
* @param[in] p_setup_ev Setup event.
*
* @return Standard error code.
*/
ret_code_t (*on_set_report)(app_usbd_class_inst_t const * p_inst,
app_usbd_setup_evt_t const * p_setup_ev);
/**
* @brief Function called on IN endpoint transfer.
*
* This function should trigger next endpoint IN transfer if required.
*
* @param[in] p_inst Class instance.
*
* @return Standard error code.
*/
ret_code_t (*ep_transfer_in)(app_usbd_class_inst_t const * p_inst);
/**
* @brief Function called on OUT endpoint transfer.
*
* This function should should read data from OUT endpoint. This function is not required and
* NULL could be pinned to this handler when class doesn't have OUT endpoint.
*
* @param[in] p_inst Class instance.
*
* @return Standard error code.
*/
ret_code_t (*ep_transfer_out)(app_usbd_class_inst_t const * p_inst);
/**
* @brief Function returns subclass descriptor count.
*
* @param[in] p_inst Class instance.
*
* @return Count of descriptors
*/
uint8_t (*subclass_count)(app_usbd_class_inst_t const * p_inst);
/**
* @brief Function returns subclass descriptor size.
*
* @param[in] p_inst Class instance.
* @param[in] desc_num Index of the subclass descriptor
*
* @return Size of descriptor
*/
size_t (*subclass_length)(app_usbd_class_inst_t const * p_inst,
uint8_t desc_num);
/**
* @brief Function returns pointer to subclass descriptor data.
*
* @param[in] p_inst Class instance.
* @param[in] desc_num Index of the subclass descriptor
* @param[in] cur_byte Index of required byte
*
* @return Pointer to requested byte in subclass descriptor
*/
const uint8_t * (*subclass_data)(app_usbd_class_inst_t const * p_inst,
uint8_t desc_num,
uint32_t cur_byte);
/**
* @brief Function called on idle transfer
*
* This function should trigger next idle transfer.
*
* @param[in,out] p_inst Instance of the class.
* @param[in] report_id Number of report ID that needs idle transfer.
*
* @return Standard error code.
*/
ret_code_t (*on_idle)(app_usbd_class_inst_t const * p_inst, uint8_t report_id);
ret_code_t (*set_idle_handler)(app_usbd_class_inst_t const * p_inst,
app_usbd_hid_idle_handler_t handler);
} app_usbd_hid_methods_t;
/**
* @brief HID report buffers.
*/
typedef struct {
uint8_t * p_buff;
size_t size;
} app_usbd_hid_report_buffer_t;
/**
* @brief Define OUT report buffer structure @ref app_usbd_hid_report_buffer_t.
*
* @param name Instance name.
* @param rep_size Output report size.
*/
#define APP_USBD_HID_GENERIC_GLOBAL_OUT_REP_DEF(name, rep_size) \
static uint8_t CONCAT_2(name, _buf)[(rep_size)]; \
const app_usbd_hid_report_buffer_t name = { \
.p_buff = CONCAT_2(name, _buf), \
.size = sizeof(CONCAT_2(name, _buf)), \
}
/**
* @brief Define FEATURE report buffer structure @ref app_usbd_hid_report_buffer_t.
*
* @param name Instance name.
* @param rep_size Feature report size.
*/
#define APP_USBD_HID_GENERIC_GLOBAL_FEATURE_REP_DEF(name, rep_size) \
static uint8_t CONCAT_2(name, _feature_buf)[(rep_size)]; \
const app_usbd_hid_report_buffer_t name = { \
.p_buff = CONCAT_2(name, _feature_buf), \
.size = sizeof(CONCAT_2(name, _feature_buf)), \
}
/**
* @brief HID subclass descriptor.
*/
typedef struct {
size_t size;
app_usbd_descriptor_t type;
uint8_t const * const p_data;
} app_usbd_hid_subclass_desc_t;
/**
* @brief Initializer of HID report descriptor
*
* @param name Report descriptor name
* @param ... Report descriptor data
*/
#define APP_USBD_HID_GENERIC_SUBCLASS_REPORT_DESC(name, ...) \
static uint8_t const CONCAT_2(name, _data)[] = \
__VA_ARGS__ \
; \
static const app_usbd_hid_subclass_desc_t name = \
{ \
sizeof(CONCAT_2(name, _data)), \
APP_USBD_DESCRIPTOR_REPORT, \
CONCAT_2(name,_data) \
}
/**
* @brief Initializer of HID physical descriptor
*
* @param name Physical descriptor name
* @param ... Physical descriptor data
*/
#define APP_USBD_HID_GENERIC_SUBCLASS_PHYSICAL_DESC(name, ...) \
static uint8_t const CONCAT_2(name, _data)[] = \
__VA_ARGS__ \
; \
static const app_usbd_hid_subclass_desc_t name = \
{ \
sizeof(CONCAT_2(name, _data)), \
APP_USBD_DESCRIPTOR_PHYSICAL, \
CONCAT_2(name,_data) \
}
/**
* @brief USB HID instance.
*/
typedef struct {
app_usbd_hid_subclass_desc_t const ** const p_subclass_desc; //!< HID subclass descriptors array.
size_t subclass_desc_count; //!< HID subclass descriptors count.
app_usbd_hid_subclass_t subclass_boot; //!< Boot device (see HID definition).
app_usbd_hid_protocol_t protocol; //!< HID protocol (see HID definition).
app_usbd_hid_report_buffer_t * p_rep_buffer_in; //!< Report buffer IN.
app_usbd_hid_report_buffer_t const * p_rep_buffer_out; //!< Report buffer OUT (only one instance).
app_usbd_hid_report_buffer_t const * p_rep_buffer_feature; //!< Report buffer FEATURE.
app_usbd_hid_methods_t const * p_hid_methods; //!< Hid interface methods.
app_usbd_hid_user_ev_handler_t user_event_handler; //!< User event handler.
uint8_t * p_ep_interval; //!< Endpoint intervals.
} app_usbd_hid_inst_t;
/**
* @brief USB HID instance initializer @ref app_usbd_hid_inst_t.
*
* @param subclass_dsc HID subclass descriptors.
* @param sub_boot Subclass boot. (@ref app_usbd_hid_subclass_t)
* @param protocl HID protocol. (@ref app_usbd_hid_protocol_t)
* @param report_buff_in Input report buffer list.
* @param report_buff_out Output report buffer.
* @param report_buff_feature Feature report buffer.
* @param user_ev_handler @ref app_usbd_hid_user_ev_handler_t.
* @param hid_methods @ref app_usbd_hid_methods_t.
* @param ep_list List of endpoints and intervals
* */
#define APP_USBD_HID_INST_CONFIG(subclass_dsc, \
sub_boot, \
protocl, \
report_buff_in, \
report_buff_out, \
report_buff_feature, \
user_ev_handler, \
hid_methods, \
ep_list) \
{ \
.p_subclass_desc = subclass_dsc, \
.subclass_desc_count = ARRAY_SIZE(subclass_dsc), \
.p_rep_buffer_in = report_buff_in, \
.p_rep_buffer_out = report_buff_out, \
.p_rep_buffer_feature = report_buff_feature, \
.user_event_handler = user_ev_handler, \
.p_hid_methods = hid_methods, \
.subclass_boot = sub_boot, \
.protocol = protocl, \
.p_ep_interval = ep_list \
}
/**
* @brief HID internal context.
* */
typedef struct {
nrf_atomic_u32_t state_flags; //!< HID state flags @ref app_usbd_hid_state_flag_t.
nrf_atomic_flag_t access_lock; //!< Lock flag to internal data.
uint8_t idle_rate[APP_USBD_HID_REPORT_IDLE_TABLE_SIZE]; //!< HID idle rate (4ms units).
app_usbd_hid_protocol_select_t selected_protocol; //!< Currently selected HID protocol.
app_usbd_hid_idle_handler_t idle_handler; //!< Idle report handler.
uint32_t first_idle[APP_USBD_HID_REPORT_IDLE_TABLE_SIZE]; //!< Number of frame at first idle transaction.
bool lock_idle[APP_USBD_HID_REPORT_IDLE_TABLE_SIZE]; //!< Lock flag to idle transactions.
bool idle_on; //!< Idle transactions flag.
bool idle_id_report; //!< Idle transactions with nonzero report id flag.
} app_usbd_hid_ctx_t;
/**
* @brief Locks internal hid context.
*
* Simple semaphore functionality to prevent concurrent access from application and
* interrupt to internal mouse data.
*
* @param[in] p_hid_ctx Internal hid context
*/
static inline void app_usbd_hid_access_lock(app_usbd_hid_ctx_t * p_hid_ctx)
{
UNUSED_RETURN_VALUE(nrf_atomic_flag_set(&p_hid_ctx->access_lock));
__DSB();
}
/**
* @brief Unlocks internal hid context.
*
* Simple semaphore functionality to prevent concurrent access from application and
* interrupt to internal mouse data.
*
* @param[in] p_hid_ctx Internal hid context.
*/
static inline void app_usbd_hid_access_unlock(app_usbd_hid_ctx_t * p_hid_ctx)
{
UNUSED_RETURN_VALUE(nrf_atomic_flag_clear(&p_hid_ctx->access_lock));
__DSB();
}
/**
* @brief Tests whether internal lock is acquired.
*
* @param[in] p_hid_ctx Internal HID context.
*
* @retval true Locked.
* @retval false Unlocked.
*/
static inline bool app_usbd_hid_access_lock_test(app_usbd_hid_ctx_t * p_hid_ctx)
{
return p_hid_ctx->access_lock != 0;
}
/**
* @brief Set one of the HID internal state flags.
*
* @param[in] p_hid_ctx Internal HID context.
* @param[in] flag Flag to set.
*/
static inline void app_usbd_hid_state_flag_set(app_usbd_hid_ctx_t * p_hid_ctx,
app_usbd_hid_state_flag_t flag)
{
UNUSED_RETURN_VALUE(nrf_atomic_u32_or(&p_hid_ctx->state_flags, 1u << flag));
}
/**
* @brief Clear one of the HID internal state flags.
*
* @param[in] p_hid_ctx Internal HID context.
* @param[in] flag Flag to clear.
*/
static inline void app_usbd_hid_state_flag_clr(app_usbd_hid_ctx_t * p_hid_ctx,
app_usbd_hid_state_flag_t flag)
{
UNUSED_RETURN_VALUE(nrf_atomic_u32_and(&p_hid_ctx->state_flags, ~(1u << flag)));
}
/**
* @brief Test one of the HID internal state flags.
*
* @param[in] p_hid_ctx Internal HID context.
* @param[in] flag Flag to test.
*
* @retval true Flag is set.
* @retval false Flag is not set.
*/
static inline bool app_usbd_hid_state_flag_test(app_usbd_hid_ctx_t * p_hid_ctx,
app_usbd_hid_state_flag_t flag)
{
return ((p_hid_ctx->state_flags >> flag) & 1) == 1;
}
/**
* @brief Checks whether HID endpoint transfer required.
*
* @param[in] p_hid_ctx Internal HID context.
*
* @retval true Input endpoint transfer required.
* @retval false Transfer in progress or not allowed.
*/
static inline bool app_usbd_hid_trans_required(app_usbd_hid_ctx_t * p_hid_ctx)
{
if (app_usbd_hid_state_flag_test(p_hid_ctx, APP_USBD_HID_STATE_FLAG_SUSPENDED) != 0)
{
UNUSED_RETURN_VALUE(app_usbd_wakeup_req());
return false;
}
return app_usbd_hid_state_flag_test(p_hid_ctx, APP_USBD_HID_STATE_FLAG_TRANS_IN_PROGRESS) == 0;
}
/**
* @brief Validates internal hid state.
*
* HID Mouse has to receive some USBD events before functions from this module could be used.
*
* @param[in] p_hid_ctx Internal hid context.
*
* @retval true State is valid.
* @retval false State is invalid.
*/
static inline bool app_usbd_hid_state_valid(app_usbd_hid_ctx_t * p_hid_ctx)
{
/*Check whether internal flags allow to enable mouse*/
if ((app_usbd_hid_state_flag_test(p_hid_ctx, APP_USBD_HID_STATE_FLAG_APPENDED) == 0) ||
(app_usbd_hid_state_flag_test(p_hid_ctx, APP_USBD_HID_STATE_FLAG_STARTED) == 0))
{
return false;
}
return true;
}
/**
* @brief HID generic event handler.
*
* This handler should process every class event after specific class handler.
* This approach allow to handle some events in the same way in all HID sub-classes.
*
* @param[in] p_inst Generic class instance.
* @param[in] p_hinst HID class instance.
* @param[in] p_hid_ctx HID context.
* @param[in] p_event Complex event structure.
*
* @return Standard error code.
*/
ret_code_t app_usbd_hid_event_handler(app_usbd_class_inst_t const * p_inst,
app_usbd_hid_inst_t const * p_hinst,
app_usbd_hid_ctx_t * p_hid_ctx,
app_usbd_complex_evt_t const * p_event);
/**
* @brief Returns IN report buffer.
*
* @param[in] p_hinst HID class instance.
*
* @return Report buffer handle or NULL if report doesn't exist.
*/
app_usbd_hid_report_buffer_t * app_usbd_hid_rep_buff_in_get(app_usbd_hid_inst_t const * p_hinst);
/**
* @brief Returns OUT report buffer.
*
* Output reports are handled in interrupt handler so only one buffer is required. Buffer returned by
* this function has predefined size, which should be equal (maximum OUTPUT report size + 1). To receive
* OUT report this function should be called on @ref APP_USBD_HID_USER_EVT_OUT_REPORT_READY event.
*
* @param[in] p_hinst HID class instance.
*
* @return Report buffer handle or NULL if report doesn't exist.
*/
static inline app_usbd_hid_report_buffer_t const *
app_usbd_hid_rep_buff_out_get(app_usbd_hid_inst_t const * p_hinst)
{
ASSERT(p_hinst);
return p_hinst->p_rep_buffer_out;
}
/**
* @brief Returns FEATURE report buffer.
*
* @param[in] p_hinst HID class instance.
*
* @return Report buffer handle or NULL if report doesn't exist.
*/
app_usbd_hid_report_buffer_t const * app_usbd_hid_rep_buff_feature_get(app_usbd_hid_inst_t const * p_hinst);
/**
* @brief Returns HID selected protocol.
*
* @param[in] p_hid_ctx HID context.
*
* @return Currently selected protocol (@ref app_usbd_hid_protocol_select_t).
*/
static inline app_usbd_hid_protocol_select_t app_usbd_hid_selected_protocol_get(app_usbd_hid_ctx_t * p_hid_ctx)
{
ASSERT(p_hid_ctx);
return p_hid_ctx->selected_protocol;
}
/**
* @brief Auxiliary function to access to HID IN endpoint address.
*
* @param[in] p_inst Class instance data.
*
* @return IN endpoint address.
*/
static inline nrf_drv_usbd_ep_t app_usbd_hid_epin_addr_get(app_usbd_class_inst_t const * p_inst)
{
app_usbd_class_iface_conf_t const * class_iface;
class_iface = app_usbd_class_iface_get(p_inst, APP_USBD_HID_IFACE_IDX);
app_usbd_class_ep_conf_t const * ep_cfg;
ep_cfg = app_usbd_class_iface_ep_get(class_iface, APP_USBD_HID_EPIN_IDX);
return app_usbd_class_ep_address_get(ep_cfg);
}
/**
* @brief Auxiliary function to access to HID generic OUT endpoint address.
*
* @param[in] p_inst Class instance data.
*
* @return OUT endpoint address.
*/
static inline nrf_drv_usbd_ep_t app_usbd_hid_epout_addr_get(app_usbd_class_inst_t const * p_inst)
{
app_usbd_class_iface_conf_t const * class_iface;
class_iface = app_usbd_class_iface_get(p_inst, APP_USBD_HID_IFACE_IDX);
app_usbd_class_ep_conf_t const * ep_cfg;
ep_cfg = app_usbd_class_iface_ep_get(class_iface, APP_USBD_HID_EPOUT_IDX);
return app_usbd_class_ep_address_get(ep_cfg);
}
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* APP_USBD_HID_H__ */

View File

@@ -1,298 +0,0 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef APP_USBD_HID_TYPES_H__
#define APP_USBD_HID_TYPES_H__
#include <stdint.h>
#include "app_usbd_types.h"
#include "sdk_common.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup app_usbd_hid_types USB HID class types
* @ingroup app_usbd_hid
*
* @brief @tagAPI52840 Module with types and definitions used by HID modules.
* @{
*/
/**
* @brief HID class definition in interface descriptor.
*
* @ref app_usbd_descriptor_iface_t::bInterfaceClass
* */
#define APP_USBD_HID_CLASS 0x03
/**
* @brief HID subclass definition.
*
* @see HID 1.11 specification: Chapter 4.2 Subclass.
* @ref app_usbd_descriptor_iface_t::bInterfaceSubClass
* */
typedef enum {
APP_USBD_HID_SUBCLASS_NONE = 0x00, /**< Undefined subclass. */
APP_USBD_HID_SUBCLASS_BOOT = 0x01, /**< Boot subclass. */
} app_usbd_hid_subclass_t;
/**
* @brief HID selected protocol.
*
* These values are used for Get_Protocol and Set_Protocol requests.
* Changing protocol is only allowed when protocol type (@ref app_usbd_hid_protocol_t)
* is set to @ref APP_USBD_HID_PROTO_KEYBOARD or @ref APP_USBD_HID_PROTO_MOUSE
* and interface uses boot subclass (@ref APP_USBD_HID_SUBCLASS_BOOT).
*
* @see HID 1.11 specification: Chapter 7.2.5 Get_Protocol Request
* and Chapter 7.2.6 Set_Protocol Request.
*/
typedef enum {
APP_USBD_HID_PROTO_BOOT = 0x00, /**< Boot protocol. */
APP_USBD_HID_PROTO_REPORT = 0x01 /**< Report protocol. */
} app_usbd_hid_protocol_select_t;
/**
* @brief HID protocol types defined by specification.
*
* Value needs to be filled in interface descriptor.
* @ref app_usbd_descriptor_iface_t::bInterfaceProtocol
*/
typedef enum {
APP_USBD_HID_PROTO_GENERIC = 0x00, /**< GENERIC protocol. */
APP_USBD_HID_PROTO_KEYBOARD = 0x01, /**< KEYBOARD protocol. */
APP_USBD_HID_PROTO_MOUSE = 0x02, /**< MOUSE protocol. */
APP_USBD_HID_PROTO_MULTITOUCH = 0x03, /**< MULTITOUCH protocol. */
} app_usbd_hid_protocol_t;
/**
* @brief HID country code ID.
*
* Look into @ref app_usbd_hid_descriptor_t::bCountryCode.
*/
typedef enum {
APP_USBD_HID_COUNTRY_NOT_SUPPORTED = 0 , /**< NOT_SUPPORTED */
APP_USBD_HID_COUNTRY_ARABIC = 1 , /**< ARABIC */
APP_USBD_HID_COUNTRY_BELGIAN = 2 , /**< BELGIAN */
APP_USBD_HID_COUNTRY_CANADIAN_BILINGUAL= 3 , /**< CANADIAN_BILINGUAL */
APP_USBD_HID_COUNTRY_CANADIAN_FRENCH = 4 , /**< CANADIAN_FRENCH */
APP_USBD_HID_COUNTRY_CZECH_REPUBLIC = 5 , /**< CZECH_REPUBLIC */
APP_USBD_HID_COUNTRY_DANISH = 6 , /**< DANISH */
APP_USBD_HID_COUNTRY_FINNISH = 7 , /**< FINNISH */
APP_USBD_HID_COUNTRY_FRENCH = 8 , /**< FRENCH */
APP_USBD_HID_COUNTRY_GERMAN = 9 , /**< GERMAN */
APP_USBD_HID_COUNTRY_GREEK = 10, /**< GREEK */
APP_USBD_HID_COUNTRY_HEBREW = 11, /**< HEBREW */
APP_USBD_HID_COUNTRY_HUNGARY = 12, /**< HUNGARY */
APP_USBD_HID_COUNTRY_INTERNATIONAL_ISO = 13, /**< INTERNATIONAL_ISO */
APP_USBD_HID_COUNTRY_ITALIAN = 14, /**< ITALIAN */
APP_USBD_HID_COUNTRY_JAPAN_KATAKANA = 15, /**< JAPAN_KATAKANA */
APP_USBD_HID_COUNTRY_KOREAN = 16, /**< KOREAN */
APP_USBD_HID_COUNTRY_LATIN_AMERICAN = 17, /**< LATIN_AMERICAN */
APP_USBD_HID_COUNTRY_NETHERLANDS_DUTCH = 18, /**< NETHERLANDS_DUTCH */
APP_USBD_HID_COUNTRY_NORWEGIAN = 19, /**< NORWEGIAN */
APP_USBD_HID_COUNTRY_PERSIAN_FARSI = 20, /**< PERSIAN_FARSI */
APP_USBD_HID_COUNTRY_POLAND = 21, /**< POLAND */
APP_USBD_HID_COUNTRY_PORTUGUESE = 22, /**< PORTUGUESE */
APP_USBD_HID_COUNTRY_RUSSIA = 23, /**< RUSSIA */
APP_USBD_HID_COUNTRY_SLOVAKIA = 24, /**< SLOVAKIA */
APP_USBD_HID_COUNTRY_SPANISH = 25, /**< SPANISH */
APP_USBD_HID_COUNTRY_SWEDISH = 26, /**< SWEDISH */
APP_USBD_HID_COUNTRY_SWISS_FRENCH = 27, /**< SWISS_FRENCH */
APP_USBD_HID_COUNTRY_SWISS_GERMAN = 28, /**< SWISS_GERMAN */
APP_USBD_HID_COUNTRY_SWITZERLAND = 29, /**< SWITZERLAND */
APP_USBD_HID_COUNTRY_TAIWAN = 30, /**< TAIWAN */
APP_USBD_HID_COUNTRY_TURKISH_Q = 31, /**< TURKISH_Q */
APP_USBD_HID_COUNTRY_UK = 32, /**< UK */
APP_USBD_HID_COUNTRY_US = 33, /**< US */
APP_USBD_HID_COUNTRY_YUGOSLAVIA = 34, /**< YUGOSLAVIA */
APP_USBD_HID_COUNTRY_TURKISH_F = 35, /**< TURKISH_F */
} app_usbd_hid_country_code_t;
/**
* @brief HID descriptor types.
*
* @ref app_usbd_hid_descriptor_t::bRDescriptorType
*/
typedef enum {
APP_USBD_HID_DESCRIPTOR_HID = 0x21, /**< HID descriptor. */
APP_USBD_HID_DESCRIPTOR_REPORT = 0x22, /**< REPORT descriptor. */
APP_USBD_HID_DESCRIPTOR_PHYSICAL = 0x23, /**< PHYSICAL descriptor. */
} app_usbd_hid_descriptor_type_t;
#pragma pack(push, 1)
/**
* @brief HID report descriptor entry at the end of HID descriptor.
*
* @param size Report descriptor size.
*/
#define APP_USBD_HID_REPORT_ITEM(size) \
APP_USBD_HID_DESCRIPTOR_REPORT, ((size) & 0xFF), ((size) / 256)
/**
* @brief HID physical descriptor entry at the end of HID descriptor.
*
* @param size Physical descriptor size.
*/
#define APP_USBD_HID_PHYSICAL_ITEM(size) \
APP_USBD_HID_DESCRIPTOR_PHYSICAL, ((size) & 0xFF), ((size) / 256)
/**
* @brief HID descriptor, binary layout.
*/
typedef union {
struct {
uint8_t bLength; //!< Length of descriptor.
uint8_t bDescriptorType; //!< Descriptor type @ref APP_USBD_HID_DESCRIPTOR_HID.
uint16_t bcdHID; //!< HID release number (BCD format, little endian).
uint8_t bCountryCode; //!< Country code.
uint8_t bNumDescriptors; //!< Number of class descriptors.
struct {
uint8_t bRDescriptorType; //!< Class descriptor type.
uint16_t wDescriptorLength; //!< Class descriptor length (little endian).
} reports[];
} raw;
} app_usbd_hid_descriptor_t;
#pragma pack(pop)
/**
* @brief HID requests defined by specification.
*/
typedef enum {
APP_USBD_HID_REQ_GET_REPORT = 0x01, /**< REPORT: device -> host (required). */
APP_USBD_HID_REQ_GET_IDLE = 0x02, /**< IDLE: device -> host (not required). */
APP_USBD_HID_REQ_GET_PROTOCOL = 0x03, /**< PROTOCOL: device -> host (required for boot protocol). */
APP_USBD_HID_REQ_SET_REPORT = 0x09, /**< REPORT: host -> device (not required). */
APP_USBD_HID_REQ_SET_IDLE = 0x0A, /**< IDLE: no data stage (required for boot protocol). */
APP_USBD_HID_REQ_SET_PROTOCOL = 0x0B, /**< PROTOCOL: no data stage (required for boot protocol). */
} app_usbd_hid_req_t;
/**
* @brief HID report type.
*/
typedef enum {
APP_USBD_HID_REPORT_TYPE_INPUT = 0x01, /**< INPUT report type */
APP_USBD_HID_REPORT_TYPE_OUTPUT = 0x02, /**< OUTPUT report type */
APP_USBD_HID_REPORT_TYPE_FEATURE = 0x03, /**< FEATURE report type */
} app_usbd_hid_report_type_t;
/**
* @brief Hid version BCD value definition.
*
* The version of the HID descriptors used.
*/
#define APP_USBD_HID_BCD_VER APP_USBD_BCD_VER_MAKE(1, 1, 1)
/**
* @brief HID version BCD value definition distributed into bytes.
*
* This is a value written directly into @ref app_usbd_hid_descriptor_t::bcdHID.
* @sa APP_USBD_HID_BCD_VER
*/
#define APP_USBD_HID_BCD_VER_BYTES LSB_16(APP_USBD_HID_BCD_VER), MSB_16(APP_USBD_HID_BCD_VER)
/**
* @brief Initializer of interface descriptor for HID classes.
*
* @param interface_number Interface number.
* @param endpoints_num Number of endpoints.
* @param subclass Subclass type @ref app_usbd_hid_subclass_t.
* @param protocol Protocol type @ref app_usbd_hid_protocol_t.
*/
#define APP_USBD_HID_INTERFACE_DSC(interface_number, endpoints_num, subclass, protocol) \
/*.bLength = */ sizeof(app_usbd_descriptor_iface_t), \
/*.bDescriptorType = */ APP_USBD_DESCRIPTOR_INTERFACE, \
/*.bInterfaceNumber = */ interface_number, \
/*.bAlternateSetting = */ 0x00, \
/*.bNumEndpoints = */ endpoints_num, \
/*.bInterfaceClass = */ APP_USBD_HID_CLASS, \
/*.bInterfaceSubClass = */ subclass, \
/*.bInterfaceProtocol = */ protocol, \
/*.iInterface = 0, */ 0x00, \
/**
* @brief Initializer of HID descriptor for HID classes.
*
* @param ... Report/physical item list.
*/
#define APP_USBD_HID_HID_DSC(...) \
/*.bLength = */ sizeof(app_usbd_hid_descriptor_t) + 3 * (NUM_VA_ARGS(__VA_ARGS__)), \
/*.bDescriptorType = */ APP_USBD_HID_DESCRIPTOR_HID, \
/*.bcdHID = */ APP_USBD_HID_BCD_VER_BYTES, \
/*.bCountryCode = */ APP_USBD_HID_COUNTRY_NOT_SUPPORTED, \
/*.bNumDescriptors = */ (NUM_VA_ARGS(__VA_ARGS__)), \
/*.bRDescriptorType = */ APP_USBD_HID_REPORT_ITEM(sizeof(GET_VA_ARG_1_(__VA_ARGS__))), \
/*.wDescriptorLength = */
/**
* @brief Initializer of endpoint descriptor for HID classes.
*
* @param endpoint Endpoint number.
* @param ep_size Endpoint size.
* @param ep_interval Endpoint interval (milliseconds).
*/
#define APP_USBD_HID_EP_DSC(endpoint, ep_size, ep_interval) \
/*.bLength = */ sizeof(app_usbd_descriptor_ep_t), \
/*.bDescriptorType = */ APP_USBD_DESCRIPTOR_ENDPOINT, \
/*.bEndpointAddress = */ endpoint, \
/*.bmAttributes = */ APP_USBD_DESCRIPTOR_EP_ATTR_TYPE_INTERRUPT, \
/*.wMaxPacketSize = */ APP_USBD_U16_TO_RAW_DSC(ep_size), \
/*.bInterval = */ ep_interval, \
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* APP_USBD_HID_TYPES_H__ */

View File

@@ -1,659 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sdk_common.h"
#if NRF_MODULE_ENABLED(APP_USBD_HID_GENERIC)
#include <string.h>
#include "app_usbd_hid_generic.h"
#include "app_util_platform.h"
/**
* @ingroup app_usbd_hid_generic
*
* Module with types, definitions and API used by HID generic.
* @{
*/
/**
* @brief Auxiliary function to access HID generic context data.
*
* @param[in] p_generic HID generic instance.
*
* @return HID generic class instance data context.
*/
static inline app_usbd_hid_generic_ctx_t *
hid_generic_ctx_get(app_usbd_hid_generic_t const * p_generic)
{
ASSERT(p_generic != NULL);
ASSERT(p_generic->specific.p_data != NULL);
return &p_generic->specific.p_data->ctx;
}
/**
* @brief Auxiliary function to access HID generic instance data.
*
* @param[in] p_inst Class instance data.
*
* @return HID generic class instance data.
*/
static inline app_usbd_hid_generic_t const *
hid_generic_get(app_usbd_class_inst_t const * p_inst)
{
ASSERT(p_inst != NULL);
return (app_usbd_hid_generic_t const *)p_inst;
}
/**
* @brief Returns report ID buffer descriptor.
*
* @param[in] p_generic Internal HID generic context.
*
* @return HID report buffer.
*/
static inline app_usbd_hid_report_buffer_t *
hid_generic_rep_buffer_get(app_usbd_hid_generic_t const * p_generic)
{
ASSERT(p_generic != NULL);
app_usbd_hid_inst_t const * p_hinst = &p_generic->specific.inst.hid_inst;
return app_usbd_hid_rep_buff_in_get(p_hinst);
}
/**
* @brief Auxiliary function to prepare report transfer buffer to next transfer.
*
* @param[in] p_generic HID generic instance.
*
* @retval true Next transfer required.
* @retval false Next transfer not required.
*/
static inline bool hid_generic_transfer_next(app_usbd_hid_generic_t const * p_generic)
{
nrf_queue_t const * p_rep_in_queue = p_generic->specific.inst.p_rep_in_queue;
return !nrf_queue_is_empty(p_rep_in_queue);
}
/**
* @brief Triggers IN endpoint transfer.
*
* @param[in] p_generic HID generic instance.
*
* @return Standard error code.
*/
static inline ret_code_t hid_generic_transfer_set(app_usbd_hid_generic_t const * p_generic)
{
app_usbd_class_inst_t const * p_inst = (app_usbd_class_inst_t const *)p_generic;
app_usbd_hid_generic_ctx_t * p_generic_ctx = hid_generic_ctx_get(p_generic);
nrf_drv_usbd_ep_t ep_addr = app_usbd_hid_epin_addr_get(p_inst);
app_usbd_hid_state_flag_clr(&p_generic_ctx->hid_ctx,
APP_USBD_HID_STATE_FLAG_TRANS_IN_PROGRESS);
if (!hid_generic_transfer_next(p_generic))
{
return NRF_SUCCESS;
}
app_usbd_hid_report_buffer_t * p_rep_buff = hid_generic_rep_buffer_get(p_generic);
nrf_queue_t const * p_rep_in_queue = p_generic->specific.inst.p_rep_in_queue;
ret_code_t ret = nrf_queue_pop(p_rep_in_queue, p_rep_buff);
ASSERT(ret == NRF_SUCCESS);
NRF_DRV_USBD_TRANSFER_IN(transfer, p_rep_buff->p_buff, p_rep_buff->size);
CRITICAL_REGION_ENTER();
ret = app_usbd_ep_transfer(ep_addr, &transfer);
if (ret == NRF_SUCCESS)
{
app_usbd_hid_state_flag_set(&p_generic_ctx->hid_ctx,
APP_USBD_HID_STATE_FLAG_TRANS_IN_PROGRESS);
}
CRITICAL_REGION_EXIT();
return ret;
}
ret_code_t hid_generic_clear_buffer(app_usbd_class_inst_t const * p_inst)
{
ASSERT(p_inst != NULL);
app_usbd_hid_generic_t const * p_generic = hid_generic_get(p_inst);
app_usbd_hid_generic_ctx_t * p_generic_ctx = hid_generic_ctx_get(p_generic);
app_usbd_hid_report_buffer_t * p_rep_buffer = hid_generic_rep_buffer_get(p_generic);
nrf_queue_t const * p_rep_in_queue = p_generic->specific.inst.p_rep_in_queue;
ret_code_t ret = NRF_SUCCESS;
/* Clear all queued reports */
while(ret != NRF_ERROR_NOT_FOUND)
{
ret = nrf_queue_pop(p_rep_in_queue, p_rep_buffer);
}
CRITICAL_REGION_ENTER();
uint8_t iface_count = app_usbd_class_iface_count_get(p_inst);
app_usbd_class_iface_conf_t const * p_iface = NULL;
for (uint8_t i = 0; i < iface_count; ++i)
{
p_iface = app_usbd_class_iface_get(p_inst, i);
uint8_t ep_count = app_usbd_class_iface_ep_count_get(p_iface);
for (uint8_t j = 0; j < ep_count; ++j)
{
/*Abort transfer on every IN endpoint*/
app_usbd_class_ep_conf_t const * p_ep = app_usbd_class_iface_ep_get(p_iface, j);
ASSERT(!NRF_USBD_EPISO_CHECK(p_ep->address));
if (NRF_USBD_EPIN_CHECK(p_ep->address))
{
nrf_drv_usbd_ep_abort(p_ep->address);
}
}
}
app_usbd_hid_state_flag_clr(&p_generic_ctx->hid_ctx, APP_USBD_HID_STATE_FLAG_TRANS_IN_PROGRESS);
CRITICAL_REGION_EXIT();
return ret;
}
ret_code_t app_usbd_hid_generic_in_report_set(app_usbd_hid_generic_t const * p_generic,
const void * p_buff,
size_t size)
{
app_usbd_hid_generic_ctx_t * p_generic_ctx = hid_generic_ctx_get(p_generic);
nrf_queue_t const * p_rep_in_queue = p_generic->specific.inst.p_rep_in_queue;
const app_usbd_hid_report_buffer_t rep_buff = {
.p_buff = (void *)p_buff,
.size = size,
};
if (nrf_queue_push(p_rep_in_queue, &rep_buff) != NRF_SUCCESS)
{
return NRF_ERROR_BUSY;
}
ret_code_t ret = NRF_SUCCESS;
if (app_usbd_hid_trans_required(&p_generic_ctx->hid_ctx) &&
!p_generic_ctx->hid_ctx.idle_on)
{
ret = hid_generic_transfer_set(p_generic);
}
return ret;
}
ret_code_t app_usbd_hid_generic_idle_report_set(app_usbd_hid_generic_t const * p_generic,
const void * p_buff,
size_t size)
{
app_usbd_class_inst_t const * p_inst = (app_usbd_class_inst_t const *)p_generic;
app_usbd_hid_generic_ctx_t * p_generic_ctx = hid_generic_ctx_get(p_generic);
ret_code_t ret;
nrf_drv_usbd_ep_t ep_addr = app_usbd_hid_epin_addr_get(p_inst);
app_usbd_hid_state_flag_clr(&p_generic_ctx->hid_ctx,
APP_USBD_HID_STATE_FLAG_TRANS_IN_PROGRESS);
NRF_DRV_USBD_TRANSFER_IN(transfer, p_buff, size);
CRITICAL_REGION_ENTER();
ret = app_usbd_ep_transfer(ep_addr, &transfer);
if (ret == NRF_SUCCESS)
{
app_usbd_hid_state_flag_set(&p_generic_ctx->hid_ctx,
APP_USBD_HID_STATE_FLAG_TRANS_IN_PROGRESS);
}
CRITICAL_REGION_EXIT();
return ret;
}
const void * app_usbd_hid_generic_in_report_get(app_usbd_hid_generic_t const * p_generic,
size_t * p_size)
{
app_usbd_hid_inst_t const * p_hinst = &p_generic->specific.inst.hid_inst;
*p_size = p_hinst->p_rep_buffer_in->size;
return p_hinst->p_rep_buffer_in->p_buff;
}
const void * app_usbd_hid_generic_out_report_get(app_usbd_hid_generic_t const * p_generic,
size_t * p_size)
{
app_usbd_hid_inst_t const * p_hinst = &p_generic->specific.inst.hid_inst;
*p_size = p_hinst->p_rep_buffer_out->size;
return p_hinst->p_rep_buffer_out->p_buff;
}
const void * app_usbd_hid_generic_feature_report_get(app_usbd_hid_generic_t const * p_generic,
size_t * p_size)
{
app_usbd_hid_inst_t const * p_hinst = &p_generic->specific.inst.hid_inst;
*p_size = p_hinst->p_rep_buffer_feature->size;
return p_hinst->p_rep_buffer_feature->p_buff;
}
/**
* @brief @ref app_usbd_hid_interface_t::on_get_report
*/
static ret_code_t hid_generic_on_get_report(app_usbd_class_inst_t const * p_inst,
app_usbd_setup_evt_t const * p_setup_ev)
{
app_usbd_hid_generic_t const * p_hinst = hid_generic_get(p_inst);
uint8_t const * p_rep_buffer = NULL;
size_t buffer_size = 0;
if (p_setup_ev->setup.wValue.hb == APP_USBD_HID_REPORT_TYPE_INPUT)
{
p_rep_buffer = app_usbd_hid_generic_in_report_get(p_hinst, &buffer_size);
}
else if (p_setup_ev->setup.wValue.hb == APP_USBD_HID_REPORT_TYPE_OUTPUT)
{
p_rep_buffer = app_usbd_hid_generic_out_report_get(p_hinst, &buffer_size);
}
else if (p_setup_ev->setup.wValue.hb == APP_USBD_HID_REPORT_TYPE_FEATURE)
{
p_rep_buffer = app_usbd_hid_generic_feature_report_get(p_hinst, &buffer_size);
}
else
{
return NRF_ERROR_NOT_SUPPORTED;
}
return app_usbd_core_setup_rsp(&(p_setup_ev->setup), p_rep_buffer, buffer_size);
}
static ret_code_t hid_generic_on_set_report_data_cb(nrf_drv_usbd_ep_status_t status,
void * p_context)
{
app_usbd_hid_user_ev_handler_t handler;
app_usbd_hid_generic_t const * p_generic = (app_usbd_hid_generic_t const *)p_context;
if (status != NRF_USBD_EP_OK)
{
return NRF_ERROR_INTERNAL;
}
handler = p_generic->specific.inst.hid_inst.user_event_handler;
handler((app_usbd_class_inst_t const *)p_generic,
APP_USBD_HID_USER_EVT_OUT_REPORT_READY);
return NRF_SUCCESS;
}
static ret_code_t hid_generic_on_set_report_feature_data_cb(nrf_drv_usbd_ep_status_t status,
void * p_context)
{
app_usbd_hid_user_ev_handler_t handler;
app_usbd_hid_generic_t const * p_generic = (app_usbd_hid_generic_t const *)p_context;
if (status != NRF_USBD_EP_OK)
{
return NRF_ERROR_INTERNAL;
}
handler = p_generic->specific.inst.hid_inst.user_event_handler;
handler((app_usbd_class_inst_t const *)p_generic,
APP_USBD_HID_USER_EVT_FEATURE_REPORT_READY);
return NRF_SUCCESS;
}
/**
* @brief @ref app_usbd_hid_interface_t::on_set_report
*/
static ret_code_t hid_generic_on_set_report(app_usbd_class_inst_t const * p_inst,
app_usbd_setup_evt_t const * p_setup_ev)
{
if (p_setup_ev->setup.wValue.hb == APP_USBD_HID_REPORT_TYPE_OUTPUT)
{
app_usbd_hid_generic_t const * p_generic = hid_generic_get(p_inst);
/*Request setup data*/
app_usbd_hid_report_buffer_t const * p_rep_buff;
p_rep_buff = app_usbd_hid_rep_buff_out_get(&p_generic->specific.inst.hid_inst);
p_rep_buff->p_buff[0] = p_setup_ev->setup.wValue.lb;
NRF_DRV_USBD_TRANSFER_OUT(transfer, p_rep_buff->p_buff + 1, p_rep_buff->size - 1);
ret_code_t ret;
CRITICAL_REGION_ENTER();
ret = app_usbd_ep_transfer(NRF_DRV_USBD_EPOUT0, &transfer);
if (ret == NRF_SUCCESS)
{
app_usbd_core_setup_data_handler_desc_t desc = {
.handler = hid_generic_on_set_report_data_cb,
.p_context = (void *)p_generic
};
ret = app_usbd_core_setup_data_handler_set(NRF_DRV_USBD_EPOUT0, &desc);
}
CRITICAL_REGION_EXIT();
return ret;
}
else if (p_setup_ev->setup.wValue.hb == APP_USBD_HID_REPORT_TYPE_FEATURE)
{
app_usbd_hid_generic_t const * p_generic = hid_generic_get(p_inst);
/*Request setup data*/
app_usbd_hid_report_buffer_t const * p_rep_buff;
p_rep_buff = app_usbd_hid_rep_buff_feature_get(&p_generic->specific.inst.hid_inst);
NRF_DRV_USBD_TRANSFER_OUT(transfer, p_rep_buff->p_buff, p_rep_buff->size);
ret_code_t ret;
CRITICAL_REGION_ENTER();
ret = app_usbd_ep_transfer(NRF_DRV_USBD_EPOUT0, &transfer);
if (ret == NRF_SUCCESS)
{
app_usbd_core_setup_data_handler_desc_t desc = {
.handler = hid_generic_on_set_report_feature_data_cb,
.p_context = (void *)p_generic
};
ret = app_usbd_core_setup_data_handler_set(NRF_DRV_USBD_EPOUT0, &desc);
}
CRITICAL_REGION_EXIT();
return ret;
}
return NRF_ERROR_NOT_SUPPORTED;
}
/**
* @brief @ref app_usbd_hid_interface_t::ep_transfer_in
*/
static ret_code_t hid_generic_ep_transfer_in(app_usbd_class_inst_t const * p_inst)
{
app_usbd_hid_generic_t const * p_generic = hid_generic_get(p_inst);
app_usbd_hid_generic_ctx_t * p_generic_ctx = hid_generic_ctx_get(p_generic);
nrf_queue_t const * p_rep_in_queue = p_generic->specific.inst.p_rep_in_queue;
if (nrf_queue_is_empty(p_rep_in_queue))
{
app_usbd_hid_state_flag_clr(&p_generic_ctx->hid_ctx,
APP_USBD_HID_STATE_FLAG_TRANS_IN_PROGRESS);
return NRF_SUCCESS;
}
/* Get next report to send */
return hid_generic_transfer_set((app_usbd_hid_generic_t const *)p_inst);
}
/**
* @brief @ref app_usbd_hid_interface_t::ep_transfer_out
*/
static ret_code_t hid_generic_ep_transfer_out(app_usbd_class_inst_t const * p_inst)
{
app_usbd_hid_generic_t const * p_generic = hid_generic_get(p_inst);
nrf_drv_usbd_ep_t ep_addr = app_usbd_hid_epout_addr_get(p_inst);
/*Request setup data*/
app_usbd_hid_report_buffer_t const * p_rep_buff;
p_rep_buff = app_usbd_hid_rep_buff_out_get(&p_generic->specific.inst.hid_inst);
NRF_DRV_USBD_TRANSFER_OUT(transfer, p_rep_buff->p_buff, p_rep_buff->size);
return app_usbd_ep_transfer(ep_addr, &transfer);
}
/**
* @brief @ref app_usbd_class_interface_t::event_handler
*/
static ret_code_t hid_generic_event_handler(app_usbd_class_inst_t const * p_inst,
app_usbd_complex_evt_t const * p_event)
{
ASSERT(p_inst != NULL);
ASSERT(p_event != NULL);
app_usbd_hid_generic_t const * p_generic = hid_generic_get(p_inst);
app_usbd_hid_inst_t const * p_hinst = &p_generic->specific.inst.hid_inst;
app_usbd_hid_generic_ctx_t * p_generic_ctx = hid_generic_ctx_get(p_generic);
app_usbd_hid_ctx_t * p_hid_ctx = &p_generic_ctx->hid_ctx;
/*Try handle event by generic HID event handler*/
return app_usbd_hid_event_handler(p_inst, p_hinst, p_hid_ctx, p_event);
}
static uint8_t hid_generic_get_class_descriptors_count(app_usbd_class_inst_t const * p_inst)
{
app_usbd_hid_generic_t const * p_generic = hid_generic_get(p_inst);
app_usbd_hid_inst_t const * p_hinst = &p_generic->specific.inst.hid_inst;
return p_hinst->subclass_desc_count;
}
static app_usbd_descriptor_t hid_generic_get_class_descriptors_type(
app_usbd_class_inst_t const * p_inst,
uint8_t desc_num)
{
app_usbd_hid_generic_t const * p_generic = hid_generic_get(p_inst);
app_usbd_hid_inst_t const * p_hinst = &p_generic->specific.inst.hid_inst;
return p_hinst->p_subclass_desc[desc_num]->type;
}
static size_t hid_generic_get_class_descriptors_length(app_usbd_class_inst_t const * p_inst,
uint8_t desc_num)
{
app_usbd_hid_generic_t const * p_generic = hid_generic_get(p_inst);
app_usbd_hid_inst_t const * p_hinst = &p_generic->specific.inst.hid_inst;
return p_hinst->p_subclass_desc[desc_num]->size;
}
static const uint8_t * hid_generic_get_class_descriptors_data(app_usbd_class_inst_t const * p_inst,
uint8_t desc_num,
uint32_t cur_byte)
{
app_usbd_hid_generic_t const * p_generic = hid_generic_get(p_inst);
app_usbd_hid_inst_t const * p_hinst = &p_generic->specific.inst.hid_inst;
const uint8_t * p_byte = &p_hinst->p_subclass_desc[desc_num]->p_data[cur_byte];
return p_byte;
}
/**
* @brief @ref app_usbd_class_interface_t::feed_descriptors
*/
static bool hid_generic_feed_descriptors(app_usbd_class_descriptor_ctx_t * p_ctx,
app_usbd_class_inst_t const * p_inst,
uint8_t * p_buff,
size_t max_size)
{
static uint8_t ifaces = 0;
ifaces = app_usbd_class_iface_count_get(p_inst);
app_usbd_hid_generic_t const * p_generic = hid_generic_get(p_inst);
APP_USBD_CLASS_DESCRIPTOR_BEGIN(p_ctx, p_buff, max_size);
static uint8_t i = 0;
for (i = 0; i < ifaces; i++)
{
/* INTERFACE DESCRIPTOR */
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x09); // bLength
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_DESCRIPTOR_INTERFACE); // bDescriptorType = Interface
static app_usbd_class_iface_conf_t const * p_cur_iface = NULL;
p_cur_iface = app_usbd_class_iface_get(p_inst, i);
APP_USBD_CLASS_DESCRIPTOR_WRITE(app_usbd_class_iface_number_get(p_cur_iface)); // bInterfaceNumber
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x00); // bAlternateSetting
APP_USBD_CLASS_DESCRIPTOR_WRITE(app_usbd_class_iface_ep_count_get(p_cur_iface)); // bNumEndpoints
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_HID_CLASS); // bInterfaceClass = HID
APP_USBD_CLASS_DESCRIPTOR_WRITE(p_generic->specific.inst.hid_inst.subclass_boot); // bInterfaceSubclass (Boot Interface)
APP_USBD_CLASS_DESCRIPTOR_WRITE(p_generic->specific.inst.hid_inst.protocol); // bInterfaceProtocol
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x00); // iInterface
/* HID DESCRIPTOR */
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x09); // bLength
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_HID_DESCRIPTOR_HID); // bDescriptorType = HID
APP_USBD_CLASS_DESCRIPTOR_WRITE(LSB_16(APP_USBD_HID_BCD_VER)); // bcdHID LSB
APP_USBD_CLASS_DESCRIPTOR_WRITE(MSB_16(APP_USBD_HID_BCD_VER)); // bcdHID MSB
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_HID_COUNTRY_NOT_SUPPORTED); // bCountryCode
APP_USBD_CLASS_DESCRIPTOR_WRITE(hid_generic_get_class_descriptors_count(p_inst)); // bNumDescriptors
static uint8_t class_desc_cnt = 0;
class_desc_cnt = hid_generic_get_class_descriptors_count(p_inst);
static uint8_t j = 0;
static uint16_t class_desc_len = 0;
for (j = 0; j < class_desc_cnt; j++)
{
APP_USBD_CLASS_DESCRIPTOR_WRITE(hid_generic_get_class_descriptors_type(p_inst, j)); // bDescriptorType
class_desc_len = hid_generic_get_class_descriptors_length(p_inst, j);
APP_USBD_CLASS_DESCRIPTOR_WRITE(LSB_16(class_desc_len)); // wDescriptorLength LSB
APP_USBD_CLASS_DESCRIPTOR_WRITE(MSB_16(class_desc_len)); // wDescriptorLength MSB
}
static uint8_t endpoints = 0;
endpoints = app_usbd_class_iface_ep_count_get(p_cur_iface);
for (j = 0; j < endpoints; j++)
{
/* ENDPOINT DESCRIPTOR */
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x07); // bLength
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_DESCRIPTOR_ENDPOINT); // bDescriptorType = Endpoint
static app_usbd_class_ep_conf_t const * p_cur_ep = NULL;
p_cur_ep = app_usbd_class_iface_ep_get(p_cur_iface, j);
APP_USBD_CLASS_DESCRIPTOR_WRITE(app_usbd_class_ep_address_get(p_cur_ep)); // bEndpointAddress
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_DESCRIPTOR_EP_ATTR_TYPE_INTERRUPT); // bmAttributes
APP_USBD_CLASS_DESCRIPTOR_WRITE(LSB_16(NRF_DRV_USBD_EPSIZE)); // wMaxPacketSize LSB
APP_USBD_CLASS_DESCRIPTOR_WRITE(MSB_16(NRF_DRV_USBD_EPSIZE)); // wMaxPacketSize MSB
APP_USBD_CLASS_DESCRIPTOR_WRITE(p_generic->specific.inst.hid_inst.p_ep_interval[j]); // bInterval
}
}
APP_USBD_CLASS_DESCRIPTOR_END();
}
ret_code_t hid_generic_on_set_protocol(app_usbd_hid_generic_t const * p_generic, app_usbd_hid_user_event_t ev)
{
app_usbd_hid_generic_ctx_t * p_generic_ctx = hid_generic_ctx_get(p_generic);
if (ev == APP_USBD_HID_USER_EVT_SET_BOOT_PROTO)
{
p_generic_ctx->hid_ctx.selected_protocol = APP_USBD_HID_PROTO_BOOT;
}
else if (ev == APP_USBD_HID_USER_EVT_SET_REPORT_PROTO)
{
p_generic_ctx->hid_ctx.selected_protocol = APP_USBD_HID_PROTO_REPORT;
}
else
{
return NRF_ERROR_NOT_SUPPORTED;
}
return NRF_SUCCESS;
}
ret_code_t hid_generic_idle_handler_set(app_usbd_class_inst_t const * p_inst,
app_usbd_hid_idle_handler_t handler)
{
ASSERT(handler != NULL);
app_usbd_hid_generic_t const * p_generic = hid_generic_get(p_inst);
app_usbd_hid_generic_ctx_t * p_generic_ctx = hid_generic_ctx_get(p_generic);
p_generic_ctx->hid_ctx.idle_handler = handler;
return NRF_SUCCESS;
}
static ret_code_t hid_generic_on_idle(app_usbd_class_inst_t const * p_inst, uint8_t report_id)
{
app_usbd_hid_generic_t const * p_generic = hid_generic_get(p_inst);
app_usbd_hid_generic_ctx_t * p_generic_ctx = hid_generic_ctx_get(p_generic);
if(p_generic_ctx->hid_ctx.idle_handler != NULL)
{
return p_generic_ctx->hid_ctx.idle_handler(p_inst, report_id);
}
else
{
return NRF_ERROR_NOT_SUPPORTED;
}
}
/** @} */
const app_usbd_hid_methods_t app_usbd_hid_generic_methods = {
.on_get_report = hid_generic_on_get_report,
.on_set_report = hid_generic_on_set_report,
.ep_transfer_in = hid_generic_ep_transfer_in,
.ep_transfer_out = hid_generic_ep_transfer_out,
.subclass_count = hid_generic_get_class_descriptors_count,
.subclass_length = hid_generic_get_class_descriptors_length,
.subclass_data = hid_generic_get_class_descriptors_data,
.on_idle = hid_generic_on_idle,
.set_idle_handler = hid_generic_idle_handler_set,
};
const app_usbd_class_methods_t app_usbd_generic_class_methods = {
.event_handler = hid_generic_event_handler,
.feed_descriptors = hid_generic_feed_descriptors,
};
#endif //NRF_MODULE_ENABLED(APP_USBD_HID_GENERIC)

View File

@@ -1,284 +0,0 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef APP_USBD_HID_GENERIC_H__
#define APP_USBD_HID_GENERIC_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "nrf_drv_usbd.h"
#include "app_usbd_class_base.h"
#include "app_usbd_hid_types.h"
#include "app_usbd_hid.h"
#include "app_usbd.h"
#include "app_usbd_core.h"
#include "app_usbd_descriptor.h"
#include "app_usbd_hid_generic_desc.h"
#include "app_usbd_hid_generic_internal.h"
/**
* @defgroup app_usbd_hid_generic USB HID generic
* @ingroup app_usbd_hid
*
* @brief @tagAPI52840 Module with types, definitions, and API used by the HID generic class.
* @{
*/
#ifdef DOXYGEN
/**
* @brief HID generic class instance type.
*
* @ref APP_USBD_CLASS_TYPEDEF
*/
typedef struct { } app_usbd_hid_generic_t;
#else
/*lint -save -e10 -e26 -e123 -e505 */
APP_USBD_CLASS_TYPEDEF(app_usbd_hid_generic, \
APP_USBD_HID_GENERIC_CONFIG(0, (NRF_DRV_USBD_EPIN1, NRF_DRV_USBD_EPOUT1)), \
APP_USBD_HID_GENERIC_INSTANCE_SPECIFIC_DEC, \
APP_USBD_HID_GENERIC_DATA_SPECIFIC_DEC \
);
/*lint -restore*/
#endif
/**
* @brief Global definition of app_usbd_hid_generic_t class.
*
* @param instance_name Name of global instance.
* @param interface_number Unique interface index.
* @param user_ev_handler User event handler (optional).
* @param endpoint_list Input endpoint list (@ref nrf_drv_usbd_ep_t).
* @param subclass_descriptors HID subclass descriptors.
* @param report_in_queue_size IN report queue size.
* @param report_out_maxsize Maximum output report size.
* @param report_feature_maxsize Maximum feature report size.
* @param subclass_boot Subclass boot (@ref app_usbd_hid_subclass_t).
* @param protocol HID protocol (@ref app_usbd_hid_protocol_t).
*
* @note This macro is just simplified version of @ref APP_USBD_HID_GENERIC_GLOBAL_DEF_INTERNAL.
*
* Example class definition:
* @code
APP_USBD_HID_GENERIC_SUBCLASS_REPORT_DESC(mouse_desc,APP_USBD_HID_MOUSE_REPORT_DSC_BUTTON(2));
static const app_usbd_hid_subclass_desc_t * reps[] = {&mouse_desc};
#define ENDPOINT_LIST \
( \
NRF_DRV_USBD_EPIN1 \
)
#define REPORT_COUNT 1
#define REPORT_OUT_MAXSIZE 0
APP_USBD_HID_GENERIC_GLOBAL_DEF(m_app_hid_generic,
0,
hid_user_ev_handler,
ENDPOINT_LIST(),
reps,
REPORT_IN_QUEUE_SIZE,
REPORT_OUT_MAXSIZE,
REPORT_FEATURE_MAXSIZE,
APP_USBD_HID_SUBCLASS_BOOT,
APP_USBD_HID_PROTO_MOUSE);
@endcode
*
*/
/*lint -emacro( (40), APP_USBD_HID_GENERIC_GLOBAL_DEF) */
#define APP_USBD_HID_GENERIC_GLOBAL_DEF(instance_name, \
interface_number, \
user_ev_handler, \
endpoint_list, \
subclass_descriptors, \
report_in_queue_size, \
report_out_maxsize, \
report_feature_maxsize, \
subclass_boot, \
protocol) \
APP_USBD_HID_GENERIC_GLOBAL_DEF_INTERNAL(instance_name, \
interface_number, \
user_ev_handler, \
endpoint_list, \
subclass_descriptors, \
report_in_queue_size, \
report_out_maxsize, \
report_feature_maxsize, \
subclass_boot, \
protocol)
/**
* @brief Helper function to get class instance from HID generic class.
*
* @param[in] p_generic HID generic class instance.
*
* @return Base class instance.
*/
static inline app_usbd_class_inst_t const *
app_usbd_hid_generic_class_inst_get(app_usbd_hid_generic_t const * p_generic)
{
return &p_generic->base;
}
/**
* @brief Helper function to get HID generic from base class instance.
*
* @param[in] p_inst Base class instance.
*
* @return HID generic class handle.
*/
static inline app_usbd_hid_generic_t const *
app_usbd_hid_generic_class_get(app_usbd_class_inst_t const * p_inst)
{
return (app_usbd_hid_generic_t const *)p_inst;
}
/**
* @brief Changes default HID idle report.
*
*
* @param[in] p_generic HID generic class instance.
* @param[in] p_buff Report buffer.
* @param[in] size Report size.
*
* @return Standard error code.
*/
ret_code_t hid_generic_idle_set(app_usbd_hid_generic_t const * p_generic,
const void * p_buff,
size_t size);
/**
* @brief New IN report trigger.
*
*
* @param[in] p_generic HID generic class instance.
* @param[in] p_buff Report buffer.
* @param[in] size Report size.
*
* @return Standard error code.
*/
ret_code_t app_usbd_hid_generic_in_report_set(app_usbd_hid_generic_t const * p_generic,
const void * p_buff,
size_t size);
/**
* @brief Returns last successful transfered IN report.
*
* @note Use this call only on @ref APP_USBD_HID_USER_EVT_IN_REPORT_DONE event.
*
* @param[in] p_generic HID generic class instance.
* @param[out] p_size Last transfered IN report size.
*
* @return Last transfered report ID.
*/
const void * app_usbd_hid_generic_in_report_get(app_usbd_hid_generic_t const * p_generic,
size_t * p_size);
/**
* @brief Returns last successful transfered OUT report.
*
* @warning Use this call only on @ref APP_USBD_HID_USER_EVT_OUT_REPORT_READY event.
*
* @param[in] p_generic HID generic class instance.
* @param[out] p_size Last transfered OUT report size.
*
* @return Last transfered OUT report.
*/
const void * app_usbd_hid_generic_out_report_get(app_usbd_hid_generic_t const * p_generic,
size_t * p_size);
/**
* @brief Function handling SET_PROTOCOL command.
*
*
* @param[in] p_generic HID generic class instance.
* @param[in] ev User event.
*
* @return Standard error code.
*/
ret_code_t hid_generic_on_set_protocol(app_usbd_hid_generic_t const * p_generic,
app_usbd_hid_user_event_t ev);
/**
* @brief Function that clears HID generic buffers and sends an empty report.
*
* @param[in] p_inst Base class instance.
*
* @return Standard error code.
*/
ret_code_t hid_generic_clear_buffer(app_usbd_class_inst_t const * p_inst);
/**
* @brief Sets handler for idle reports.
*
* @param[in] p_inst Base class instance.
* @param[in] handler Handler.
*
* @return Standard error code.
*/
ret_code_t hid_generic_idle_handler_set(app_usbd_class_inst_t const * p_inst,
app_usbd_hid_idle_handler_t handler);
/**
* @brief Sends idle reoprt.
*
* @param[in] p_generic HID generic class instance.
* @param[in] p_buff Report buffer.
* @param[in] size Size of report.
*
* @return Standard error code.
*/
ret_code_t app_usbd_hid_generic_idle_report_set(app_usbd_hid_generic_t const * p_generic,
const void * p_buff,
size_t size);
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* APP_USBD_HID_GENERIC_H__ */

View File

@@ -1,96 +0,0 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef APP_USBD_HID_GENERIC_DESC_H__
#define APP_USBD_HID_GENERIC_DESC_H__
#ifdef __cplusplus
extern "C" {
#endif
/**
* @defgroup app_usbd_hid_generic_desc USB HID generic descriptors
* @ingroup app_usbd_hid_generic
*
* @brief @tagAPI52840 Module with descriptors used by the HID generic class.
* @{
*/
/**
* @brief Initializer of interface descriptor for HID generic class.
*
* @param interface_number Interface number.
* @param endpoints_num Number of endpoints.
* @param subclass Subclass type @ref app_usbd_hid_subclass_t.
* @param protocol Protocol type @ref app_usbd_hid_protocol_t.
*/
#define APP_USBD_HID_GENERIC_INTERFACE_DSC(interface_number, \
endpoints_num, \
subclass, \
protocol) \
APP_USBD_HID_INTERFACE_DSC(interface_number, \
endpoints_num, \
subclass, \
protocol) \
/**
* @brief Initializer of HID descriptor for HID generic class.
*
* @param ... Report descriptor item.
*/
#define APP_USBD_HID_GENERIC_HID_DSC(...) \
APP_USBD_HID_HID_DSC(__VA_ARGS__)
/**
* @brief Initializer of endpoint descriptor for HID generic class.
*
* @param endpoint Endpoint number.
*/
#define APP_USBD_HID_GENERIC_EP_DSC(endpoint) \
APP_USBD_HID_EP_DSC(endpoint, NRF_DRV_USBD_EPSIZE, 1)
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* APP_USBD_HID_GENERIC_DESC_H__ */

View File

@@ -1,210 +0,0 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef APP_USBD_HID_GENERIC_INTERNAL_H__
#define APP_USBD_HID_GENERIC_INTERNAL_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "app_usbd_hid.h"
#include "nrf_queue.h"
/**
* @defgroup app_usbd_hid_generic_internal USB HID generic internals
* @ingroup app_usbd_hid_generic
*
* @brief @tagAPI52840 Module with types, definitions, and API used by the HID generic protocol.
* @{
*/
/**
* @brief Forward declaration of HID generic class type.
*
*/
APP_USBD_CLASS_FORWARD(app_usbd_hid_generic);
/**
* @brief HID generic part of class instance data.
*
*/
typedef struct {
app_usbd_hid_inst_t hid_inst; //!< HID instance data.
nrf_queue_t const * p_rep_in_queue; //!< Input report queue.
} app_usbd_hid_generic_inst_t;
/**
* @brief HID generic context
*
*/
typedef struct {
app_usbd_hid_ctx_t hid_ctx; //!< HID class context.
} app_usbd_hid_generic_ctx_t;
/**
* @brief HID generic configuration macro.
*
* Used by @ref APP_USBD_HID_GENERIC_GLOBAL_DEF.
*
* @param iface Interface number.
* @param endpoints Endpoint list.
*/
#define APP_USBD_HID_GENERIC_CONFIG(iface, endpoints) ((iface, BRACKET_EXTRACT(endpoints)))
/**
* @brief Specific class constant data for HID generic class.
*/
#define APP_USBD_HID_GENERIC_INSTANCE_SPECIFIC_DEC app_usbd_hid_generic_inst_t inst;
/**
* @brief Specific class data for HID generic class.
*/
#define APP_USBD_HID_GENERIC_DATA_SPECIFIC_DEC app_usbd_hid_generic_ctx_t ctx;
/**
* @brief Default interval value
*
*/
#define APP_USBD_HID_GENERIC_DEFAULT_INTERVAL 0x01
#define APP_USBD_HID_GENERIC_INTERVAL(ep) \
(APP_USBD_EXTRACT_INTERVAL_FLAG(ep) ? APP_USBD_EXTRACT_INTERVAL_VALUE(ep) : APP_USBD_HID_GENERIC_DEFAULT_INTERVAL),
/**
* @brief Configure internal part of HID generic instance.
*
* @param report_buff_in Input report buffers array.
* @param report_buff_out Output report buffer.
* @param report_buff_feature Feature report buffer.
* @param user_ev_handler User event handler.
* @param in_report_queue IN report queue.
* @param subclass_descriptors HID subclass descriptors.
* @param subclass_boot Subclass boot (@ref app_usbd_hid_subclass_t).
* @param protocol HID protocol (@ref app_usbd_hid_protocol_t).
* @param endpoint_list List of endpoints and intervals
*/
#define APP_USBD_HID_GENERIC_INST_CONFIG(report_buff_in, \
report_buff_out, \
report_buff_feature, \
user_ev_handler, \
in_report_queue, \
subclass_descriptors, \
subclass_boot, \
protocol, \
endpoint_list) \
.inst = { \
.hid_inst = APP_USBD_HID_INST_CONFIG(subclass_descriptors, \
subclass_boot, \
protocol, \
report_buff_in, \
report_buff_out, \
report_buff_feature, \
user_ev_handler, \
&app_usbd_hid_generic_methods, \
endpoint_list), \
.p_rep_in_queue = in_report_queue, \
}
/**
* @brief Public HID generic interface.
*/
extern const app_usbd_hid_methods_t app_usbd_hid_generic_methods;
/**
* @brief Public HID generic class interface.
*/
extern const app_usbd_class_methods_t app_usbd_generic_class_methods;
/**
* @brief Global definition of @ref app_usbd_hid_generic_t class.
*
* @ref APP_USBD_HID_GENERIC_GLOBAL_DEF
*/
/*lint -esym( 40, APP_USBD_HID_GENERIC_INTERVAL) */
#define APP_USBD_HID_GENERIC_GLOBAL_DEF_INTERNAL(instance_name, \
interface_number, \
user_ev_handler, \
endpoint_list, \
subclass_descriptors, \
report_in_queue_size, \
report_out_maxsize, \
report_feature_maxsize, \
subclass_boot, \
protocol) \
static app_usbd_hid_report_buffer_t CONCAT_2(instance_name, _in); \
APP_USBD_HID_GENERIC_GLOBAL_OUT_REP_DEF(CONCAT_2(instance_name, _out), \
report_out_maxsize + 1); \
APP_USBD_HID_GENERIC_GLOBAL_FEATURE_REP_DEF(CONCAT_2(instance_name, _feature), \
report_feature_maxsize + 1); \
static uint8_t CONCAT_2(instance_name, _ep)[]= \
{MACRO_MAP(APP_USBD_HID_GENERIC_INTERVAL,BRACKET_EXTRACT(endpoint_list))}; \
NRF_QUEUE_DEF(app_usbd_hid_report_buffer_t, \
instance_name##_queue, \
report_in_queue_size, \
NRF_QUEUE_MODE_OVERFLOW); \
APP_USBD_CLASS_INST_GLOBAL_DEF( \
instance_name, \
app_usbd_hid_generic, \
&app_usbd_generic_class_methods, \
APP_USBD_HID_GENERIC_CONFIG(interface_number, endpoint_list), \
(APP_USBD_HID_GENERIC_INST_CONFIG(&CONCAT_2(instance_name, _in), \
&CONCAT_2(instance_name, _out), \
&CONCAT_2(instance_name, _feature), \
user_ev_handler, \
&instance_name##_queue, \
subclass_descriptors, \
subclass_boot, \
protocol, \
CONCAT_2(instance_name, _ep))) \
)
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* APP_USBD_HID_GENERIC_INTERNAL_H__ */

View File

@@ -1,613 +0,0 @@
/**
* Copyright (c) 2016 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "sdk_common.h"
#if NRF_MODULE_ENABLED(APP_USBD_HID_KBD)
#include <string.h>
#include "app_usbd_hid_kbd.h"
#include "app_util_platform.h"
/**
* @defgroup app_usbd_hid_kbd_internals USB HID keyboard internals
* @{
* @ingroup app_usbd_hid_kbd
* @internal
*/
STATIC_ASSERT(sizeof(app_usbd_hid_descriptor_t) == 6);
/**
* @brief Auxiliary function to access HID keyboard context data.
*
* @param[in] p_inst class instance data.
*
* @return HID keyboard instance data context.
*/
static inline app_usbd_hid_kbd_ctx_t * hid_kbd_ctx_get(app_usbd_hid_kbd_t const * p_kbd)
{
ASSERT(p_kbd != NULL);
ASSERT(p_kbd->specific.p_data != NULL);
return &p_kbd->specific.p_data->ctx;
}
/**
* @brief Auxiliary function to access HID keyboard instance data.
*
* @param[in] p_inst class instance data.
*
* @return HID keyboard instance data.
*/
static inline app_usbd_hid_kbd_t const * hid_kbd_get(app_usbd_class_inst_t const * p_inst)
{
ASSERT(p_inst != NULL);
return (app_usbd_hid_kbd_t const *)p_inst;
}
/**
* @brief Returns keyboard report buffer handle.
*
* @param[in] p_kbd HID keyboard instance.
*
* @return HID report buffer.
*/
static inline
app_usbd_hid_report_buffer_t const * hid_kbd_rep_buffer_get(app_usbd_hid_kbd_t const * p_kbd)
{
ASSERT(p_kbd != NULL);
app_usbd_hid_inst_t const * p_hinst = &p_kbd->specific.inst.hid_inst;
app_usbd_hid_kbd_ctx_t * p_kbd_ctx = hid_kbd_ctx_get(p_kbd);
app_usbd_hid_report_buffer_t * p_rep_buff = app_usbd_hid_rep_buff_in_get(p_hinst);
p_rep_buff->p_buff = p_kbd_ctx->report_buff;
p_rep_buff->size = sizeof(p_kbd_ctx->report_buff);
/*Keyboard has only one report input/output report buffer */
return app_usbd_hid_rep_buff_in_get(p_hinst);
}
/**
* @brief Auxiliary function to prepare report transfer buffer to next transfer.
*
* @param[in] p_kbd HID keyboard instance.
*
* @retval true Next transfer is required.
* @retval false Next transfer is not required.
*/
static inline bool hid_kbd_transfer_next(app_usbd_hid_kbd_t const * p_kbd)
{
/*Send report only when state has changed*/
app_usbd_hid_report_buffer_t const * p_rep_buffer = hid_kbd_rep_buffer_get(p_kbd);
app_usbd_hid_kbd_ctx_t * p_kbd_ctx = hid_kbd_ctx_get(p_kbd);
if (memcmp(p_rep_buffer->p_buff, &p_kbd_ctx->rep, p_rep_buffer->size))
{
memcpy(p_rep_buffer->p_buff, &p_kbd_ctx->rep, p_rep_buffer->size);
return true;
}
return false;
}
/**
* @brief Triggers IN endpoint transfer.
*
* @param[in] p_kbd HID keyboard instance.
*
* @return Standard error code.
*/
static inline ret_code_t hid_kbd_transfer_set(app_usbd_hid_kbd_t const * p_kbd)
{
app_usbd_class_inst_t const * p_inst = (app_usbd_class_inst_t const *)p_kbd;
app_usbd_hid_kbd_ctx_t * p_kbd_ctx = hid_kbd_ctx_get(p_kbd);
nrf_drv_usbd_ep_t ep_addr = app_usbd_hid_epin_addr_get(p_inst);
app_usbd_hid_state_flag_clr(&p_kbd_ctx->hid_ctx, APP_USBD_HID_STATE_FLAG_TRANS_IN_PROGRESS);
if (!hid_kbd_transfer_next(p_kbd))
{
/* Transfer buffer hasn't changed since last transfer. No need to setup
* next transfer.
* */
return NRF_SUCCESS;
}
app_usbd_hid_report_buffer_t const * p_rep_buffer = hid_kbd_rep_buffer_get(p_kbd);
NRF_DRV_USBD_TRANSFER_IN(transfer, p_rep_buffer->p_buff, p_rep_buffer->size);
ret_code_t ret;
CRITICAL_REGION_ENTER();
ret = app_usbd_ep_transfer(ep_addr, &transfer);
if (ret == NRF_SUCCESS)
{
app_usbd_hid_state_flag_set(&p_kbd_ctx->hid_ctx, APP_USBD_HID_STATE_FLAG_TRANS_IN_PROGRESS);
}
CRITICAL_REGION_EXIT();
return ret;
}
ret_code_t app_usbd_hid_kbd_modifier_state_set(app_usbd_hid_kbd_t const * p_kbd,
app_usbd_hid_kbd_modifier_t modifier,
bool state)
{
app_usbd_hid_kbd_ctx_t * p_kbd_ctx = hid_kbd_ctx_get(p_kbd);
bool actual_state = (p_kbd_ctx->rep.modifier & modifier) != 0;
if (actual_state == state)
{
/*Modifier has already the same state*/
return NRF_SUCCESS;
}
app_usbd_hid_access_lock(&p_kbd_ctx->hid_ctx);
if (state)
{
p_kbd_ctx->rep.modifier |= modifier;
}
else
{
p_kbd_ctx->rep.modifier &= ~modifier;
}
app_usbd_hid_access_unlock(&p_kbd_ctx->hid_ctx);
if (app_usbd_hid_trans_required(&p_kbd_ctx->hid_ctx))
{
/*New transfer need to be triggered*/
return hid_kbd_transfer_set(p_kbd);
}
return NRF_SUCCESS;
}
ret_code_t app_usbd_hid_kbd_key_control(app_usbd_hid_kbd_t const * p_kbd,
app_usbd_hid_kbd_codes_t key,
bool press)
{
app_usbd_hid_kbd_ctx_t * p_kbd_ctx = hid_kbd_ctx_get(p_kbd);
uint8_t * destination = NULL;
if (press)
{
for (size_t i = 0; i < ARRAY_SIZE(p_kbd_ctx->rep.key_table); ++i)
{
if (p_kbd_ctx->rep.key_table[i] == key)
{
/*Already pressed*/
return NRF_SUCCESS;
}
if ((destination == NULL) && (p_kbd_ctx->rep.key_table[i] == 0))
{
destination = &p_kbd_ctx->rep.key_table[i];
}
}
if (destination == NULL)
{
return NRF_ERROR_BUSY;
}
}
else
{
/*Find if key is pressed*/
for (size_t i = 0; i < ARRAY_SIZE(p_kbd_ctx->rep.key_table); ++i)
{
if (p_kbd_ctx->rep.key_table[i] == key)
{
destination = &p_kbd_ctx->rep.key_table[i];
break;
}
}
if (destination == NULL)
{
/*Key hasn't been pressed*/
return NRF_SUCCESS;
}
}
/*Save destination*/
app_usbd_hid_access_lock(&p_kbd_ctx->hid_ctx);
*destination = press ? key : 0;
app_usbd_hid_access_unlock(&p_kbd_ctx->hid_ctx);
if (app_usbd_hid_trans_required(&p_kbd_ctx->hid_ctx))
{
/*New transfer need to be triggered*/
return hid_kbd_transfer_set(p_kbd);
}
return NRF_SUCCESS;
}
bool app_usbd_hid_kbd_led_state_get(app_usbd_hid_kbd_t const * p_kbd,
app_usbd_hid_kbd_led_t led)
{
app_usbd_hid_kbd_ctx_t * p_kbd_ctx = hid_kbd_ctx_get(p_kbd);
return (p_kbd_ctx->leds_state & led) != 0;
}
const void * app_usbd_hid_kbd_in_report_get(app_usbd_hid_kbd_t const * p_kbd,
size_t * p_size)
{
app_usbd_hid_inst_t const * p_kinst = &p_kbd->specific.inst.hid_inst;
*p_size = p_kinst->p_rep_buffer_in->size;
return p_kinst->p_rep_buffer_in->p_buff;
}
const void * app_usbd_hid_kbd_out_report_get(app_usbd_hid_kbd_t const * p_kbd,
size_t * p_size)
{
app_usbd_hid_inst_t const * p_kinst = &p_kbd->specific.inst.hid_inst;
*p_size = p_kinst->p_rep_buffer_out->size;
return p_kinst->p_rep_buffer_out->p_buff;
}
/**
* @brief @ref app_usbd_hid_interface_t::on_get_report
*/
static ret_code_t hid_kbd_on_get_report(app_usbd_class_inst_t const * p_inst,
app_usbd_setup_evt_t const * p_setup_ev)
{
app_usbd_hid_kbd_t const * p_kinst = hid_kbd_get(p_inst);
uint8_t const * p_rep_buffer = NULL;
size_t buffer_size = 0;
if (p_setup_ev->setup.wValue.hb == APP_USBD_HID_REPORT_TYPE_INPUT)
{
p_rep_buffer = app_usbd_hid_kbd_in_report_get(p_kinst, &buffer_size);
}
else if (p_setup_ev->setup.wValue.hb == APP_USBD_HID_REPORT_TYPE_OUTPUT)
{
p_rep_buffer = app_usbd_hid_kbd_out_report_get(p_kinst, &buffer_size);
}
else
{
return NRF_ERROR_NOT_SUPPORTED;
}
/* Return LEDs state (only the second byte) */
return app_usbd_core_setup_rsp(&(p_setup_ev->setup), p_rep_buffer + 1, buffer_size - 1);
}
static ret_code_t hid_kbd_on_set_report_data_cb(nrf_drv_usbd_ep_status_t status, void * p_context)
{
if (status != NRF_USBD_EP_OK)
{
return NRF_ERROR_INTERNAL;
}
app_usbd_hid_kbd_t const * p_kbd = p_context;
app_usbd_hid_report_buffer_t const * p_rep_buff;
p_rep_buff = app_usbd_hid_rep_buff_out_get(&p_kbd->specific.inst.hid_inst);
/*Update LEDs state*/
app_usbd_hid_kbd_ctx_t * p_kbd_ctx = hid_kbd_ctx_get(p_kbd);
p_kbd_ctx->leds_state = p_rep_buff->p_buff[1];
app_usbd_hid_user_ev_handler_t handler = p_kbd->specific.inst.hid_inst.user_event_handler;
handler((app_usbd_class_inst_t const *)(p_kbd), APP_USBD_HID_USER_EVT_OUT_REPORT_READY);
return NRF_SUCCESS;
}
/**
* @brief @ref app_usbd_hid_interface_t::hid_kbd_on_set_report
*/
static ret_code_t hid_kbd_on_set_report(app_usbd_class_inst_t const * p_inst,
app_usbd_setup_evt_t const * p_setup_ev)
{
app_usbd_hid_kbd_t const * p_kbd = hid_kbd_get(p_inst);
/*Request setup data*/
app_usbd_hid_report_buffer_t const * p_rep_buff;
p_rep_buff = app_usbd_hid_rep_buff_out_get(&p_kbd->specific.inst.hid_inst);
p_rep_buff->p_buff[0] = 0;
NRF_DRV_USBD_TRANSFER_OUT(transfer, p_rep_buff->p_buff + 1, p_rep_buff->size - 1);
ret_code_t ret;
CRITICAL_REGION_ENTER();
ret = app_usbd_ep_transfer(NRF_DRV_USBD_EPOUT0, &transfer);
if (ret == NRF_SUCCESS)
{
app_usbd_core_setup_data_handler_desc_t desc = {
.handler = hid_kbd_on_set_report_data_cb,
.p_context = (app_usbd_hid_kbd_t *)p_kbd
};
ret = app_usbd_core_setup_data_handler_set(NRF_DRV_USBD_EPOUT0, &desc);
}
CRITICAL_REGION_EXIT();
return ret;
}
/**
* @brief @ref app_usbd_hid_interface_t::hid_kbd_ep_transfer_in
*/
static ret_code_t hid_kbd_ep_transfer_in(app_usbd_class_inst_t const * p_inst)
{
return hid_kbd_transfer_set((app_usbd_hid_kbd_t const *)p_inst);
}
/**
* @brief @ref app_usbd_class_interface_t::event_handler
*/
static ret_code_t hid_kbd_event_handler(app_usbd_class_inst_t const * p_inst,
app_usbd_complex_evt_t const * p_event)
{
ASSERT(p_inst != NULL);
ASSERT(p_event != NULL);
app_usbd_hid_kbd_t const * p_kbd = hid_kbd_get(p_inst);
app_usbd_hid_inst_t const * p_hinst = &p_kbd->specific.inst.hid_inst;
app_usbd_hid_kbd_ctx_t * p_kbd_ctx = hid_kbd_ctx_get(p_kbd);
app_usbd_hid_ctx_t * p_hid_ctx = &p_kbd_ctx->hid_ctx;
/*Try handle event by generic HID event handler*/
return app_usbd_hid_event_handler(p_inst, p_hinst, p_hid_ctx, p_event);
}
ret_code_t hid_kbd_clear_buffer(app_usbd_class_inst_t const * p_inst)
{
ASSERT(p_inst != NULL);
app_usbd_hid_kbd_t const * p_kbd = hid_kbd_get(p_inst);
app_usbd_hid_kbd_ctx_t * p_kbd_ctx = hid_kbd_ctx_get(p_kbd);
app_usbd_hid_report_buffer_t const * p_rep_buffer = hid_kbd_rep_buffer_get(p_kbd);
memset(p_rep_buffer->p_buff, 0, p_rep_buffer->size);
memset(p_kbd_ctx->report_buff, 0, p_rep_buffer->size);
memset(&p_kbd_ctx->rep, 0, p_rep_buffer->size);
CRITICAL_REGION_ENTER();
nrf_drv_usbd_ep_t ep_addr = app_usbd_hid_epin_addr_get(p_inst);
ASSERT(!NRF_USBD_EPISO_CHECK(ep_addr));
if (NRF_USBD_EPIN_CHECK(ep_addr))
{
nrf_drv_usbd_ep_abort(ep_addr);
}
app_usbd_hid_state_flag_clr(&p_kbd_ctx->hid_ctx, APP_USBD_HID_STATE_FLAG_TRANS_IN_PROGRESS);
CRITICAL_REGION_EXIT();
return NRF_SUCCESS;
}
static uint8_t hid_kbd_get_class_descriptors_count(app_usbd_class_inst_t const * p_inst)
{
app_usbd_hid_kbd_t const * p_kbd = hid_kbd_get(p_inst);
app_usbd_hid_inst_t const * p_hinst = &p_kbd->specific.inst.hid_inst;
return p_hinst->subclass_desc_count;
}
static app_usbd_descriptor_t hid_kbd_get_class_descriptors_type(
app_usbd_class_inst_t const * p_inst,
uint8_t desc_num)
{
app_usbd_hid_kbd_t const * p_kbd = hid_kbd_get(p_inst);
app_usbd_hid_inst_t const * p_hinst = &p_kbd->specific.inst.hid_inst;
return p_hinst->p_subclass_desc[desc_num]->type;
}
static size_t hid_kbd_get_class_descriptors_length(app_usbd_class_inst_t const * p_inst,
uint8_t desc_num)
{
app_usbd_hid_kbd_t const * p_kbd = hid_kbd_get(p_inst);
app_usbd_hid_inst_t const * p_hinst = &p_kbd->specific.inst.hid_inst;
return p_hinst->p_subclass_desc[desc_num]->size;
}
static const uint8_t * hid_kbd_get_class_descriptors_data(app_usbd_class_inst_t const * p_inst,
uint8_t desc_num,
uint32_t cur_byte)
{
app_usbd_hid_kbd_t const * p_kbd = hid_kbd_get(p_inst);
app_usbd_hid_inst_t const * p_hinst = &p_kbd->specific.inst.hid_inst;
const uint8_t * p_byte = &p_hinst->p_subclass_desc[desc_num]->p_data[cur_byte];
return p_byte;
}
static bool hid_kbd_feed_descriptors(app_usbd_class_descriptor_ctx_t * p_ctx,
app_usbd_class_inst_t const * p_inst,
uint8_t * p_buff,
size_t max_size)
{
static uint8_t ifaces = 0;
ifaces = app_usbd_class_iface_count_get(p_inst);
app_usbd_hid_kbd_t const * p_kbd = hid_kbd_get(p_inst);
APP_USBD_CLASS_DESCRIPTOR_BEGIN(p_ctx, p_buff, max_size);
static uint8_t i = 0;
for (i = 0; i < ifaces; i++)
{
/* INTERFACE DESCRIPTOR */
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x09); // bLength
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_DESCRIPTOR_INTERFACE); // bDescriptorType = Interface
static app_usbd_class_iface_conf_t const * p_cur_iface = NULL;
p_cur_iface = app_usbd_class_iface_get(p_inst, i);
APP_USBD_CLASS_DESCRIPTOR_WRITE(app_usbd_class_iface_number_get(p_cur_iface)); // bInterfaceNumber
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x00); // bAlternateSetting
APP_USBD_CLASS_DESCRIPTOR_WRITE(app_usbd_class_iface_ep_count_get(p_cur_iface)); // bNumEndpoints
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_HID_CLASS); // bInterfaceClass = HID
APP_USBD_CLASS_DESCRIPTOR_WRITE(p_kbd->specific.inst.hid_inst.subclass_boot); // bInterfaceSubclass (Boot Interface)
APP_USBD_CLASS_DESCRIPTOR_WRITE(p_kbd->specific.inst.hid_inst.protocol); // bInterfaceProtocol
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x00); // iInterface
/* HID DESCRIPTOR */
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x09); // bLength
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_HID_DESCRIPTOR_HID); // bDescriptorType = HID
APP_USBD_CLASS_DESCRIPTOR_WRITE(LSB_16(APP_USBD_HID_BCD_VER)); // bcdHID LSB
APP_USBD_CLASS_DESCRIPTOR_WRITE(MSB_16(APP_USBD_HID_BCD_VER)); // bcdHID MSB
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_HID_COUNTRY_NOT_SUPPORTED); // bCountryCode
APP_USBD_CLASS_DESCRIPTOR_WRITE(hid_kbd_get_class_descriptors_count(p_inst)); // bNumDescriptors
static uint8_t class_desc_cnt = 0;
class_desc_cnt = hid_kbd_get_class_descriptors_count(p_inst);
static uint8_t j = 0;
static uint16_t class_desc_len = 0;
for (j = 0; j < class_desc_cnt; j++)
{
APP_USBD_CLASS_DESCRIPTOR_WRITE(hid_kbd_get_class_descriptors_type(p_inst, j)); // bDescriptorType
class_desc_len = hid_kbd_get_class_descriptors_length(p_inst, j);
APP_USBD_CLASS_DESCRIPTOR_WRITE(LSB_16(class_desc_len)); // wDescriptorLength LSB
APP_USBD_CLASS_DESCRIPTOR_WRITE(MSB_16(class_desc_len)); // wDescriptorLength MSB
}
static uint8_t endpoints = 0;
endpoints = app_usbd_class_iface_ep_count_get(p_cur_iface);
for (j = 0; j < endpoints; j++)
{
/* ENDPOINT DESCRIPTOR */
APP_USBD_CLASS_DESCRIPTOR_WRITE(0x07); // bLength
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_DESCRIPTOR_ENDPOINT); // bDescriptorType = Endpoint
static app_usbd_class_ep_conf_t const * p_cur_ep = NULL;
p_cur_ep = app_usbd_class_iface_ep_get(p_cur_iface, j);
APP_USBD_CLASS_DESCRIPTOR_WRITE(app_usbd_class_ep_address_get(p_cur_ep)); // bEndpointAddress
APP_USBD_CLASS_DESCRIPTOR_WRITE(APP_USBD_DESCRIPTOR_EP_ATTR_TYPE_INTERRUPT); // bmAttributes
APP_USBD_CLASS_DESCRIPTOR_WRITE(LSB_16(NRF_DRV_USBD_EPSIZE)); // wMaxPacketSize LSB
APP_USBD_CLASS_DESCRIPTOR_WRITE(MSB_16(NRF_DRV_USBD_EPSIZE)); // wMaxPacketSize MSB
APP_USBD_CLASS_DESCRIPTOR_WRITE(p_kbd->specific.inst.hid_inst.p_ep_interval[j]); // bInterval
}
}
APP_USBD_CLASS_DESCRIPTOR_END();
}
ret_code_t hid_kbd_on_set_protocol(app_usbd_hid_kbd_t const * p_kbd, app_usbd_hid_user_event_t ev)
{
app_usbd_hid_kbd_ctx_t * p_kbd_ctx = hid_kbd_ctx_get(p_kbd);
if (ev == APP_USBD_HID_USER_EVT_SET_BOOT_PROTO)
{
p_kbd_ctx->hid_ctx.selected_protocol = APP_USBD_HID_PROTO_BOOT;
}
else if (ev == APP_USBD_HID_USER_EVT_SET_REPORT_PROTO)
{
p_kbd_ctx->hid_ctx.selected_protocol = APP_USBD_HID_PROTO_REPORT;
}
else
{
return NRF_ERROR_NOT_SUPPORTED;
}
return NRF_SUCCESS;
}
static ret_code_t hid_kbd_on_idle(app_usbd_class_inst_t const * p_inst, uint8_t report_id)
{
UNUSED_PARAMETER(report_id);
app_usbd_hid_kbd_t const * p_kbd = (app_usbd_hid_kbd_t const *)p_inst;
app_usbd_hid_kbd_ctx_t * p_kbd_ctx = hid_kbd_ctx_get(p_kbd);
nrf_drv_usbd_ep_t ep_addr = app_usbd_hid_epin_addr_get(p_inst);
app_usbd_hid_state_flag_clr(&p_kbd_ctx->hid_ctx, APP_USBD_HID_STATE_FLAG_TRANS_IN_PROGRESS);
app_usbd_hid_report_buffer_t const * p_rep_buffer = hid_kbd_rep_buffer_get(p_kbd);
NRF_DRV_USBD_TRANSFER_IN(transfer, p_rep_buffer->p_buff, p_rep_buffer->size);
UNUSED_RETURN_VALUE(hid_kbd_transfer_next(p_kbd));
ret_code_t ret;
CRITICAL_REGION_ENTER();
ret = app_usbd_ep_transfer(ep_addr, &transfer);
if (ret == NRF_SUCCESS)
{
app_usbd_hid_state_flag_set(&p_kbd_ctx->hid_ctx, APP_USBD_HID_STATE_FLAG_TRANS_IN_PROGRESS);
}
CRITICAL_REGION_EXIT();
return NRF_SUCCESS;
}
/** @} */
const app_usbd_hid_methods_t app_usbd_hid_kbd_methods = {
.on_get_report = hid_kbd_on_get_report,
.on_set_report = hid_kbd_on_set_report,
.ep_transfer_in = hid_kbd_ep_transfer_in,
.ep_transfer_out = NULL,
.subclass_count = hid_kbd_get_class_descriptors_count,
.subclass_length = hid_kbd_get_class_descriptors_length,
.subclass_data = hid_kbd_get_class_descriptors_data,
.on_idle = hid_kbd_on_idle,
};
const app_usbd_class_methods_t app_usbd_hid_kbd_class_methods = {
.event_handler = hid_kbd_event_handler,
.feed_descriptors = hid_kbd_feed_descriptors,
};
#endif //NRF_MODULE_ENABLED(APP_USBD_HID_KBD)

View File

@@ -1,330 +0,0 @@
/**
* Copyright (c) 2017 - 2021, Nordic Semiconductor ASA
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form, except as embedded into a Nordic
* Semiconductor ASA integrated circuit in a product or a software update for
* such product, must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. Neither the name of Nordic Semiconductor ASA nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* 4. This software, with or without modification, must only be used with a
* Nordic Semiconductor ASA integrated circuit.
*
* 5. Any software provided in binary form under this license must not be reverse
* engineered, decompiled, modified and/or disassembled.
*
* THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#ifndef APP_USBD_HID_KBD_H__
#define APP_USBD_HID_KBD_H__
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include <stdbool.h>
#include "nrf_drv_usbd.h"
#include "app_usbd_class_base.h"
#include "app_usbd_hid_types.h"
#include "app_usbd_hid.h"
#include "app_usbd.h"
#include "app_usbd_core.h"
#include "app_usbd_descriptor.h"
#include "app_usbd_hid_kbd_desc.h"
#include "app_usbd_hid_kbd_internal.h"
/**
* @defgroup app_usbd_hid_kbd USB HID keyboard
* @ingroup app_usbd_hid
*
* @brief @tagAPI52840 Module with types, definitions, and API used by the HID keyboard class.
* @{
*/
/**
* @brief HID keyboard codes.
*/
typedef enum {
APP_USBD_HID_KBD_A = 4, /**<KBD_A code*/
APP_USBD_HID_KBD_B = 5, /**<KBD_B code*/
APP_USBD_HID_KBD_C = 6, /**<KBD_C code*/
APP_USBD_HID_KBD_D = 7, /**<KBD_D code*/
APP_USBD_HID_KBD_E = 8, /**<KBD_E code*/
APP_USBD_HID_KBD_F = 9, /**<KBD_F code*/
APP_USBD_HID_KBD_G = 10, /**<KBD_G code*/
APP_USBD_HID_KBD_H = 11, /**<KBD_H code*/
APP_USBD_HID_KBD_I = 12, /**<KBD_I code*/
APP_USBD_HID_KBD_J = 13, /**<KBD_J code*/
APP_USBD_HID_KBD_K = 14, /**<KBD_K code*/
APP_USBD_HID_KBD_L = 15, /**<KBD_L code*/
APP_USBD_HID_KBD_M = 16, /**<KBD_M code*/
APP_USBD_HID_KBD_N = 17, /**<KBD_N code*/
APP_USBD_HID_KBD_O = 18, /**<KBD_O code*/
APP_USBD_HID_KBD_P = 19, /**<KBD_P code*/
APP_USBD_HID_KBD_Q = 20, /**<KBD_Q code*/
APP_USBD_HID_KBD_R = 21, /**<KBD_R code*/
APP_USBD_HID_KBD_S = 22, /**<KBD_S code*/
APP_USBD_HID_KBD_T = 23, /**<KBD_T code*/
APP_USBD_HID_KBD_U = 24, /**<KBD_U code*/
APP_USBD_HID_KBD_V = 25, /**<KBD_V code*/
APP_USBD_HID_KBD_W = 26, /**<KBD_W code*/
APP_USBD_HID_KBD_X = 27, /**<KBD_X code*/
APP_USBD_HID_KBD_Y = 28, /**<KBD_Y code*/
APP_USBD_HID_KBD_Z = 29, /**<KBD_Z code*/
APP_USBD_HID_KBD_1 = 30, /**<KBD_1 code*/
APP_USBD_HID_KBD_2 = 31, /**<KBD_2 code*/
APP_USBD_HID_KBD_3 = 32, /**<KBD_3 code*/
APP_USBD_HID_KBD_4 = 33, /**<KBD_4 code*/
APP_USBD_HID_KBD_5 = 34, /**<KBD_5 code*/
APP_USBD_HID_KBD_6 = 35, /**<KBD_6 code*/
APP_USBD_HID_KBD_7 = 36, /**<KBD_7 code*/
APP_USBD_HID_KBD_8 = 37, /**<KBD_8 code*/
APP_USBD_HID_KBD_9 = 38, /**<KBD_9 code*/
APP_USBD_HID_KBD_0 = 39, /**<KBD_0 code*/
APP_USBD_HID_KBD_ENTER = 40, /**<KBD_ENTER code*/
APP_USBD_HID_KBD_ESCAPE = 41, /**<KBD_ESCAPE code*/
APP_USBD_HID_KBD_BACKSPACE = 42, /**<KBD_BACKSPACE code*/
APP_USBD_HID_KBD_TAB = 43, /**<KBD_TAB code*/
APP_USBD_HID_KBD_SPACEBAR = 44, /**<KBD_SPACEBAR code*/
APP_USBD_HID_KBD_UNDERSCORE = 45, /**<KBD_UNDERSCORE code*/
APP_USBD_HID_KBD_PLUS = 46, /**<KBD_PLUS code*/
APP_USBD_HID_KBD_OPEN_BRACKET = 47, /**<KBD_OPEN_BRACKET code*/
APP_USBD_HID_KBD_CLOSE_BRACKET = 48, /**<KBD_CLOSE_BRACKET code*/
APP_USBD_HID_KBD_BACKSLASH = 49, /**<KBD_BACKSLASH code*/
APP_USBD_HID_KBD_ASH = 50, /**<KBD_ASH code*/
APP_USBD_HID_KBD_COLON = 51, /**<KBD_COLON code*/
APP_USBD_HID_KBD_QUOTE = 52, /**<KBD_QUOTE code*/
APP_USBD_HID_KBD_TILDE = 53, /**<KBD_TILDE code*/
APP_USBD_HID_KBD_COMMA = 54, /**<KBD_COMMA code*/
APP_USBD_HID_KBD_DOT = 55, /**<KBD_DOT code*/
APP_USBD_HID_KBD_SLASH = 56, /**<KBD_SLASH code*/
APP_USBD_HID_KBD_CAPS_LOCK = 57, /**<KBD_CAPS_LOCK code*/
APP_USBD_HID_KBD_F1 = 58, /**<KBD_F1 code*/
APP_USBD_HID_KBD_F2 = 59, /**<KBD_F2 code*/
APP_USBD_HID_KBD_F3 = 60, /**<KBD_F3 code*/
APP_USBD_HID_KBD_F4 = 61, /**<KBD_F4 code*/
APP_USBD_HID_KBD_F5 = 62, /**<KBD_F5 code*/
APP_USBD_HID_KBD_F6 = 63, /**<KBD_F6 code*/
APP_USBD_HID_KBD_F7 = 64, /**<KBD_F7 code*/
APP_USBD_HID_KBD_F8 = 65, /**<KBD_F8 code*/
APP_USBD_HID_KBD_F9 = 66, /**<KBD_F9 code*/
APP_USBD_HID_KBD_F10 = 67, /**<KBD_F10 code*/
APP_USBD_HID_KBD_F11 = 68, /**<KBD_F11 code*/
APP_USBD_HID_KBD_F12 = 69, /**<KBD_F12 code*/
APP_USBD_HID_KBD_PRINTSCREEN = 70, /**<KBD_PRINTSCREEN code*/
APP_USBD_HID_KBD_SCROLL_LOCK = 71, /**<KBD_SCROLL_LOCK code*/
APP_USBD_HID_KBD_PAUSE = 72, /**<KBD_PAUSE code*/
APP_USBD_HID_KBD_INSERT = 73, /**<KBD_INSERT code*/
APP_USBD_HID_KBD_HOME = 74, /**<KBD_HOME code*/
APP_USBD_HID_KBD_PAGEUP = 75, /**<KBD_PAGEUP code*/
APP_USBD_HID_KBD_DELETE = 76, /**<KBD_DELETE code*/
APP_USBD_HID_KBD_END = 77, /**<KBD_END code*/
APP_USBD_HID_KBD_PAGEDOWN = 78, /**<KBD_PAGEDOWN code*/
APP_USBD_HID_KBD_RIGHT = 79, /**<KBD_RIGHT code*/
APP_USBD_HID_KBD_LEFT = 80, /**<KBD_LEFT code*/
APP_USBD_HID_KBD_DOWN = 81, /**<KBD_DOWN code*/
APP_USBD_HID_KBD_UP = 82, /**<KBD_UP code*/
APP_USBD_HID_KBD_KEYPAD_NUM_LOCK = 83, /**<KBD_KEYPAD_NUM_LOCK code*/
APP_USBD_HID_KBD_KEYPAD_DIVIDE = 84, /**<KBD_KEYPAD_DIVIDE code*/
APP_USBD_HID_KBD_KEYPAD_AT = 85, /**<KBD_KEYPAD_AT code*/
APP_USBD_HID_KBD_KEYPAD_MULTIPLY = 85, /**<KBD_KEYPAD_MULTIPLY code*/
APP_USBD_HID_KBD_KEYPAD_MINUS = 86, /**<KBD_KEYPAD_MINUS code*/
APP_USBD_HID_KBD_KEYPAD_PLUS = 87, /**<KBD_KEYPAD_PLUS code*/
APP_USBD_HID_KBD_KEYPAD_ENTER = 88, /**<KBD_KEYPAD_ENTER code*/
APP_USBD_HID_KBD_KEYPAD_1 = 89, /**<KBD_KEYPAD_1 code*/
APP_USBD_HID_KBD_KEYPAD_2 = 90, /**<KBD_KEYPAD_2 code*/
APP_USBD_HID_KBD_KEYPAD_3 = 91, /**<KBD_KEYPAD_3 code*/
APP_USBD_HID_KBD_KEYPAD_4 = 92, /**<KBD_KEYPAD_4 code*/
APP_USBD_HID_KBD_KEYPAD_5 = 93, /**<KBD_KEYPAD_5 code*/
APP_USBD_HID_KBD_KEYPAD_6 = 94, /**<KBD_KEYPAD_6 code*/
APP_USBD_HID_KBD_KEYPAD_7 = 95, /**<KBD_KEYPAD_7 code*/
APP_USBD_HID_KBD_KEYPAD_8 = 96, /**<KBD_KEYPAD_8 code*/
APP_USBD_HID_KBD_KEYPAD_9 = 97, /**<KBD_KEYPAD_9 code*/
APP_USBD_HID_KBD_KEYPAD_0 = 98, /**<KBD_KEYPAD_0 code*/
} app_usbd_hid_kbd_codes_t;
/**
* @brief HID keyboard modifier.
*/
typedef enum {
APP_USBD_HID_KBD_MODIFIER_NONE = 0x00, /**< MODIFIER_NONE bit*/
APP_USBD_HID_KBD_MODIFIER_LEFT_CTRL = 0x01, /**< MODIFIER_LEFT_CTRL bit*/
APP_USBD_HID_KBD_MODIFIER_LEFT_SHIFT = 0x02, /**< MODIFIER_LEFT_SHIFT bit*/
APP_USBD_HID_KBD_MODIFIER_LEFT_ALT = 0x04, /**< MODIFIER_LEFT_ALT bit*/
APP_USBD_HID_KBD_MODIFIER_LEFT_UI = 0x08, /**< MODIFIER_LEFT_UI bit*/
APP_USBD_HID_KBD_MODIFIER_RIGHT_CTRL = 0x10, /**< MODIFIER_RIGHT_CTRL bit*/
APP_USBD_HID_KBD_MODIFIER_RIGHT_SHIFT = 0x20, /**< MODIFIER_RIGHT_SHIFT bit*/
APP_USBD_HID_KBD_MODIFIER_RIGHT_ALT = 0x40, /**< MODIFIER_RIGHT_ALT bit*/
APP_USBD_HID_KBD_MODIFIER_RIGHT_UI = 0x80, /**< MODIFIER_RIGHT_UI bit*/
} app_usbd_hid_kbd_modifier_t;
/**
* @brief HID keyboard LEDs.
*/
typedef enum {
APP_USBD_HID_KBD_LED_NUM_LOCK = 0x01, /**< LED_NUM_LOCK id*/
APP_USBD_HID_KBD_LED_CAPS_LOCK = 0x02, /**< LED_CAPS_LOCK id*/
APP_USBD_HID_KBD_LED_SCROLL_LOCK = 0x04, /**< LED_SCROLL_LOCK id*/
APP_USBD_HID_KBD_LED_COMPOSE = 0x08, /**< LED_COMPOSE id*/
APP_USBD_HID_KBD_LED_KANA = 0x10, /**< LED_KANA id*/
} app_usbd_hid_kbd_led_t;
#ifdef DOXYGEN
/**
* @brief HID keyboard class instance type.
*
* @ref APP_USBD_CLASS_TYPEDEF
*/
typedef struct { } app_usbd_hid_kbd_t;
#else
/*lint -save -e10 -e26 -e123 -e505 */
APP_USBD_CLASS_TYPEDEF(app_usbd_hid_kbd, \
APP_USBD_HID_KBD_CONFIG(0, NRF_DRV_USBD_EPIN1), \
APP_USBD_HID_KBD_INSTANCE_SPECIFIC_DEC, \
APP_USBD_HID_KBD_DATA_SPECIFIC_DEC \
);
/*lint -restore*/
#endif
/**
* @brief Global definition of app_usbd_hid_kbd_t class.
*
* @param instance_name Name of global instance.
* @param interface_number Unique interface index.
* @param endpoint Input endpoint (@ref nrf_drv_usbd_ep_t).
* @param user_ev_handler User event handler (optional parameter: NULL might be passed here).
* @param subclass_boot Subclass boot (@ref app_usbd_hid_subclass_t).
*
* Example class definition:
* @code
APP_USBD_HID_KBD_GLOBAL_DEF(my_awesome_kbd, 0, NRF_DRV_USBD_EPIN1, NULL, APP_USBD_HID_SUBCLASS_BOOT);
* @endcode
*/
#define APP_USBD_HID_KBD_GLOBAL_DEF(instance_name, interface_number, endpoint, user_ev_handler, subclass_boot) \
APP_USBD_HID_GENERIC_SUBCLASS_REPORT_DESC(keyboard_desc, APP_USBD_HID_KBD_REPORT_DSC()); \
static const app_usbd_hid_subclass_desc_t * keyboard_descs[] = {&keyboard_desc}; \
APP_USBD_HID_KBD_GLOBAL_DEF_INTERNAL(instance_name, \
interface_number, \
endpoint, \
user_ev_handler, \
subclass_boot)
/**
* @brief Helper function to get class instance from HID keyboard internals.
*
* @param[in] p_kbd Keyboard instance (declared by @ref APP_USBD_HID_KBD_GLOBAL_DEF).
*
* @return Base class instance.
*/
static inline app_usbd_class_inst_t const *
app_usbd_hid_kbd_class_inst_get(app_usbd_hid_kbd_t const * p_kbd)
{
return &p_kbd->base;
}
/**
* @brief Helper function to get HID keyboard from base class instance.
*
* @param[in] p_inst Base class instance.
*
* @return HID keyboard class handle.
*/
static inline app_usbd_hid_kbd_t const *
app_usbd_hid_kbd_class_get(app_usbd_class_inst_t const * p_inst)
{
return (app_usbd_hid_kbd_t const *)p_inst;
}
/**
* @brief Set HID keyboard modifier state.
*
* @param[in] p_kbd Keyboard instance (declared by @ref APP_USBD_HID_KBD_GLOBAL_DEF).
* @param[in] modifier Type of modifier.
* @param[in] state State, true active, false inactive.
*
* @return Standard error code.
*/
ret_code_t app_usbd_hid_kbd_modifier_state_set(app_usbd_hid_kbd_t const * p_kbd,
app_usbd_hid_kbd_modifier_t modifier,
bool state);
/**
* @brief Press/release HID keyboard key.
*
* @param[in] p_kbd Keyboard instance (declared by @ref APP_USBD_HID_KBD_GLOBAL_DEF).
* @param[in] key Keyboard key code.
* @param[in] press True -> key press, false -> release.
*
* @return Standard error code.
*/
ret_code_t app_usbd_hid_kbd_key_control(app_usbd_hid_kbd_t const * p_kbd,
app_usbd_hid_kbd_codes_t key,
bool press);
/**
* @brief HID Keyboard LEDs state get.
*
* @param[in] p_kbd Keyboard instance (declared by @ref APP_USBD_HID_KBD_GLOBAL_DEF).
* @param[in] led LED code.
*
* @retval true LED is set.
* @retval false LED is not set.
*/
bool app_usbd_hid_kbd_led_state_get(app_usbd_hid_kbd_t const * p_kbd,
app_usbd_hid_kbd_led_t led);
/**
* @brief Function handling SET_PROTOCOL command.
*
*
* @param[in] p_kbd Keyboard instance.
* @param[in] ev User event.
*
* @return Standard error code.
*/
ret_code_t hid_kbd_on_set_protocol(app_usbd_hid_kbd_t const * p_kbd,
app_usbd_hid_user_event_t ev);
/**
* @brief Function that clears HID keyboard buffers and sends an empty report.
*
* @param[in] p_inst Base class instance.
*
* @return Standard error code.
*/
ret_code_t hid_kbd_clear_buffer(app_usbd_class_inst_t const * p_inst);
/** @} */
#ifdef __cplusplus
}
#endif
#endif /* APP_USBD_HID_KBD_H__ */

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