Random Number Generator driver

This commit is contained in:
Stephane D'Alu 2016-02-08 23:45:59 +01:00
parent 5af8452153
commit d9a3d8493c
8 changed files with 671 additions and 2 deletions

View File

@ -4,6 +4,7 @@ HALSRC += ${CHIBIOS_CONTRIB}/os/hal/src/hal_community.c \
${CHIBIOS_CONTRIB}/os/hal/src/nand.c \
${CHIBIOS_CONTRIB}/os/hal/src/onewire.c \
${CHIBIOS_CONTRIB}/os/hal/src/eicu.c \
${CHIBIOS_CONTRIB}/os/hal/src/crc.c
${CHIBIOS_CONTRIB}/os/hal/src/crc.c \
${CHIBIOS_CONTRIB}/os/hal/src/rng.c
HALINC += ${CHIBIOS_CONTRIB}/os/hal/include

View File

@ -32,6 +32,7 @@
/* Normal drivers.*/
#include "nand.h"
#include "eicu.h"
#include "rng.h"
/* Complex drivers.*/
#include "onewire.h"

141
os/hal/include/rng.h Normal file
View File

@ -0,0 +1,141 @@
/*
RNG for ChibiOS - Copyright (C) 2016 Stephane D'Alu
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#ifndef _RNG_H_
#define _RNG_H_
#if (HAL_USE_RNG == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief Enables the @p rngAcquireBus() and @p rngReleaseBus() APIs.
* @note Disabling this option saves both code and data space.
*/
#if !defined(RNG_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
#define RNG_USE_MUTUAL_EXCLUSION TRUE
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if NRF51_RNG_USE_RNG1 != TRUE && RNGSW_USE_RNG1 != TRUE
#error "RNG requires at least one LLD driver."
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Driver state machine possible states.
*/
typedef enum {
RNG_UNINIT, /* Not initialized. */
RNG_STOP, /* Stopped. */
RNG_READY, /* Ready. */
} rngstate_t;
#include "rng_lld.h"
//#include "rngsw.h" /* Include software LL driver */
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @name Low level driver helper macros
* @{
*/
/**
* @brief Wakes up the waiting thread.
*
* @param[in] rngp pointer to the @p RNGDriver object
*
* @notapi
*/
#define _rng_wakeup_isr(rngp) { \
osalSysLockFromISR(); \
osalThreadResumeI(&(rngp)->thread, MSG_OK); \
osalSysUnlockFromISR(); \
}
/**
* @brief Common ISR code.
* @details This code handles the portable part of the ISR code:
* - Callback invocation.
* - Waiting thread wakeup, if any.
* - Driver state transitions.
* .
* @note This macro is meant to be used in the low level drivers
* implementation only.
*
* @param[in] rngp pointer to the @p RNGDriver object
*
* @notapi
*/
#define _rng_isr_code(rngp, rng) { \
if ((rngp)->config->end_cb) { \
(rngp)->state = RNG_COMPLETE; \
(rngp)->config->end_cb(rngp, rng); \
if ((rngp)->state == RNG_COMPLETE) \
(rngp)->state = RNG_READY; \
} \
else \
(rngp)->state = RNG_READY; \
_rng_wakeup_isr(rngp); \
}
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void rngInit(void);
void rngObjectInit(RNGDriver *rngp);
void rngStart(RNGDriver *rngp, const RNGConfig *config);
void rngStop(RNGDriver *rngp);
msg_t rngWriteI(RNGDriver *rngp, uint8_t *buf, size_t n, systime_t timeout);
msg_t rngWrite(RNGDriver *rngp, uint8_t *buf, size_t n, systime_t timeout);
#if RNG_USE_MUTUAL_EXCLUSION == TRUE
void rngAcquireUnit(RNGDriver *rngp);
void rngReleaseUnit(RNGDriver *rngp);
#endif
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_RNG */
#endif /* _RNG_H_ */
/** @} */

View File

