summaryrefslogtreecommitdiffstats
path: root/src/oscilloscopedata.h
blob: b73eb4c73e97ceef6ff37bc0e36add1047b4e5f8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
/***************************************************************************
 *   Copyright (C) 2005 by David Saxton                                    *
 *   david@bluehaze.org                                                    *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 ***************************************************************************/

#ifndef OSCILLOSCOPEDATA_H
#define OSCILLOSCOPEDATA_H

#include <tqcolor.h>
#include <tqobject.h>

typedef long long llong;
typedef unsigned long long ullong;
typedef unsigned int uint;

#define DATA_CHUNK_SIZE (8192/sizeof(T))
#define DATA_CHUNK_ARRAY_SIZE ((8192-sizeof(uint))/sizeof(DataChunk<T>*))

// Allow a minimum of 64 megabytes of stored data (67108864 bytes)
/// \todo The maximum allowed amount of stored data should be configurable or
/// more intelligent (e.g. taking into account the number of probes or the
/// amount of physical memory on the system).
#define DCARRAY_ARRAY_SIZE ((67108864/(8192*DATA_CHUNK_ARRAY_SIZE))+1)


/**
For use in LogicProbe: Every time the input changes state, the new input state
is recorded in value, along with the simulator time that it occurs at.
 */
class LogicDataPoint
{
	public:
		LogicDataPoint()
		{
			value = 0;
			time = 0;
		}
		LogicDataPoint( bool v, ullong t )
		{
			value = v;
			time = t;
		}
		bool	value	:  1;
		ullong	time	: 63;
};


template <typename T>
class DataChunk
{
	public:
		DataChunk() { memset( data, 0, DATA_CHUNK_SIZE*sizeof(T) ); }
		
		T data[ DATA_CHUNK_SIZE ];
		
	private:
		// We don't want to accidently copy a shedload of data
		DataChunk( const DataChunk & );
};

typedef DataChunk<LogicDataPoint> LogicChunk;
typedef DataChunk<float> FloatingChunk;


template <typename T>
class DCArray
{
	public:
		DCArray()
		{
			memset( m_data, 0, DATA_CHUNK_ARRAY_SIZE*sizeof(DataChunk<T> *) );
			m_allocatedUpTo = 0;
		}
		~DCArray()
		{
			for ( uint i=0; i<m_allocatedUpTo; ++i)
				delete m_data[i];
		}
		
		inline DataChunk<T> * chunk( uint i )
		{
			if ( i >= m_allocatedUpTo )
				allocateUpTo(i+1024);
			
			if ( i >= DATA_CHUNK_ARRAY_SIZE )
				return 0l;
			
			return m_data[i];
		}
		uint allocatedUpTo() const { return m_allocatedUpTo; }
		
		
	protected:
		void allocateUpTo( uint upTo )
		{
			if ( upTo > DATA_CHUNK_ARRAY_SIZE )
				upTo = DATA_CHUNK_ARRAY_SIZE;
	
			for ( uint i=m_allocatedUpTo; i<upTo; ++i )
				m_data[i] = new DataChunk<T>;
			m_allocatedUpTo = upTo;
		}
		
		DataChunk<T> * m_data[DATA_CHUNK_ARRAY_SIZE];
		uint m_allocatedUpTo;
		
	private:
		// We don't want to accidently copy a shedload of data
		DCArray( const DCArray & );
};


template <typename T>
class StoredData
{
	public:
		StoredData()
		{
			memset( m_data, 0, DCARRAY_ARRAY_SIZE*sizeof(DCArray<T> *) );
			m_allocatedUpTo = 0;
		}
		~StoredData()
		{
			reset();
		}
		
		inline T & operator[]( ullong i )
		{
			return dataAt(i);
		}
		inline T & dataAt( ullong i, ullong * insertPos = 0 )
		{
			ullong c = i % DATA_CHUNK_SIZE;
			ullong b = ullong((i-c)/DATA_CHUNK_SIZE) % DATA_CHUNK_ARRAY_SIZE;
			ullong a = ullong((ullong((i-c)/DATA_CHUNK_SIZE)-b)/DATA_CHUNK_ARRAY_SIZE);
			
			if ( a >= m_allocatedUpTo )
				allocateUpTo(a+1);
			
			if ( a >= DCARRAY_ARRAY_SIZE )
			{
				a = DCARRAY_ARRAY_SIZE - 1;
				if ( insertPos )
					*insertPos = toPos( a, b, c );
			}
			
			return m_data[a]->chunk(b)->data[c];
		}
		
		ullong toPos( ullong a, ullong b, ullong c ) const
		{
			return (((a*DATA_CHUNK_ARRAY_SIZE)+b)*DATA_CHUNK_SIZE)+c;
		}
		
		uint allocatedUpTo() const { return m_allocatedUpTo; }
		
		DCArray<T> * dcArray( unsigned pos ) const
		{
			return (pos < m_allocatedUpTo) ? m_data[pos] : 0l;
		}
		
		/**
		 * Initialises all data to 0
		 */
		void reset()
		{
			for ( uint i=0; i<m_allocatedUpTo; ++i)
				delete m_data[i];
			m_allocatedUpTo = 0;
		}
		
