// Based on https://github.com/manitou48/CC3200/blob/master/rng.ino //#include #include "rng.h" #include #include #include #include #define DTICKS 200 #define gWDT_buffer_SIZE 32 #define WDT_POOL_SIZE 8 //const uint8_t gWDT_buffer_SIZE=32; //const uint8_t WDT_POOL_SIZE=8; uint8_t gWDT_buffer[gWDT_buffer_SIZE]; uint8_t gWDT_buffer_position; uint8_t gWDT_loop_counter; volatile uint8_t gWDT_pool_start; volatile uint8_t gWDT_pool_end; volatile uint8_t gWDT_pool_count; volatile uint32_t gWDT_entropy_pool[WDT_POOL_SIZE]; uint32_t random(void) { uint32_t retVal; uint8_t waiting; while (gWDT_pool_count < 1) waiting += 1; noInterrupts(); // crtical section retVal = gWDT_entropy_pool[gWDT_pool_start]; gWDT_pool_start = (gWDT_pool_start + 1) % WDT_POOL_SIZE; --gWDT_pool_count; interrupts(); return(retVal); } void tick(void) { long long t = PRCMSlowClkCtrGet(); PRCMSlowClkCtrMatchSet(t + DTICKS); // next interrupt time PRCMIntStatus(); // clear gWDT_buffer[gWDT_buffer_position] = SysTickValueGet(); gWDT_buffer_position++; // every time the WDT interrupt is triggered if (gWDT_buffer_position >= gWDT_buffer_SIZE) { gWDT_pool_end = (gWDT_pool_start + gWDT_pool_count) % WDT_POOL_SIZE; // The following code is an implementation of Jenkin's one at a time hash // This hash function has had preliminary testing to verify that it // produces reasonably uniform random results when using WDT jitter // on a variety of Arduino platforms for(gWDT_loop_counter = 0; gWDT_loop_counter < gWDT_buffer_SIZE; ++gWDT_loop_counter) { gWDT_entropy_pool[gWDT_pool_end] += gWDT_buffer[gWDT_loop_counter]; gWDT_entropy_pool[gWDT_pool_end] += (gWDT_entropy_pool[gWDT_pool_end] << 10); gWDT_entropy_pool[gWDT_pool_end] ^= (gWDT_entropy_pool[gWDT_pool_end] >> 6); } gWDT_entropy_pool[gWDT_pool_end] += (gWDT_entropy_pool[gWDT_pool_end] << 3); gWDT_entropy_pool[gWDT_pool_end] ^= (gWDT_entropy_pool[gWDT_pool_end] >> 11); gWDT_entropy_pool[gWDT_pool_end] += (gWDT_entropy_pool[gWDT_pool_end] << 15); gWDT_entropy_pool[gWDT_pool_end] = gWDT_entropy_pool[gWDT_pool_end]; gWDT_buffer_position = 0; // Start collecting the next 32 bytes of Timer 1 counts if (gWDT_pool_count == WDT_POOL_SIZE) // The entropy pool is full gWDT_pool_start = (gWDT_pool_start + 1) % WDT_POOL_SIZE; else // Add another unsigned long (32 bits) to the entropy pool ++gWDT_pool_count; } } void RNGSetup(void) { long t = PRCMSlowClkCtrGet(); PRCMSlowClkCtrMatchSet(t + DTICKS); // next interrupt time PRCMIntRegister(tick); PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR); gWDT_buffer_position=0; gWDT_pool_start = 0; gWDT_pool_end = 0; gWDT_pool_count = 0; }