using System; using System.Collections.Generic; using System.Runtime.Serialization; using OneWireAPI; using WeatherService.Values; namespace WeatherService.Devices { [DataContract] public class PressureDevice : DeviceBase { #region Constants private readonly byte[] _resetSequence = new byte[] { 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0 }; // Binary sequence to reset the device private readonly byte[] _readWord1Sequence = new byte[] { 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0 }; // Binary sequence to read word 1 private readonly byte[] _readWord2Sequence = new byte[] { 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0 }; // Binary sequence to read word 2 private readonly byte[] _readWord3Sequence = new byte[] { 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0 }; // Binary sequence to read word 3 private readonly byte[] _readWord4Sequence = new byte[] { 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0 }; // Binary sequence to read word 4 private readonly byte[] _readPressureSequence = new byte[] { 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0 }; // Binary sequence to read pressure private readonly byte[] _readTemperatureSequence = new byte[] { 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 0 }; // Binary sequence to read temperature private const byte ChannelAccessCommand = 0xF5; private const byte ConfigRead = 0xEC; private const byte ConfigWrite = 0x8C; private const byte ConfigPulseRead = 0xC8; #endregion #region Member variables private readonly owDeviceFamily12 _writeDevice; // Device for writing to the pressure sensor private readonly owDeviceFamily12 _readDevice; // Device for reading from the pressure sensor private readonly Value _temperatureValue; // Last temperature (degrees C) private readonly Value _pressureValue; // Last pressure (mbar) private bool _readCalibration; // Have we read the calibration constants? private int _calibration1; // Calibration constant private int _calibration2; // Calibration constant private int _calibration3; // Calibration constant private int _calibration4; // Calibration constant private int _calibration5; // Calibration constant private int _calibration6; // Calibration constant #endregion #region Constructor public PressureDevice(Session session, owDevice firstDevice, owDevice secondDevice) : base(session, firstDevice, DeviceType.Pressure) { // Get both devices owDeviceFamily12 oDevice1 = (owDeviceFamily12) firstDevice; owDeviceFamily12 oDevice2 = (owDeviceFamily12) secondDevice; // Get the state of both devices byte[] baState1 = oDevice1.ReadDevice(); byte[] baState2 = oDevice2.ReadDevice(); // If both devices have the same power state then this isn't a proper pressure device if (oDevice1.IsPowered(baState1) == oDevice2.IsPowered(baState2)) { // Throw an exception throw new Exception("Invalid TAI8570"); } // The powered device is the write device - sort this out and remember which is which if (oDevice1.IsPowered(baState1)) { _writeDevice = oDevice1; _readDevice = oDevice2; } else { _writeDevice = oDevice2; _readDevice = oDevice1; } _temperatureValue = new Value(WeatherValueType.Temperature, this); _pressureValue = new Value(WeatherValueType.Pressure, this); _valueList.Add(WeatherValueType.Temperature, _temperatureValue); _valueList.Add(WeatherValueType.Pressure, _pressureValue); } #endregion #region PIO methods private void PrepPioForWrite() { byte[] baState = _writeDevice.ReadDevice(); _writeDevice.SetLatchState(0, true, baState); _writeDevice.SetLatchState(1, false, baState); _writeDevice.WriteDevice(baState); baState = _readDevice.ReadDevice(); _readDevice.SetLatchState(0, false, baState); _readDevice.SetLatchState(1, false, baState); _readDevice.WriteDevice(baState); } private void PrepPioForRead() { byte[] baState = _readDevice.ReadDevice(); _readDevice.SetLatchState(0, false, baState); _readDevice.SetLatchState(1, false, baState); _readDevice.WriteDevice(baState); baState = _writeDevice.ReadDevice(); _writeDevice.SetLatchState(0, false, baState); _writeDevice.SetLatchState(1, false, baState); _writeDevice.WriteDevice(baState); } private bool OpenPio(int pio) { byte[] baWriteState = _writeDevice.ReadDevice(); byte[] baReadState = _readDevice.ReadDevice(); _writeDevice.SetLatchState(pio, false, baWriteState); _readDevice.SetLatchState(pio, false, baReadState); _writeDevice.WriteDevice(baWriteState); _writeDevice.WriteDevice(baReadState); baWriteState = _writeDevice.ReadDevice(); baReadState = _readDevice.ReadDevice(); bool bResult = (_writeDevice.GetLevel(pio, baWriteState) && _readDevice.GetLevel(pio, baReadState)); return bResult; } private bool OpenPioA() { return OpenPio(0); } private bool OpenPioB() { return OpenPio(1); } #endregion #region Private methods private bool SetupForWrite() { byte[] data = new byte[3]; // Data buffer to send over the network short dataCount = 0; // How many bytes of data to send PrepPioForWrite(); owAdapter.Select(_writeDevice.ID); data[dataCount++] = ChannelAccessCommand; data[dataCount++] = ConfigWrite; data[dataCount++] = 0xFF; owAdapter.SendBlock(data, dataCount); owAdapter.ReadByte(); return true; } private bool SetupForRead() { byte[] data = new byte[3]; // Data buffer to send over the network short dataCount = 0; // How many bytes of data to send PrepPioForRead(); owAdapter.Select(_readDevice.ID); data[dataCount++] = ChannelAccessCommand; data[dataCount++] = ConfigRead; data[dataCount++] = 0xFF; owAdapter.SendBlock(data, dataCount); owAdapter.ReadByte(); return true; } private bool SetupForPulseRead() { byte[] data = new byte[3]; // Data buffer to send over the network short dataCount = 0; // How many bytes of data to send PrepPioForWrite(); owAdapter.Select(_readDevice.ID); data[dataCount++] = ChannelAccessCommand; data[dataCount++] = ConfigPulseRead; data[dataCount++] = 0xFF; owAdapter.SendBlock(data, dataCount); owAdapter.ReadByte(); return true; } private bool WriteBitSequence(IEnumerable sequence) { bool result = false; if (SetupForWrite()) { foreach (byte t in sequence) { SendBit(t != 0); } SendBit(false); result = true; } return result; } private byte[] ReadBitSequence(IEnumerable sequence) { byte[] result = new byte[16]; if (WriteBitSequence(sequence)) { result = GetBits(16); OpenPioB(); } return result; } private static void SendBit(bool value) { if (value) { owAdapter.SendBit(0); owAdapter.SendBit(1); owAdapter.SendBit(1); owAdapter.SendBit(1); owAdapter.SendBit(0); owAdapter.SendBit(0); } else { owAdapter.SendBit(0); owAdapter.SendBit(0); owAdapter.SendBit(1); owAdapter.SendBit(0); owAdapter.SendBit(0); owAdapter.SendBit(0); } } private static bool ReadBit() { owAdapter.ReadBit(); // Read PIO A #1 owAdapter.ReadBit(); // Read PIO B #1 owAdapter.ReadBit(); // Read PIO A #2 owAdapter.ReadBit(); // Read PIO B #2 owAdapter.ReadBit(); // Read PIO A #3 owAdapter.ReadBit(); // Read PIO B #3 owAdapter.ReadBit(); // Read PIO A #4 short data = owAdapter.ReadBit(); bool result = (data == 1); owAdapter.SendBit(0); // Write PIO A #1 owAdapter.SendBit(1); // Write PIO B #1 owAdapter.SendBit(0); // Write PIO A #2 owAdapter.SendBit(1); // Write PIO B #2 owAdapter.SendBit(1); // Write PIO A #3 owAdapter.SendBit(1); // Write PIO B #3 owAdapter.SendBit(1); // Write PIO A #4 owAdapter.SendBit(1); // Write PIO B #4 return result; } private bool Reset() { return WriteBitSequence(_resetSequence); } private bool CheckConversionStatus() { int i; if (!SetupForPulseRead()) return false; for (i = 0; i < 100; i++) if (owAdapter.SendBit(0) == 0) break; return (i < 100); } private bool ReadCalibrationConstants() { int i; if (!Reset()) return false; byte[] word1 = ReadBitSequence(_readWord1Sequence); byte[] word2 = ReadBitSequence(_readWord2Sequence); byte[] word3 = ReadBitSequence(_readWord3Sequence); byte[] word4 = ReadBitSequence(_readWord4Sequence); _calibration1 = _calibration2 = _calibration3 = _calibration4 = _calibration5 = _calibration6 = 0; for (i = 0; i < 15; i++) { _calibration1 = (_calibration1 << 1); if (word1[i] == 1) _calibration1 = _calibration1 + 1; } if (word1[15] == 1) _calibration5 = 1; for (i = 0; i < 10; i++) { _calibration5 = (_calibration5 << 1); if (word2[i] == 1) _calibration5 = _calibration5 + 1; } for (i = 10; i < 16; i++) { _calibration6 = (_calibration6 << 1); if (word2[i] == 1) _calibration6 = _calibration6 + 1; } for (i = 0; i < 10; i++) { _calibration4 = (_calibration4 << 1); if (word3[i] == 1) _calibration4 = _calibration4 + 1; } for (i = 10; i < 16; i++) { _calibration2 = (_calibration2 << 1); if (word3[i] == 1) _calibration2 = _calibration2 + 1; } for (i = 10; i < 16; i++) { _calibration2 = (_calibration2 << 1); if (word4[i] == 1) _calibration2 = _calibration2 + 1; } for (i = 0; i < 10; i++) { _calibration3 = (_calibration3 << 1); if (word4[i] == 1) _calibration3 = _calibration3 + 1; } return true; } private byte[] GetBits(byte bitCount) { byte[] result = new byte[bitCount]; if (SetupForRead()) { for (int i = 0; i < bitCount; i++) { if (ReadBit()) result[i] = 1; else result[i] = 0; } } return result; } private int ReadValue(IEnumerable sequence) { int result = 0; if (!Reset()) return 0; if (!WriteBitSequence(sequence)) return 0; if (!CheckConversionStatus()) return 0; if (!OpenPioA()) return 0; byte[] data = GetBits(16); if (!OpenPioB()) return 0; for (int i = 0; i < 16; i++) { result = (result << 1); if (data[i] == 1) result = result + 1; } return result; } private bool ReadSensorData() { int pressure = ReadValue(_readPressureSequence); int temperature = ReadValue(_readTemperatureSequence); double calibrationTemperature = (8 * _calibration5) + 20224; double temperatureDifference = temperature - calibrationTemperature; _temperatureValue.SetValue(20 + ((temperatureDifference * (_calibration6 + 50)) / 10240)); double offset = _calibration2 * 4 + (((_calibration4 - 512) * temperatureDifference) / 4096); double sensitivity = _calibration1 + ((_calibration3 * temperatureDifference) / 1024) + 24576; double actualPressure = ((sensitivity * (pressure - 7168)) / 16384) - offset; _pressureValue.SetValue((actualPressure / 32) + 250); return true; } private void ReadDevice() { if (!_readCalibration) { if (!ReadCalibrationConstants()) throw new Exception("Error reading calibration constants"); _readCalibration = true; } if (!ReadSensorData()) throw new Exception("Error reading Pressure and Temperature values"); } #endregion #region Internal methods internal override void RefreshCache() { ReadDevice(); base.RefreshCache(); } #endregion #region Elevation code (not used yet) //private double m_dElevation = 0.0; // Height above sea level (meters) //public void set_height_over_sea_level_meter(double height) //{ // m_dElevation = height; //} //public void set_height_over_sea_level_feet(double height) //{ // m_dElevation = height * 0.3048; //} //public double get_height_over_sea_level_meter() //{ // return m_dElevation; //} //public double get_height_over_sea_level_feet() //{ // return (3.281 * m_dElevation); //} //public double get_calc_height_over_sea_level_meter() //{ // return (288.15 / 0.0065) * (1 - Math.Pow((double) (getPressure_Pa() / 101325), (double) (0.0065 * (287.052 / 9.81)))); //} #endregion } }