@ -28,6 +28,9 @@ endif
ifneq ($(findstring HAL_USE_GPT TRUE,$(HALCONF)),)
PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/NRF51/NRF51822/gpt_lld.c
endif
ifneq ($(findstring HAL_USE_RNG TRUE,$(HALCONF)),)
PLATFORMSRC += ${CHIBIOS_CONTRIB}/os/hal/ports/NRF51/NRF51822/rng_lld.c
endif
else
PLATFORMSRC = ${CHIBIOS}/os/hal/ports/common/ARMCMx/nvic.c \
${CHIBIOS_CONTRIB}/os/hal/ports/NRF51/NRF51822/hal_lld.c \
@ -39,7 +42,8 @@ PLATFORMSRC = ${CHIBIOS}/os/hal/ports/common/ARMCMx/nvic.c \
${CHIBIOS_CONTRIB}/os/hal/ports/NRF51/NRF51822/ext_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/NRF51/NRF51822/i2c_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/NRF51/NRF51822/adc_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/NRF51/NRF51822/gpt_lld.c
${CHIBIOS_CONTRIB}/os/hal/ports/NRF51/NRF51822/gpt_lld.c \
${CHIBIOS_CONTRIB}/os/hal/ports/NRF51/NRF51822/rng_lld.c
endif
# Required include directories

View File

@ -0,0 +1,155 @@
/*
RNG for ChibiOS - Copyright (C) 2016 Stephane D'Alu
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file NRF51/RNGv1/rng_lld.c
* @brief NRF51 RNG subsystem low level driver source.
*
* @addtogroup RNG
* @{
*/
#include "hal.h"
#if (HAL_USE_RNG == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/**
* @brief RNG default configuration.
*/
static const RNGConfig default_config = {
.digital_error_correction = 1,
.power_on_write = 1,
};
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/** @brief RNG1 driver identifier.*/
#if NRF51_RNG_USE_RNG1 || defined(__DOXYGEN__)
RNGDriver RNGD1;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level RNG driver initialization.
*
* @notapi
*/
void rng_lld_init(void) {
rngObjectInit(&RNGD1);
RNGD1.rng = NRF_RNG;
}
/**
* @brief Configures and activates the RNG peripheral.
*
* @param[in] rngp pointer to the @p RNGDriver object
*
* @notapi
*/
void rng_lld_start(RNGDriver *rngp) {
if (rngp->config == NULL)
rngp->config = &default_config;
rngp->rng->POWER = 1;
if (rngp->config->digital_error_correction)
rngp->rng->CONFIG |= RNG_CONFIG_DERCEN_Msk;
else
rngp->rng->CONFIG &= ~RNG_CONFIG_DERCEN_Msk;
rngp->rng->INTENSET = RNG_INTENSET_VALRDY_Msk;
rngp->rng->TASKS_START = 1;
}
/**
* @brief Deactivates the RNG peripheral.
*
* @param[in] rngp pointer to the @p RNGDriver object
*
* @notapi
*/
void rng_lld_stop(RNGDriver *rngp) {
rngp->rng->TASKS_STOP = 1;
rngp->rng->POWER = 0;
}
/**
* @brief Write random bytes;
*
* @param[in] rngp pointer to the @p RNGDriver object
* @param[in] n size of buf in bytes
* @param[in] buf @p buffer location
*
* @notapi
*/
msg_t rng_lld_write(RNGDriver *rngp, uint8_t *buf, size_t n,
systime_t timeout) {
size_t i;
if (n == 0)
return MSG_OK;
if (n == 1)
rngp->rng->SHORTS |= RNG_SHORTS_VALRDY_STOP_Msk;
NRF_RNG->EVENTS_VALRDY = 0;
for (i = 0 ; i < n ; i++) {
/* sleep until number is generated */
while (NRF_RNG->EVENTS_VALRDY == 0) {
/* enable wake up on events for __WFE CPU sleep */
SCB->SCR |= SCB_SCR_SEVONPEND_Msk;
/* sleep until next event */
__SEV();
__WFE();
__WFE();
}
buf[i] = (char)NRF_RNG->VALUE;
NRF_RNG->EVENTS_VALRDY = 0;
nvicClearPending(RNG_IRQn);
}
return MSG_OK;
}
#endif /* HAL_USE_RNG */
/** @} */

View File

