3cbfd0b0b3797b44d91bb07016bfa3a099048da2
1 /* --COPYRIGHT--,BSD
2 * Copyright (c) $(CPYYEAR), Texas Instruments Incorporated
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * * Neither the name of Texas Instruments Incorporated nor the names of
17 * its contributors may be used to endorse or promote products derived
18 * from this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
27 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
29 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
30 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 * --/COPYRIGHT--*/
32 /*
33 * ======== dgn2.c ========
34 * Streaming Generator Driver
35 *
36 * A DGN2 device is a "pseudo-device" that generates one of several
37 * possible data streams. For example, a DGN2 can generate sin/cos
38 * series or white noise. This driver can be very useful for testing
39 * applications that require an input stream of data.
40 */
43 #include <xdc/std.h>
44 #include <xdc/runtime/Error.h>
45 #include <xdc/runtime/Memory.h>
46 #include <xdc/runtime/System.h>
47 #include <xdc/runtime/Log.h>
49 #include <stddef.h>
51 #include <ti/sysbios/knl/Queue.h>
53 #include "dgn2.h"
54 #include "dev2.h"
56 #define MAXRANGE ((1U << (16 - 1)) - 1)
58 __FAR__ DGN2_Params DGN2_PARAMS = {
59 { 1 }, /* constant: value */
60 { 1, -MAXRANGE, MAXRANGE }, /* rand: seed, lower, upper */
61 { MAXRANGE, 1, 0, 256 }, /* sine: gain, freq, phase, sample rate */
62 { NULL, NULL } /* user: fxn, arg */
63 };
65 Int DGN2_close(DEV2_Handle device);
66 Int DGN2_idle(DEV2_Handle device, Bool flush);
67 Int DGN2_open(DEV2_Handle device, String name);
68 Int DGN2_ioFunc(DEV2_Handle device);
70 /*
71 * Driver function table.
72 */
73 __FAR__ DEV2_Fxns DGN2_FXNS = {
74 DGN2_close, /* close */
75 DEV2_CTRL, /* ctrl */
76 DGN2_idle, /* idle */
77 DGN2_ioFunc, /* issue */
78 DGN2_open, /* open */
79 DEV2_READY, /* ready */ /* generator is always ready */
80 (DEV2_Treclaim)DEV2_zero, /* reclaim */
81 };
83 /*
84 * ======== DGN2_close ========
85 * All that needs to be done to close a generator is to
86 * free memory associated with the driver. And return
87 * a status when done.
88 */
89 Int DGN2_close(DEV2_Handle device)
90 {
91 Memory_free(0, device->object, sizeof(DGN2_GenObj));
93 return (DEV2_OK);
94 }
96 /*
97 * ======== DGN2_idle ========
98 * For DGN2 idling, we don't need to do any queue manipulation since
99 * there's no way for frames to build up on a queue (they always get
100 * processed).
101 * All we need to do is reset state variables.
102 */
103 Int DGN2_idle(DEV2_Handle device, Bool flush)
104 {
105 DGN2_GenObj *gen = (DGN2_GenObj *)device->object;
107 gen->seed = gen->dparams->rand.seed;
109 gen->index = 0;
111 return (DEV2_OK);
112 }
114 /*
115 * ======== DGN2_ioFunc ========
116 * This routine removes a frame from the 'todevice' list, fills it
117 * with data, and moves it to the 'fromdevice' list.
118 */
119 Int DGN2_ioFunc(DEV2_Handle device)
120 {
121 DGN2_GenObj *gen;
122 DEV2_Frame *frame;
124 frame = Queue_get(device->todevice);
125 gen = (DGN2_GenObj *)device->object;
127 (*gen->fxn)(gen, frame->addr, frame->size);
129 Queue_put(device->fromdevice, (Queue_Elem *)frame);
131 return (DEV2_OK);
132 }
134 /*
135 * ======== DGN2_open ========
136 * This routine creates a generator object that will be used
137 * when manipulating this device (ie. getting data, getting
138 * status, etc.).
139 */
140 Int DGN2_open(DEV2_Handle device, String name)
141 {
142 DGN2_GenObj *gen;
143 Int gain;
144 Int cnst;
145 Error_Block eb;
147 cnst = 0;
148 Error_init(&eb);
150 /* allocate generator object */
151 if ((gen = Memory_alloc(0, sizeof(DGN2_GenObj), 0, &eb)) == NULL) {
152 Log_error0("DGN2_open: Memory_alloc() failed");
153 return (DEV2_ENOMEM);
154 }
156 gen->dparams = (device->params) ?
157 (DGN2_Params *)device->params : &DGN2_PARAMS;
159 /*
160 * bug fix MR 4493
161 * gain = gain - 1 to fix boundary case --
162 * gain of 128 was yielding values between -256 and 256
163 * gain of 16 gave -32 to 32
164 * etc.
165 */
166 gain = gen->dparams->sine.gain - 1;
167 while (gain > 0) {
168 cnst++;
169 gain >>= 1;
170 }
172 gen->shift = 16 - 1 - cnst;
173 gen->step = (256 * gen->dparams->sine.freq) / gen->dparams->sine.rate;
174 gen->index = 0;
176 gen->seed = gen->dparams->rand.seed;
178 gen->fxn = (Fxn)device->devid;
180 device->object = (Ptr)gen;
182 return (DEV2_OK);
183 }
185 /*
186 * ======== DGN2_user ========
187 * Fill the buffer whose address is "addr" with random values generated
188 * "size" times. The random values are generated using a recursive
189 * equation.
190 */
191 Void DGN2_user(DGN2_GenObj *gen, Ptr addr, size_t size)
192 {
193 Arg arg;
194 Fxn fxn;
196 arg = gen->dparams->user.arg;
197 fxn = gen->dparams->user.fxn;
199 (*fxn)(arg, addr, size);
200 }
202 /*
203 * ======== DGN2_printHex ========
204 */
205 Void DGN2_printHex(Arg arg, Ptr addr, size_t size)
206 {
207 Int16 *buf = (Int16 *)addr;
208 Int tmp;
210 size = size / sizeof(Int16);
212 for (; size > 0; size--, buf++) {
213 tmp = *buf & 0xffff;
214 System_printf("0x%04x\n", tmp);
215 }
216 }
218 /*
219 * ======== DGN2_printInt ========
220 */
221 Void DGN2_printInt(Arg arg, Ptr addr, Uns size)
222 {
223 Int16 *buf = (Int16 *)addr;
225 size = size / sizeof(Int16);
227 for (; size > 0; size--, buf++) {
228 System_printf("%d\n", *buf);
229 }
230 }
232 /*
233 * ======== DGN2_iconst ========
234 * Fill the buffer whose address is "addr" with constant values generated
235 * "size" times.
236 */
237 Void DGN2_iconst(DGN2_GenObj *gen, Int16 *addr, size_t size)
238 {
239 size_t i;
241 for (i = (size / sizeof(Int16)); i > 0; i--) {
242 *addr++ = gen->dparams->constant.value;
243 }
244 }
246 /*
247 * ======== DGN2_irand ========
248 * Fill the buffer whose address is "addr" with random values generated
249 * "size" times. The random values are generated using a recursive
250 * equation.
251 */
252 Void DGN2_irand(DGN2_GenObj *gen, Int16 *addr, size_t size)
253 {
254 size_t i;
255 Uns range;
256 Uns rnd;
257 UInt32 next;
259 range = gen->dparams->rand.upper - gen->dparams->rand.lower + 1;
260 next = gen->seed;
262 for (i = (size / sizeof(Int16)); i > 0; i--) {
263 /*
264 * Random numbers are generated using a linear congruential
265 * psuedo random generator using the equation:
266 * f(n+1) = (a * f(n) + c) mod M, for (n >= 0)
267 * to insure the cycle length to be M = 2^N for an N-bit
268 * binary two's complement machine:
269 * a mod 8 == 5
270 * c mod 2 == 1
271 * See Knuth Vol II Seminumerical Algorithms for theory.
272 */
273 next = next * 1103515245 + 12345;
275 /*
276 * Note the top bits are "more random" than the bottom bits
277 * so to scale the number treat the top 16 bits as a binary
278 * fraction (from 0.0 - < 1.0) and multiply by the desired
279 * range and truncate the result.
280 */
281 rnd = (next >> 16);
282 if (range) {
283 rnd = (Uint16) (((UInt32) rnd * (UInt32) range) >> 16);
284 }
285 *addr++ = rnd + gen->dparams->rand.lower;
286 }
288 gen->seed = next;
289 }
291 /*
292 * ======== DGN2_isine ========
293 * Fill the buffer whose address is "addr" with sine values generated
294 * "size" times.
295 *
296 * NOTE: If the sampling rate is not evenly divisible by the
297 * frequency, the generated output is not a sine wave
298 * but a sequence of a sine-like wave.
299 */
300 Void DGN2_isine(DGN2_GenObj *gen, Int16 *addr, size_t size)
301 {
302 size_t i;
303 static __FAR__ Int16 sineTable[256] = {
304 0x0000,0x0324,0x0647,0x096A,0x0C8B,0x0FAB,0x12C8,0x15E2,
305 0x18F8,0x1C0B,0x1F19,0x2223,0x2528,0x2826,0x2B1F,0x2E11,
306 0x30FB,0x33DE,0x36BA,0x398C,0x3C56,0x3F17,0x41CE,0x447A,
307 0x471C,0x49B4,0x4C3F,0x4EBF,0x5133,0x539B,0x55F5,0x5842,
308 0x5A82,0x5CB4,0x5ED7,0x60EC,0x62F2,0x64E8,0x66CF,0x68A6,
309 0x6A6D,0x6C24,0x6DCA,0x6F5F,0x70E2,0x7255,0x73B5,0x7504,
310 0x7641,0x776C,0x7884,0x798A,0x7A7D,0x7B5D,0x7C29,0x7CE3,
311 0x7D8A,0x7E1D,0x7E9D,0x7F09,0x7F62,0x7FA7,0x7FD8,0x7FF6,
312 0x7FFF,0x7FF6,0x7FD8,0x7FA7,0x7F62,0x7F09,0x7E9D,0x7E1D,
313 0x7D8A,0x7CE3,0x7C29,0x7B5D,0x7A7D,0x798A,0x7884,0x776C,
314 0x7641,0x7504,0x73B5,0x7255,0x70E2,0x6F5F,0x6DCA,0x6C24,
315 0x6A6D,0x68A6,0x66CF,0x64E8,0x62F2,0x60EC,0x5ED7,0x5CB4,
316 0x5A82,0x5842,0x55F5,0x539B,0x5133,0x4EBF,0x4C3F,0x49B4,
317 0x471C,0x447A,0x41CE,0x3F17,0x3C56,0x398C,0x36BA,0x33DE,
318 0x30FB,0x2E11,0x2B1F,0x2826,0x2528,0x2223,0x1F19,0x1C0B,
319 0x18F8,0x15E2,0x12C8,0x0FAB,0x0C8B,0x096A,0x0647,0x0324,
320 0x0000,0xFCDB,0xF9B8,0xF695,0xF374,0xF054,0xED37,0xEA1D,
321 0xE707,0xE3F4,0xE0E6,0xDDDC,0xDAD7,0xD7D9,0xD4E0,0xD1EE,
322 0xCF04,0xCC21,0xC945,0xC673,0xC3A9,0xC0E8,0xBE31,0xBB85,
323 0xB8E3,0xB64B,0xB3C0,0xB140,0xAECC,0xAC64,0xAA0A,0xA7BD,
324 0xA57D,0xA34B,0xA128,0x9F13,0x9D0D,0x9B17,0x9930,0x9759,
325 0x9592,0x93DB,0x9235,0x90A0,0x8F1D,0x8DAA,0x8C4A,0x8AFB,
326 0x89BE,0x8893,0x877B,0x8675,0x8582,0x84A2,0x83D6,0x831C,
327 0x8275,0x81E2,0x8162,0x80F6,0x809D,0x8058,0x8027,0x8009,
328 0x8000,0x8009,0x8027,0x8058,0x809D,0x80F6,0x8162,0x81E2,
329 0x8275,0x831C,0x83D6,0x84A2,0x8582,0x8675,0x877B,0x8893,
330 0x89BE,0x8AFB,0x8C4A,0x8DAA,0x8F1D,0x90A0,0x9235,0x93DB,
331 0x9592,0x9759,0x9930,0x9B17,0x9D0D,0x9F13,0xA128,0xA34B,
332 0xA57D,0xA7BD,0xAA0A,0xAC64,0xAECC,0xB140,0xB3C0,0xB64B,
333 0xB8E3,0xBB85,0xBE31,0xC0E8,0xC3A9,0xC673,0xC945,0xCC21,
334 0xCF04,0xD1EE,0xD4E0,0xD7D9,0xDAD7,0xDDDC,0xE0E6,0xE3F4,
335 0xE707,0xEA1D,0xED37,0xF054,0xF374,0xF695,0xF9B8,0xFCDB,
336 };
338 for (i = (size / sizeof(Int16)); i > 0; i--) {
339 *addr++ = (Int16) sineTable[gen->index] >> (gen->shift); /* modified by gain */
340 gen->index += gen->step;
341 gen->index = gen->index & 0xff; /* count % 256 */
342 }
343 }