From 505ef0e627906a830ec5bdc97b774742c6daf93f Mon Sep 17 00:00:00 2001 From: BlubbFish Date: Wed, 3 Jul 2019 21:27:38 +0200 Subject: [PATCH] Now working, first version with all parts --- IotThermometer/App.config | 6 - IotThermometer/IotThermometer.csproj | 5 +- IotThermometer/Librarys/Bme280.cs | 378 ++++++---------- IotThermometer/Librarys/Rainbowdruino.cs | 215 +++++++++ IotThermometer/Librarys/TSL2591.cs | 531 +++++++++++------------ IotThermometer/Program.cs | 33 +- IotThermometer/System/ATwi.cs | 39 ++ 7 files changed, 661 insertions(+), 546 deletions(-) delete mode 100644 IotThermometer/App.config create mode 100644 IotThermometer/Librarys/Rainbowdruino.cs create mode 100644 IotThermometer/System/ATwi.cs diff --git a/IotThermometer/App.config b/IotThermometer/App.config deleted file mode 100644 index 4bba09a..0000000 --- a/IotThermometer/App.config +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/IotThermometer/IotThermometer.csproj b/IotThermometer/IotThermometer.csproj index e5c4454..27df099 100644 --- a/IotThermometer/IotThermometer.csproj +++ b/IotThermometer/IotThermometer.csproj @@ -43,14 +43,13 @@ + + - - - {8C5D4DE9-377F-4EC8-873D-6EEF15F43516} diff --git a/IotThermometer/Librarys/Bme280.cs b/IotThermometer/Librarys/Bme280.cs index 8eebcbe..53547b5 100644 --- a/IotThermometer/Librarys/Bme280.cs +++ b/IotThermometer/Librarys/Bme280.cs @@ -1,274 +1,154 @@ using System; +using BlubbFish.Iot.Thermometer.System; using BlubbFish.Utils; -using Unosquare.RaspberryIO; -using Unosquare.RaspberryIO.Gpio; namespace BlubbFish.Iot.Thermometer.Librarys { - class Bme280 { - public Bme280(Int32 address) => this.w = Pi.I2C.AddDevice(address); + class Bme280 : ATwi { + private CalibrationData dig; + private Boolean init = false; + public Double Temperatur { get; private set; } + public Double Pressure { get; private set; } + public Double Humidity { get; private set; } + + public Bme280(Int32 address) : base(address) { } + + #region Main public void Begin() { - if(this.Read8((Byte)Register.BME280_REG_ID) != 0x60) { - Helper.WriteError("Fail to init Barometer\n"); + if(!this.init) { + if(this.ReadByte(RegisterAddress.ID) != 0x60) { + Helper.WriteError("Fail to init Barometer"); + return; + } + this.dig = new CalibrationData(this); + //Humidity oversampling 16X oversampling [2..0] + this.WriteByte(RegisterAddress.CTRL_HUM, 0b00000101); + //Pressure oversampling 16X oversampling [7..5], Temperature oversampling 16X oversampling [4..2], Mode Normal mode [1..0] + this.WriteByte(RegisterAddress.CTRL_MEAS, 0b10110111); + //inactive duration 250 ms [7..5], IIR filter Filter coefficient 16 [4..2], SPI Interface off [0] + this.WriteByte(RegisterAddress.CONFIG, 0b01110000); + Console.WriteLine("Barometer ok"); + this.init = true; } - this.ReadTrimming(); - //Humidity oversampling 16X oversampling [2..0] - this.WriteRegister((Byte)Register.BME280_REG_CTRL_HUM, 0b00000101); - //Pressure oversampling 16X oversampling [7..5], Temperature oversampling 16X oversampling [4..2], Mode Normal mode [1..0] - this.WriteRegister((Byte)Register.BME280_REG_CTRL_MEAS, 0b10110111); - //inactive duration 250 ms [7..5], IIR filter Filter coefficient 16 [4..2], SPI Interface off [0] - this.WriteRegister((Byte)Register.BME280_REG_CONFIG, 0b01110000); - Console.WriteLine("Barometer ok\n"); } public void Measure() { - this._adc_T = (Int32)this.Read20((Byte)Register.BME280_REG_TEMP_DATA); - this._adc_P = (Int32)this.Read20((Byte)Register.BME280_REG_PRESS_DATA); - //this._adc_H = this.Read16((Byte)Register.BME280_REG_HUM_DATA); + if(this.init) { + UInt32 temperatur = this.Read20(RegisterAddress.TEMP_DATA); + UInt32 pressure = this.Read20(RegisterAddress.PRESS_DATA); + UInt16 humidity = this.ReadShortLE(RegisterAddress.HUM_DATA); + this.CalcTemp((Int32)temperatur); + this.CalcPress((Int32)pressure); + this.CalcHum(humidity); + } + } + #endregion + + #region Calculation + private void CalcTemp(Int32 adc_T) { + Double var1 = (adc_T / 16384.0 - this.dig.T1 / 1024.0) * this.dig.T2; + Double var2 = ((adc_T / 131072.0 - this.dig.T1 / 8192.0) * (adc_T / 131072.0 - this.dig.T1 / 8192.0)) * this.dig.T3; + this.Temperatur = (var1 + var2) / 5120.0; } - public Double GetTemperature() { - Int32 adc_T = this._adc_T; - //Int32 var1, var2; - - Double var1, var2; - var1 = (adc_T / 16384.0 - this._dig_T1 / 1024.0) * this._dig_T2; - var2 = ((adc_T / 131072.0 - this._dig_T1 / 8192.0) * (adc_T / 131072.0 - this._dig_T1 / 8192.0)) * this._dig_T3; - this._t_fine = (Int32)(var1 + var2); - return (var1 + var2) / 5120.0; - - /*var1 = (((adc_T >> 3) - (this._dig_T1 << 1)) * this._dig_T2) >> 11; - var2 = (((((adc_T >> 4) - this._dig_T1) * ((adc_T >> 4) - this._dig_T1)) >> 12) * this._dig_T3) >> 14; - this._t_fine = var1 + var2; - return ((Double)(this._t_fine * 5 + 128 >> 8)) / 100;*/ - - /*adc_T >>= 4; - var1 = (((adc_T >> 3) - ((int32_t)(this->_dig_T1 << 1))) * ((int32_t)this->_dig_T2)) >> 11; - var2 = (((((adc_T >> 4) - ((int32_t)this->_dig_T1)) * ((adc_T >> 4) - ((int32_t)this->_dig_T1))) >> 12) * ((int32_t)this->_dig_T3)) >> 14; - t_fine = var1 + var2; - float T = (t_fine * 5 + 128) >> 8; - return T/100;*/ - } - - public Double GetPressure() { - Int32 adc_P = this._adc_P; - - Double var1, var2, p; - var1 = (this._t_fine / 2.0) - 64000.0; - var2 = var1 * var1 * this._dig_P6 / 32768.0; - var2 = var2 + var1 * this._dig_P5 * 2.0; - var2 = (var2 / 4.0) + (this._dig_P4 * 65536.0); - var1 = (this._dig_P3 * var1 * var1 / 524288.0 + this._dig_P2 * var1) / 524288.0; - var1 = (1.0 + var1 / 32768.0) * this._dig_P1; + private void CalcPress(Int32 adc_P) { + Double var1 = (this.Temperatur * 5120 / 2.0) - 64000.0; + Double var2 = var1 * var1 * this.dig.P6 / 32768.0; + var2 = var2 + var1 * this.dig.P5 * 2.0; + var2 = (var2 / 4.0) + (this.dig.P4 * 65536.0); + var1 = (this.dig.P3 * var1 * var1 / 524288.0 + this.dig.P2 * var1) / 524288.0; + var1 = (1.0 + var1 / 32768.0) * this.dig.P1; if(var1 == 0.0) { - return 0; // avoid exception caused by division by zero + this.Pressure = 0; // avoid exception caused by division by zero + return; } - p = 1048576.0 - adc_P; + Double p = 1048576.0 - adc_P; p = (p - (var2 / 4096.0)) * 6250.0 / var1; - var1 = this._dig_P9 * p * p / 2147483648.0; - var2 = p * this._dig_P8 / 32768.0; - return (p + (var1 + var2 + this._dig_P7) / 16.0) / 100.0; - - /*Int64 var1, var2, P; - - var1 = ((Int64)this._t_fine) - 128000; - var2 = var1 * var1 * this._dig_P6; - var2 = var2 + ((var1 * this._dig_P5) << 17); - var2 = var2 + (((Int64)this._dig_P4) << 35); - var1 = ((var1 * var1 * this._dig_P3) >> 8) + ((var1 * this._dig_P2) << 12); - var1 = ((((Int64)1) << 47) + var1) * this._dig_P1 >> 33; - if(var1 == 0) { - return 0.0; // avoid exception caused by division by zero - } - P = 1048576 - adc_P; - P = (((P << 31) - var2) * 3125) / var1; - var1 = (this._dig_P9 * (P >> 13) * (P >> 13)) >> 25; - var2 = (this._dig_P8 * P) >> 19; - P = ((P + var1 + var2) >> 8) + (((Int64)this._dig_P7) << 4); - return ((Double)((UInt32)P)) / 25600;*/ - - - /*adc_P >>= 4; - var1 = ((int64_t)t_fine) - 128000; - var2 = var1 * var1 * (int64_t)this->_dig_P6; - var2 = var2 + ((var1*(int64_t)this->_dig_P5)<<17); - var2 = var2 + (((int64_t)this->_dig_P4)<<35); - var1 = ((var1 * var1 * (int64_t)this->_dig_P3)>>8) + ((var1 * (int64_t)this->_dig_P2)<<12); - var1 = (((((int64_t)1)<<47)+var1))*((int64_t)this->_dig_P1)>>33; - if (var1 == 0) { - return 0; // avoid exception caused by division by zero - } - p = 1048576-adc_P; - p = (((p<<31)-var2)*3125)/var1; - var1 = (((int64_t)this->_dig_P9) * (p>>13) * (p>>13)) >> 25; - var2 = (((int64_t)this->_dig_P8) * p) >> 19; - p = ((p + var1 + var2) >> 8) + (((int64_t)this->_dig_P7)<<4); - return ((float)(uint32_t)p/256)/100;*/ + var1 = this.dig.P9 * p * p / 2147483648.0; + var2 = p * this.dig.P8 / 32768.0; + this.Pressure = (p + (var1 + var2 + this.dig.P7) / 16.0) / 100.0; } - public Double GetHumidity() { - Int32 adc_H = this._adc_H; + private void CalcHum(Int32 adc_H) { + Double var_H = (this.Temperatur * 5120) - 76800.0; + var_H = (adc_H - (this.dig.H4 * 64.0 + this.dig.H5 / 16384.0 * var_H)) * + (this.dig.H2 / 65536.0 * (1.0 + this.dig.H6 / 67108864.0 * var_H * (1.0 + this.dig.H3 / 67108864.0 * var_H))); + var_H = var_H * (1.0 - this.dig.H1 * var_H / 524288.0); + this.Humidity = var_H > 100 ? 100 : var_H < 0 ? 0 : var_H; + } + #endregion - Double var_H; - var_H = this._t_fine - 76800.0; - var_H = (adc_H - (this._dig_H4 * 64.0 + this._dig_H5 / 16384.0 * var_H)) * (this._dig_H2 / 65536.0 * (1.0 + this._dig_H6 / 67108864.0 * var_H * (1.0 + this._dig_H3 / 67108864.0 * var_H))); - var_H = var_H * (1.0 - this._dig_H1 * var_H / 524288.0); - return var_H; - return var_H > 100 ? 100 : var_H < 0 ? 0: var_H; - /*if(var_H > 100.0) { - var_H = 100.0; - } else if(var_H < 0.0) { - var_H = 0.0; + private struct CalibrationData { + public CalibrationData(Bme280 bme) { + this.T1 = bme.ReadShort(RegisterAddress.CALIB00); + this.T2 = bme.ReadSingedShort(RegisterAddress.CALIB02); + this.T3 = bme.ReadSingedShort(RegisterAddress.CALIB04); + this.P1 = bme.ReadShort(RegisterAddress.CALIB06); + this.P2 = bme.ReadSingedShort(RegisterAddress.CALIB08); + this.P3 = bme.ReadSingedShort(RegisterAddress.CALIB10); + this.P4 = bme.ReadSingedShort(RegisterAddress.CALIB12); + this.P5 = bme.ReadSingedShort(RegisterAddress.CALIB14); + this.P6 = bme.ReadSingedShort(RegisterAddress.CALIB16); + this.P7 = bme.ReadSingedShort(RegisterAddress.CALIB18); + this.P8 = bme.ReadSingedShort(RegisterAddress.CALIB20); + this.P9 = bme.ReadSingedShort(RegisterAddress.CALIB22); + this.H1 = bme.ReadByte(RegisterAddress.CALIB25); + this.H2 = bme.ReadSingedShort(RegisterAddress.CALIB26); + this.H3 = bme.ReadByte(RegisterAddress.CALIB28); + this.H4 = (Int16)((bme.ReadByte(RegisterAddress.CALIB29) << 4) | (0b00001111 & bme.ReadByte(RegisterAddress.CALIB30))); + this.H5 = (Int16)((bme.ReadByte(RegisterAddress.CALIB31) << 4) | ((0b11110000 & bme.ReadByte(RegisterAddress.CALIB30)) >> 4)); + this.H6 = (SByte)bme.ReadByte(RegisterAddress.CALIB32); } - return var_H;*/ - /*Int32 H; - - H = this._t_fine - 76800; - H = ((((adc_H << 14) - (this._dig_H4 << 20) - (this._dig_H5 * H)) + 16384) >> 15) * - (((((((H * this._dig_H6) >> 10) * (((H * this._dig_H3) >> 11) + 32768)) >> 10) + 2097152) * this._dig_H2 + 8192) >> 14); - H = H - (((((H >> 15) * (H >> 15)) >> 7) * this._dig_H1) >> 4); - H = H < 0 ? 0 : H; - H = H > 419430400 ? 419430400 : H; - return ((Double)(H >> 12)) / 1024;*/ + public UInt16 T1 { get; private set; } + public Int16 T2 { get; private set; } + public Int16 T3 { get; private set; } + public UInt16 P1 { get; private set; } + public Int16 P2 { get; private set; } + public Int16 P3 { get; private set; } + public Int16 P4 { get; private set; } + public Int16 P5 { get; private set; } + public Int16 P6 { get; private set; } + public Int16 P7 { get; private set; } + public Int16 P8 { get; private set; } + public Int16 P9 { get; private set; } + public Byte H1 { get; private set; } + public Int16 H2 { get; private set; } + public Byte H3 { get; private set; } + public Int16 H4 { get; private set; } + public Int16 H5 { get; private set; } + public SByte H6 { get; private set; } } - public void ReadTrimming() { - this._dig_T1 = this.Read16LE((Byte)Calibration.BME280_REG_CALIB00); - this._dig_T2 = this.ReadS16LE((Byte)Calibration.BME280_REG_CALIB02); - this._dig_T3 = this.ReadS16LE((Byte)Calibration.BME280_REG_CALIB04); - this._dig_P1 = this.Read16LE((Byte)Calibration.BME280_REG_CALIB06); - this._dig_P2 = this.ReadS16LE((Byte)Calibration.BME280_REG_CALIB08); - this._dig_P3 = this.ReadS16LE((Byte)Calibration.BME280_REG_CALIB10); - this._dig_P4 = this.ReadS16LE((Byte)Calibration.BME280_REG_CALIB12); - this._dig_P5 = this.ReadS16LE((Byte)Calibration.BME280_REG_CALIB14); - this._dig_P6 = this.ReadS16LE((Byte)Calibration.BME280_REG_CALIB16); - this._dig_P7 = this.ReadS16LE((Byte)Calibration.BME280_REG_CALIB18); - this._dig_P8 = this.ReadS16LE((Byte)Calibration.BME280_REG_CALIB20); - this._dig_P9 = this.ReadS16LE((Byte)Calibration.BME280_REG_CALIB22); - this._dig_H1 = this.Read8((Byte)Calibration.BME280_REG_CALIB25); - this._dig_H2 = this.ReadS16LE((Byte)Calibration.BME280_REG_CALIB26); - this._dig_H3 = this.Read8((Byte)Calibration.BME280_REG_CALIB28); - this._dig_H4 = (Int16)((this.Read8((Byte)Calibration.BME280_REG_CALIB29) << 4) | (0b00001111 & this.Read8((Byte)Calibration.BME280_REG_CALIB30))); - this._dig_H5 = (Int16)((this.Read8((Byte)Calibration.BME280_REG_CALIB31) << 4) | ((0b11110000 & this.Read8((Byte)Calibration.BME280_REG_CALIB30)) >> 4)); - this._dig_H6 = (SByte)this.Read8((Byte)Calibration.BME280_REG_CALIB32); - } - - private readonly I2CDevice w; - private Int32 _adc_T; - private Int32 _adc_P; - private Int32 _adc_H; - private Int32 _t_fine; - - private UInt16 _dig_T1; - private Int16 _dig_T2; - private Int16 _dig_T3; - private UInt16 _dig_P1; - private Int16 _dig_P2; - private Int16 _dig_P3; - private Int16 _dig_P4; - private Int16 _dig_P5; - private Int16 _dig_P6; - private Int16 _dig_P7; - private Int16 _dig_P8; - private Int16 _dig_P9; - private Byte _dig_H1; - private Int16 _dig_H2; - private Byte _dig_H3; - private Int16 _dig_H4; - private Int16 _dig_H5; - private SByte _dig_H6; - - //Calibration Register Adresses - private enum Calibration { - BME280_REG_CALIB00 = 0b10001000, - BME280_REG_CALIB02 = 0b10001010, - BME280_REG_CALIB04 = 0b10001100, - BME280_REG_CALIB06 = 0b10001110, - BME280_REG_CALIB08 = 0b10010000, - BME280_REG_CALIB10 = 0b10010010, - BME280_REG_CALIB12 = 0b10010100, - BME280_REG_CALIB14 = 0b10010110, - BME280_REG_CALIB16 = 0b10011000, - BME280_REG_CALIB18 = 0b10011010, - BME280_REG_CALIB20 = 0b10011100, - BME280_REG_CALIB22 = 0b10011110, - BME280_REG_CALIB25 = 0b10100001, - BME280_REG_CALIB26 = 0b11100001, - BME280_REG_CALIB28 = 0b11100011, - BME280_REG_CALIB29 = 0b11100100, - BME280_REG_CALIB30 = 0b11100101, - BME280_REG_CALIB31 = 0b11100110, - BME280_REG_CALIB32 = 0b11100111 + private struct RegisterAddress { + public const Byte CALIB00 = 0x88; + public const Byte CALIB02 = 0x8A; + public const Byte CALIB04 = 0x8C; + public const Byte CALIB06 = 0x8E; + public const Byte CALIB08 = 0x90; + public const Byte CALIB10 = 0x92; + public const Byte CALIB12 = 0x94; + public const Byte CALIB14 = 0x96; + public const Byte CALIB16 = 0x98; + public const Byte CALIB18 = 0x9A; + public const Byte CALIB20 = 0x9C; + public const Byte CALIB22 = 0x9E; + public const Byte CALIB25 = 0xA1; + public const Byte ID = 0xD0; + public const Byte RESET = 0xE0; + public const Byte CALIB26 = 0xE1; + public const Byte CALIB28 = 0xE3; + public const Byte CALIB29 = 0xE4; + public const Byte CALIB30 = 0xE5; + public const Byte CALIB31 = 0xE6; + public const Byte CALIB32 = 0xE7; + public const Byte CTRL_HUM = 0xF2; + public const Byte STATUS = 0xF3; + public const Byte CTRL_MEAS = 0xF4; + public const Byte CONFIG = 0xF5; + public const Byte PRESS_DATA = 0xF7; + public const Byte TEMP_DATA = 0xFA; + public const Byte HUM_DATA = 0xFD; }; - - //Register Adresses - private enum Register { - BME280_REG_ID = 0b11010000, - BME280_REG_RESET = 0b11100000, - BME280_REG_CTRL_HUM = 0b11110010, - BME280_REG_STATUS = 0b11110011, - BME280_REG_CTRL_MEAS = 0b11110100, - BME280_REG_CONFIG = 0b11110101, - BME280_REG_PRESS_DATA = 0b11110111, - BME280_REG_TEMP_DATA = 0b11111010, - BME280_REG_HUM_DATA = 0b11111101 - }; - - - - //TWI Writes - private Byte Read8(Byte reg) => this.w.ReadAddressByte(reg); - /*this->w->beginTransmission(address); - this->w->write(reg); - this->w->endTransmission(); - this->w->requestFrom(address, 1); - while(!this->w->available()) - ; - return this->w->read();*/ - - private UInt16 Read16LE(Byte reg) => this.w.ReadAddressWord(reg); - /*uint8_t msb, lsb; - this->w->beginTransmission(address); - this->w->write(reg); - this->w->endTransmission(); - this->w->requestFrom(address, 2); - while(this->w->available() < 2) - ; - msb = this->w->read(); - lsb = this->w->read(); - return (uint16_t)msb << 8 | lsb;*/ - - private UInt16 Read16(Byte reg) { - UInt16 data = this.Read16LE(reg); - return (UInt16)((data >> 8) | (data << 8)); - } - - private Int16 ReadS16LE(Byte reg) => (Int16)this.Read16LE(reg); - - private UInt32 Read20(Byte reg) { - UInt32 data; - this.w.Write(reg); - Byte[] dr = this.w.Read(3); - /*this->w->beginTransmission(address); - this->w->write(reg); - this->w->endTransmission(); - this->w->requestFrom(address, 3); - while(this->w->available() < 3) - ;*/ - data = dr[0]; - data <<= 8; - data |= dr[1]; - data <<= 8; - data |= dr[2]; - data >>= 4; - return data; - } - - private void WriteRegister(Byte reg, Byte val) => this.w.WriteAddressByte(reg, val); - /*this->w->beginTransmission(address); - this->w->write(reg); - this->w->write(val); - this->w->endTransmission();*/ } } diff --git a/IotThermometer/Librarys/Rainbowdruino.cs b/IotThermometer/Librarys/Rainbowdruino.cs new file mode 100644 index 0000000..44799f0 --- /dev/null +++ b/IotThermometer/Librarys/Rainbowdruino.cs @@ -0,0 +1,215 @@ +using System; +using System.Collections.Generic; +using System.IO.Ports; + +namespace BlubbFish.Iot.Thermometer.Librarys { + class Rainbowdruino { + private readonly SerialPort serial; + private readonly UInt32[,] zbuffer = new UInt32[8, 16]; + + private struct Digets { + public static readonly Boolean[][] Null = { + new Boolean[]{ false, true, false }, + new Boolean[] { true, false, true }, + new Boolean[] { true, false, true }, + new Boolean[] { true, false, true }, + new Boolean[]{ false, true, false } + }; + public static readonly Boolean[][] One = { + new Boolean[] { false, false, true }, + new Boolean[] { false, true, true }, + new Boolean[] { false, false, true }, + new Boolean[] { false, false, true }, + new Boolean[] { false, false, true } + }; + public static readonly Boolean[][] Two = { + new Boolean[] { false, true, false }, + new Boolean[] { true, false, true }, + new Boolean[] { false, false, true }, + new Boolean[] { false, true, false }, + new Boolean[] { true, true, true } + }; + public static readonly Boolean[][] Three = { + new Boolean[] { true, true, false }, + new Boolean[] { false, false, true }, + new Boolean[] { false, true, false }, + new Boolean[] { false, false, true }, + new Boolean[] { true, true, false } + }; + public static readonly Boolean[][] Four = { + new Boolean[] { false, false, true }, + new Boolean[] { false, true, true }, + new Boolean[] { true, false, true }, + new Boolean[] { true, true, true }, + new Boolean[] { false, false, true } + }; + public static readonly Boolean[][] Five = { + new Boolean[] { true, true, true }, + new Boolean[] { true, false, false }, + new Boolean[] { true, true, false }, + new Boolean[] { false, false, true }, + new Boolean[] { true, true, false } + }; + public static readonly Boolean[][] Six = { + new Boolean[] { false, true, true }, + new Boolean[] { true, false, false }, + new Boolean[] { true, true, true }, + new Boolean[] { true, false, true }, + new Boolean[] { false, true, false } + }; + public static readonly Boolean[][] Seven = { + new Boolean[] { true, true, true }, + new Boolean[] { false, false, true }, + new Boolean[] { false, true, false }, + new Boolean[] { true, false, false }, + new Boolean[] { true, false, false } + }; + public static readonly Boolean[][] Eight = { + new Boolean[] { false, true, false }, + new Boolean[] { true, false, true }, + new Boolean[] { false, true, false }, + new Boolean[] { true, false, true }, + new Boolean[] { false, true, false } + }; + public static readonly Boolean[][] Nine = { + new Boolean[] { false, true, false }, + new Boolean[] { true, false, true }, + new Boolean[] { true, true, true }, + new Boolean[] { false, false, true }, + new Boolean[] { true, true, false } + }; + } + + public Rainbowdruino(String com) { + this.serial = new SerialPort(com, 19200); + this.serial.Open(); + } + + public void DrawDigets(String number, UInt32 color) { + Int32 sub = number.Length; + if(number.Length > 4 && number.Substring(0, 5).Contains(".")) { + sub = 5; + } else if(number.Length >= 4) { + sub = 4; + } + String a = number.Substring(0, sub); + Int32 y = 0; + foreach(Char item in a) { + if(item != '.') { + this.CopyDigetToZbuffer(this.GetDiget(item), 3, y, color); + y += 4; + } else { + this.DrawDot(y - 1, 7, color); + } + } + } + + public void DrawDot(Int32 x, Int32 y, UInt32 color) { + try { + this.zbuffer[y, x] = color; + } catch { + Console.WriteLine("out of bound"); + } + } + + public void DrawLineX(Int32 x, Int32 y, Int32 l, UInt32 color) { + for(Int32 i = x; i < x + l; i++) { + this.DrawDot(i, y, color); + } + } + + public void DrawLineY(Int32 x, Int32 y, Int32 l, UInt32 color) { + for(Int32 i = y; i < y + l; i++) { + this.DrawDot(x, i, color); + } + } + + public void Write() { + this.Clear(); + List colors = this.GetAllColors(); + foreach(UInt32 item in colors) { + this.serial.Write(String.Join(" ", this.GetZbufferPage(0, item)) + " " + String.Join(" ", this.GetZbufferPage(1, item)) + " " + String.Join(" ", this.GetAllColors(item)) + "\n"); + } + this.ClearZbuffer(); + } + + public void Clear() => this.serial.Write("clear\n"); + + private void ClearZbuffer() { + for(Int32 i = 0; i < 8; i++) { + for(Int32 j = 0; j < 16; j++) { + this.zbuffer[i, j] = 0; + } + } + } + + private String[] GetAllColors(UInt32 color) { + String[] ret = new String[3]; + ret[0] = ((Byte)((color & 0x00FF0000) >> 16)).ToString().PadLeft(3, '0'); + ret[1] = ((Byte)((color & 0x0000FF00) >> 8)).ToString().PadLeft(3, '0'); + ret[2] = ((Byte)((color & 0x000000FF) >> 0)).ToString().PadLeft(3, '0'); + return ret; + } + + private String[] GetZbufferPage(Int32 page, UInt32 color) { + String[] ret = new String[8]; + for(Int32 i = 0; i < 8; i++) { + Byte p = 0; + for(Int32 j = 0; j < 8; j++) { + if(this.zbuffer[i, j + (page * 8)] == color) { + p |= (Byte)(1 << (7 - j)); + } + } + ret[i] = p.ToString().PadLeft(3, '0'); + } + return ret; + } + + private List GetAllColors() { + List colors = new List(); + foreach(UInt32 item in this.zbuffer) { + if(!colors.Contains(item) && item != 0) { + colors.Add(item); + } + } + return colors; + } + + private Boolean[][] GetDiget(Char item) { + switch(item) { + case '1': + return Digets.One; + case '2': + return Digets.Two; + case '3': + return Digets.Three; + case '4': + return Digets.Four; + case '5': + return Digets.Five; + case '6': + return Digets.Six; + case '7': + return Digets.Seven; + case '8': + return Digets.Eight; + case '9': + return Digets.Nine; + default: + return Digets.Null; + } + } + + private void CopyDigetToZbuffer(Boolean[][] diget, Int32 x, Int32 y, UInt32 color) { + try { + for(Int32 i = 0; i < diget.Length; i++) { + for(Int32 j = 0; j < diget[i].Length; j++) { + this.zbuffer[i + x, j + y] = diget[i][j] ? color : this.zbuffer[i + x, j + y]; + } + } + } catch { + Console.WriteLine("out of bound"); + } + } + } +} diff --git a/IotThermometer/Librarys/TSL2591.cs b/IotThermometer/Librarys/TSL2591.cs index b06f033..b52ecbf 100644 --- a/IotThermometer/Librarys/TSL2591.cs +++ b/IotThermometer/Librarys/TSL2591.cs @@ -1,170 +1,214 @@ using System; using System.Threading; +using BlubbFish.Iot.Thermometer.System; using BlubbFish.Utils; -using Unosquare.RaspberryIO; -using Unosquare.RaspberryIO.Gpio; namespace BlubbFish.Iot.Thermometer.Librarys { - public class TSL2591 { - public enum Gain { - TSL2591_GAIN_LOW = 0b00000000, /// low gain (1x) - TSL2591_GAIN_MED = 0b00010000, /// medium gain (25x) - TSL2591_GAIN_HIGH = 0b00100000, /// medium gain (428x) - TSL2591_GAIN_MAX = 0b00110000, /// max gain (9876x) - }; - public enum IntegrationTime { - TSL2591_INTEGRATIONTIME_100MS = 0b00000000, // INTEGRATION TIME 100 ms, MAX COUNT 37889 - TSL2591_INTEGRATIONTIME_200MS = 0b00000001, // INTEGRATION TIME 200 ms, MAX COUNT 65535 - TSL2591_INTEGRATIONTIME_300MS = 0b00000010, // INTEGRATION TIME 300 ms, MAX COUNT 65535 - TSL2591_INTEGRATIONTIME_400MS = 0b00000011, // INTEGRATION TIME 400 ms, MAX COUNT 65535 - TSL2591_INTEGRATIONTIME_500MS = 0b00000100, // INTEGRATION TIME 500 ms, MAX COUNT 65535 - TSL2591_INTEGRATIONTIME_600MS = 0b00000101, // INTEGRATION TIME 600 ms, MAX COUNT 65535 - }; - public enum LuxAlg { - TSL2591_LUXALG1 = 0, - TSL2591_LUXALG2 = 1, - TSL2591_LUXALG3 = 2 - }; - public enum Persist { - TSL2591_PERSIST_EVERY = 0b00000000, // Every ALS cycle generates an interrupt - TSL2591_PERSIST_ANY = 0b00000001, // Any value outside of threshold range - TSL2591_PERSIST_2 = 0b00000010, // 2 consecutive values out of range - TSL2591_PERSIST_3 = 0b00000011, // 3 consecutive values out of range - TSL2591_PERSIST_5 = 0b00000100, // 5 consecutive values out of range - TSL2591_PERSIST_10 = 0b00000101, // 10 consecutive values out of range - TSL2591_PERSIST_15 = 0b00000110, // 15 consecutive values out of range - TSL2591_PERSIST_20 = 0b00000111, // 20 consecutive values out of range - TSL2591_PERSIST_25 = 0b00001000, // 25 consecutive values out of range - TSL2591_PERSIST_30 = 0b00001001, // 30 consecutive values out of range - TSL2591_PERSIST_35 = 0b00001010, // 35 consecutive values out of range - TSL2591_PERSIST_40 = 0b00001011, // 40 consecutive values out of range - TSL2591_PERSIST_45 = 0b00001100, // 45 consecutive values out of range - TSL2591_PERSIST_50 = 0b00001101, // 50 consecutive values out of range - TSL2591_PERSIST_55 = 0b00001110, // 55 consecutive values out of range - TSL2591_PERSIST_60 = 0b00001111 // 60 consecutive values out of range - }; + public class TSL2591 : ATwi { + private Boolean init = false; - /// Class TSL2591 Constructor - /// An instance of wificlass, that also can log - /// The default integration time - public TSL2591(IntegrationTime integration, Int32 address) { - this.w = Pi.I2C.AddDevice(address); - this._integration = integration; - this._gain = Gain.TSL2591_GAIN_LOW; - } + public Double Luminosity { get; private set; } - /// Starts the Communication with the Device + public TSL2591(Int32 address) : base(address) { } + + #region Main public void Begin() { - Byte id = this.Read8((Byte)OP.TSL2591_COMMAND_NORMAL_OP | (Byte)REGISTER.TSL2591_REGISTER_DEVICE_ID); - if(id != 0x50) { - Helper.WriteError("Fail to init Lightsensor"); - return; + if(!this.init) { + if(this.ReadByte(RegisterAddresses.ID) != 0x50) { + Helper.WriteError("Fail to init Lightsensor"); + return; + } + this.IntegrationTime = ATime.I200MS; + this.IntegrationAmplifier = AGain.TSL2591_GAIN_LOW; + this.Disable(); + Console.WriteLine("Lightsensor ok"); + this.init = true; } - this.SetTiming(this._integration); - this.SetGain(this._gain); - this.Disable(); - Console.WriteLine("Lightsensor ok"); } - /// Starts a measurement and stores the value internal - public void Measure() => this._fulllum = this.GetLumAdv(this._gain); + public void Measure() { + if(this.init) { + this.CalcLux(this.GetLumAdv(this.IntegrationAmplifier)); + } + } + #endregion - /// Get the calculated lux value - /// Select the algorith for calculating lux - /// Lux in float - public Double CalculateLux(LuxAlg alg) { - UInt16 full = (UInt16)(this._fulllum & 0xFFFF); - UInt16 ir = (UInt16)(this._fulllum >> 16); - if(((full == 0xFFFF) || (ir == 0xFFFF)) && this._integration != IntegrationTime.TSL2591_INTEGRATIONTIME_100MS) { + #region Calculation + private struct CalculationConstances { + public const Double TSL2591_LUX_COEFA = 1.7; + public const Double TSL2591_LUX_COEFB = 1.64; + public const Double TSL2591_LUX_COEFC = 0.59; + public const Double TSL2591_LUX_COEFD = 0.86; + public const Double TSL2591_LUX_DF = 408; + } + + private void CalcLux((UInt16 full, UInt16 ir) lum) => this.Luminosity = (this.CalculateLux(1, lum) + this.CalculateLux(2, lum) + this.CalculateLux(3, lum)) / 3; + + private Double CalculateLux(Byte alg, (UInt16 full, UInt16 ir) lum) { + if(((lum.full == 0xFFFF) || (lum.ir == 0xFFFF)) && this.IntegrationTime != ATime.I100MS) { return 200000.0F; } - if(((full >= 0x9400) || (ir >= 0x9400)) && this._integration == IntegrationTime.TSL2591_INTEGRATIONTIME_100MS) { + if(((lum.full >= 0x9400) || (lum.ir >= 0x9400)) && this.IntegrationTime == ATime.I100MS) { return 200000.0F; } - UInt16 atime = 100; - switch(this._integration) { - case IntegrationTime.TSL2591_INTEGRATIONTIME_100MS: - atime = 100; - break; - case IntegrationTime.TSL2591_INTEGRATIONTIME_200MS: - atime = 200; - break; - case IntegrationTime.TSL2591_INTEGRATIONTIME_300MS: - atime = 300; - break; - case IntegrationTime.TSL2591_INTEGRATIONTIME_400MS: - atime = 400; - break; - case IntegrationTime.TSL2591_INTEGRATIONTIME_500MS: - atime = 500; - break; - case IntegrationTime.TSL2591_INTEGRATIONTIME_600MS: - atime = 600; - break; - } - UInt16 again = 25; - switch(this._gain) { - case Gain.TSL2591_GAIN_LOW: - again = 1; - break; - case Gain.TSL2591_GAIN_MED: - again = 25; - break; - case Gain.TSL2591_GAIN_HIGH: - again = 428; - break; - case Gain.TSL2591_GAIN_MAX: - again = 9876; - break; - } - Double cpl = ((Double)(atime * again)) / TSL2591_LUX_DF; + Double cpl = this.IntegrationTimeCount * this.IntegrationAmplifierCount / CalculationConstances.TSL2591_LUX_DF; Double lux = 0; - if(alg == LuxAlg.TSL2591_LUXALG1) { - Double lux1 = (full - TSL2591_LUX_COEFB * ir) / cpl; - Double lux2 = (full * TSL2591_LUX_COEFC - ir * TSL2591_LUX_COEFD) / cpl; - lux = lux1 > lux2 ? lux1 : lux2; - } else if(alg == LuxAlg.TSL2591_LUXALG2) { - lux = full == 0 ? 0 : (full - ((Double)ir)) * (1.0F - (((Double)ir) / full)) / cpl; - } else if(alg == LuxAlg.TSL2591_LUXALG3) { - lux = (full - ir * TSL2591_LUX_COEFA) / cpl; + switch(alg) { + case 1: + Double lux1 = (lum.full - CalculationConstances.TSL2591_LUX_COEFB * lum.ir) / cpl; + Double lux2 = (lum.full * CalculationConstances.TSL2591_LUX_COEFC - lum.ir * CalculationConstances.TSL2591_LUX_COEFD) / cpl; + lux = lux1 > lux2 ? lux1 : lux2; + break; + case 2: + lux = lum.full == 0 ? 0 : (lum.full - ((Double)lum.ir)) * (1.0F - (((Double)lum.ir) / lum.full)) / cpl; + break; + case 3: + lux = (lum.full - lum.ir * CalculationConstances.TSL2591_LUX_COEFA) / cpl; + break; } return lux > 0 ? lux : 0; } - /// Get the calculated lux value with all algorthims and make an average over all values - /// Lux in float - public Double GetLux() => (this.CalculateLux(LuxAlg.TSL2591_LUXALG1) + this.CalculateLux(LuxAlg.TSL2591_LUXALG2) + this.CalculateLux(LuxAlg.TSL2591_LUXALG3)) / 3; - - /// Set the integration timing - /// Integration timing value - public void SetTiming(IntegrationTime integration) { + private (UInt16 full, UInt16 ir) GetFullLuminosity() { this.Enable(); - this._integration = integration; - this.Write8((Byte)OP.TSL2591_COMMAND_NORMAL_OP | (Byte)REGISTER.TSL2591_REGISTER_CONTROL, (Byte)((Byte)this._integration | (Byte)this._gain)); + for(Byte d = 0; d <= this.IntegrationTime; d++) { + Thread.Sleep(108); + } + UInt16 ch0 = this.ReadShort(RegisterAddresses.C0DATAL); + UInt16 ch1 = this.ReadShort(RegisterAddresses.C1DATAL); this.Disable(); + return (full: ch0, ir: ch1); } - /// Get the activated timing value - /// Active timing value - public IntegrationTime GetTiming() => this._integration; + private (UInt16 full, UInt16 ir) GetLumAdv(Byte gain) { + if(gain != this.IntegrationAmplifier) { + this.IntegrationAmplifier = gain; + } + (UInt16 full, UInt16 ir) lum = this.GetFullLuminosity(); + UInt16 max = 0; + if(this.IntegrationTime != ATime.I100MS) { + max = 60000; + } else { + max = 30000; + } - /// Set the gain level - /// Gain value - public void SetGain(Gain gain) { - this.Enable(); - this._gain = gain; - this.Write8((Byte)OP.TSL2591_COMMAND_NORMAL_OP | (Byte)REGISTER.TSL2591_REGISTER_CONTROL, (Byte)((Byte)this._integration | (Byte)this._gain)); - this.Disable(); + if(((lum.full < max * (1.0f / 25) && lum.full / (1.0f / 25) < max) && (lum.ir < max * (1.0f / 25) && lum.ir / (1.0f / 25) < max)) && this.IntegrationAmplifier == AGain.TSL2591_GAIN_LOW) { + return this.GetLumAdv(AGain.TSL2591_GAIN_MED); + } + if(((lum.full < max * (25.0f / 428) && lum.full / (25.0f / 428) < max) && (lum.ir < max * (25.0f / 428) && lum.ir / (25.0f / 428) < max)) && this.IntegrationAmplifier == AGain.TSL2591_GAIN_MED) { + return this.GetLumAdv(AGain.TSL2591_GAIN_HIGH); + } + if(((lum.full < max * (428.0f / 9876) && lum.full / (428.0f / 9876) < max) && (lum.ir < max * (428.0f / 9876) && lum.ir / (428.0f / 9876) < max)) && this.IntegrationAmplifier == AGain.TSL2591_GAIN_HIGH) { + return this.GetLumAdv(AGain.TSL2591_GAIN_MAX); + } + if((lum.full > max || lum.ir > max) && this.IntegrationAmplifier == AGain.TSL2591_GAIN_MAX) { + return this.GetLumAdv(AGain.TSL2591_GAIN_HIGH); + } + if((lum.full > max || lum.ir > max) && this.IntegrationAmplifier == AGain.TSL2591_GAIN_HIGH) { + return this.GetLumAdv(AGain.TSL2591_GAIN_MED); + } + if((lum.full > max || lum.ir > max) && this.IntegrationAmplifier == AGain.TSL2591_GAIN_MED) { + return this.GetLumAdv(AGain.TSL2591_GAIN_LOW); + } + return lum; } + #endregion - /// Get the activated gain value - /// Active gain value - public Gain GetGain() => this._gain; + #region Settings + #region IntegrationTime + public struct ATime { + public const Byte I100MS = 0b00000000; // INTEGRATION TIME 100 ms, MAX COUNT 37889 + public const Byte I200MS = 0b00000001; // INTEGRATION TIME 200 ms, MAX COUNT 65535 + public const Byte I300MS = 0b00000010; // INTEGRATION TIME 300 ms, MAX COUNT 65535 + public const Byte I400MS = 0b00000011; // INTEGRATION TIME 400 ms, MAX COUNT 65535 + public const Byte I500MS = 0b00000100; // INTEGRATION TIME 500 ms, MAX COUNT 65535 + public const Byte I600MS = 0b00000101; // INTEGRATION TIME 600 ms, MAX COUNT 65535 + }; + private Byte integrationTime; + public Byte IntegrationTime { + get => this.integrationTime; + set { + this.Enable(); + this.integrationTime = value; + this.WriteByte(RegisterAddresses.CONTROL, (Byte)(this.integrationTime | this.IntegrationAmplifier)); + this.Disable(); + } + } + public Double IntegrationTimeCount { + get { + switch(this.IntegrationTime) { + case ATime.I100MS: + return 100; + case ATime.I200MS: + return 200; + case ATime.I300MS: + return 300; + case ATime.I400MS: + return 400; + case ATime.I500MS: + return 500; + default: + return 600; + } + } + } + #endregion + #region Gain + public struct AGain { + public const Byte TSL2591_GAIN_LOW = 0b00000000; // low gain (1x) + public const Byte TSL2591_GAIN_MED = 0b00010000; // medium gain (25x) + public const Byte TSL2591_GAIN_HIGH = 0b00100000; // medium gain (428x) + public const Byte TSL2591_GAIN_MAX = 0b00110000; // max gain (9876x) + }; + private Byte integrationAmplifier; + public Byte IntegrationAmplifier { + get => this.integrationAmplifier; + set { + this.Enable(); + this.integrationAmplifier = value; + this.WriteByte(RegisterAddresses.CONTROL, (Byte)(this.IntegrationTime | this.integrationAmplifier)); + this.Disable(); + } + } + public Double IntegrationAmplifierCount { + get { + switch(this.IntegrationAmplifier) { + case AGain.TSL2591_GAIN_LOW: + return 1; + case AGain.TSL2591_GAIN_MED: + return 25; + case AGain.TSL2591_GAIN_HIGH: + return 428; + default: + return 9876; + } + } + } + #endregion + #endregion - /// Clear the last Interrupt flag + #region Interrupts + public struct Persist { + public const Byte EVERY = 0b00000000; // Every ALS cycle generates an interrupt + public const Byte ANY = 0b00000001; // Any value outside of threshold range + public const Byte P2 = 0b00000010; // 2 consecutive values out of range + public const Byte P3 = 0b00000011; // 3 consecutive values out of range + public const Byte P5 = 0b00000100; // 5 consecutive values out of range + public const Byte P10 = 0b00000101; // 10 consecutive values out of range + public const Byte P15 = 0b00000110; // 15 consecutive values out of range + public const Byte P20 = 0b00000111; // 20 consecutive values out of range + public const Byte P25 = 0b00001000; // 25 consecutive values out of range + public const Byte P30 = 0b00001001; // 30 consecutive values out of range + public const Byte P35 = 0b00001010; // 35 consecutive values out of range + public const Byte P40 = 0b00001011; // 40 consecutive values out of range + public const Byte P45 = 0b00001100; // 45 consecutive values out of range + public const Byte P50 = 0b00001101; // 50 consecutive values out of range + public const Byte P55 = 0b00001110; // 55 consecutive values out of range + public const Byte P60 = 0b00001111; // 60 consecutive values out of range + }; public void ClearInterrupt() { this.Enable(); - this.Write8((Byte)OP.TSL2591_COMMAND_CLEAR_INT); + this.WriteByte(RegisterAddresses.COMMAND_CLEAR_INT); this.Disable(); } @@ -172,160 +216,89 @@ namespace BlubbFish.Iot.Thermometer.Librarys { /// Lower border for interrupt /// Higher border for interrupt /// Value for persist register, defines when the interrupt occours - public void RegisterInterrupt(UInt16 lowerThreshold, UInt16 upperThreshold, Persist persist) { + public void RegisterInterrupt(UInt16 lowerThreshold, UInt16 upperThreshold, Byte persist) { this.Enable(); - this.Write8((Byte)OP.TSL2591_COMMAND_NORMAL_OP | (Byte)REGISTER.TSL2591_REGISTER_PERSIST, (Byte)persist); - this.Write8((Byte)OP.TSL2591_COMMAND_NORMAL_OP | (Byte)REGISTER.TSL2591_REGISTER_THRESHOLD_AILTL, (Byte)lowerThreshold); - this.Write8((Byte)OP.TSL2591_COMMAND_NORMAL_OP | (Byte)REGISTER.TSL2591_REGISTER_THRESHOLD_AILTH, (Byte)(lowerThreshold >> 8)); - this.Write8((Byte)OP.TSL2591_COMMAND_NORMAL_OP | (Byte)REGISTER.TSL2591_REGISTER_THRESHOLD_AIHTL, (Byte)upperThreshold); - this.Write8((Byte)OP.TSL2591_COMMAND_NORMAL_OP | (Byte)REGISTER.TSL2591_REGISTER_THRESHOLD_AIHTH, (Byte)(upperThreshold >> 8)); + this.WriteByte(RegisterAddresses.PERSIST, persist); + this.WriteByte(RegisterAddresses.AILTL, (Byte)lowerThreshold); + this.WriteByte(RegisterAddresses.AILTH, (Byte)(lowerThreshold >> 8)); + this.WriteByte(RegisterAddresses.AIHTL, (Byte)upperThreshold); + this.WriteByte(RegisterAddresses.AIHTH, (Byte)(upperThreshold >> 8)); this.Disable(); } - /// Return the Interrupt flags - /// Bit [5] Indicates that the device has encountered a no-persist interrupt condition, - /// Bit [4] Indicates that the device is asserting an ALS interrupt, - /// Bit [0] ALS Valid. Indicates that the ADC channels have completed an integration cycle since the AEN bit (This field activates ALS function.) was asserted. - public Byte GetStatus() { + public struct StatusRegister { + public StatusRegister(Byte x) { + this.AVALID = (x & (1 << 0)) != 0; + this.AINT = (x & (1 << 4)) != 0; + this.NPINTR = (x & (1 << 5)) != 0; + } + /// + /// Indicates that the ADC channels have completed an integration cycle since the AEN bit (This field activates ALS function.) was asserted. + /// + public Boolean AVALID { get; private set; } + /// + /// Indicates that the device is asserting an ALS interrupt, + /// + public Boolean AINT { get; private set; } + /// + /// Indicates that the device has encountered a no-persist interrupt condition, + /// + public Boolean NPINTR { get; private set; } + } + + public StatusRegister GetStatus() { this.Enable(); - Byte x = this.Read8((Byte)OP.TSL2591_COMMAND_NORMAL_OP | (Byte)REGISTER.TSL2591_REGISTER_DEVICE_STATUS); + Byte x = this.ReadByte(RegisterAddresses.STATUS); this.Disable(); - return x; + return new StatusRegister(x); } + #endregion - private readonly I2CDevice w; - private IntegrationTime _integration; - private Gain _gain; - private UInt32 _fulllum; + #region Powerusage + private void Disable() => this.WriteByte(RegisterAddresses.ENABLE, RegisterValues.ENABLE_AEN); + private void Enable() => this.WriteByte(RegisterAddresses.ENABLE, RegisterValues.ENABLE_POWERON | RegisterValues.ENABLE_AEN); + #endregion - /// The ENABLE register is used to power the device on/off, enable functions and interrupts. - enum ENABLE { - TSL2591_ENABLE_POWERON = 0b00000001, //PON = Power ON. This field activates the internal oscillator to permit the timers and ADC channels to operate. Writing a one activates the oscillator. Writing a zero disables the oscillator. - TSL2591_ENABLE_AEN = 0b00000010, //AEN = ALS Enable. This field activates ALS function. Writing a one activates the ALS. Writing a zero disables the ALS. - TSL2591_ENABLE_AIEN = 0b00001000, //AIEN = ALS Interrupt Enable. When asserted permits ALS interrupts to be generated, subject to the persist filter. - TSL2591_ENABLE_NPIEN = 0b10000000 //NPIEN = No Persist Interrupt Enable. When asserted NP Threshold conditions will generate an interrupt, bypassing the persist filter. + private struct RegisterValues { + /// + /// PON = Power ON. This field activates the internal oscillator to permit the timers and ADC channels to operate. Writing a one activates the oscillator. Writing a zero disables the oscillator. + /// + public const Byte ENABLE_POWERON = 0b00000001; + /// + /// AEN = ALS Enable. This field activates ALS function. Writing a one activates the ALS. Writing a zero disables the ALS. + /// + public const Byte ENABLE_AEN = 0b00000010; + /// + /// AIEN = ALS Interrupt Enable. When asserted permits ALS interrupts to be generated, subject to the persist filter. + /// + public const Byte ENABLE_AIEN = 0b00001000; + /// + /// NPIEN = No Persist Interrupt Enable. When asserted NP Threshold conditions will generate an interrupt, bypassing the persist filter. + /// + public const Byte ENABLE_NPIEN = 0b10000000; }; - /// he COMMAND register specifies the address of the target register for future read and write operations, as well as issues special function commands. - private enum OP { - TSL2591_COMMAND_NORMAL_OP = 0b10100000, //Select Command Register. Must write as 1 when addressing COMMAND register. TRANSACTION Normal Operation. - TSL2591_COMMAND_CLEAR_INT = 0b11100111, //Select Command Register. Must write as 1 when addressing COMMAND register. TRANSACTION Special Function. ADDR/SF Clears ALS and no persist ALS interrupt. + private struct RegisterAddresses { + public const Byte ENABLE = 0x00 | 0b10100000; // Enable register + public const Byte CONTROL = 0x01 | 0b10100000; // Control register + public const Byte AILTL = 0x04 | 0b10100000; // ALS low threshold lower byte + public const Byte AILTH = 0x05 | 0b10100000; // ALS low threshold upper byte + public const Byte AIHTL = 0x06 | 0b10100000; // ALS high threshold lower byte + public const Byte AIHTH = 0x07 | 0b10100000; // ALS high threshold upper byte + //public const Byte NPAILTL = 0b00001000; // No Persist ALS low threshold lower byte + //public const Byte NPAILTH = 0b00001001; // No Persist ALS low threshold higher byte + //public const Byte NPAIHTL = 0b00001010; // No Persist ALS high threshold lower byte + //public const Byte NPAIHTH = 0b00001011; // No Persist ALS high threshold higher byte + public const Byte PERSIST = 0x0C | 0b10100000; // Interrupt persistence filter + //public const Byte PID = 0b00010001; // Package Identification + public const Byte ID = 0x12 | 0b10100000; // Device Identification + public const Byte STATUS = 0x13 | 0b10100000; // Internal Status + public const Byte C0DATAL = 0x14 | 0b10100000; // Channel 0 data, low byte + //public const Byte C0DATAH = 0b00010101; // Channel 0 data, high byte + public const Byte C1DATAL = 0x16 | 0b10100000; // Channel 1 data, low byte + //public const Byte C1DATAH = 0b00010111; // Channel 1 data, high byte + //public const Byte TSL2591_COMMAND_NORMAL_OP = 0b10100000;//Select Command Register. Must write as 1 when addressing COMMAND register. TRANSACTION Normal Operation. + public const Byte COMMAND_CLEAR_INT = 0b11100111; //Select Command Register. Must write as 1 when addressing COMMAND register. TRANSACTION Special Function. ADDR/SF Clears ALS and no persist ALS interrupt. }; - - /// Register Addresses - private enum REGISTER { - TSL2591_REGISTER_ENABLE = 0b00000000, // Enable register - TSL2591_REGISTER_CONTROL = 0b00000001, // Control register - TSL2591_REGISTER_THRESHOLD_AILTL = 0b00000100, // ALS low threshold lower byte - TSL2591_REGISTER_THRESHOLD_AILTH = 0b00000101, // ALS low threshold upper byte - TSL2591_REGISTER_THRESHOLD_AIHTL = 0b00000110, // ALS high threshold lower byte - TSL2591_REGISTER_THRESHOLD_AIHTH = 0b00000111, // ALS high threshold upper byte - TSL2591_REGISTER_THRESHOLD_NPAILTL = 0b00001000, // No Persist ALS low threshold lower byte - TSL2591_REGISTER_THRESHOLD_NPAILTH = 0b00001001, // No Persist ALS low threshold higher byte - TSL2591_REGISTER_THRESHOLD_NPAIHTL = 0b00001010, // No Persist ALS high threshold lower byte - TSL2591_REGISTER_THRESHOLD_NPAIHTH = 0b00001011, // No Persist ALS high threshold higher byte - TSL2591_REGISTER_PERSIST = 0b00001100, // Interrupt persistence filter - TSL2591_REGISTER_PACKAGE_PID = 0b00010001, // Package Identification - TSL2591_REGISTER_DEVICE_ID = 0b00010010, // Device Identification - TSL2591_REGISTER_DEVICE_STATUS = 0b00010011, // Internal Status - TSL2591_REGISTER_CHAN0_LOW = 0b00010100, // Channel 0 data, low byte - TSL2591_REGISTER_CHAN0_HIGH = 0b00010101, // Channel 0 data, high byte - TSL2591_REGISTER_CHAN1_LOW = 0b00010110, // Channel 1 data, low byte - TSL2591_REGISTER_CHAN1_HIGH = 0b00010111, // Channel 1 data, high byte - }; - - /// Constances to calculating lux - private const Single TSL2591_LUX_COEFA = 1.7f; - private const Single TSL2591_LUX_COEFB = 1.64f; - private const Single TSL2591_LUX_COEFC = 0.59f; - private const Single TSL2591_LUX_COEFD = 0.86f; - private const UInt16 TSL2591_LUX_DF = 408; - - /// Disable the device - /// TSL2591::TSL2591_ENABLE_AEN | TSL2591::TSL2591_ENABLE_AIEN | TSL2591::TSL2591_ENABLE_NPIEN - private void Disable() => this.Write8((Byte)OP.TSL2591_COMMAND_NORMAL_OP | (Byte)REGISTER.TSL2591_REGISTER_ENABLE, (Byte)ENABLE.TSL2591_ENABLE_AEN); - - /// Enable the device - /// TSL2591::TSL2591_ENABLE_POWERON | TSL2591::TSL2591_ENABLE_AEN | TSL2591::TSL2591_ENABLE_AIEN | TSL2591::TSL2591_ENABLE_NPIEN - private void Enable() => this.Write8((Byte)OP.TSL2591_COMMAND_NORMAL_OP | (Byte)REGISTER.TSL2591_REGISTER_ENABLE, (Byte)ENABLE.TSL2591_ENABLE_POWERON | (Byte)ENABLE.TSL2591_ENABLE_AEN); - - /// Gets the Complete Luminosity of the Device, reads out - /// Both Channels and return them in unsinged int32 - /// The upper unsinged int16 half contains the adc value - /// of the ir channel, the lower half the visible channel - private UInt32 GetFullLuminosity() { - this.Enable(); - for(Byte d = 0; d <= (Byte)this._integration; d++) { - Thread.Sleep(108); - } - UInt16 ch0 = this.Read16((Byte)OP.TSL2591_COMMAND_NORMAL_OP | (Byte)REGISTER.TSL2591_REGISTER_CHAN0_LOW); - UInt16 ch1 = this.Read16((Byte)OP.TSL2591_COMMAND_NORMAL_OP | (Byte)REGISTER.TSL2591_REGISTER_CHAN1_LOW); - this.Disable(); - return (UInt32)ch1 << 16 | ch0; - } - - /// Get the Complete Luminosity of the Device, reads out - /// Both Channels and return them in unsinged int32, but Switch through - /// the Gain if lower or higher bounds are reached - /// Set the gainlevel for the measure - /// The upper unsinged int16 half contains the adc value - /// of the ir channel, the lower half the visible channel - private UInt32 GetLumAdv(Gain gain) { - if(gain != this._gain) { - this.SetGain(gain); - } - UInt32 lum = this.GetFullLuminosity(); - UInt16 fu = (UInt16)(lum & 0xFFFF); - UInt16 ir = (UInt16)(lum >> 16); - - UInt16 max = 0; - if(this._integration != IntegrationTime.TSL2591_INTEGRATIONTIME_100MS) { - max = 60000; - } else { - max = 30000; - } - - if(((fu < max * (1.0f / 25) && fu / (1.0f / 25) < max) && (ir < max * (1.0f / 25) && ir / (1.0f / 25) < max)) && this._gain == Gain.TSL2591_GAIN_LOW) { - return this.GetLumAdv(Gain.TSL2591_GAIN_MED); - } - if(((fu < max * (25.0f / 428) && fu / (25.0f / 428) < max) && (ir < max * (25.0f / 428) && ir / (25.0f / 428) < max)) && this._gain == Gain.TSL2591_GAIN_MED) { - return this.GetLumAdv(Gain.TSL2591_GAIN_HIGH); - } - if(((fu < max * (428.0f / 9876) && fu / (428.0f / 9876) < max) && (ir < max * (428.0f / 9876) && ir / (428.0f / 9876) < max)) && this._gain == Gain.TSL2591_GAIN_HIGH) { - return this.GetLumAdv(Gain.TSL2591_GAIN_MAX); - } - if((fu > max || ir > max) && this._gain == Gain.TSL2591_GAIN_MAX) { - return this.GetLumAdv(Gain.TSL2591_GAIN_HIGH); - } - if((fu > max || ir > max) && this._gain == Gain.TSL2591_GAIN_HIGH) { - return this.GetLumAdv(Gain.TSL2591_GAIN_MED); - } - if((fu > max || ir > max) && this._gain == Gain.TSL2591_GAIN_MED) { - return this.GetLumAdv(Gain.TSL2591_GAIN_LOW); - } - return lum; - } - - /// Write a unsinged int8 value to the TWI interface - /// Value to write - private void Write8(Byte reg) => this.w.Write(reg); - - /// Write two unsinged int8 value to the TWI interface - /// Value to write - /// Value to write - private void Write8(Byte reg1, Byte reg2) => this.w.WriteAddressByte(reg1, reg2); - - /// Read a unsinged int16 value from two registers - /// Lower address - /// Value of the two int8 registers combined to unsinged int16 - private UInt16 Read16(Byte reg) => this.w.ReadAddressWord(reg); - /*this.w.Write(reg); - Byte[] data = this.w.Read(2); - return (UInt16)(data[1] << 8 | data[0]);*/ - - /// Read a unsinged int8 value from a registers - /// Address of the Register - /// Value of the register in unsinged int8 - private Byte Read8(Byte reg) => this.w.ReadAddressByte(reg); } } diff --git a/IotThermometer/Program.cs b/IotThermometer/Program.cs index 927f731..2a723d1 100644 --- a/IotThermometer/Program.cs +++ b/IotThermometer/Program.cs @@ -1,29 +1,44 @@ using System; using BlubbFish.Iot.Thermometer.Librarys; +using System.Threading; namespace BlubbFish.Iot.Thermometer { class Program { private readonly TSL2591 tls; private readonly Bme280 bme; + private readonly Rainbowdruino disp; public Program(String[] args) { - this.tls = new TSL2591(TSL2591.IntegrationTime.TSL2591_INTEGRATIONTIME_200MS, 0x29); + this.tls = new TSL2591(0x29); this.bme = new Bme280(0x76); + this.disp = new Rainbowdruino("/dev/ttyUSB0"); this.tls.Begin(); this.bme.Begin(); while(true) { - //this.tls.Measure(); + this.tls.Measure(); this.bme.Measure(); - //Console.WriteLine(this.tls.GetLux()+" lux"); - Console.WriteLine(this.bme.GetTemperature() + " °C"); - Console.WriteLine(this.bme.GetPressure() + " mbHp"); - Console.WriteLine(this.bme.GetHumidity() + " Hm%"); - - - System.Threading.Thread.Sleep(1000); + this.DrawDisp(this.bme.Temperatur, 0x110000); + Thread.Sleep(5000); + this.DrawDisp(this.bme.Humidity, 0x001100); + Thread.Sleep(2000); + this.DrawDisp(this.bme.Pressure, 0x111100); + Thread.Sleep(2000); + this.DrawDisp(this.tls.Luminosity, 0x000011); + Thread.Sleep(2000); + Console.WriteLine(this.tls.Luminosity.ToString("F5") + " lux"); + Console.WriteLine(this.bme.Temperatur.ToString("F2") + " °C"); + Console.WriteLine(this.bme.Pressure.ToString("F2") + " mbHp"); + Console.WriteLine(this.bme.Humidity.ToString("F3") + " Hm%"); + Console.WriteLine(); } } + private void DrawDisp(Double c, UInt32 color) { + this.disp.DrawDigets(c.ToString().Replace(",", "."), color); + this.disp.DrawLineX(0, 0, 16, color); + this.disp.Write(); + } + static void Main(String[] args) => new Program(args); } } diff --git a/IotThermometer/System/ATwi.cs b/IotThermometer/System/ATwi.cs new file mode 100644 index 0000000..4038254 --- /dev/null +++ b/IotThermometer/System/ATwi.cs @@ -0,0 +1,39 @@ +using System; +using Unosquare.RaspberryIO; +using Unosquare.RaspberryIO.Gpio; + +namespace BlubbFish.Iot.Thermometer.System { + public abstract class ATwi { + protected readonly I2CDevice w; + + protected ATwi(Int32 address) => this.w = Pi.I2C.AddDevice(address); + + protected Byte ReadByte(Byte reg) => this.w.ReadAddressByte(reg); + + protected void WriteByte(Byte reg, Byte val) => this.w.WriteAddressByte(reg, val); + + protected void WriteByte(Byte reg) => this.w.Write(reg); + + protected UInt16 ReadShort(Byte reg) => this.w.ReadAddressWord(reg); + + protected UInt16 ReadShortLE(Byte reg) { + UInt16 data = this.ReadShort(reg); + return (UInt16)((data >> 8) | (data << 8)); + } + + protected Int16 ReadSingedShort(Byte reg) => (Int16)this.ReadShort(reg); + + protected UInt32 Read20(Byte reg) { + UInt32 data; + this.w.Write(reg); + Byte[] dr = this.w.Read(3); + data = dr[0]; + data <<= 8; + data |= dr[1]; + data <<= 8; + data |= dr[2]; + data >>= 4; + return data; + } + } +}