uhd/host/python/uhd/chdr.py
Samuel O'Brien 51bf7717e2 python: Add payload agnostic methods to CHDR API
In the c++ api, methods like chdr_packet#set_payload() and
chdr_packet#get_payload() are templated over the payload type
(payload_t). For methods like set_payload, they are overloaded by the
type of an argument, so in pybind we can just explicitly instaniate the
template for each payload_t and register it with pybind under the same
name. At runtime, pybind looks at the type of the argument and decides
which to call.

The problem arose with methods like get_payload, which are overloaded by
return type. In C++, the compiler can infer the template type by the
type of the target at the call site. In python, there is no way for the
pybind to determine which variant of get_payload to call, and it would
crash. Previously, the workaround for this was to declare
get_payload_ctrl, get_payload_mgmt, etc, but this was rather
anti-pythonic. This commit utilizes the fact that python methods don't
have a constrained return type to resolve this. Now, get_payload will
call a python method which looks at the chdr_packet#header#pkt_type
field to determine which variant of get_payload to call and returns that
type of payload_t.

Signed-off-by: Samuel O'Brien <sam.obrien@ni.com>
2020-07-16 09:59:25 -05:00

60 lines
2 KiB
Python

#
# Copyright 2020 Ettus Research, a National Instruments Brand
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
from . import libpyuhd as lib
ChdrPacket = lib.chdr.ChdrPacket
Endianness = lib.chdr.Endianness
ChdrWidth = lib.chdr.ChdrWidth
ChdrHeader = lib.chdr.ChdrHeader
CtrlPayload = lib.chdr.CtrlPayload
CtrlStatus = lib.chdr.CtrlStatus
PacketType = lib.chdr.PacketType
CtrlOpCode = lib.chdr.CtrlOpCode
MgmtPayload = lib.chdr.MgmtPayload
MgmtHop = lib.chdr.MgmtHop
MgmtOp = lib.chdr.MgmtOp
MgmtOpCode = lib.chdr.MgmtOpCode
MgmtOpSelDest = lib.chdr.MgmtOpSelDest
MgmtOpCfg = lib.chdr.MgmtOpCfg
MgmtOpNodeInfo = lib.chdr.MgmtOpNodeInfo
StrsPayload = lib.chdr.StrsPayload
StrsStatus = lib.chdr.StrsStatus
StrcPayload = lib.chdr.StrcPayload
StrcOpCode = lib.chdr.StrcOpCode
def __get_payload(self):
pkt_type = self.get_header().pkt_type
if pkt_type == PacketType.MGMT:
return self.get_payload_mgmt()
elif pkt_type == PacketType.CTRL:
return self.get_payload_ctrl()
elif pkt_type == PacketType.STRC:
return self.get_payload_strc()
elif pkt_type == PacketType.STRS:
return self.get_payload_strs()
elif pkt_type in {PacketType.DATA_NO_TS, PacketType.DATA_WITH_TS}:
raise RuntimeError("Cannot deserialize a Data Payload")
else:
raise RuntimeError("Invalid pkt_type in ChdrHeader")
ChdrPacket.get_payload = __get_payload
def __to_string_with_payload(self):
pkt_type = self.get_header().pkt_type
if pkt_type == PacketType.MGMT:
return self.to_string_with_payload_mgmt()
elif pkt_type == PacketType.CTRL:
return self.to_string_with_payload_ctrl()
elif pkt_type == PacketType.STRC:
return self.to_string_with_payload_strc()
elif pkt_type == PacketType.STRS:
return self.to_string_with_payload_strs()
elif pkt_type in {PacketType.DATA_NO_TS, PacketType.DATA_WITH_TS}:
return self.__str__()
else:
raise RuntimeError("Invalid pkt_type in ChdrHeader")
ChdrPacket.to_string_with_payload = __to_string_with_payload