	protected:
		void allocateUpTo( uint upTo )
		{
			if ( upTo >= DCARRAY_ARRAY_SIZE )
			{
				// Shuffle all data (getting rid of the oldest data)
				delete m_data[0];
				for ( unsigned i = 1; i < m_allocatedUpTo; ++i )
					m_data[i-1] = m_data[i];
				
				upTo = DCARRAY_ARRAY_SIZE;
				m_allocatedUpTo--;
			}
	
			for ( unsigned i = m_allocatedUpTo; i < upTo; ++i )
				m_data[i] = new DCArray<T>;
			
			m_allocatedUpTo = upTo;
		}
		DCArray<T> * m_data[DCARRAY_ARRAY_SIZE];
		
		uint m_allocatedUpTo;
		
	private:
		// We don't want to accidently copy a shedload of data
		StoredData( const StoredData<T> & );
};


/**
@author David Saxton
 */
class ProbeData : public TQObject
{
	Q_OBJECT
	

	public:
		ProbeData( int id );
		~ProbeData();
		
		/**
		 * @returns unique id for oscilloscope, set on construction
		 */
		int id() const { return m_id; }
		/**
		 * Set the proportion (0 = top, 1 = bottom) of the way down the
		 * oscilloscope view that the probe output is drawn. If the proportion
		 * is out of range ( <0, or >1), then the drawPosition is set to 0/1
		 */
		void setDrawPosition( float drawPosition ) { m_drawPosition = drawPosition; }
		/**
		 * Returns the draw position. Default is 0.5.
		 * @see setDrawPosition
		 */
		float drawPosition() const { return m_drawPosition; }
		/**
		 * Set the colour that is used to display the probe in the oscilloscope.
		 * Default is black.
		 */
		void setColor( TQColor color );
		/**
		 * @returns the colour that is used to display the probe in the oscilloscope
		 */
		TQColor color() const { return m_color; }
// 		/**
// 		 * Will not record any data when paused
// 		 */
// 		void setPaused( bool isPaused ) { b_isPaused = isPaused; }
		/**
		 * Returns the time (in Simulator time) that this probe was created at,
		 * or last reset.
		 */
		ullong resetTime() const { return m_resetTime; }
		/**
		 * Erases all recorded data, and sets m_resetTime to the current
		 * simulator time.
		 */
		virtual void eraseData() = 0;
		/**
		 * Searches for and returns the position of the last DataPoint that was
		 * added before or at the given Simulator time. If no DataPoints were
		 * were recorded before the given time, then will return the one closest
		 * to the given time. Will return 0 if no DataPoints have been recorded
		 * yet.
		 */
		virtual ullong findPos( llong time ) const = 0;
		
		ullong insertPos() const { return m_insertPos; }
		
	signals:
		/**
		 * Emitted when an attribute that affects how the probe is drawn in the
		 * oscilloscope is changed.
		 */
		void displayAttributeChanged();
		
	protected:
		const int m_id;
		float m_drawPosition;
		ullong m_insertPos;
// 		bool b_isPaused;
		ullong m_resetTime;
		TQColor m_color;
};


/**
@author David Saxton
*/
class LogicProbeData : public ProbeData
{
	public:
		LogicProbeData( int id );
		
		/**
		 * Appends the data point to the set of data.
		 */
		void addDataPoint( LogicDataPoint data )
		{
			ullong next = m_insertPos++;
			m_data.dataAt( next, & m_insertPos ) = data;
		}
		
		virtual void eraseData();
		virtual ullong findPos( llong time ) const;
		
	protected:
		StoredData<LogicDataPoint> m_data;
		friend class OscilloscopeView;
};


/**
@author David Saxton
*/
class FloatingProbeData : public ProbeData
{
	public:
		enum Scaling { Linear, Logarithmic };
		
		FloatingProbeData( int id );
		
		/**
		 * Appends the data point to the set of data.
		 */
		void addDataPoint( float data ) { m_data[m_insertPos++] = data; }
		/**
		 * Converts the insert position to a Simulator time.
		 */
		ullong toTime( ullong at ) const;
		/**
		 * Sets the scaling to use in the oscilloscope display.
		 */
		void setScaling( Scaling scaling );
		/**
		 * @return the scaling used for the oscilloscope display.
		 */
		Scaling scaling() const { return m_scaling; }
		/**
		 * Sets the value to use as the upper absolute value in the display.
		 */
		void setUpperAbsValue( double upperAbsValue );
		/**
		 * @return the upper absolute value to use in the display.
		 */
		double upperAbsValue() const { return m_upperAbsValue; }
		/**
		 * Sets the value to use as the lower absolute value in the display
		 * (this is only used with logarithmic scaling).
		 */
		void setLowerAbsValue( double lowerAbsValue );
		/**
		 * @return the lower absolute value to use in the display (this is
		 * only used with logarithmic scaling).
		 */
		double lowerAbsValue() const { return m_lowerAbsValue; }
		
		virtual void eraseData();
		virtual ullong findPos( llong time ) const;
		
	protected:
		Scaling m_scaling;
		double m_upperAbsValue;
		double m_lowerAbsValue;
		StoredData<float> m_data;
		friend class OscilloscopeView;
};
	

#endif