Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

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

#!/usr/bin/env python 

# encoding: utf-8 

 

# Copyright (C) 2015 Chintalagiri Shashank 

# 

# This file is part of tendril. 

# 

# This program is free software: you can redistribute it and/or modify 

# it under the terms of the GNU Affero General Public License as published by 

# the Free Software Foundation, either version 3 of the License, or 

# (at your option) any later version. 

# 

# This program is distributed in the hope that it will be useful, 

# but WITHOUT ANY WARRANTY; without even the implied warranty of 

# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 

# GNU Affero General Public License for more details. 

# 

# You should have received a copy of the GNU Affero General Public License 

# along with this program.  If not, see <http://www.gnu.org/licenses/>. 

 

""" 

Docstring for measurements 

""" 

 

import time 

import arrow 

 

from colorama import Fore 

from tendril.utils.types.electromagnetic import Voltage 

 

from tendril.utils import log 

logger = log.get_logger(__name__, log.INFO) 

 

 

class TestMeasurementBase(object): 

    """ Object representing a single measurement for a Test """ 

    def __init__(self): 

        self._parent = None 

        self._ts = None 

 

    def do_measurement(self): 

        """ 

        This is the measurement function. This should be overridden 

        by the actual Test classes to perform the actual measurement. 

        """ 

        raise NotImplementedError 

 

    def render(self): 

        """ 

        This is an example render function. This should be overridden by the 

        actual Test classes to render the actual result. 

 

        Rendering means encoding the test result into a JSON representation, 

        which can later be dumped into a postgres database. 

        """ 

        raise NotImplementedError 

 

    def render_dox(self): 

        if self._ts is None: 

            logger.warning("render_dox can't find _ts for Measurement Class" 

                           + str(self.__class__)) 

            meas_dict = {} 

        else: 

            meas_dict = {'ts': self._ts.format()} 

        return meas_dict 

 

    def load_result_from_obj(self, result_db_obj): 

        raise NotImplementedError 

 

    @property 

    def parent(self): 

        return self._parent 

 

    @parent.setter 

    def parent(self, value): 

        self._parent = value 

 

    @property 

    def yesorno(self): 

        raise NotImplementedError 

 

 

class TestSimpleMeasurement(TestMeasurementBase): 

    def __init__(self): 

        super(TestSimpleMeasurement, self).__init__() 

        self._outputchannel = None 

        self._output = None 

        self._stime = None 

        self._inputchannel = None 

        self._input = None 

        self._inputtype = None 

        self._instrument = None 

 

    def do_measurement(self): 

        """ 

        This is an example measurement function. This should be overridden 

        by the actual Test classes to perform the actual measurement, and 

        this code can be used as a starting point. 

 

        The result of the measurement would typically be some composition of 

        instances of :class:`tendril.utils.type.signalbase.SignalBase`. 

        """ 

        logger.debug("Making measurement : " + repr(self)) 

        if self._output is not None: 

            if self._outputchannel is None: 

                raise IOError("Output channel is not defined") 

            self._outputchannel.set(self._output) 

 

        if self.stime is not None: 

            time.sleep(self.stime) 

 

        if self._inputtype is not None: 

            if self._inputchannel is None: 

                raise IOError("Input channel is not defined") 

            self._input = self._inputchannel.get() 

            if self._input.unitclass is not None and \ 

                    not self._input.unitclass == self._inputtype: 

                raise TypeError( 

                    "Expected " + self._inputtype.unitclass + 

                    ", got " + type(self._input) 

                ) 

 

        self._ts = arrow.utcnow() 

 

    @property 

    def stime(self): 

        return self._stime 

 

    @property 

    def yesorno(self): 

        raise NotImplementedError 

 

    def render(self): 

        return {'instrument': 

                (self._instrument.ident if self._instrument is not None 

                 else None), 

                'output': self._output, 

                'input': self._input} 

 

    def load_result_from_obj(self, result_db_obj): 

        raise NotImplementedError 

 

 

class DCVoltageMeasurement(TestSimpleMeasurement): 

    def __init__(self): 

        super(DCVoltageMeasurement, self).__init__() 

        self._outputchannel = None 

        self._inputtype = None 

        self._inputchannel = None 

 

    def do_measurement(self): 

        """ 

        This function is present only because the instrument return value is 

        not of a SignalPoint Type. Instrument classes should be changed to 

        use Signal Point type instead and this class should fall back to the 

        parent's implementation. 

        """ 

        logger.debug("Making measurement : " + repr(self)) 

        if self._output is not None: 

            if self._outputchannel is None: 

                raise IOError("Output channel is not defined") 

            self._outputchannel.set(self._output) 

 

        if self.stime is not None: 

            time.sleep(self.stime) 

 

        if self._inputtype is not None: 

            if self._inputchannel is None: 

                raise IOError("Input channel is not defined") 

            self._input = self._inputchannel.get() 

            # if self._input.unitclass and \ 

            #         not self._input.unitclass == self._inputtype: 

            #     raise TypeError( 

            #         "Expected " + self._inputtype.unitclass + 

            #         ", got " + type(self._input) 

            #     ) 

        logger.info("Measured Voltage: " + repr(self._input)) 

        self._ts = arrow.utcnow() 

 

    @property 

    def parent(self): 

        return self._parent 

 

    @parent.setter 

    def parent(self, value): 

        self._parent = value 

        self._inputtype = Voltage 

        if self._parent._offline is not True: 

            self._inputchannel = self._parent.instrument.voltage_input 

 

    @property 

    def input_voltage(self): 

        return self._input 

 

    def yesorno(self): 

        pass 

 

    def render(self): 

        return { 

            'input': {'v': repr(self._input)}, 

            'timestamp': self._ts.isoformat() 

            } 

 

    def load_result_from_obj(self, result_db_obj): 

        self._input = Voltage(result_db_obj['input']['v']) 

        self._ts = arrow.get(result_db_obj['timestamp']) 

 

 

class TestUserMeasurement(TestMeasurementBase): 

    def __init__(self, string): 

        super(TestUserMeasurement, self).__init__() 

        self._string = string 

        self._user_input = None 

 

    def do_measurement(self): 

        while self.input_valid is False: 

            self._user_input = raw_input( 

                Fore.CYAN + self._string + ' [y/n] : ' + Fore.RESET 

            ).strip() 

        self._ts = arrow.utcnow() 

 

    @property 

    def input_valid(self): 

        if self._user_input is None: 

            return False 

        if self._user_input.lower() in ['y', 'yes', 'ok', 'pass', 'n', 

                                        'no', 'fail', 'true', 'false']: 

            return True 

        else: 

            return False 

 

    @property 

    def yesorno(self): 

        if self._user_input.lower() in ['y', 'yes', 'ok', 'pass', 'true']: 

            return True 

        else: 

            return False 

 

    def render(self): 

        return {'question': self._string + ' [y/n] : ' + str(self.yesorno), 

                'timestamp': self._ts.isoformat()} 

 

    def load_result_from_obj(self, result_db_obj): 

        self._ts = arrow.get(result_db_obj['timestamp']) 

        self._user_input = result_db_obj['question'].split(' ')[-1]