-
Notifications
You must be signed in to change notification settings - Fork 75
/
fields.py
117 lines (86 loc) · 3.49 KB
/
fields.py
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
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import array
from .errors import DecodingError
from .utils import py3_array_tobytes
class VersionField(object):
"""This class represent the Version fields defines by IPMI.
Introduced with HPM the version field can hold additional auxiliary bytes.
"""
VERSION_FIELD_LEN = 2
VERSION_WITH_AUX_FIELD_LEN = 6
def __init__(self, data=None):
self.major = None
self.minor = None
if data:
self._from_data(data)
def _from_data(self, data):
if isinstance(data, str):
data = [ord(c) for c in data]
data = array.array('B', data)
self.version = self._decode_data(data[0:2])
if len(data) == self.VERSION_WITH_AUX_FIELD_LEN:
self.auxiliary = data[2:6]
def __str__(self):
return self.version_to_string()
def _decode_data(self, data):
"""`data` is array.array."""
self.major = data[0]
if data[1] == 0xff:
self.minor = data[1]
elif data[1] <= 0x99:
self.minor = int(py3_array_tobytes(data[1:2]).decode('bcd+'))
else:
raise DecodingError()
def version_to_string(self):
return ''.join("%s.%s" % (self.major, self.minor))
def _unpack6bitascii(data):
"""Unpack the 6bit ascii encoded string."""
string = ''
for i in range(0, len(data), 3):
d = data[i:i+3]
string += chr(0x20 + (d[0] & 0x3f))
string += chr(0x20 + (((d[0] & 0xc0) >> 6) | ((d[1] & 0xf) << 2)))
string += chr(0x20 + (((d[1] & 0xf0) >> 4) | ((d[2] & 0x3) << 4)))
string += chr(0x20 + ((d[2] & 0xfc) >> 2))
return string
class TypeLengthString(object):
"""
This is the TYPE/LENGTH BYTE FORMAT field represenation according the
Platform Management FRU Information Storage Definition v1.0.
In addition the difference to the 'FRU Information Storage Definition' to
the variant used in Type/Length for the Device ID String used in the SDR.
"""
TYPE_FRU_BINARY = 0
TYPE_SDR_UNICODE = 0
TYPE_BCD_PLUS = 1
TYPE_6BIT_ASCII = 2
TYPE_ASCII_OR_UTF16 = 3
def __init__(self, data=None, offset=0, force_lang_eng=False, sdr=False):
if data:
self._from_data(data, offset, force_lang_eng)
def __str__(self):
if self.field_type is self.TYPE_FRU_BINARY:
return ' '.join('%02x' % b for b in self.raw)
else:
return self.string.replace('\x00', '')
def _from_data(self, data, offset=0, force_lang_eng=False):
self.offset = offset
self.field_type = data[offset] >> 6 & 0x3
self.length = data[offset] & 0x3f
self.raw = data[offset+1:offset+1+self.length]
if self.field_type == self.TYPE_BCD_PLUS:
self.string = self.raw.decode('bcd+')
elif self.field_type == self.TYPE_6BIT_ASCII:
self.string = _unpack6bitascii(self.raw)
else:
chr_data = ''.join([chr(c) for c in self.raw])
self.string = chr_data
class FruTypeLengthString(TypeLengthString):
def __init__(self, data=None, offset=0, force_lang_eng=False):
super(FruTypeLengthString, self).__init__(data, offset,
force_lang_eng,
sdr=False)
class SdrTypeLengthString(TypeLengthString):
def __init__(self, data=None, offset=0, force_lang_eng=False):
super(SdrTypeLengthString, self).__init__(data, sdr=True)