1 /*
2 * Copyright (c) 2011-2023, Shanghai Real-Thread Electronic Technology Co.,Ltd
3 *
4 * Change Logs:
5 * Date Author Notes
6 * 2020-12-18 quanzhao the first version
7 */
8
9 #include <time.h>
10 #include <string.h>
11 #include <rtthread.h>
12
13 static struct rt_device random_dev;
14 static unsigned long seed;
15
calc_random(void)16 static rt_uint16_t calc_random(void)
17 {
18 seed = 214013L * seed + 2531011L;
19 return (seed >> 16) & 0x7FFF; /* return bits 16~30 */
20 }
21
random_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)22 static rt_ssize_t random_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
23 {
24 rt_uint16_t rand;
25 ssize_t ret = 0;
26 while (size >= sizeof(rand))
27 {
28 /* update rand */
29 rand = calc_random();
30
31 *(rt_uint16_t *)buffer = rand;
32 buffer = (char *)buffer + sizeof(rand);
33 ret += sizeof(rand);
34 size -= sizeof(rand);
35 }
36
37 if (size)
38 {
39 rand = calc_random();
40 memcpy(buffer, &rand, size);
41 ret += size;
42 }
43
44 return ret;
45 }
46
random_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)47 static rt_ssize_t random_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
48 {
49 ssize_t ret = sizeof(seed) < size ? sizeof(seed) : size;
50 rt_memcpy(&seed, buffer, ret);
51 return ret;
52 }
53
random_control(rt_device_t dev,int cmd,void * args)54 static rt_err_t random_control(rt_device_t dev, int cmd, void *args)
55 {
56 return RT_EOK;
57 }
58
59 #ifdef RT_USING_DEVICE_OPS
60 const static struct rt_device_ops random_ops =
61 {
62 RT_NULL,
63 RT_NULL,
64 RT_NULL,
65 random_read,
66 random_write,
67 random_control
68 };
69 #endif
70
random_device_init(void)71 int random_device_init(void)
72 {
73 static rt_bool_t init_ok = RT_FALSE;
74
75 if (init_ok)
76 {
77 return 0;
78 }
79 RT_ASSERT(!rt_device_find("random"));
80 random_dev.type = RT_Device_Class_Miscellaneous;
81
82 #ifdef RT_USING_DEVICE_OPS
83 random_dev.ops = &random_ops;
84 #else
85 random_dev.init = RT_NULL;
86 random_dev.open = RT_NULL;
87 random_dev.close = RT_NULL;
88 random_dev.read = random_read;
89 random_dev.write = random_write;
90 random_dev.control = random_control;
91 #endif
92
93 /* no private */
94 random_dev.user_data = RT_NULL;
95
96 rt_device_register(&random_dev, "random", RT_DEVICE_FLAG_RDWR);
97
98 init_ok = RT_TRUE;
99
100 return 0;
101 }
102 INIT_DEVICE_EXPORT(random_device_init);
103
104 static struct rt_device urandom_dev;
105 static unsigned long useed;
106
calc_urandom(void)107 static rt_uint16_t calc_urandom(void)
108 {
109 useed = 214013L * useed + 2531011L;
110 return (useed >> 16) & 0x7FFF; /* return bits 16~30 */
111 }
112
random_uread(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)113 static rt_ssize_t random_uread(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
114 {
115 rt_uint16_t rand;
116 ssize_t ret = 0;
117 while (size >= sizeof(rand))
118 {
119 /* update rand */
120 rand = calc_urandom();
121
122 *(rt_uint16_t *)buffer = rand;
123 buffer = (char *)buffer + sizeof(rand);
124 ret += sizeof(rand);
125 size -= sizeof(rand);
126 }
127
128 if (size)
129 {
130 rand = calc_urandom();
131 memcpy(buffer, &rand, size);
132 ret += size;
133 }
134
135 return ret;
136 }
137
random_uwrite(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)138 static rt_ssize_t random_uwrite(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
139 {
140 ssize_t ret = sizeof(useed) < size ? sizeof(useed) : size;
141 rt_memcpy(&useed, buffer, ret);
142 return ret;
143 }
144
random_ucontrol(rt_device_t dev,int cmd,void * args)145 static rt_err_t random_ucontrol(rt_device_t dev, int cmd, void *args)
146 {
147 return RT_EOK;
148 }
149
150 #ifdef RT_USING_DEVICE_OPS
151 const static struct rt_device_ops urandom_ops =
152 {
153 RT_NULL,
154 RT_NULL,
155 RT_NULL,
156 random_uread,
157 random_uwrite,
158 random_ucontrol
159 };
160 #endif
161
urandom_device_init(void)162 int urandom_device_init(void)
163 {
164 static rt_bool_t init_ok = RT_FALSE;
165
166 if (init_ok)
167 {
168 return 0;
169 }
170 RT_ASSERT(!rt_device_find("urandom"));
171 urandom_dev.type = RT_Device_Class_Miscellaneous;
172
173 #ifdef RT_USING_DEVICE_OPS
174 urandom_dev.ops = &urandom_ops;
175 #else
176 urandom_dev.init = RT_NULL;
177 urandom_dev.open = RT_NULL;
178 urandom_dev.close = RT_NULL;
179 urandom_dev.read = random_uread;
180 urandom_dev.write = random_uwrite;
181 urandom_dev.control = random_ucontrol;
182 #endif
183
184 /* no private */
185 urandom_dev.user_data = RT_NULL;
186
187 rt_device_register(&urandom_dev, "urandom", RT_DEVICE_FLAG_RDWR);
188
189 init_ok = RT_TRUE;
190
191 return 0;
192 }
193 INIT_DEVICE_EXPORT(urandom_device_init);
194