Completed
Pull Request — master (#380)
by
unknown
03:38
created

TSYS01SPI   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 131
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
dl 0
loc 131
rs 10
c 0
b 0
f 0
wmc 17

13 Methods

Rating   Name   Duplication   Size   Complexity  
A readROM() 0 8 2
A startADC() 0 8 2
A diag() 0 12 1
A readADC() 0 7 1
A readRomAddr() 0 9 1
A temperatureCelsius() 0 15 2
A on_deactivate() 0 4 1
A temperatureKelvin() 0 8 1
A reset() 0 5 1
A on_activate() 0 8 1
A __init__() 0 5 1
A get_process_unit() 0 6 1
A get_process_value() 0 8 2
1
# -*- coding: utf-8 -*-
2
"""
3
A hardware module for acessing the Measurement Systems TSYS01 temperature
4
sensor chip via SPI.
5
6
Qudi is free software: you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation, either version 3 of the License, or
9
(at your option) any later version.
10
11
Qudi is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
GNU General Public License for more details.
15
16
You should have received a copy of the GNU General Public License
17
along with Qudi. If not, see <http://www.gnu.org/licenses/>.
18
19
Copyright (c) the Qudi Developers. See the COPYRIGHT.txt file at the
20
top-level directory of this distribution and at <https://github.com/Ulm-IQO/qudi/>
21
"""
22
23
from core.module import Base, ConfigOption
24
from interface.process_interface import ProcessInterface
25
from core.util.mutex import Mutex
26
27
import spidev
28
import struct
29
import time
30
31
32
class TSYS01SPI(Base, ProcessInterface):
33
    """ Measurement Systems TSYS01 temperature sensor.
34
    """
35
    _modclass = 'TSYS01'
36
    _modtype = 'hardware'
37
38
    # config opts
39
    bus = ConfigOption('bus', 0, missing='warn')
40
    device = ConfigOption('device', 0, missing='warn')
41
42
    # commands to chip (constants)
43
    READ_ADC  = 0x00
44
    RESET     = 0x1E
45
    START_ADC = 0x48
46
    READ_ROM0 = 0xA0
47
48
    def __init__(self, **kwargs):
49
        super().__init__(**kwargs)
50
51
        #locking for thread safety
52
        self.threadlock = Mutex()
53
54
    def on_activate(self):
55
        """ Activate module.
56
        """
57
        self.rom = []
58
        self.spi = spidev.SpiDev()
59
        self.spi.open(self.bus, self.device)
60
        self.reset()
61
        self.readROM()
62
63
    def on_deactivate(self):
64
        """ Deactivate module.
65
        """
66
        self.spi.close()
67
68
    def diag(self):
69
        """ SPI bus diagnostic output.
70
        """
71
        print('==== SPI Diagnostics ====')
72
        print('Bits per word: {0:>10}'.format(self.spi.bits_per_word))
73
        print('CS is active high: {0!s:>6}'.format(self.spi.cshigh))
74
        print('Loopback: {0!s:>15}'.format(self.spi.loop))
75
        print('LSB first: {0!s:>14}'.format(self.spi.lsbfirst))
76
        print('Max clock speed: {0:>8}'.format(self.spi.max_speed_hz))
77
        print('Clock mode: {0:>13}'.format(self.spi.mode))
78
        print('SI/SO shared: {0!s:>11}'.format(self.spi.threewire))
79
        print('=========================')
80
81
    def reset(self):
82
        """ Reset the sensor chip.
83
        """
84
        rbuf = self.spi.xfer( [self.RESET], 8000, 3000 )
85
        time.sleep(0.003)
86
87
    def readRomAddr(self, addr):
88
        """ Read a 16bit rom address.
89
90
            @param int addr: momory address to read
91
            @return int: 16bit contents of rom at address
92
        """
93
        bytes = self.READ_ROM0 | 0x0F & ( addr << 1)
94
        rbuf = self.spi.xfer( [bytes, 0x00, 0x00] )
95
        return 2**8*rbuf[1] + rbuf[2]
96
97
    def readROM(self):
98
        """ Read the whole device ROM.
99
100
            @return list(int): contents of all 8 ROM registers
101
        """
102
        self.rom = []
103
        for i in range(8):
104
            self.rom.append(self.readRomAddr(i))
105
106
    def startADC(self):
107
        """ Start the temperature sensor ADC.
108
        """
109
        try:
110
            rbuf = self.spi.xfer([self.START_ADC])
111
        except OSError:
112
            pass
113
        time.sleep(0.010)
114
115
    def readADC(self):
116
        """ Read value from the ADC.
117
118
            @return int: raw ADC value
119
        """
120
        rbuf = self.spi.xfer([self.READ_ADC, 0x00, 0x00, 0x00] )
121
        return struct.unpack('>I', b'\0' + bytes(rbuf[1:]))[0]
122
123
    def temperatureCelsius(self, adcValue):
124
        """ Convert ADC value to degrees Celsius.
125
126
            @param int adcValue: raw ADC value
127
128
            @return float: temperature in degrees Celsius
129
        """
130
        if len(self.rom) < 8:
131
            self.readROM()
132
        adc16 = adcValue / 2**8
133
        return (-2.0 * self.rom[1] * 10**-21 * adc16**4
134
              +  4.0 * self.rom[2] * 10**-16 * adc16**3
135
              + -2.0 * self.rom[3] * 10**-11 * adc16**2
136
              +  1.0 * self.rom[4] * 10**-6  * adc16
137
              + -1.5 * self.rom[5] * 10**-2 );
138
139
    def temperatureKelvin(self, adcValue):
140
        """ Convert ADC value to Kelvin.
141
142
            @param int adcValue: raw ADC value
143
144
            @return float: temperature in Kelvin
145
        """
146
        return 273.15 + self.temperatureCelsius(adcValue)
147
148
    def get_process_value(self):
149
        """ Read ADC and return emperature in Kelvin.
150
151
            @return float: current temperature in Kelvin
152
        """
153
        with self.threadlock:
154
            self.startADC()
155
            return self.temperatureKelvin(self.readADC())
156
157
    def get_process_unit(self):
158
        """ Return Process unit, here Kelvin.
159
160
            @return tuple(str, str): short and text form of process unit
161
        """
162
        return ('K', 'kelvin')
163