@ -0,0 +1,178 @@
/*
RNG for ChibiOS - Copyright (C) 2016 Stephane D'Alu
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/**
* @file NRF51/NRF51822/rng_lld.h
* @brief NRF51 RNG subsystem low level driver header.
*
* @addtogroup RNG
* @{
*/
#ifndef _RNG_LLD_H_
#define _RNG_LLD_H_
#if (HAL_USE_RNG == TRUE) || defined(__DOXYGEN__)
/*
* This error check must occur outsite of RNGSW_USE_RNG1 to check if
* two LLD drivers are enabled at the same time
*/
#if (NRF51_RNG_USE_RNG1 == TRUE) && (RNGSW_USE_RNG1 == TRUE)
#error "Software RNG can't be enable with NRF51_RNG_USE_RNG1"
#endif
/**
* Allow RNG Software override.
*/
#if RNGSW_USE_RNG1 != TRUE
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief RNG1 driver enable switch.
* @details If set to @p TRUE the support for RNG1 is included.
* @note The default is @p FALSE.
*/
#if !defined(NRF51_RNG_USE_RNG1) || defined(__DOXYGEN__)
#define NRF51_RNG_USE_RNG1 FALSE
#endif
/**
* @brief RNG1 driver enable switch.
* @details If set to @p TRUE the support for RNG1 is included.
* @note The default is @p FALSE.
*/
#if !defined(NRF51_RNG_USE_RNG1) || defined(__DOXYGEN__)
#define NRF51_RNG_USE_POWER_ON_WRITE FALSE
#endif
/**
* @brief RNG1 interrupt priority level setting.
*/
#if !defined(NRF51_RNG_RNG1_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define NRF51_RNG_RNG1_IRQ_PRIORITY 8
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of a structure representing an RNG driver.
*/
typedef struct RNGDriver RNGDriver;
/**
* @brief Driver configuration structure.
*/
typedef struct {
/* End of the mandatory fields.*/
/**
* @brief Activate the digital error correction
*
* @details A digital corrector algorithm is employed to remove any
* bias toward '1' or '0'. Disabling it offers a substantial
* speed advantage, but may result in a statistical distribution
* that is not perfectly uniform.
*
* @note On average, it take 167µs to get a byte without digitial
* error correction and 677µs with, but no garantee is made
* on the necessary time to generate one byte.
*/
uint8_t digital_error_correction:1;
/**
* @brief Only power the RNG device when requeting random bytes
*
* @details Device will not be powered when started/stopped
* but only when writint bytes.
*/
uint8_t power_on_write:1;
} RNGConfig;
/**
* @brief Structure representing an RNG driver.
*/
struct RNGDriver {
/**
* @brief Driver state.
*/
rngstate_t state;
/**
* @brief Current configuration data.
*/
const RNGConfig *config;
#if RNG_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
/**
* @brief Mutex protecting the peripheral.
*/
mutex_t mutex;
#endif /* RNG_USE_MUTUAL_EXCLUSION */
/* End of the mandatory fields.*/
/**
* @brief Pointer to the RNGx registers block.
*/
NRF_RNG_Type *rng;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if NRF51_RNG_USE_RNG1 && !defined(__DOXYGEN__)
extern RNGDriver RNGD1;
#endif /* NRF51_RNG_USE_RNG1 */
#ifdef __cplusplus
extern "C" {
#endif
void rng_lld_init(void);
void rng_lld_start(RNGDriver *rngp);
void rng_lld_stop(RNGDriver *rngp);
msg_t rng_lld_write(RNGDriver *rngp, uint8_t *buf, size_t n,
systime_t timeout);
#ifdef __cplusplus
}
#endif
#endif /* RNGSW_USE_RNG1 */
#endif /* HAL_USE_RNG */
#endif /* _RNG_LLD_H_ */
/** @} */

View File

@ -64,6 +64,10 @@ void halCommunityInit(void) {
#if HAL_USE_CRC || defined(__DOXYGEN__)
crcInit();
#endif
#if HAL_USE_RNG || defined(__DOXYGEN__)
rngInit();
#endif
}
#endif /* HAL_USE_COMMUNITY */

185
os/hal/src/rng.c Normal file
View File

@ -0,0 +1,185 @@
/*
RNG for ChibiOS - Copyright (C) 2016 Stephane D'Alu
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
* Hardware Abstraction Layer for RNG Unit
*/
#include "hal.h"
#if (HAL_USE_RNG == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief RNG Driver initialization.
*
* @init
*/
void rngInit(void) {
rng_lld_init();
}
/**
* @brief Initializes the standard part of a @p RNGDriver structure.
*
* @param[out] rngp Pointer to the @p RNGDriver object
*
* @init
*/
void rngObjectInit(RNGDriver *rngp) {
rngp->state = RNG_STOP;
rngp->config = NULL;
#if RNG_USE_MUTUAL_EXCLUSION == TRUE
osalMutexObjectInit(&rngp->mutex);
#endif
#if defined(RNG_DRIVER_EXT_INIT_HOOK)
RNG_DRIVER_EXT_INIT_HOOK(rngp);
#endif
}
/**
* @brief Configures and activates the RNG peripheral.
*
* @param[in] rngp Pointer to the @p RNGDriver object
* @param[in] config Pointer to the @p RNGConfig object
* @p NULL if the low level driver implementation
* supports a default configuration
*
* @api
*/
void rngStart(RNGDriver *rngp, const RNGConfig *config) {
osalDbgCheck(rngp != NULL);
osalSysLock();
osalDbgAssert((rngp->state == RNG_STOP) || (rngp->state == RNG_READY),
"invalid state");
rngp->config = config;
rng_lld_start(rngp);
rngp->state = RNG_READY;
osalSysUnlock();
}
/**
* @brief Deactivates the RNG peripheral.
*
* @param[in] rngp Pointer to the @p RNGDriver object
*
* @api
*/
void rngStop(RNGDriver *rngp) {
osalDbgCheck(rngp != NULL);
osalSysLock();
osalDbgAssert((rngp->state == RNG_STOP) || (rngp->state == RNG_READY),
"invalid state");
rng_lld_stop(rngp);
rngp->state = RNG_STOP;
osalSysUnlock();
}
/**
* @brief Performs a RNG calculation.
* @details This synchronous function performs a rng calculation operation.
* @pre In order to use this function the driver must have been configured
* without callbacks (@p end_cb = @p NULL).
*
* @param[in] rngp pointer to the @p RNGDriver object
* @param[in] n number of bytes to send
* @param[in] buf the pointer to the buffer
*
* @api
*/
msg_t rngWrite(RNGDriver *rngp, uint8_t *buf, size_t n, systime_t timeout) {
msg_t msg;
osalSysLock();
msg = rngWriteI(rngp, buf, n, timeout);
osalSysUnlock();
return msg;
}
/**
* @brief Performs a RNG calculation.
* @details This synchronous function performs a rng calcuation operation.
* @pre In order to use this function the driver must have been configured
* without callbacks (@p end_cb = @p NULL).
* @post At the end of the operation the configured callback is invoked.
*
* @param[in] rngp pointer to the @p RNGDriver object
* @param[in] n number of bytes to send
* @param[in] buf the pointer to the buffer
*
* @iclass
*/
msg_t rngWriteI(RNGDriver *rngp, uint8_t *buf, size_t n, systime_t timeout) {
osalDbgCheck((rngp != NULL) && (n > 0U) && (buf != NULL));
osalDbgAssert(rngp->state == RNG_READY, "not ready");
return rng_lld_write(rngp, buf, n, timeout);
}
#if (RNG_USE_MUTUAL_EXCLUSION == TRUE) || defined(__DOXYGEN__)
/**
* @brief Gains exclusive access to the RNG unit.
* @details This function tries to gain ownership to the RNG, if the RNG is
* already being used then the invoking thread is queued.
* @pre In order to use this function the option @p RNG_USE_MUTUAL_EXCLUSION
* must be enabled.
*
* @param[in] rngp pointer to the @p RNGDriver object
*
* @api
*/
void rngAcquireUnit(RNGDriver *rngp) {
osalDbgCheck(rngp != NULL);
osalMutexLock(&rngp->mutex);
}
/**
* @brief Releases exclusive access to the RNG unit.
* @pre In order to use this function the option @p RNG_USE_MUTUAL_EXCLUSION
* must be enabled.
*
* @param[in] rngp pointer to the @p RNGDriver object
*
* @api
*/
void rngReleaseUnit(RNGDriver *rngp) {
osalDbgCheck(rngp != NULL);
osalMutexUnlock(&rngp->mutex);
}
#endif /* RNG_USE_MUTUAL_EXCLUSION == TRUE */
#endif /* HAL_USE_RNG */