summaryrefslogtreecommitdiffstats
path: root/awlstatusword.py
blob: 69939e651a49852db235c73eb97fb4d04a1690d3 (plain)
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
# -*- coding: utf-8 -*-
#
# AWL simulator - status word
# Copyright 2012-2013 Michael Buesch <m@bues.ch>
#
# Licensed under the terms of the GNU General Public License version 2.
#

from util import *
from awldatatypehelpers import *


class S7StatusWord(object):
	"STEP 7 status word"

	name2nr = {
		"/ER"	: 0,
		"VKE"	: 1,
		"STA"	: 2,
		"OR"	: 3,
		"OS"	: 4,
		"OV"	: 5,
		"A0"	: 6,
		"A1"	: 7,
		"BIE"	: 8,
	}

	nr2name = { }
	for name, type in name2nr.items():
		nr2name[type] = name

	NR_BITS = 9

	@classmethod
	def getBitnrByName(cls, name):
		try:
			return cls.name2nr[name]
		except KeyError as e:
			raise AwlSimError("Invalid status word bit "
				"name: " + str(name))

	def __init__(self):
		self.reset()

	def getByBitNumber(self, bitNumber):
		try:
			return (self.NER, self.VKE, self.STA, self.OR,
				self.OS, self.OV, self.A0, self.A1,
				self.BIE)[bitNumber]
		except IndexError as e:
			raise AwlSimError("Status word bit fetch '%d' "
				"out of range" % bitNumber)

	def getWord(self):
		return self.NER | (self.VKE << 1) | (self.STA << 2) |\
		       (self.OR << 3) | (self.OS << 4) | (self.OV << 5) |\
		       (self.A0 << 6) | (self.A1 << 7) | (self.BIE << 8)

	def setWord(self, word):
		self.NER = 1 if (word & (1 << 0)) else 0
		self.VKE = 1 if (word & (1 << 1)) else 0
		self.STA = 1 if (word & (1 << 2)) else 0
		self.OR = 1 if (word & (1 << 3)) else 0
		self.OS = 1 if (word & (1 << 4)) else 0
		self.OV = 1 if (word & (1 << 5)) else 0
		self.A0 = 1 if (word & (1 << 6)) else 0
		self.A1 = 1 if (word & (1 << 7)) else 0
		self.BIE = 1 if (word & (1 << 8)) else 0

	def reset(self):
		self.NER = 0	# /ER	=> Erstabfrage
		self.VKE = 0	# VKE	=> Verknuepfungsergebnis
		self.STA = 0	# STA	=> Statusbit
		self.OR = 0	# OR	=> Oderbit
		self.OS = 0	# OS	=> Ueberlauf speichernd
		self.OV = 0	# OV	=> Ueberlauf
		self.A0 = 0	# A0	=> Ergebnisanzeige 0
		self.A1 = 0	# A1	=> Ergebnisanzeige 1
		self.BIE = 0	# BIE	=> Binaerergebnis

	def copy(self):
		new = S7StatusWord()
		new.NER = self.NER
		new.VKE = self.VKE
		new.STA = self.STA
		new.OR = self.OR
		new.OS = self.OS
		new.OV = self.OV
		new.A0 = self.A0
		new.A1 = self.A1
		new.BIE = self.BIE
		return new

	def setForFloatingPoint(self, pyFloat):
		dword = pyFloatToDWord(pyFloat)
		dwordNoSign, s = dword & 0x7FFFFFFF, self
		if isDenormalPyFloat(pyFloat) or\
		   (dwordNoSign < 0x00800000 and dwordNoSign != 0):
			# denorm
			s.A1, s.A0, s.OV, s.OS = 0, 0, 1, 1
		elif dwordNoSign == 0:
			# zero
			s.A1, s.A0, s.OV = 0, 0, 0
		elif dwordNoSign >= 0x7F800000:
			if dwordNoSign == 0x7F800000:
				# inf
				if dword & 0x80000000:
					s.A1, s.A0, s.OV, s.OS = 0, 1, 1, 1
				else:
					s.A1, s.A0, s.OV, s.OS = 1, 0, 1, 1
			else:
				# nan
				s.A1, s.A0, s.OV, s.OS = 1, 1, 1, 1
		elif dword & 0x80000000:
			# norm neg
			s.A1, s.A0, s.OV = 0, 1, 0
		else:
			# norm pos
			s.A1, s.A0, s.OV = 1, 0, 0

	def __repr__(self):
		ret = []
		for i in range(self.NR_BITS - 1, -1, -1):
			ret.append("%s:%d" % (
				self.nr2name[i],
				self.getByBitNumber(i)
			))
		return '  '.join(ret)
bues.ch cgit interface