Coverage for d7a/d7atp/frame.py: 67%
70 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#
20from d7a.support.schema import Validatable, Types
21from d7a.d7atp.control import Control
22from d7a.types.ct import CT
23from d7a.alp.command import Command
24from d7a.alp.parser import Parser as AlpParser
26class Frame(Validatable):
28 SCHEMA = [{
29 "control": Types.OBJECT(Control),
30 "dialog_id": Types.INTEGER(min=0, max=255),
31 "transaction_id": Types.INTEGER(min=0, max=255),
32 "agc_rx_level_i": Types.INTEGER(min=0, max=31),
33 "tl": Types.OBJECT(CT, nullable=True),
34 "te": Types.OBJECT(CT, nullable=True),
35 "tc": Types.OBJECT(CT, nullable=True),
36 "ack_template": Types.OBJECT(nullable=True), # TODO
37 "alp_command": Types.OBJECT(Command)
38 }]
40 def __init__(self, control, dialog_id, transaction_id, alp_command, agc_rx_level_i=10, tl=None, te=None, tc=None, ack_template=None):
41 if agc_rx_level_i == None:
42 agc_rx_level_i = 10
44 self.control = control
45 self.dialog_id = dialog_id
46 self.transaction_id = transaction_id
47 self.agc_rx_level_i = agc_rx_level_i
48 self.tl = tl
49 self.te = te
50 self.tc = tc
51 self.ack_template = ack_template
52 self.alp_command = alp_command
53 super(Frame, self).__init__()
55 @staticmethod
56 def parse(bitstream, payload_length):
57 control = Control.parse(bitstream)
58 payload_length = payload_length - 1 # subtract control byte
60 dialog_id = bitstream.read("uint:8")
61 payload_length = payload_length - 1
63 transaction_id = bitstream.read("uint:8")
64 payload_length = payload_length - 1
66 target_rx_level_i = None
67 if control.has_agc:
68 target_rx_level_i = bitstream.read("uint:8")
69 payload_length -= 1
71 tl = None
72 if control.has_tl:
73 tl = CT.parse(bitstream)
74 payload_length -= 1
76 te = None
77 if control.has_te:
78 te = CT.parse(bitstream)
79 payload_length -= 1
81 tc = None
82 # TODO currently we have no way to know if Tc is present or not
83 # Tc is present when control.is_ack_requested AND when we are requester,
84 # while responders copy this flag but do NOT provide a Tc.
85 # When parsing single frames without knowledge of dialogs we cannot determine this.
86 # We use control.is_dialog_start for now but this will break when we start supporting multiple transactions per dialog
87 if control.is_ack_requested and control.is_dialog_start:
88 tc = CT.parse(bitstream)
89 payload_length -= 1
91 ack_template = None
92 if control.is_ack_not_void:
93 transaction_id_start = bitstream.read("uint:8")
94 payload_length = payload_length - 1
95 transaction_id_stop = bitstream.read("uint:8")
96 payload_length = payload_length - 1
97 assert transaction_id_start == transaction_id, "Other case not implemented yet"
98 assert transaction_id_stop == transaction_id, "Other case not implemented yet"
99 # TODO ack bitmap (for when transaction_id_start != transaction_id)
100 ack_template = [ transaction_id_start, transaction_id_stop ]
102 assert control.is_ack_record_requested == False, "Not implemented yet"
103 assert control.is_ack_not_void == False, "Not implemented yet"
105 alp_command = AlpParser().parse(bitstream, payload_length)
107 return Frame(
108 control=control,
109 dialog_id=dialog_id,
110 transaction_id=transaction_id,
111 agc_rx_level_i=target_rx_level_i,
112 tl=tl,
113 te=te,
114 tc=tc,
115 ack_template=ack_template,
116 alp_command=alp_command
117 )
119 def __iter__(self):
120 for byte in self.control: yield byte
121 yield self.dialog_id
122 yield self.transaction_id
123 if self.control.has_agc:
124 yield self.agc_rx_level_i
126 if self.control.has_tl:
127 yield self.tl
129 if self.control.has_te:
130 yield self.te
132 if self.control.is_ack_not_void:
133 for byte in self.ack_template: yield byte
135 for byte in self.alp_command: yield byte