Coverage for d7a/d7anp/addressee.py: 97%

64 statements  

« prev     ^ index     » next       coverage.py v7.5.0, created at 2024-05-24 08:03 +0200

1# 

2# Copyright (c) 2015-2021 University of Antwerp, Aloxy NV. 

3# 

4# This file is part of pyd7a. 

5# See https://github.com/Sub-IoT/pyd7a for further info. 

6# 

7# Licensed under the Apache License, Version 2.0 (the "License"); 

8# you may not use this file except in compliance with the License. 

9# You may obtain a copy of the License at 

10# 

11# http://www.apache.org/licenses/LICENSE-2.0 

12# 

13# Unless required by applicable law or agreed to in writing, software 

14# distributed under the License is distributed on an "AS IS" BASIS, 

15# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

16# See the License for the specific language governing permissions and 

17# limitations under the License. 

18# 

19 

20# author: Christophe VG <contact@christophe.vg> 

21# class implementation of addressee parameters 

22 

23 

24import struct 

25from enum import Enum 

26 

27from d7a.support.schema import Validatable, Types 

28from d7a.types.ct import CT 

29 

30 

31class IdType(Enum): 

32 NBID = 0 

33 NOID = 1 

34 UID = 2 

35 VID = 3 

36 

37class NlsMethod(Enum): 

38 NONE = 0 

39 AES_CTR = 1 

40 AES_CBC_MAC_128 = 2 

41 AES_CBC_MAC_64 = 3 

42 AES_CBC_MAC_32 = 4 

43 AES_CCM_128 = 5 

44 AES_CCM_64 = 6 

45 AES_CCM_32 = 7 

46 

47class Addressee(Validatable): 

48 

49 # addressee ID length 

50 ID_LENGTH_NBID = 1 

51 ID_LENGTH_NOID = 0 

52 ID_LENGTH_VID = 2 

53 ID_LENGTH_UID = 8 

54 

55 SCHEMA = [ 

56 { 

57 # void identifier with reached devices estimation 

58 "id_type" : Types.ENUM(IdType, allowedvalues=[IdType.NBID]), 

59 "nls_method": Types.ENUM(NlsMethod), 

60 "access_class": Types.BYTE(), 

61 "id" : Types.OBJECT(CT) 

62 }, 

63 { 

64 # void identifier without reached devices estimation 

65 "id_type": Types.ENUM(IdType, allowedvalues=[IdType.NOID]), 

66 "nls_method": Types.ENUM(NlsMethod), 

67 "access_class": Types.BYTE(), 

68 "id": Types.INTEGER([None]) 

69 }, 

70 { 

71 # virtual 

72 "id_type" : Types.ENUM(IdType, allowedvalues=[IdType.VID]), 

73 "nls_method": Types.ENUM(NlsMethod), 

74 "access_class": Types.BYTE(), 

75 "id" : Types.INTEGER(min=0, max=0xFFFF) 

76 }, 

77 { 

78 # unicast 

79 "id_type" : Types.ENUM(IdType, allowedvalues=[IdType.UID]), 

80 "nls_method": Types.ENUM(NlsMethod), 

81 "access_class": Types.BYTE(), 

82 "id" : Types.INTEGER(min=0, max=0xFFFFFFFFFFFFFFFF) 

83 } 

84 ] 

85 

86 

87# SCHEMA = [ 

88# { 

89# "id_type" : Types.INTEGER(IdType.ALL), 

90# "cl" : Types.BITS(4), 

91# "id_length" : Types.INTEGER([0, 2, 8]), 

92# "id" : Types.INTEGER(min=0, max=0xFFFFFFFFFFFFFFFF) 

93# } 

94# ] 

95 

96 def __init__(self, access_class=0, id_type=IdType.NOID, id=None, nls_method=NlsMethod.NONE): 

97 self.id_type = id_type 

98 self.access_class = access_class 

99 self.id = id 

100 self.nls_method = nls_method 

101 super(Addressee, self).__init__() 

102 

103 @property 

104 def id_length(self): 

105 return Addressee.length_for(id_type=self.id_type) 

106 

107 @classmethod 

108 def length_for(self, id_type): 

109 if id_type == IdType.NBID: return Addressee.ID_LENGTH_NBID 

110 if id_type == IdType.NOID: return Addressee.ID_LENGTH_NOID 

111 if id_type == IdType.VID: return Addressee.ID_LENGTH_VID 

112 if id_type == IdType.UID: return Addressee.ID_LENGTH_UID 

113 

114 @staticmethod 

115 def parse(s): 

116 _ = s.read("pad:2") 

117 id_type = IdType(s.read("uint:2")) 

118 nls_method = NlsMethod(s.read("uint:4")) 

119 cl = s.read("uint:8") 

120 l = Addressee.length_for(id_type) 

121 id = s.read("uint:"+str(l*8)) if l > 0 else None 

122 if id_type == IdType.NBID: 

123 id = CT().compress(value=id) 

124 

125 return Addressee(id_type=id_type, access_class=cl, id=id, nls_method=nls_method) 

126 

127 def __iter__(self): 

128 byte = 0 

129 # pad 2 << 7 << 6 

130 byte |= self.id_type.value << 4 

131 byte += self.nls_method.value 

132 yield byte 

133 yield self.access_class 

134 if self.id_length > 0: 

135 id_value = self.id 

136 if self.id_type == IdType.NBID: 

137 # self.id is a CT 

138 id_value = self.id.compressed_value() 

139 

140 id = bytearray(struct.pack(">Q", id_value))[8-self.id_length:] 

141 for byte in id: yield byte 

142 

143 def __str__(self): 

144 return "ac={}, id_type={}, id={}".format(self.access_class, self.id_type, self.id)