|
2842
|
1 //========================================================================== |
|
|
2 // |
|
|
3 // adc_synth.c |
|
|
4 // |
|
2844
|
5 // ADC driver for Synthetic ADC |
|
2842
|
6 // |
|
|
7 //========================================================================== |
|
|
8 // ####ECOSGPLCOPYRIGHTBEGIN#### |
|
|
9 // ------------------------------------------- |
|
|
10 // This file is part of eCos, the Embedded Configurable Operating System. |
|
|
11 // Copyright (C) 2009 Free Software Foundation, Inc. |
|
|
12 // |
|
|
13 // eCos is free software; you can redistribute it and/or modify it under |
|
|
14 // the terms of the GNU General Public License as published by the Free |
|
|
15 // Software Foundation; either version 2 or (at your option) any later |
|
|
16 // version. |
|
|
17 // |
|
|
18 // eCos is distributed in the hope that it will be useful, but WITHOUT |
|
|
19 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
|
20 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
|
21 // for more details. |
|
|
22 // |
|
|
23 // You should have received a copy of the GNU General Public License |
|
|
24 // along with eCos; if not, write to the Free Software Foundation, Inc., |
|
|
25 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
|
26 // |
|
|
27 // As a special exception, if other files instantiate templates or use |
|
|
28 // macros or inline functions from this file, or you compile this file |
|
|
29 // and link it with other works to produce a work based on this file, |
|
|
30 // this file does not by itself cause the resulting work to be covered by |
|
|
31 // the GNU General Public License. However the source code for this file |
|
|
32 // must still be made available in accordance with section (3) of the GNU |
|
|
33 // General Public License v2. |
|
|
34 // |
|
|
35 // This exception does not invalidate any other reasons why a work based |
|
|
36 // on this file might be covered by the GNU General Public License. |
|
|
37 // ------------------------------------------- |
|
|
38 // ####ECOSGPLCOPYRIGHTEND#### |
|
|
39 //========================================================================== |
|
|
40 //#####DESCRIPTIONBEGIN#### |
|
|
41 // |
|
|
42 // Author(s): Simon Kallweit <simon.kallweit@intefo.ch> |
|
|
43 // Contributors: |
|
|
44 // Date: 2009-02-27 |
|
|
45 // Purpose: |
|
|
46 // Description: |
|
|
47 // |
|
|
48 //####DESCRIPTIONEND#### |
|
|
49 // |
|
|
50 //========================================================================== |
|
|
51 |
|
|
52 #include <pkgconf/kernel.h> |
|
|
53 #include <pkgconf/devs_adc_synth.h> |
|
|
54 |
|
|
55 #include <cyg/infra/cyg_type.h> |
|
|
56 #include <cyg/infra/cyg_ass.h> |
|
|
57 #include <cyg/io/adc.h> |
|
|
58 #include <cyg/hal/hal_arch.h> |
|
|
59 #include <cyg/hal/hal_io.h> |
|
|
60 #include <cyg/hal/hal_intr.h> |
|
|
61 #include <cyg/hal/drv_api.h> |
|
|
62 |
|
|
63 //----------------------------------------------------------------------------- |
|
|
64 // Diagnostic support |
|
|
65 // Switch the #if to 1 to generate some diagnostic messages. |
|
|
66 |
|
|
67 #if 0 |
|
|
68 #include <cyg/infra/diag.h> |
|
|
69 #define adc_diag( __fmt, ... ) diag_printf("ADC: %30s[%4d]: " __fmt, __FUNCTION__, __LINE__, ## __VA_ARGS__ ); |
|
|
70 #else |
|
|
71 #define adc_diag( __fmt, ... ) |
|
|
72 #endif |
|
|
73 |
|
|
74 #define NUM_CHANNELS 16 |
|
|
75 |
|
|
76 #define MODE_CONST 0 |
|
|
77 #define MODE_RANDOM 1 |
|
|
78 #define MODE_FILE 2 |
|
|
79 |
|
|
80 #define SAMPLE_BITS ((1 << CYGNUM_DEVS_ADC_SYNTH_SAMPLE_SIZE) - 1) |
|
|
81 |
|
|
82 //----------------------------------------------------------------------------- |
|
|
83 // Synthetic ADC channel |
|
|
84 |
|
|
85 typedef struct synth_adc_channel_info { |
|
|
86 cyg_uint32 mode; // Channel mode |
|
|
87 cyg_uint32 const_value; // Const sample value |
|
|
88 char *filename; // Sampling data filename |
|
|
89 |
|
|
90 int fd; // File descriptor of sample file |
|
|
91 cyg_uint32 num_samples; // Number of samples in the file |
|
|
92 cyg_adc_sample_t *base; // Base address of mapped sample file |
|
|
93 cyg_adc_sample_t *sample; // Current sample |
|
|
94 |
|
|
95 cyg_adc_sample_t (*get_sample)(cyg_adc_channel *chan); |
|
|
96 } synth_adc_channel_info; |
|
|
97 |
|
|
98 //----------------------------------------------------------------------------- |
|
2844
|
99 // Synthetic ADC device |
|
2842
|
100 |
|
|
101 typedef struct synth_adc_info { |
|
|
102 synth_adc_channel_info *chan_info; // Channel infos |
|
|
103 cyg_adc_channel *chan[NUM_CHANNELS]; // Channel references |
|
|
104 cyg_uint32 chan_mask; // Active channels |
|
|
105 cyg_handle_t alarm_handle; // Alarm handle |
|
|
106 cyg_alarm alarm_data; // Alarm data |
|
|
107 cyg_tick_count_t alarm_interval; // Alarm interval in ticks |
|
|
108 cyg_uint32 alarm_samples; // Number of samples per tick |
|
|
109 } synth_adc_info; |
|
|
110 |
|
|
111 //----------------------------------------------------------------------------- |
|
|
112 // API function call forward references |
|
|
113 |
|
|
114 static bool synth_adc_init(struct cyg_devtab_entry *tab); |
|
|
115 static Cyg_ErrNo synth_adc_lookup(struct cyg_devtab_entry **tab, |
|
|
116 struct cyg_devtab_entry *sub_tab, |
|
|
117 const char *name); |
|
|
118 |
|
|
119 static void synth_adc_enable(cyg_adc_channel *chan); |
|
|
120 static void synth_adc_disable(cyg_adc_channel *chan); |
|
|
121 static void synth_adc_set_rate(cyg_adc_channel *chan, cyg_uint32 rate); |
|
|
122 |
|
|
123 static void alarm_handler(cyg_handle_t alarm, cyg_addrword_t data); |
|
|
124 |
|
|
125 static cyg_adc_sample_t synth_adc_get_sample_const(cyg_adc_channel *chan); |
|
|
126 static cyg_adc_sample_t synth_adc_get_sample_random(cyg_adc_channel *chan); |
|
|
127 static cyg_adc_sample_t synth_adc_get_sample_file(cyg_adc_channel *chan); |
|
|
128 |
|
|
129 static cyg_uint32 rand(void); |
|
|
130 |
|
|
131 CYG_ADC_FUNCTIONS(synth_adc_funs, |
|
|
132 synth_adc_enable, |
|
|
133 synth_adc_disable, |
|
|
134 synth_adc_set_rate); |
|
|
135 |
|
|
136 //----------------------------------------------------------------------------- |
|
2844
|
137 // Synthetic ADC channel info macro |
|
2842
|
138 |
|
|
139 #define SYNTH_ADC_CHANNEL_INFO(_chan_) \ |
|
|
140 { \ |
|
|
141 .mode = CYGNUM_DEVS_ADC_SYNTH_CHANNEL##_chan_##_MODE, \ |
|
|
142 .const_value = CYGNUM_DEVS_ADC_SYNTH_CHANNEL##_chan_##_CONST_VALUE, \ |
|
|
143 .filename = CYGDAT_DEVS_ADC_SYNTH_CHANNEL##_chan_##_FILENAME, \ |
|
|
144 } |
|
|
145 |
|
|
146 //----------------------------------------------------------------------------- |
|
2844
|
147 // Synthetic ADC channel instance macro |
|
2842
|
148 |
|
|
149 #define SYNTH_ADC_CHANNEL(_chan_) \ |
|
|
150 CYG_ADC_CHANNEL( \ |
|
|
151 synth_adc_channel##_chan_, \ |
|
|
152 _chan_, \ |
|
|
153 CYGNUM_DEVS_ADC_SYNTH_CHANNEL##_chan_##_BUFSIZE, \ |
|
|
154 &synth_adc_device \ |
|
|
155 ); \ |
|
|
156 DEVTAB_ENTRY( \ |
|
|
157 synth_adc_channel##_chan_##_device, \ |
|
|
158 CYGDAT_DEVS_ADC_SYNTH_CHANNEL##_chan_##_NAME, \ |
|
|
159 0, \ |
|
|
160 &cyg_io_adc_devio, \ |
|
|
161 synth_adc_init, \ |
|
|
162 synth_adc_lookup, \ |
|
|
163 &synth_adc_channel##_chan_ \ |
|
|
164 ); |
|
|
165 |
|
|
166 //----------------------------------------------------------------------------- |
|
2844
|
167 // Synthetic ADC device instance |
|
2842
|
168 |
|
|
169 static synth_adc_channel_info synth_adc_channel_infos[NUM_CHANNELS] = { |
|
|
170 SYNTH_ADC_CHANNEL_INFO(0), |
|
|
171 SYNTH_ADC_CHANNEL_INFO(1), |
|
|
172 SYNTH_ADC_CHANNEL_INFO(2), |
|
|
173 SYNTH_ADC_CHANNEL_INFO(3), |
|
|
174 SYNTH_ADC_CHANNEL_INFO(4), |
|
|
175 SYNTH_ADC_CHANNEL_INFO(5), |
|
|
176 SYNTH_ADC_CHANNEL_INFO(6), |
|
|
177 SYNTH_ADC_CHANNEL_INFO(7), |
|
|
178 SYNTH_ADC_CHANNEL_INFO(8), |
|
|
179 SYNTH_ADC_CHANNEL_INFO(9), |
|
|
180 SYNTH_ADC_CHANNEL_INFO(10), |
|
|
181 SYNTH_ADC_CHANNEL_INFO(11), |
|
|
182 SYNTH_ADC_CHANNEL_INFO(12), |
|
|
183 SYNTH_ADC_CHANNEL_INFO(13), |
|
|
184 SYNTH_ADC_CHANNEL_INFO(14), |
|
|
185 SYNTH_ADC_CHANNEL_INFO(15), |
|
|
186 }; |
|
|
187 |
|
|
188 static synth_adc_info synth_adc_info0 = { |
|
|
189 .chan_info = synth_adc_channel_infos, |
|
|
190 }; |
|
|
191 |
|
|
192 CYG_ADC_DEVICE(synth_adc_device, |
|
|
193 &synth_adc_funs, |
|
|
194 &synth_adc_info0, |
|
|
195 CYGNUM_DEVS_ADC_SYNTH_DEFAULT_RATE); |
|
|
196 |
|
|
197 SYNTH_ADC_CHANNEL(0) |
|
|
198 SYNTH_ADC_CHANNEL(1) |
|
|
199 SYNTH_ADC_CHANNEL(2) |
|
|
200 SYNTH_ADC_CHANNEL(3) |
|
|
201 SYNTH_ADC_CHANNEL(4) |
|
|
202 SYNTH_ADC_CHANNEL(5) |
|
|
203 SYNTH_ADC_CHANNEL(6) |
|
|
204 SYNTH_ADC_CHANNEL(7) |
|
|
205 SYNTH_ADC_CHANNEL(8) |
|
|
206 SYNTH_ADC_CHANNEL(9) |
|
|
207 SYNTH_ADC_CHANNEL(10) |
|
|
208 SYNTH_ADC_CHANNEL(11) |
|
|
209 SYNTH_ADC_CHANNEL(12) |
|
|
210 SYNTH_ADC_CHANNEL(13) |
|
|
211 SYNTH_ADC_CHANNEL(14) |
|
|
212 SYNTH_ADC_CHANNEL(15) |
|
|
213 |
|
|
214 |
|
|
215 //----------------------------------------------------------------------------- |
|
|
216 // This function is called from the device IO infrastructure to initialize the |
|
|
217 // device. It should perform any work needed to start up the device, short of |
|
|
218 // actually starting the generation of samples. This function will be called |
|
|
219 // for each channel, so if there is initialization that only needs to be done |
|
|
220 // once, such as creating and interrupt object, then care should be taken to do |
|
|
221 // this. This function should also call cyg_adc_device_init() to initialize the |
|
|
222 // generic parts of the driver. |
|
|
223 |
|
|
224 static bool |
|
|
225 synth_adc_init(struct cyg_devtab_entry *tab) |
|
|
226 { |
|
|
227 static cyg_bool initialized = false; |
|
|
228 cyg_adc_channel *chan = (cyg_adc_channel *) tab->priv; |
|
|
229 cyg_adc_device *device = chan->device; |
|
|
230 synth_adc_info *info = device->dev_priv; |
|
|
231 synth_adc_channel_info *chan_info = &info->chan_info[chan->channel]; |
|
|
232 cyg_handle_t counter; |
|
|
233 |
|
|
234 adc_diag("Initializing device\n"); |
|
|
235 |
|
|
236 // Initialize channel |
|
|
237 info->chan[chan->channel] = chan; |
|
|
238 switch (chan_info->mode) { |
|
|
239 case MODE_CONST: |
|
|
240 chan_info->get_sample = synth_adc_get_sample_const; |
|
|
241 break; |
|
|
242 case MODE_RANDOM: |
|
|
243 chan_info->get_sample = synth_adc_get_sample_random; |
|
|
244 break; |
|
|
245 case MODE_FILE: |
|
|
246 chan_info->get_sample = synth_adc_get_sample_file; |
|
|
247 break; |
|
|
248 } |
|
|
249 |
|
|
250 // Set default rate |
|
|
251 if (!initialized) { |
|
|
252 // Initialize alarm |
|
|
253 cyg_clock_to_counter(cyg_real_time_clock(), &counter); |
|
|
254 cyg_alarm_create(counter, alarm_handler, (cyg_addrword_t) device, |
|
|
255 &info->alarm_handle, &info->alarm_data); |
|
|
256 |
|
|
257 synth_adc_set_rate(chan, chan->device->config.rate); |
|
|
258 initialized = true; |
|
|
259 } |
|
|
260 |
|
|
261 // Initialize generic parts of ADC device |
|
|
262 cyg_adc_device_init(device); |
|
|
263 |
|
|
264 return true; |
|
|
265 } |
|
|
266 |
|
|
267 //----------------------------------------------------------------------------- |
|
|
268 // This function is called when a client looks up or opens a channel. It should |
|
|
269 // call cyg_adc_channel_init() to initialize the generic part of the channel. |
|
|
270 // It should also perform any operations needed to start the channel generating |
|
|
271 // samples. |
|
|
272 |
|
|
273 static Cyg_ErrNo |
|
|
274 synth_adc_lookup(struct cyg_devtab_entry **tab, |
|
|
275 struct cyg_devtab_entry *sub_tab, |
|
|
276 const char *name) |
|
|
277 { |
|
|
278 cyg_adc_channel *chan = (cyg_adc_channel *) (*tab)->priv; |
|
|
279 synth_adc_info *info = chan->device->dev_priv; |
|
|
280 synth_adc_channel_info *chan_info = &info->chan_info[chan->channel]; |
|
|
281 |
|
|
282 adc_diag("Opening device\n"); |
|
|
283 |
|
|
284 // When this channel is in file mode, initialize file access |
|
|
285 if (chan_info->mode == MODE_FILE) { |
|
|
286 struct cyg_hal_sys_new_stat stat; |
|
|
287 |
|
|
288 // Open the file |
|
|
289 chan_info->fd = cyg_hal_sys_open(chan_info->filename, |
|
|
290 CYG_HAL_SYS_O_RDONLY, 0); |
|
|
291 if (chan_info->fd == -ENOENT) { |
|
|
292 adc_diag("Cannot open sampling file '%s' for channel '%s'\n", |
|
|
293 chan_info->filename, (*tab)->name); |
|
|
294 CYG_FAIL("Cannot open sampling file\n"); |
|
|
295 } |
|
|
296 |
|
|
297 // Get file size |
|
|
298 if (cyg_hal_sys_newfstat(chan_info->fd, &stat) != 0) { |
|
|
299 CYG_FAIL("Cannot stat sampling file\n"); |
|
|
300 } |
|
|
301 chan_info->num_samples = stat.st_size / sizeof(cyg_adc_sample_t); |
|
|
302 if (chan_info->num_samples <= 0) |
|
|
303 CYG_FAIL("Sampling file too small\n"); |
|
|
304 |
|
|
305 // Memory map |
|
|
306 chan_info->base = (cyg_adc_sample_t *) cyg_hal_sys_mmap( |
|
|
307 NULL, |
|
|
308 chan_info->num_samples * sizeof(cyg_adc_sample_t), |
|
|
309 CYG_HAL_SYS_PROT_READ, |
|
|
310 CYG_HAL_SYS_MAP_SHARED, |
|
|
311 chan_info->fd, |
|
|
312 0); |
|
|
313 if (chan_info->base == (void *) -1) |
|
|
314 CYG_FAIL("Cannot memory map sampling file\n"); |
|
|
315 chan_info->sample = chan_info->base; |
|
|
316 |
|
|
317 adc_diag("Mapped to %p\n", chan_info->base); |
|
|
318 } |
|
|
319 |
|
|
320 // Initialize generic parts of the channel |
|
|
321 cyg_adc_channel_init(chan); |
|
|
322 |
|
|
323 // The generic ADC manual says: When a channel is first looked up or |
|
|
324 // opened, then it is automatically enabled and samples start to |
|
|
325 // accumulate - so we start the channel now |
|
|
326 chan->enabled = true; |
|
|
327 synth_adc_enable(chan); |
|
|
328 |
|
|
329 return ENOERR; |
|
|
330 } |
|
|
331 |
|
|
332 //----------------------------------------------------------------------------- |
|
|
333 // This function is called from the generic ADC package to enable the channel |
|
|
334 // in response to a CYG_IO_SET_CONFIG_ADC_ENABLE config operation. It should |
|
|
335 // take any steps needed to start the channel generating samples |
|
|
336 |
|
|
337 static void |
|
|
338 synth_adc_enable(cyg_adc_channel *chan) |
|
|
339 { |
|
|
340 synth_adc_info *info = chan->device->dev_priv; |
|
|
341 cyg_bool start; |
|
|
342 |
|
|
343 adc_diag("Enabling channel\n"); |
|
|
344 |
|
|
345 start = !info->chan_mask; |
|
|
346 info->chan_mask |= (1 << chan->channel); |
|
|
347 |
|
|
348 // Start scanning when first channel was activated |
|
|
349 if (start) { |
|
|
350 // Enable timer |
|
|
351 adc_diag("Starting scanning\n"); |
|
|
352 cyg_alarm_initialize(info->alarm_handle, |
|
|
353 cyg_current_time() + info->alarm_interval, |
|
|
354 info->alarm_interval); |
|
|
355 } |
|
|
356 } |
|
|
357 |
|
|
358 //----------------------------------------------------------------------------- |
|
|
359 // This function is called from the generic ADC package to enable the channel |
|
|
360 // in response to a CYG_IO_SET_CONFIG_ADC_DISABLE config operation. It should |
|
|
361 // take any steps needed to stop the channel generating samples. |
|
|
362 |
|
|
363 static void |
|
|
364 synth_adc_disable(cyg_adc_channel *chan) |
|
|
365 { |
|
|
366 synth_adc_info *info = chan->device->dev_priv; |
|
|
367 |
|
|
368 adc_diag("Disabling channel\n"); |
|
|
369 |
|
|
370 info->chan_mask &= ~(1 << chan->channel); |
|
|
371 |
|
|
372 // Stop scanning when no channel is active |
|
|
373 if (!info->chan_mask) { |
|
|
374 // Disable timer |
|
|
375 adc_diag("Stopping scanning\n"); |
|
|
376 cyg_alarm_disable(info->alarm_handle); |
|
|
377 } |
|
|
378 } |
|
|
379 |
|
|
380 //----------------------------------------------------------------------------- |
|
|
381 // This function is called from the generic ADC package to enable the channel |
|
|
382 // in response to a CYG_IO_SET_CONFIG_ADC_RATE config operation. It should take |
|
|
383 // any steps needed to change the sample rate of the channel, or of the entire |
|
|
384 // device. We use a timer channel to generate the interrupts for sampling the |
|
|
385 // analog channels |
|
|
386 |
|
|
387 static void |
|
|
388 synth_adc_set_rate(cyg_adc_channel *chan, cyg_uint32 rate) |
|
|
389 { |
|
|
390 cyg_adc_device *device = chan->device; |
|
|
391 synth_adc_info *info = device->dev_priv; |
|
|
392 cyg_uint64 interval; |
|
|
393 |
|
|
394 adc_diag("Setting rate to %d\n", rate); |
|
|
395 |
|
|
396 interval = 1000000000000LL / rate; |
|
|
397 interval /= (CYGNUM_HAL_RTC_NUMERATOR / CYGNUM_HAL_RTC_DENOMINATOR); |
|
|
398 |
|
|
399 if (interval > 1000) { |
|
|
400 info->alarm_interval = interval / 1000; |
|
|
401 info->alarm_samples = 1; |
|
|
402 } else { |
|
|
403 info->alarm_interval = 1; |
|
|
404 info->alarm_samples = 1000 / interval; |
|
|
405 } |
|
|
406 |
|
|
407 if (info->chan_mask) |
|
|
408 cyg_alarm_initialize(info->alarm_handle, |
|
|
409 cyg_current_time() + info->alarm_interval, |
|
|
410 info->alarm_interval); |
|
|
411 |
|
|
412 device->config.rate = rate; |
|
|
413 } |
|
|
414 |
|
|
415 static void |
|
|
416 alarm_handler(cyg_handle_t alarm, cyg_addrword_t data) |
|
|
417 { |
|
|
418 cyg_adc_device *device = (cyg_adc_device *) data; |
|
|
419 synth_adc_info *info = device->dev_priv; |
|
|
420 cyg_adc_channel *chan; |
|
|
421 synth_adc_channel_info *chan_info; |
|
|
422 cyg_uint32 active_mask; |
|
|
423 int i, j; |
|
|
424 |
|
|
425 if (!info->chan_mask) |
|
|
426 return; |
|
|
427 |
|
|
428 active_mask = info->chan_mask; |
|
|
429 |
|
|
430 for (i = 0; i < NUM_CHANNELS; i++) { |
|
|
431 if (active_mask & 0x01) { |
|
|
432 chan = info->chan[i]; |
|
|
433 chan_info = &info->chan_info[chan->channel]; |
|
|
434 for (j = 0; j < info->alarm_samples; j++) |
|
|
435 cyg_adc_receive_sample(chan, chan_info->get_sample(chan)); |
|
|
436 cyg_adc_wakeup(info->chan[i]); |
|
|
437 } |
|
|
438 active_mask >>= 1; |
|
|
439 } |
|
|
440 } |
|
|
441 |
|
|
442 static cyg_adc_sample_t |
|
|
443 synth_adc_get_sample_const(cyg_adc_channel *chan) |
|
|
444 { |
|
|
445 synth_adc_info *info = chan->device->dev_priv; |
|
|
446 synth_adc_channel_info *chan_info = &info->chan_info[chan->channel]; |
|
|
447 |
|
|
448 return chan_info->const_value; |
|
|
449 } |
|
|
450 |
|
|
451 static cyg_adc_sample_t |
|
|
452 synth_adc_get_sample_random(cyg_adc_channel *chan) |
|
|
453 { |
|
|
454 return rand() & SAMPLE_BITS; |
|
|
455 } |
|
|
456 |
|
|
457 static cyg_adc_sample_t |
|
|
458 synth_adc_get_sample_file(cyg_adc_channel *chan) |
|
|
459 { |
|
|
460 synth_adc_info *info = chan->device->dev_priv; |
|
|
461 synth_adc_channel_info *chan_info = &info->chan_info[chan->channel]; |
|
|
462 cyg_adc_sample_t sample; |
|
|
463 |
|
|
464 sample = *chan_info->sample++; |
|
|
465 if (chan_info->sample >= chan_info->base + chan_info->num_samples) |
|
|
466 chan_info->sample = chan_info->base; |
|
|
467 |
|
|
468 return sample; |
|
|
469 } |
|
|
470 |
|
|
471 //----------------------------------------------------------------------------- |
|
|
472 // Simple random number generator |
|
|
473 |
|
|
474 static cyg_uint32 rand(void) |
|
|
475 { |
|
|
476 static cyg_uint32 seed; |
|
|
477 |
|
|
478 seed = (seed * 1103515245) + 12345; // permutate seed |
|
|
479 |
|
|
480 return seed; |
|
|
481 } |
|
|
482 |