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
« 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
21from d7a.support.schema import Validatable, Types
24class ChannelCoding(Enum):
25 PN9 = 0x00
26 RFU = 0x01
27 FEC_PN9 = 0x02
28 CW = 0x03
30 def to_char(self):
31 return self.name[:1]
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
39 raise NotImplementedError
41class ChannelClass(Enum):
42 LO_RATE = 0x00
43 LORA = 0x01 # TODO not part of spec
44 NORMAL_RATE = 0x02
45 HI_RATE = 0x03
47 def to_char(self):
48 c = self.name[:1]
49 if self.value == ChannelClass.LORA:
50 c = "R"
52 return c
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
61 raise NotImplementedError
63class ChannelBand(Enum):
64 NOT_IMPL = 0x00
65 BAND_433 = 0x02
66 BAND_868 = 0x03
67 BAND_915 = 0x04
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
75 raise NotImplementedError
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 }]
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__()
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
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)
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()
110 return "{0}{1}{2}".format(band, cl, coding)
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)
119 def __eq__(self, other):
120 if type(other) is type(self):
121 return self.__dict__ == other.__dict__
122 return False
124 def __ne__(self, other):
125 if isinstance(other, self.__class__):
126 return not self.__eq__(other)
127 return False