source: ReferenceDesigns/w3_802.11/python/wlan_exp/transport/cmds.py

Last change on this file was 6320, checked in by chunter, 5 years ago

1.8.0 release wlan-exp

File size: 13.1 KB
Line 
1# -*- coding: utf-8 -*-
2"""
3------------------------------------------------------------------------------
4Mango 802.11 Reference Design Experiments Framework
5    - Transport / Network / Basic Node Commands
6------------------------------------------------------------------------------
7License:   Copyright 2019 Mango Communications, Inc. All rights reserved.
8           Use and distribution subject to terms in LICENSE.txt
9------------------------------------------------------------------------------
10
11This module provides class definitions for transport, network, and basic node
12commands. 
13
14Functions (see below for more information):
15    GetType()
16    Identify()
17    GetNodeInfo()
18    SetupNetwork()
19    ResetNetwork()
20    Ping()   
21    TestPayloadSize()
22    AddNodeGrpId()
23    ClearNodeGrpId()
24
25Integer constants:
26    GRPID_NODE, GRPID_TRANS - Command Groups
27    GRP_NODE, GRP_TRANSPORT - Command Group Names
28
29Many other constants may be defined; please do not use these values when
30defining other sub-classes of CmdResp and BufferCmd.
31
32"""
33
34
35from . import message
36
37
38__all__ = ['NodeGetType', 'NodeIdentify', 'GetNodeInfo', 
39           'NodeSetupNetwork', 'NodeResetNetwork', 'NodeGetTemperature', 
40           'TransportPing', 'TestTransportMTU', 
41           'TransportAddNodeGroupId', 'TransportClearNodeGroupId']
42
43
44# Command Groups
45GROUP_NODE                                       = 0x00
46GROUP_TRANSPORT                                  = 0x10
47GROUP_USER                                       = 0x20
48
49
50# Command Group names
51GROUP_NAME_NODE                                  = 'node'
52GROUP_NAME_TRANSPORT                             = 'transport'
53GROUP_NAME_USER                                  = 'user'
54
55
56# Node Command IDs
57#     - The C counterparts are found in *_node.h
58
59CMD_PARAM_NODE_TYPE_RSVD                         = 0xFFFFFFFF
60
61CMDID_NODE_TYPE                                  = 0x000000
62CMDID_NODE_INFO                                  = 0x000001
63
64CMDID_NODE_IDENTIFY                              = 0x000002
65
66CMD_PARAM_NODE_IDENTIFY_ALL_NODES                = 0xFFFFFFFF
67
68CMDID_NODE_CONFIG_SETUP                          = 0x000003
69CMDID_NODE_CONFIG_RESET_MULTICAST                = 0x000004
70
71CMD_PARAM_NODE_NETWORK_RESET_ALL_NODES           = 0xFFFFFFFF
72
73CMDID_NODE_TEMPERATURE                           = 0x000005
74
75
76# Transport Command IDs
77#     - The C counterparts are found in *_transport.h
78CMDID_TRANSPORT_PING                             = 0x000001
79CMDID_TRANSPORT_SET_MAX_RESP_WORDS               = 0x000002
80CMDID_TRANSPORT_TEST_MTU                         = 0x000003
81CMDID_TRANSPORT_NODE_GROUP_ID_ADD                = 0x000100
82CMDID_TRANSPORT_NODE_GROUP_ID_CLEAR              = 0x000101
83
84
85# Local Constants
86_CMD_GROUP_NODE                                  = (GROUP_NODE << 24)
87_CMD_GROUP_TRANSPORT                             = (GROUP_TRANSPORT << 24)
88_CMD_GROUP_USER                                  = (GROUP_USER << 24)
89
90
91
92# -----------------------------------------------------------------------------
93# Node Commands
94# -----------------------------------------------------------------------------
95class NodeGetType(message.Cmd):
96    """Command to get the Type of the node"""
97    def __init__(self):
98        super(NodeGetType, self).__init__()
99        self.command = _CMD_GROUP_NODE + CMDID_NODE_TYPE
100   
101    def process_resp(self, resp):
102        if resp.resp_is_valid(num_args=3):
103            args = resp.get_args()
104           
105            # Command returns 3 arguments:
106            #  Platform ID
107            #  High software application ID
108            #  Low software application ID
109            # Return 3 IDs in tuple
110            return (args[0], args[1], args[2])
111
112        else:
113            raise Exception('ERROR: node returned invalid Node Type values: {}'.format(args))
114
115
116class NodeIdentify(message.Cmd):
117    """Command to blink the Node LEDs."""
118    def __init__(self, serial_number):
119        super(NodeIdentify, self).__init__()
120        self.command = _CMD_GROUP_NODE + CMDID_NODE_IDENTIFY
121
122        if (serial_number == CMD_PARAM_NODE_IDENTIFY_ALL_NODES):
123            (sn, sn_str) = (CMD_PARAM_NODE_IDENTIFY_ALL_NODES, "All nodes")
124            platform_id = CMD_PARAM_NODE_IDENTIFY_ALL_NODES
125        else:
126            from . import util
127            from .. import platform
128
129            (sn, sn_str) = util.get_serial_number(serial_number)
130            p = platform.lookup_platform_by_serial_num(serial_number)
131
132            if p is None:
133                raise Exception('ERROR: no registered platform matches serial number {0}')
134
135            platform_id = p.platform_id
136
137        self.id = sn_str
138        self.add_args(platform_id)
139        self.add_args(sn)
140             
141    def process_resp(self, resp):
142        print("Blinking LEDs of node: {0}".format(self.id))
143
144# End Class
145
146
147class GetNodeInfo(message.Cmd):
148    """Command to get the hardware parameters from the node."""
149    def __init__(self):
150        super(GetNodeInfo, self).__init__()
151        self.command = _CMD_GROUP_NODE + CMDID_NODE_INFO
152   
153    def process_resp(self, resp):
154        # NODE_INFO response format:
155        #  No arguments
156        #  payload[0:N-1]: Framework node info struct (same for all platforms)
157        #  payload[N:end]: Platform node info struct (platform-specific format)
158        from wlan_exp.info import NodeInfo
159        import wlan_exp.platform as platform
160
161        # Parse the framework node info from the first N bytes of the response payload
162        ni = NodeInfo()
163        N = ni.sizeof()
164        ni.deserialize(resp.resp_payload[0:N])
165       
166        # Pass rest of payload to platform-specific InfoStruct
167        #  The current code only constructs one platform-specific node info struct
168        #  Additional info structs could be constructed here and appended to the return tuple
169        p_id = ni['platform_id']
170        p_config = ni['platform_config']
171        p_ni = platform.get_platform_node_info_format(p_id, p_config)
172       
173        if p_ni is None:
174            # node object is out-of-scope, so rely on serial number from NODE_INFO in error msg
175            raise Exception('ERROR: no wlan_exp_platform found for platform_id {0} reported by node with s/n {1}'.format(p_id, ni['serial_number']))
176       
177        p_ni.deserialize(resp.resp_payload[N:])
178
179        return (ni, p_ni)
180
181# End Class
182
183
184class NodeSetupNetwork(message.Cmd):
185    """Command to perform initial network setup of a node."""
186    def __init__(self, node):
187        super(NodeSetupNetwork, self).__init__()
188       
189        self.command = _CMD_GROUP_NODE + CMDID_NODE_CONFIG_SETUP
190        self.add_args(node.platform_id)
191        self.add_args(node.serial_number)
192        self.add_args(node.node_id)
193        self.add_args(node.transport.ip_to_int(node.transport.ip_address))
194        self.add_args(node.transport.unicast_port)
195        self.add_args(node.transport.broadcast_port)
196   
197    def process_resp(self, resp):
198        pass
199
200# End Class
201
202class NodeResetNetwork(message.Cmd):
203    """Command to reset the network configuration of a node."""
204    def __init__(self, serial_number, output=False):
205        super(NodeResetNetwork, self).__init__()
206        self.command = _CMD_GROUP_NODE + CMDID_NODE_CONFIG_RESET_MULTICAST
207        self.output = output
208       
209        if (serial_number == CMD_PARAM_NODE_NETWORK_RESET_ALL_NODES):
210            (sn, sn_str) = (CMD_PARAM_NODE_NETWORK_RESET_ALL_NODES, "All nodes")
211            platform_id = CMD_PARAM_NODE_NETWORK_RESET_ALL_NODES
212        else:
213            from . import util
214            from .. import platform
215
216            (sn, sn_str) = util.get_serial_number(serial_number)
217            p = platform.lookup_platform_by_serial_num(serial_number)
218
219            if p is None:
220                raise Exception('ERROR: no registered platform matches serial number {0}')
221
222            platform_id = p.platform_id
223       
224        self.id = sn_str
225        self.add_args(platform_id)
226        self.add_args(sn)
227   
228    def process_resp(self, resp):
229        if (self.output):
230            print("Reset network config of node: {0}".format(self.id))
231
232# End Class
233
234
235class NodeGetTemperature(message.Cmd):
236    """Command to get the temperature of a node.
237   
238    The response must be converted to Celsius with the given formula:
239        ((double(temp)/65536.0)/0.00198421639) - 273.15
240        - http://www.xilinx.com/support/documentation/user_guides/ug370.pdf
241        - 16 bit value where 10 MSBs are an ADC value
242    """
243    def __init__(self):
244        super(NodeGetTemperature, self).__init__()
245        self.command = _CMD_GROUP_NODE + CMDID_NODE_TEMPERATURE
246   
247    def process_resp(self, resp):
248        if resp.resp_is_valid(num_args=3):
249            args = resp.get_args()
250            curr_temp = ((float(args[0])/65536.0)/0.00198421639) - 273.15
251            min_temp  = ((float(args[1])/65536.0)/0.00198421639) - 273.15
252            max_temp  = ((float(args[2])/65536.0)/0.00198421639) - 273.15
253            return (curr_temp, min_temp, max_temp)
254        else:
255            return (0, 0, 0)
256
257# End Class
258
259
260# -----------------------------------------------------------------------------
261# Transport Commands
262# -----------------------------------------------------------------------------
263class TransportPing(message.Cmd):
264    """Command to ping the node."""
265    def __init__(self):
266        super(TransportPing, self).__init__()
267        self.command = _CMD_GROUP_TRANSPORT + CMDID_TRANSPORT_PING
268   
269    def process_resp(self, resp):
270        pass
271
272# End Class
273
274class TransportSetMaxRespWords(message.Cmd):
275    """Sets the maximum number words the node may send in any response packet"""
276   
277    def __init__(self, max_words):
278        super(TransportSetMaxRespWords, self).__init__()
279        self.command = _CMD_GROUP_TRANSPORT + CMDID_TRANSPORT_SET_MAX_RESP_WORDS
280       
281        self.add_args(max_words)
282       
283    def process_resp(self, resp):
284        # Response has no arguments - always successful if node responds
285        return True
286   
287class TestTransportMTU(message.Cmd):
288    """Command to perform an uplink payload size test on a node."""
289    def __init__(self, req_mtu):
290        super(TestTransportMTU, self).__init__()
291        self.command = _CMD_GROUP_TRANSPORT + CMDID_TRANSPORT_TEST_MTU
292
293        # Remember the requested MTU for comparison to the length of the
294        #  payload in the response packet
295        self.req_mtu = req_mtu
296
297        # Single argument is the MTU of the packet the node should send in
298        #  its reponse to this command. "MTU" in this context refers to the
299        #  entire Ethernet payload (raw bytes-on-wire minus 14-byte header and
300        #  4-byte FCS). The the command argument below is computed from the
301        #  requested MTU less the size of the wlan_exp transport and response
302        #  headers that will precede the long payload in the response packet.
303
304        import wlan_exp.transport.util as util
305       
306        # Response packet includes one u32 argument after
307        #  the cmdRespHdr, before the bogus payload  (hence +4 below)
308        self.num_hdr_bytes = util.get_total_header_len() + 4
309       
310        self.add_args(int(req_mtu) - self.num_hdr_bytes)
311
312    def process_resp(self, resp):
313        args = resp.get_args()
314
315        if resp.resp_is_valid(num_args=1):
316            resp_req_len = int(args[0])
317
318            if resp_req_len == (self.req_mtu - self.num_hdr_bytes):
319                # Response packet header arg matched requested size
320
321                # Verify the response packet itself was the expected length
322                # The 'resp' argument is the command response payload including
323                #  args and bogus payload. Response has 1 argument (4 bytes)
324                #  followed by bogus payload to fill requested MTU
325                if (resp.length - 4) == resp_req_len:
326                    # Entire requested payload was received
327                    return True
328               
329            # Response packet was tuncated or malformed
330            return False
331
332        else:
333            raise Exception('ERROR: TestTransportMTU response arguments invalid; args={}'.format(args))
334       
335# End Class
336           
337class TransportAddNodeGroupId(message.Cmd):
338    """Command to add a Node Group ID to the node so that it can process
339    broadcast commands that are received from that node group."""
340    def __init__(self, group):
341        super(TransportAddNodeGroupId, self).__init__()
342        self.command = _CMD_GROUP_TRANSPORT + CMDID_TRANSPORT_NODE_GROUP_ID_ADD
343        self.add_args(group)
344   
345    def process_resp(self, resp):
346        pass
347
348# End Class
349
350
351class TransportClearNodeGroupId(message.Cmd):
352    """Command to clear a Node Group ID to the node so that it can ignore
353    broadcast commands that are received from that node group."""
354    def __init__(self, group):
355        super(TransportClearNodeGroupId, self).__init__()
356        self.command = _CMD_GROUP_TRANSPORT + CMDID_TRANSPORT_NODE_GROUP_ID_CLEAR
357        self.add_args(group)
358   
359    def process_resp(self, resp):
360        pass
361
362# End Class
363
364
Note: See TracBrowser for help on using the repository browser.