blob: 3795934a5c926a6239e26c148c42584a9914c62e [file] [log] [blame]
/*
* Copyright (c) 2016 Nordic Semiconductor ASA
* Copyright (c) 2016 Vinayak Kariappa Chettimada
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <soc.h>
#include "hal/rand.h"
#include "common/log.h"
#include "hal/debug.h"
#define RAND_RESERVED (4)
struct rand {
u8_t count;
u8_t first;
u8_t last;
u8_t rand[1];
};
static struct rand *rng;
void rand_init(u8_t *context, u8_t context_len)
{
LL_ASSERT(context_len > sizeof(struct rand));
rng = (struct rand *)context;
rng->count = context_len - sizeof(struct rand) + 1;
rng->first = rng->last = 0;
NRF_RNG->CONFIG = RNG_CONFIG_DERCEN_Msk;
NRF_RNG->EVENTS_VALRDY = 0;
NRF_RNG->INTENSET = RNG_INTENSET_VALRDY_Msk;
NRF_RNG->TASKS_START = 1;
}
size_t rand_get(size_t octets, u8_t *rand)
{
u8_t reserved;
u8_t first;
while (octets) {
if (rng->first == rng->last) {
break;
}
rand[--octets] = rng->rand[rng->first];
first = rng->first + 1;
if (first == rng->count) {
first = 0;
}
rng->first = first;
}
reserved = RAND_RESERVED;
first = rng->first;
while (reserved--) {
if (first == rng->last) {
NRF_RNG->TASKS_START = 1;
break;
}
first++;
if (first == rng->count) {
first = 0;
}
}
return octets;
}
void isr_rand(void *param)
{
ARG_UNUSED(param);
if (NRF_RNG->EVENTS_VALRDY) {
u8_t last;
last = rng->last + 1;
if (last == rng->count) {
last = 0;
}
if (last == rng->first) {
/* this condition should not happen
* , but due to probable bug in HW
* , new value could be generated
* before task is stopped.
*/
NRF_RNG->TASKS_STOP = 1;
NRF_RNG->EVENTS_VALRDY = 0;
return;
}
rng->rand[rng->last] = NRF_RNG->VALUE;
rng->last = last;
last = rng->last + 1;
if (last == rng->count) {
last = 0;
}
NRF_RNG->EVENTS_VALRDY = 0;
if (last == rng->first) {
NRF_RNG->TASKS_STOP = 1;
}
}
}