I suspect the reason for the miscommunication above is that we are concurrently discussing two different issues: internal data modeling and UI design. To make sure that we are on the same page, I’d like to reiterate how I see things applied to the Global Register View. As far as the data model is concerned, I don’t think any special treatment is warranted. This means that the JSON representation we’ve discussed above should probably be used for transferring register-related over REST. The GUI, on the other hand, need not be generic, because we don’t want to burden the user with the overhead of dealing with unions and stuff; so here I suggest we tightly optimize the UI design specifically for registers. Practically this means that when a user wants to edit a register that contains a vector of (123, 456, -9) of type uavcan.primitive.array.Integer32
, they see a neat little edit widget containing only this (metadata like type, name, flags, etc. not shown here):
[123, 456, -9]
There is no point informing the user that the values shown above are actually contained in a field named value
, which is a part of a type which in turn is a field named integer32
contained inside the union type uavcan.register.Value
. It’s irrelevant if the user just wants to have some registers edited. On the other hand, if the user asked the GUI tool to invoke the service uavcan.register.Access
manually, they’d get the full blown value structure in the response, with unions and stuff.
Speaking about unions, this is how they will be modeled on the back end (that is, in pyuavcan); the example below is generated from uavcan.register.Value
:
#
# AUTOGENERATED, DO NOT EDIT.
#
# Generated at: 2019-04-16 17:01:28.164445 UTC
# Is deprecated: no
# Fixed port ID: None
# Full name: uavcan.register.Value
# Version: 0.1
#
import numpy as _np_
from typing import Optional as _Optional_, List as _List_, Union as _Union_
from pyuavcan.dsdl import CompositeObject as _CompositeObject_
from pydsdl import UnionType as _UnionType_
import uavcan.primitive
import uavcan.primitive.array
# noinspection PyUnresolvedReferences, PyPep8, PyPep8Naming, SpellCheckingInspection
class Value_0_1(_CompositeObject_):
def __init__(self, *,
empty: _Optional_[uavcan.primitive.Empty_1_0] = None,
string: _Optional_[uavcan.primitive.String_1_0] = None,
unstructured: _Optional_[uavcan.primitive.Unstructured_1_0] = None,
bit: _Optional_[uavcan.primitive.array.Bit_1_0] = None,
integer64: _Optional_[uavcan.primitive.array.Integer64_1_0] = None,
integer32: _Optional_[uavcan.primitive.array.Integer32_1_0] = None,
integer16: _Optional_[uavcan.primitive.array.Integer16_1_0] = None,
integer8: _Optional_[uavcan.primitive.array.Integer8_1_0] = None,
natural64: _Optional_[uavcan.primitive.array.Natural64_1_0] = None,
natural32: _Optional_[uavcan.primitive.array.Natural32_1_0] = None,
natural16: _Optional_[uavcan.primitive.array.Natural16_1_0] = None,
natural8: _Optional_[uavcan.primitive.array.Natural8_1_0] = None,
real64: _Optional_[uavcan.primitive.array.Real64_1_0] = None,
real32: _Optional_[uavcan.primitive.array.Real32_1_0] = None,
real16: _Optional_[uavcan.primitive.array.Real16_1_0] = None):
"""
uavcan.register.Value.0.1
If no parameters are provided, the first field will be default-initialized and selected.
If one parameter is provided, it will be used to initialize and select the field under the same name.
If more than one parameter is provided, a ValueError will be raised.
"""
self._empty: _Optional_[uavcan.primitive.Empty_1_0] = None
self._string: _Optional_[uavcan.primitive.String_1_0] = None
self._unstructured: _Optional_[uavcan.primitive.Unstructured_1_0] = None
self._bit: _Optional_[uavcan.primitive.array.Bit_1_0] = None
self._integer64: _Optional_[uavcan.primitive.array.Integer64_1_0] = None
self._integer32: _Optional_[uavcan.primitive.array.Integer32_1_0] = None
self._integer16: _Optional_[uavcan.primitive.array.Integer16_1_0] = None
self._integer8: _Optional_[uavcan.primitive.array.Integer8_1_0] = None
self._natural64: _Optional_[uavcan.primitive.array.Natural64_1_0] = None
self._natural32: _Optional_[uavcan.primitive.array.Natural32_1_0] = None
self._natural16: _Optional_[uavcan.primitive.array.Natural16_1_0] = None
self._natural8: _Optional_[uavcan.primitive.array.Natural8_1_0] = None
self._real64: _Optional_[uavcan.primitive.array.Real64_1_0] = None
self._real32: _Optional_[uavcan.primitive.array.Real32_1_0] = None
self._real16: _Optional_[uavcan.primitive.array.Real16_1_0] = None
_init_cnt_: int = 0
if empty is not None:
_init_cnt_ += 1
self.empty = empty
if string is not None:
_init_cnt_ += 1
self.string = string
if unstructured is not None:
_init_cnt_ += 1
self.unstructured = unstructured
if bit is not None:
_init_cnt_ += 1
self.bit = bit
if integer64 is not None:
_init_cnt_ += 1
self.integer64 = integer64
if integer32 is not None:
_init_cnt_ += 1
self.integer32 = integer32
if integer16 is not None:
_init_cnt_ += 1
self.integer16 = integer16
if integer8 is not None:
_init_cnt_ += 1
self.integer8 = integer8
if natural64 is not None:
_init_cnt_ += 1
self.natural64 = natural64
if natural32 is not None:
_init_cnt_ += 1
self.natural32 = natural32
if natural16 is not None:
_init_cnt_ += 1
self.natural16 = natural16
if natural8 is not None:
_init_cnt_ += 1
self.natural8 = natural8
if real64 is not None:
_init_cnt_ += 1
self.real64 = real64
if real32 is not None:
_init_cnt_ += 1
self.real32 = real32
if real16 is not None:
_init_cnt_ += 1
self.real16 = real16
if _init_cnt_ == 0:
self.empty = uavcan.primitive.Empty_1_0() # Default initialization
elif _init_cnt_ == 1:
pass # A value is already assigned, nothing to do
else:
raise ValueError(f'Union cannot hold values of more than one field')
@property
def empty(self) -> _Optional_[uavcan.primitive.Empty_1_0]:
"""uavcan.primitive.Empty.1.0 empty"""
return self._empty
@empty.setter
def empty(self, x: uavcan.primitive.Empty_1_0) -> None:
self._reset_()
if isinstance(x, uavcan.primitive.Empty_1_0):
self._empty = x
else:
raise ValueError(f'empty: expected uavcan.primitive.Empty_1_0 got {type(x).__name__}')
@property
def string(self) -> _Optional_[uavcan.primitive.String_1_0]:
"""uavcan.primitive.String.1.0 string"""
return self._string
@string.setter
def string(self, x: uavcan.primitive.String_1_0) -> None:
self._reset_()
if isinstance(x, uavcan.primitive.String_1_0):
self._string = x
else:
raise ValueError(f'string: expected uavcan.primitive.String_1_0 got {type(x).__name__}')
@property
def unstructured(self) -> _Optional_[uavcan.primitive.Unstructured_1_0]:
"""uavcan.primitive.Unstructured.1.0 unstructured"""
return self._unstructured
@unstructured.setter
def unstructured(self, x: uavcan.primitive.Unstructured_1_0) -> None:
self._reset_()
if isinstance(x, uavcan.primitive.Unstructured_1_0):
self._unstructured = x
else:
raise ValueError(f'unstructured: expected uavcan.primitive.Unstructured_1_0 got {type(x).__name__}')
@property
def bit(self) -> _Optional_[uavcan.primitive.array.Bit_1_0]:
"""uavcan.primitive.array.Bit.1.0 bit"""
return self._bit
@bit.setter
def bit(self, x: uavcan.primitive.array.Bit_1_0) -> None:
self._reset_()
if isinstance(x, uavcan.primitive.array.Bit_1_0):
self._bit = x
else:
raise ValueError(f'bit: expected uavcan.primitive.array.Bit_1_0 got {type(x).__name__}')
@property
def integer64(self) -> _Optional_[uavcan.primitive.array.Integer64_1_0]:
"""uavcan.primitive.array.Integer64.1.0 integer64"""
return self._integer64
@integer64.setter
def integer64(self, x: uavcan.primitive.array.Integer64_1_0) -> None:
self._reset_()
if isinstance(x, uavcan.primitive.array.Integer64_1_0):
self._integer64 = x
else:
raise ValueError(f'integer64: expected uavcan.primitive.array.Integer64_1_0 got {type(x).__name__}')
@property
def integer32(self) -> _Optional_[uavcan.primitive.array.Integer32_1_0]:
"""uavcan.primitive.array.Integer32.1.0 integer32"""
return self._integer32
@integer32.setter
def integer32(self, x: uavcan.primitive.array.Integer32_1_0) -> None:
self._reset_()
if isinstance(x, uavcan.primitive.array.Integer32_1_0):
self._integer32 = x
else:
raise ValueError(f'integer32: expected uavcan.primitive.array.Integer32_1_0 got {type(x).__name__}')
@property
def integer16(self) -> _Optional_[uavcan.primitive.array.Integer16_1_0]:
"""uavcan.primitive.array.Integer16.1.0 integer16"""
return self._integer16
@integer16.setter
def integer16(self, x: uavcan.primitive.array.Integer16_1_0) -> None:
self._reset_()
if isinstance(x, uavcan.primitive.array.Integer16_1_0):
self._integer16 = x
else:
raise ValueError(f'integer16: expected uavcan.primitive.array.Integer16_1_0 got {type(x).__name__}')
@property
def integer8(self) -> _Optional_[uavcan.primitive.array.Integer8_1_0]:
"""uavcan.primitive.array.Integer8.1.0 integer8"""
return self._integer8
@integer8.setter
def integer8(self, x: uavcan.primitive.array.Integer8_1_0) -> None:
self._reset_()
if isinstance(x, uavcan.primitive.array.Integer8_1_0):
self._integer8 = x
else:
raise ValueError(f'integer8: expected uavcan.primitive.array.Integer8_1_0 got {type(x).__name__}')
@property
def natural64(self) -> _Optional_[uavcan.primitive.array.Natural64_1_0]:
"""uavcan.primitive.array.Natural64.1.0 natural64"""
return self._natural64
@natural64.setter
def natural64(self, x: uavcan.primitive.array.Natural64_1_0) -> None:
self._reset_()
if isinstance(x, uavcan.primitive.array.Natural64_1_0):
self._natural64 = x
else:
raise ValueError(f'natural64: expected uavcan.primitive.array.Natural64_1_0 got {type(x).__name__}')
@property
def natural32(self) -> _Optional_[uavcan.primitive.array.Natural32_1_0]:
"""uavcan.primitive.array.Natural32.1.0 natural32"""
return self._natural32
@natural32.setter
def natural32(self, x: uavcan.primitive.array.Natural32_1_0) -> None:
self._reset_()
if isinstance(x, uavcan.primitive.array.Natural32_1_0):
self._natural32 = x
else:
raise ValueError(f'natural32: expected uavcan.primitive.array.Natural32_1_0 got {type(x).__name__}')
@property
def natural16(self) -> _Optional_[uavcan.primitive.array.Natural16_1_0]:
"""uavcan.primitive.array.Natural16.1.0 natural16"""
return self._natural16
@natural16.setter
def natural16(self, x: uavcan.primitive.array.Natural16_1_0) -> None:
self._reset_()
if isinstance(x, uavcan.primitive.array.Natural16_1_0):
self._natural16 = x
else:
raise ValueError(f'natural16: expected uavcan.primitive.array.Natural16_1_0 got {type(x).__name__}')
@property
def natural8(self) -> _Optional_[uavcan.primitive.array.Natural8_1_0]:
"""uavcan.primitive.array.Natural8.1.0 natural8"""
return self._natural8
@natural8.setter
def natural8(self, x: uavcan.primitive.array.Natural8_1_0) -> None:
self._reset_()
if isinstance(x, uavcan.primitive.array.Natural8_1_0):
self._natural8 = x
else:
raise ValueError(f'natural8: expected uavcan.primitive.array.Natural8_1_0 got {type(x).__name__}')
@property
def real64(self) -> _Optional_[uavcan.primitive.array.Real64_1_0]:
"""uavcan.primitive.array.Real64.1.0 real64"""
return self._real64
@real64.setter
def real64(self, x: uavcan.primitive.array.Real64_1_0) -> None:
self._reset_()
if isinstance(x, uavcan.primitive.array.Real64_1_0):
self._real64 = x
else:
raise ValueError(f'real64: expected uavcan.primitive.array.Real64_1_0 got {type(x).__name__}')
@property
def real32(self) -> _Optional_[uavcan.primitive.array.Real32_1_0]:
"""uavcan.primitive.array.Real32.1.0 real32"""
return self._real32
@real32.setter
def real32(self, x: uavcan.primitive.array.Real32_1_0) -> None:
self._reset_()
if isinstance(x, uavcan.primitive.array.Real32_1_0):
self._real32 = x
else:
raise ValueError(f'real32: expected uavcan.primitive.array.Real32_1_0 got {type(x).__name__}')
@property
def real16(self) -> _Optional_[uavcan.primitive.array.Real16_1_0]:
"""uavcan.primitive.array.Real16.1.0 real16"""
return self._real16
@real16.setter
def real16(self, x: uavcan.primitive.array.Real16_1_0) -> None:
self._reset_()
if isinstance(x, uavcan.primitive.array.Real16_1_0):
self._real16 = x
else:
raise ValueError(f'real16: expected uavcan.primitive.array.Real16_1_0 got {type(x).__name__}')
def _reset_(self) -> None:
self._empty = None
self._string = None
self._unstructured = None
self._bit = None
self._integer64 = None
self._integer32 = None
self._integer16 = None
self._integer8 = None
self._natural64 = None
self._natural32 = None
self._natural16 = None
self._natural8 = None
self._real64 = None
self._real32 = None
self._real16 = None
_TYPE_: _UnionType_ = _CompositeObject_._restore_constant_(
'ABzY8XbQGm0{`upTW`}y6vv%~Y!g~`VJR1J(e@3{3dfF<)P3uMsI<ybA=nnA6<Cvah^IKV8IPl;2yJ-)3CVBFe$V{|aD0hV<Jd~8'
'CYuNR5RGOsGw1(1XU_5X@a(_;tP0`duR25B)lE@zF(t?(2dHCW?pJp#Vq1R=9n3%TyYKlse#b9s7V5*;We*Ly$Py{;5tm^q?jqBJ'
'{)#rh)P-r>5d5Xxxc!;8g?8y9f6x784KYSZ$79&#FZdn!TX~CMQy=efPSX)X8Vfdt;qy-!^}5WXIAw}a_OHZ7IF$4WBLgfx>^p48'
'jU}VnF13YVLu2Jdu&It6io1wmoqzIw(q55$tZR-<nMQQJ?O)Vf+oN3!118oS#0>7gsTp=3*Bms!W-Z#O<_x38y|DM*YeEUOUfW53'
'&G9-W>1u$*GlSj6Qru*Xk+rqZT2U4yF&g4t2UL}DC<59)$4Y-ORuj!vGnxSpv3eQNM`jED)m;Rh1+V^ztsXOerxXp-jy<no6Zf&j'
'67H9FESK~wtp8y#+`}~e|7ER1m}Z8{@pc8A)<rJU`nDcUzVdivUocI40Ar7Wp&$}I@F$?oufhxmbqQ!~e~FY2!XWZG$hh&zxVdfI'
'^6AW-5aG*s;YT;Zn&XCB88-l}QJm^U&iE~EiG~!nly=2v7%J?vkq=^j<{*v=$lzG<j>^k{ay<hD1%W2sCoDrGIQT1%k*)*e^!X11'
'wz6vz{b<AirLr4XBBXa8;}rbm`?hUjlulVNu{6T_=)a{jU!3suX3jTcQ3DnkxM$!f<uP5$VHzLGR$~I$XURH$kJ$YXurprfqPzGs'
'_o&0{%_Kh8^7y@-6Td`vhGLZ@NKVF5sZYnURLJseLTxRfwz(kGlzJ{T5Pvdia%;M5H|BC7;c}Rl?dHryZsl?Tc{yBuE#{&g7t0hy'
';9$O3)C`ph8Hqb)uxul!9LPMKbR{ifVoDTdL&-|SpN!h+BqnJQ6H}rvm)h|YQ@rN1iAh?-#FS{r<#PPQ6tAhy;O+EazE~zCCTk>a'
'>KFD1$`gEASxNA#Tc(ZJ#Fr<yAN5hsBFxi+oAoP-x(sf{F5H;6;x^2A-Yf}%yuPvC+E8Srp|<LZ++3GbxhZ{r3LhR_DvJui{+wbo'
'im2>`lH#HgP!yl1lK=NELu{o>z}_|J+PeWi{%xfp)z!MvXtflzSy$EOhAP*KIBzZj=LvNq<eXnLia1YMG14S2d_%I_YBr_DnA73^'
'ccUM3novhVPGJ!lyUv-BNu#fXweTw;7$T2N5x)Y%#fpuJ6aWA'
)
assert isinstance(_TYPE_, _UnionType_)
The actual internal implementation may be changed, but the API is unlikely to.