forked from buchhla/WeatherLoggerHackster.IO
-
Notifications
You must be signed in to change notification settings - Fork 0
/
TCS34725.cs
456 lines (376 loc) · 17.4 KB
/
TCS34725.cs
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
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Devices.Enumeration;
using Windows.Devices.Gpio;
using Windows.Devices.I2c;
using Windows.UI;
namespace WeatherLogger
{
//Create a class for the raw color data (Red, Green, Blue, Clear)
public class ColorData
{
public UInt16 Red { get; set; }
public UInt16 Green { get; set; }
public UInt16 Blue { get; set; }
public UInt16 Clear { get; set; }
}
//Create a class for the RGB data (Red, Green, Blue)
public class RgbData
{
public int Red { get; set; }
public int Green { get; set; }
public int Blue { get; set; }
public int Clear { get; set; }
}
class TCS34725
{
//Address values set according to the datasheet: http://www.adafruit.com/datasheets/TCS34725.pdf
const byte TCS34725_Address = 0x29;
const byte TCS34725_ENABLE = 0x00;
const byte TCS34725_ENABLE_PON = 0x01; //Power on: 1 activates the internal oscillator, 0 disables it
const byte TCS34725_ENABLE_AEN = 0x02; //RGBC Enable: 1 actives the ADC, 0 disables it
const byte TCS34725_ID = 0x12;
const byte TCS34725_CDATAL = 0x14; //Clear channel data
const byte TCS34725_CDATAH = 0x15;
const byte TCS34725_RDATAL = 0x16; //Red channel data
const byte TCS34725_RDATAH = 0x17;
const byte TCS34725_GDATAL = 0x18; //Green channel data
const byte TCS34725_GDATAH = 0x19;
const byte TCS34725_BDATAL = 0x1A; //Blue channel data */
const byte TCS34725_BDATAH = 0x1B;
const byte TCS34725_ATIME = 0x01; //Integration time
const byte TCS34725_CONTROL = 0x0F; //Set the gain level for the sensor
const byte TCS34725_COMMAND_BIT = 0x80; // Have to | addresses with this value when asking for values
//String for the friendly name of the I2C bus
const string I2CControllerName = "I2C1";
//Create an I2C device
private I2cDevice colorSensor = null;
//Create a GPIO Controller for the LED pin on the sensor
private GpioController gpio;
//Create a GPIO pin for the LED pin on the sensor
private GpioPin LedControlGPIOPin;
//Create a variable to store the GPIO pin number for the sensor LED
private int LedControlPin;
//Variable to check if device is initialized
bool Init = false;
//Create a list of common colors for approximations
private string[] limitColorList = { "Black", "White", "Blue", "Red", "Green", "Purple", "Yellow", "Orange", "DarkSlateBlue", "DarkGray", "Pink" };
//Create a structure to store the name and value of the known colors.
public struct KnownColor
{
public Color colorValue;
public string colorName;
public KnownColor(Color value, string name)
{
colorValue = value;
colorName = name;
}
};
//Create a list to store the known colors
private List<KnownColor> colorList;
// We will default the led control pin to GPIO12 (Pin 32)
public TCS34725(int ledControlPin = 12)
{
Debug.WriteLine("New TCS34725");
//Set the LED control pin
LedControlPin = ledControlPin;
}
//Method to initialize the TCS34725 sensor
public async Task Initialize()
{
Debug.WriteLine("TCS34725::Initialize");
try
{
//Instantiate the I2CConnectionSettings using the device address of the TCS34725
I2cConnectionSettings settings = new I2cConnectionSettings(TCS34725_Address);
//Set the I2C bus speed of connection to fast mode
settings.BusSpeed = I2cBusSpeed.FastMode;
//Use the I2CBus device selector to create an advanced query syntax string
string aqs = I2cDevice.GetDeviceSelector(I2CControllerName);
//Use the Windows.Devices.Enumeration.DeviceInformation class to create a
//collection using the advanced query syntax string
DeviceInformationCollection dis = await DeviceInformation.FindAllAsync(aqs);
//Instantiate the the TCS34725 I2C device using the device id of the I2CBus
//and the I2CConnectionSettings
colorSensor = await I2cDevice.FromIdAsync(dis[0].Id, settings);
////Create a default GPIO controller
//gpio = GpioController.GetDefault();
////Open the LED control pin using the GPIO controller
//LedControlGPIOPin = gpio.OpenPin(LedControlPin);
////Set the pin to output
//LedControlGPIOPin.SetDriveMode(GpioPinDriveMode.Output);
//Initialize the known color list
initColorList();
}
catch (Exception e)
{
Debug.WriteLine("Exception: " + e.Message + "\n" + e.StackTrace);
throw;
}
}
//Method to get the known color list
private void initColorList()
{
colorList = new List<KnownColor>();
//Read the all the known colors from Windows.UI.Colors
foreach (PropertyInfo property in typeof(Colors).GetProperties())
{
//Select the colors in the limited colors list
if (limitColorList.Contains(property.Name))
{
KnownColor temp = new KnownColor((Color)property.GetValue(null), property.Name);
colorList.Add(temp);
}
}
}
//Enum for the LED state
public enum eLedState { On, Off };
//Default state is ON
private eLedState _LedState = eLedState.On;
public eLedState LedState
{
get { return _LedState; }
set
{
Debug.WriteLine("TCS34725::LedState::set");
//To set the LED state, first check for a valid LED control pin
if (LedControlGPIOPin != null)
{
//Set the GPIO pin value to the new value
GpioPinValue newValue = (value == eLedState.On ? GpioPinValue.High : GpioPinValue.Low);
LedControlGPIOPin.Write(newValue);
//Update the LED state variable
_LedState = value;
}
}
}
//An enum for the sensor intergration time, based on the values from the datasheet
enum eTCS34725IntegrationTime
{
TCS34725_INTEGRATIONTIME_2_4MS = 0xFF, //2.4ms - 1 cycle - Max Count: 1024
TCS34725_INTEGRATIONTIME_24MS = 0xF6, //24ms - 10 cycles - Max Count: 10240
TCS34725_INTEGRATIONTIME_50MS = 0xEB, //50ms - 20 cycles - Max Count: 20480
TCS34725_INTEGRATIONTIME_101MS = 0xD5, //101ms - 42 cycles - Max Count: 43008
TCS34725_INTEGRATIONTIME_154MS = 0xC0, //154ms - 64 cycles - Max Count: 65535
TCS34725_INTEGRATIONTIME_700MS = 0x00 //700ms - 256 cycles - Max Count: 65535
};
//Set the default integration time as 700ms
eTCS34725IntegrationTime _tcs34725IntegrationTime = eTCS34725IntegrationTime.TCS34725_INTEGRATIONTIME_700MS;
//An enum for the sensor gain, based on the values from the datasheet
enum eTCS34725Gain
{
TCS34725_GAIN_1X = 0x00, // No gain
TCS34725_GAIN_4X = 0x01, // 2x gain
TCS34725_GAIN_16X = 0x02, // 16x gain
TCS34725_GAIN_60X = 0x03 // 60x gain
};
//Set the default integration time as no gain
eTCS34725Gain _tcs34725Gain = eTCS34725Gain.TCS34725_GAIN_1X;
private async Task begin()
{
Debug.WriteLine("TCS34725::Begin");
byte[] WriteBuffer = new byte[] { TCS34725_ID | TCS34725_COMMAND_BIT };
byte[] ReadBuffer = new byte[] { 0xFF };
//Read and check the device signature
colorSensor.WriteRead(WriteBuffer, ReadBuffer);
Debug.WriteLine("TCS34725 Signature: " + ReadBuffer[0].ToString());
if (ReadBuffer[0] != 0x44)
{
Debug.WriteLine("TCS34725::Begin Signature Mismatch.");
return;
}
//Set the initalize variable to true
Init = true;
//Set the default integration time
setIntegrationTime(_tcs34725IntegrationTime);
//Set default gain
setGain(_tcs34725Gain);
//Note: By default the device is in power down mode on bootup so need to enable it.
await Enable();
}
//Method to write the gain value to the control register
private async void setGain(eTCS34725Gain gain)
{
if (!Init) await begin();
_tcs34725Gain = gain;
byte[] WriteBuffer = new byte[] { TCS34725_CONTROL | TCS34725_COMMAND_BIT,
(byte)_tcs34725Gain };
colorSensor.Write(WriteBuffer);
}
//Method to write the integration time value to the ATIME register
private async void setIntegrationTime(eTCS34725IntegrationTime integrationTime)
{
if (!Init) await begin();
_tcs34725IntegrationTime = integrationTime;
byte[] WriteBuffer = new byte[] { TCS34725_ATIME | TCS34725_COMMAND_BIT,
(byte)_tcs34725IntegrationTime };
colorSensor.Write(WriteBuffer);
}
//Method to enable the sensor
public async Task Enable()
{
Debug.WriteLine("TCS34725::enable");
if (!Init) await begin();
byte[] WriteBuffer = new byte[] { 0x00, 0x00 };
//Enable register
WriteBuffer[0] = TCS34725_ENABLE | TCS34725_COMMAND_BIT;
//Send power on
WriteBuffer[1] = TCS34725_ENABLE_PON;
colorSensor.Write(WriteBuffer);
//Pause between commands
await Task.Delay(3);
//Send ADC Enable
WriteBuffer[1] = (TCS34725_ENABLE_PON | TCS34725_ENABLE_AEN);
colorSensor.Write(WriteBuffer);
}
//Method to disable the sensor
public async Task Disable()
{
Debug.WriteLine("TCS34725::disable");
if (!Init) await begin();
byte[] WriteBuffer = new byte[] { TCS34725_ENABLE | TCS34725_COMMAND_BIT };
byte[] ReadBuffer = new byte[] { 0xFF };
//Read the enable buffer
colorSensor.WriteRead(WriteBuffer, ReadBuffer);
//Turn the device off to save power by reversing the on conditions
byte onState = (TCS34725_ENABLE_PON | TCS34725_ENABLE_AEN);
byte offState = (byte)~onState;
offState &= ReadBuffer[0];
byte[] OffBuffer = new byte[] { TCS34725_ENABLE, offState };
//Write the off buffer
colorSensor.Write(OffBuffer);
}
//Method to get the 16-bit color from 2 8-bit buffers
UInt16 ColorFromBuffer(byte[] buffer)
{
UInt16 color = 0x00;
color = buffer[1];
color <<= 8;
color |= buffer[0];
return color;
}
//Method to read the raw color data
public async Task<ColorData> getRawData()
{
//Create an object to store the raw color data
ColorData colorData = new ColorData();
//Make sure the I2C device is initialized
if (!Init) await begin();
byte[] WriteBuffer = new byte[] { 0x00 };
byte[] ReadBuffer = new byte[] { 0x00, 0x00 };
//Read and store the clear data
WriteBuffer[0] = TCS34725_CDATAL | TCS34725_COMMAND_BIT;
colorSensor.WriteRead(WriteBuffer, ReadBuffer);
colorData.Clear = ColorFromBuffer(ReadBuffer);
//Read and store the red data
WriteBuffer[0] = TCS34725_RDATAL | TCS34725_COMMAND_BIT;
colorSensor.WriteRead(WriteBuffer, ReadBuffer);
colorData.Red = ColorFromBuffer(ReadBuffer);
//Read and store the green data
WriteBuffer[0] = TCS34725_GDATAL | TCS34725_COMMAND_BIT;
colorSensor.WriteRead(WriteBuffer, ReadBuffer);
colorData.Green = ColorFromBuffer(ReadBuffer);
//Read and store the blue data
WriteBuffer[0] = TCS34725_BDATAL | TCS34725_COMMAND_BIT;
colorSensor.WriteRead(WriteBuffer, ReadBuffer);
colorData.Blue = ColorFromBuffer(ReadBuffer);
//Output the raw data to the debug console
Debug.WriteLine("Raw Data - red: {0}, green: {1}, blue: {2}, clear: {3}",
colorData.Red, colorData.Green, colorData.Blue, colorData.Clear);
//Return the data
return colorData;
}
//Method to read the RGB data
public async Task<RgbData> getRgbData()
{
//Create an object to store the raw color data
RgbData rgbData = new RgbData();
//First get the raw color data
ColorData colorData = await getRawData();
//Check if clear data is received
if (colorData.Clear > 0)
{
//Find the RGB values from the raw data using the clear data as reference
rgbData.Red = (colorData.Red * 255 / colorData.Clear);
rgbData.Blue = (colorData.Blue * 255 / colorData.Clear);
rgbData.Green = (colorData.Green * 255 / colorData.Clear);
}
//Write the RGB values to the debug console
Debug.WriteLine("RGB Data - red: {0}, green: {1}, blue: {2}", rgbData.Red, rgbData.Green, rgbData.Blue);
//Return the data
return rgbData;
}
//Method to find the approximate color
public async Task<string> getClosestColor()
{
//Create an object to store the raw color data
RgbData rgbData = await getRgbData();
//Create a variable to store the closest color. Black by default.
KnownColor closestColor = colorList[7];
//Create a variable to store the minimum Euclidean distance between 2 colors
double minDiff = double.MaxValue;
//For every known color, check the Euclidean distance and store the minimum distance
foreach (var color in colorList)
{
Color colorValue = color.colorValue;
double diff = Math.Pow((colorValue.R - rgbData.Red), 2) +
Math.Pow((colorValue.G - rgbData.Green), 2) +
Math.Pow((colorValue.B - rgbData.Blue), 2);
diff = (int)Math.Sqrt(diff);
if (diff < minDiff)
{
minDiff = diff;
closestColor = color;
}
}
//Write the approximate color to the debug console
Debug.WriteLine("Approximate color: " + closestColor.colorName + " - "
+ closestColor.colorValue.ToString());
//Return the approximate color
return closestColor.colorName;
}
public static float getLuxSimple(RgbData rgb)
{
float illuminance;
/* This only uses RGB ... how can we integrate clear or calculate lux */
/* based exclusively on clear since this might be more reliable? */
illuminance = (-0.32466F * rgb.Red) + (1.57837F * rgb.Green) + (-0.73191F * rgb.Blue);
return illuminance;
}
//public static float getLux(RgbData rgb)
//{
// float illuminance;
// float ir;
// ir = (rgb.Red + rgb.Green + rgb.Blue)
// return illuminance;
//}
public static float calculateColorTemperature(RgbData rgb)
{
float X, Y, Z; /* RGB to XYZ correlation */
float xc, yc; /* Chromaticity co-ordinates */
float n; /* McCamy's formula */
float cct;
/* 1. Map RGB values to their XYZ counterparts. */
/* Based on 6500K fluorescent, 3000K fluorescent */
/* and 60W incandescent values for a wide range. */
/* Note: Y = Illuminance or lux */
X = (-0.14282F * rgb.Red) + (1.54924F * rgb.Green) + (-0.95641F * rgb.Blue);
Y = (-0.32466F * rgb.Red) + (1.57837F * rgb.Green) + (-0.73191F * rgb.Blue);
Z = (-0.68202F * rgb.Red) + (0.77073F * rgb.Green) + (0.56332F * rgb.Blue);
/* 2. Calculate the chromaticity co-ordinates */
xc = (X) / (X + Y + Z);
yc = (Y) / (X + Y + Z);
/* 3. Use McCamy's formula to determine the CCT */
n = (xc - 0.3320F) / (0.1858F - yc);
/* Calculate the final CCT */
cct = (float)((449.0F * Math.Pow(n, 3)) + (3525.0F * Math.Pow(n, 2)) + (6823.3F * n) + 5520.33F);
/* Return the results in degrees Kelvin */
return cct;
}
}
}