-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathutility.c
288 lines (221 loc) · 11.2 KB
/
utility.c
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
// ========================================================================================================
// ========================================================================================================
// ********************************************** utility.c ***********************************************
// ========================================================================================================
// ========================================================================================================
//
//--------------------------------------------------------------------------------
// Company: IC-Safety, LLC and University of New Mexico
// Engineer: Professor Jim Plusquellic
// Exclusive License: IC-Safety, LLC
// Copyright: Univ. of New Mexico
//--------------------------------------------------------------------------------
#include "utility.h"
// ===========================================================================================================
// ===========================================================================================================
// Largest integer number NOT greater than argument. So floor(-0.6 + 0.5) = floor(-0.1) = -1.0. So this function
// rounds AWAY from 0, which is exactly what we want when arg is negative.
float Round(float d)
{ return (float)floor((double)d + 0.5); }
// ===========================================================================================================
// ===========================================================================================================
float ComputeMean(int num_vals, float *vals)
{
int i;
double mean;
if ( num_vals == 0 )
{ printf("ERROR: ComputeMean(): num_vals is 0!\n"); exit(EXIT_FAILURE); }
mean = 0.0;
for ( i = 0; i < num_vals; i++ )
{ mean += (double)vals[i]; }
return (float)(mean/(double)num_vals);
}
// ===========================================================================================================
// ===========================================================================================================
// qsort: Return -x if ele1 < ele2, 0 if ele1 == ele2 and +x if ele1 > ele2.
int MedianCompareFunc(const void *v1, const void *v2)
{
if ( *(float *)v1 - *(float *)v2 == 0.0 )
return 0;
else if ( *(float *)v1 - *(float *)v2 < 0.0 )
return -1;
else
return 1;
}
// ===========================================================================================================
// ===========================================================================================================
// Compute the median value by sorting and returning the value of the middle value.
float ComputeMedian(int num_vals, float *vals)
{
float *median_vals;
float median;
int i;
if ( num_vals == 0 )
{ printf("ERROR: ComputeMedian(): Number of values MUST be > 0!\n"); exit(EXIT_FAILURE); }
if ( num_vals == 1 )
return vals[0];
if ( (median_vals = (float *)malloc(num_vals*sizeof(float))) == NULL )
{ printf("ERROR: ComputeMedian(): Malloc FAILED!\n"); exit(EXIT_FAILURE); }
// Copy array to temporary array so we can sort it without disturbing the array passed in.
for ( i = 0; i < num_vals; i++ )
median_vals[i] = vals[i];
qsort(median_vals, num_vals, sizeof(float), MedianCompareFunc);
// If even number, compute average of two middle samples, otherwise return middle value;
if ( num_vals % 2 == 0 )
median = (median_vals[num_vals/2 - 1] + median_vals[num_vals/2])/2;
else
median = median_vals[num_vals/2];
#ifdef DEBUG
for ( i = 0; i < num_vals; i++ )
printf("\t%d) Median val %f\n", i, median_vals[i]);
printf("MEDIAN => %f\n", median);
fflush(stdout);
#endif
free(median_vals);
return median;
}
// ===========================================================================================================
// ===========================================================================================================
float ComputeStdDev(int num_vals, float mean, float *vals)
{
int i;
double std_dev;
if ( num_vals <= 1 )
{ printf("ERROR: ComputeStdDev(): num_vals is <= 1!\n"); exit(EXIT_FAILURE); }
std_dev = 0.0;
for ( i = 0; i < num_vals; i++ )
{ std_dev += pow((double)mean - (double)vals[i], (double)2); }
return (float)sqrt(std_dev/(double)(num_vals - 1));
}
// ===========================================================================================================
// ===========================================================================================================
// This routine takes a char (a byte) and a bit position between 0 and 7 and returns the value of the bit
// at that position as 0 or 1. It is used to make use of compact bitstring arrays.
int GetBitFromByte(unsigned char byte, int bit_pos)
{
// Note this is equal to 0 or SOMETHING LARGER THAN 0 WHICH IS NOT NECESSARILY 1 so we MUST compare to 0 or
// >0 -- NOT to 1.
return ((byte & (1 << bit_pos)) == 0) ? 0 : 1;
}
// ===========================================================================================================
// ===========================================================================================================
// This routine takes a char (a byte), a bit value and a bit position between 0 and 7 and overwrites the bit
// in the byte with the new bit. The byte is returned.
void SetBitInByte(unsigned char *byte_ptr, int bit_val, int bit_pos)
{
*byte_ptr = (bit_val == 0) ? (*byte_ptr) & ~(1 << bit_pos) : (*byte_ptr) | (1 << bit_pos);
}
// ========================================================================================================
// ========================================================================================================
// ASCII '0'/'1' string to binary.
void ASCIIByteToBin(unsigned char *binary_byte_ptr, char *ascii_str)
{
int i;
*binary_byte_ptr = 0;
for ( i = 0; i < 8; i++ )
if ( ascii_str[i] == '1' )
*binary_byte_ptr *= 2 + 1;
else
*binary_byte_ptr *= 2;
return;
}
// ========================================================================================================
// ========================================================================================================
// Binary byte to ASCII '0'/'1' string
void BinByteToASCII(unsigned char binary_byte, char *ascii_str)
{
int i;
for ( i = 0; i < 8; i++ )
if ( (binary_byte & (unsigned char)(1 << (7 - i))) == 0 )
ascii_str[i] = '0';
else
ascii_str[i] = '1';
return;
}
// ===========================================================================================================
// ===========================================================================================================
// Convert a binary vec/mask to an ASCII vec/mask. Assume storage is allocated in caller. NOTE: mask_asc is
// num_POs + 1 in size (for NULL character). NOTE that the ORDER is reversed so that low addresses in the ASCII
// version correspond to high order bits in the binary vector/mask. This also works for packed SHD, SBS, DHD,
// etc.
void ConvertBinVecMaskToASCII(int num_PI_POs, unsigned char *vec_mask_bin, char *vec_mask_asc)
{
int PI_PO_num;
for ( PI_PO_num = 0; PI_PO_num < num_PI_POs; PI_PO_num++ )
vec_mask_asc[num_PI_POs - PI_PO_num - 1] = (GetBitFromByte(vec_mask_bin[PI_PO_num/8], PI_PO_num % 8) == 1 ) ? '1' : '0';
vec_mask_asc[num_PI_POs] = '\0';
return;
}
// ===========================================================================================================
// ===========================================================================================================
// Covert ASCII vec/mask to binary version. Note that ASCII vector is specified from char[0] to char[num_PIs]
// in high order bit to low order bit order. Reverse this order in the the unsigned char binary byte array by
// starting the load at the highest byte and working toward the lowest byte. The hardware transfer by the chip
// to the PL side loads the data in this order. Note that the ASCII version is convenient because when printed,
// the high-order byte is printed on the left (which is the natural way to read the vector). But the left-most
// character of the ASCII version for the high-order bit has the lowest address so we need to reverse it.
// Storage MUST be allocated in caller. NOTE: 'num_PIs' MUST BE DIVISIBLE BY 8.
void ConvertASCIIVecMaskToBinary(int num_PI_POs, char *vec_mask_asc, unsigned char *vec_mask_bin)
{
int bit_cnter, byte_cnter, mod_8_val;
if ( (num_PI_POs % 8) != 0 )
{
printf("ERROR: ConvertASCIIVecMaskToBinary(): number of ASCII chars to convert MUST be a multiple of 8 => %d!\n",
num_PI_POs); exit(EXIT_FAILURE);
}
byte_cnter = num_PI_POs/8 - 1;
for ( bit_cnter = 0; bit_cnter < num_PI_POs; )
{
// Sanity check
if ( byte_cnter < 0 )
{
printf("ERROR: ConvertASCIIVecMaskToBinary(): Program error: 'byte_cnter' %d is LESS THAN 0!\n", byte_cnter);
exit(EXIT_FAILURE);
}
// Zero out the unsigned char byte on multiples of 8 bits.
mod_8_val = bit_cnter % 8;
if ( mod_8_val == 0 )
vec_mask_bin[byte_cnter] = 0;
// Keep adding in bits to the current byte at the appropriate bit position in the byte. Left to right processing of the line needs to make
// the first (left-most) ASCII bit in file 'line' the high order bit in the binary byte.
if ( vec_mask_asc[bit_cnter] == '1' )
vec_mask_bin[byte_cnter] += (unsigned char)(1 << (7 - mod_8_val));
// Increment to the next ASCII bit.
bit_cnter++;
// After processing 8 ASCII bits, decrement the unsigned char index.
if ( (bit_cnter % 8) == 0 )
{
#ifdef DEBUG
printf("%02X ", vec_ptr[byte_cnter]); fflush(stdout);
#endif
byte_cnter--;
}
}
#ifdef DEBUG
printf("\n"); fflush(stdout);
#endif
return;
}
// ===========================================================================================================
// ===========================================================================================================
// 10_10_2022: Save ASCII '0'/'1' bitstring to a file so we can do a statistical analysis on them.
void WriteASCIIBitstringToFile(int max_string_len, char *outfile_name, int create_or_append, int num_bits,
unsigned char *bitstring_binary)
{
int bit_num;
FILE *OUTFILE;
if ( create_or_append == 0 )
{
if ( (OUTFILE = fopen(outfile_name, "w")) == NULL )
{ printf("ERROR: WriteASCIIBitstringToFile(): Data file '%s' open failed for writing!\n", outfile_name); exit(EXIT_FAILURE); }
}
else
if ( (OUTFILE = fopen(outfile_name, "a")) == NULL )
{ printf("ERROR: WriteASCIIBitstringToFile(): Data file '%s' open failed for writing!\n", outfile_name); exit(EXIT_FAILURE); }
// Save only the exposed SHD sent by the device. Doing this analysis in CobraAnalyzeSHD.c now -- NOT HERE.
for ( bit_num = 0; bit_num < num_bits; bit_num++ )
fprintf(OUTFILE, "%d", GetBitFromByte(bitstring_binary[bit_num/8], bit_num % 8));
fprintf(OUTFILE, "\n");
fclose(OUTFILE);
return;
}