Coverage for d7a/phy/channel_header.py: 84%

81 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# 

19from enum import Enum 

20 

21from d7a.support.schema import Validatable, Types 

22 

23 

24class ChannelCoding(Enum): 

25 PN9 = 0x00 

26 RFU = 0x01 

27 FEC_PN9 = 0x02 

28 CW = 0x03 

29 

30 def to_char(self): 

31 return self.name[:1] 

32 

33 @staticmethod 

34 def from_char(c): 

35 if c == "P": return ChannelCoding.PN9 

36 if c == "F": return ChannelCoding.FEC_PN9 

37 if c == "C": return ChannelCoding.CW 

38 

39 raise NotImplementedError 

40 

41class ChannelClass(Enum): 

42 LO_RATE = 0x00 

43 LORA = 0x01 # TODO not part of spec 

44 NORMAL_RATE = 0x02 

45 HI_RATE = 0x03 

46 

47 def to_char(self): 

48 c = self.name[:1] 

49 if self.value == ChannelClass.LORA: 

50 c = "R" 

51 

52 return c 

53 

54 @staticmethod 

55 def from_char(c): 

56 if c == "L": return ChannelClass.LO_RATE 

57 if c == "N": return ChannelClass.NORMAL_RATE 

58 if c == "H": return ChannelClass.HI_RATE 

59 if c == "R": return ChannelClass.LORA 

60 

61 raise NotImplementedError 

62 

63class ChannelBand(Enum): 

64 NOT_IMPL = 0x00 

65 BAND_433 = 0x02 

66 BAND_868 = 0x03 

67 BAND_915 = 0x04 

68 

69 @staticmethod 

70 def from_string(s): 

71 if s == "433": return ChannelBand.BAND_433 

72 if s == "868": return ChannelBand.BAND_868 

73 if s == "915": return ChannelBand.BAND_915 

74 

75 raise NotImplementedError 

76 

77class ChannelHeader(Validatable): 

78 # TODO 

79 SCHEMA = [{ 

80 "channel_coding": Types.ENUM(ChannelCoding), 

81 "channel_class": Types.ENUM(ChannelClass), 

82 "channel_band": Types.ENUM(ChannelBand) 

83 }] 

84 

85 def __init__(self, channel_coding, channel_class, channel_band): 

86 self.channel_coding = channel_coding 

87 self.channel_class = channel_class 

88 self.channel_band = channel_band 

89 super(ChannelHeader, self).__init__() 

90 

91 def __iter__(self): 

92 byte = self.channel_band.value << 4 

93 byte += self.channel_class.value << 2 

94 byte += self.channel_coding.value 

95 yield byte 

96 

97 @staticmethod 

98 def parse(s): 

99 s.read("uint:1") # RFU 

100 channel_band = ChannelBand(s.read("uint:3")) 

101 channel_class = ChannelClass(s.read("uint:2")) 

102 channel_coding = ChannelCoding(s.read("uint:2")) 

103 return ChannelHeader(channel_coding=channel_coding, channel_class=channel_class, channel_band=channel_band) 

104 

105 def __str__(self): 

106 band = self.channel_band.name.lstrip("BAND_") 

107 cl = self.channel_class.to_char() 

108 coding = self.channel_coding.to_char() 

109 

110 return "{0}{1}{2}".format(band, cl, coding) 

111 

112 @staticmethod 

113 def from_string(s): 

114 channel_band = ChannelBand.from_string(s[0:3]) 

115 channel_class = ChannelClass.from_char(s[3]) 

116 channel_coding = ChannelCoding.from_char(s[4]) 

117 return ChannelHeader(channel_band=channel_band, channel_class=channel_class, channel_coding=channel_coding) 

118 

119 def __eq__(self, other): 

120 if type(other) is type(self): 

121 return self.__dict__ == other.__dict__ 

122 return False 

123 

124 def __ne__(self, other): 

125 if isinstance(other, self.__class__): 

126 return not self.__eq__(other) 

127 return False