rng.c 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. // Based on https://github.com/manitou48/CC3200/blob/master/rng.ino
  2. //#include <rng.h>
  3. #include "rng.h"
  4. #include <stdint.h>
  5. #include <Energia.h>
  6. #include <driverlib/prcm.h>
  7. #include <driverlib/systick.h>
  8. #define DTICKS 200
  9. #define gWDT_buffer_SIZE 32
  10. #define WDT_POOL_SIZE 8
  11. //const uint8_t gWDT_buffer_SIZE=32;
  12. //const uint8_t WDT_POOL_SIZE=8;
  13. uint8_t gWDT_buffer[gWDT_buffer_SIZE];
  14. uint8_t gWDT_buffer_position;
  15. uint8_t gWDT_loop_counter;
  16. volatile uint8_t gWDT_pool_start;
  17. volatile uint8_t gWDT_pool_end;
  18. volatile uint8_t gWDT_pool_count;
  19. volatile uint32_t gWDT_entropy_pool[WDT_POOL_SIZE];
  20. uint32_t random(void) {
  21. uint32_t retVal;
  22. uint8_t waiting;
  23. while (gWDT_pool_count < 1) waiting += 1;
  24. noInterrupts(); // crtical section
  25. retVal = gWDT_entropy_pool[gWDT_pool_start];
  26. gWDT_pool_start = (gWDT_pool_start + 1) % WDT_POOL_SIZE;
  27. --gWDT_pool_count;
  28. interrupts();
  29. return(retVal);
  30. }
  31. void tick(void) {
  32. long long t = PRCMSlowClkCtrGet();
  33. PRCMSlowClkCtrMatchSet(t + DTICKS); // next interrupt time
  34. PRCMIntStatus(); // clear
  35. gWDT_buffer[gWDT_buffer_position] = SysTickValueGet();
  36. gWDT_buffer_position++; // every time the WDT interrupt is triggered
  37. if (gWDT_buffer_position >= gWDT_buffer_SIZE)
  38. {
  39. gWDT_pool_end = (gWDT_pool_start + gWDT_pool_count) % WDT_POOL_SIZE;
  40. // The following code is an implementation of Jenkin's one at a time hash
  41. // This hash function has had preliminary testing to verify that it
  42. // produces reasonably uniform random results when using WDT jitter
  43. // on a variety of Arduino platforms
  44. for(gWDT_loop_counter = 0; gWDT_loop_counter < gWDT_buffer_SIZE; ++gWDT_loop_counter)
  45. {
  46. gWDT_entropy_pool[gWDT_pool_end] += gWDT_buffer[gWDT_loop_counter];
  47. gWDT_entropy_pool[gWDT_pool_end] += (gWDT_entropy_pool[gWDT_pool_end] << 10);
  48. gWDT_entropy_pool[gWDT_pool_end] ^= (gWDT_entropy_pool[gWDT_pool_end] >> 6);
  49. }
  50. gWDT_entropy_pool[gWDT_pool_end] += (gWDT_entropy_pool[gWDT_pool_end] << 3);
  51. gWDT_entropy_pool[gWDT_pool_end] ^= (gWDT_entropy_pool[gWDT_pool_end] >> 11);
  52. gWDT_entropy_pool[gWDT_pool_end] += (gWDT_entropy_pool[gWDT_pool_end] << 15);
  53. gWDT_entropy_pool[gWDT_pool_end] = gWDT_entropy_pool[gWDT_pool_end];
  54. gWDT_buffer_position = 0; // Start collecting the next 32 bytes of Timer 1 counts
  55. if (gWDT_pool_count == WDT_POOL_SIZE) // The entropy pool is full
  56. gWDT_pool_start = (gWDT_pool_start + 1) % WDT_POOL_SIZE;
  57. else // Add another unsigned long (32 bits) to the entropy pool
  58. ++gWDT_pool_count;
  59. }
  60. }
  61. void RNGSetup(void) {
  62. long t = PRCMSlowClkCtrGet();
  63. PRCMSlowClkCtrMatchSet(t + DTICKS); // next interrupt time
  64. PRCMIntRegister(tick);
  65. PRCMIntEnable(PRCM_INT_SLOW_CLK_CTR);
  66. gWDT_buffer_position=0;
  67. gWDT_pool_start = 0;
  68. gWDT_pool_end = 0;
  69. gWDT_pool_count = 0;
  70. }