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