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