Esempio n. 1
0
    def set_data(self, parsed_data):
        """
        Set GPS data dictionary from UBX sentences.
        """

        try:
            if parsed_data.identity == "NAV-PVT":
                self.gpsdata[
                    "date"] = f"{parsed_data.day:02}/{parsed_data.month:02}/{parsed_data.year}"
                self.gpsdata[
                    "time"] = f"{parsed_data.hour:02}:{parsed_data.min:02}:{parsed_data.second:02}"
                self.gpsdata["latitude"] = parsed_data.lat
                self.gpsdata["longitude"] = parsed_data.lon
                self.gpsdata["elevation"] = parsed_data.height / 1000
                self.gpsdata["speed"] = parsed_data.gSpeed
                self.gpsdata["track"] = parsed_data.headVeh
                self.gpsdata["fix"] = parsed_data.fixType
                self.gpsdata["pDOP"] = parsed_data.pDOP
            if parsed_data.identity == "NAV-POSLLH":
                self.gpsdata["latitude"] = parsed_data.lat
                self.gpsdata["longitude"] = parsed_data.lon
                self.gpsdata["elevation"] = parsed_data.height / 1000
            if parsed_data.identity == "NAV-DOP":
                self.gpsdata["pdop"] = parsed_data.pDOP
                self.gpsdata["hdop"] = parsed_data.hDOP
                self.gpsdata["vdop"] = parsed_data.vDOP
            if parsed_data.identity == "NAV-SAT":
                self.gpsdata["siv"] = parsed_data.numSvs

        except ube.UBXMessageError() as err:
            print(err)
            self._stopevent.set()
Esempio n. 2
0
    def _do_attributes(self, **kwargs):
        """Populate UBXMessage from named attribute keywords.
        Where a named attribute is absent, set to a nominal value (zeros or blanks).

        :param **kwargs:

        """

        offset = 0

        try:

            if len(kwargs) == 0:  # if no kwargs, assume null payload
                self._payload = None
            else:
                pdict = self._get_dict()  # get appropriate payload dict
                for key in pdict.keys():  # set each attribute in dict
                    (offset,
                     att) = self._set_attribute(offset, pdict, key, **kwargs)
            self._do_len_checksum()

        except (AttributeError, OverflowError, struct.error, TypeError,
                ValueError) as err:
            raise ube.UBXTypeError((f"Incorrect type for attribute '{key}' "
                                    f"in {self.mode2str(self._mode)} message "
                                    f"class {self.identity}")) from err
        except ube.UBXTypeError as err:
            raise ube.UBXTypeError((f"Undefined attribute type '{att}' "
                                    f"in {self.mode2str(self._mode)} message "
                                    f"class {self.identity}")) from err
        except KeyError as err:
            raise ube.UBXMessageError(
                (f"Undefined {self.mode2str(self._mode)} "
                 f"message class={self._ubxClass}, "
                 f"id={self._ubxID}")) from err
Esempio n. 3
0
    def _get_esfmeas_version(self, **kwargs) -> dict:
        """
        Select appropriate payload definition version for
        ESF-MEAS message by checking bit 3 (calibTtagValid)
        in the'flags' attribute.

        :param **kwargs: payload key value pairs
        :return dictionary representing payload definition
        :rtype dict
        :raise UBXMessageError
        """
        # pylint: disable=no-self-use

        if "flags" in kwargs:
            flags = kwargs["flags"]
        elif "payload" in kwargs:
            flags = kwargs["payload"][4:6]
        else:
            raise ube.UBXMessageError(
                "ESF-MEAS message definitions must include flags or payload keyword"
            )
        flags = int(flags.hex(), 16)  # int
        calibTtagValid = flags >> 3 & 1  # test bit 3
        if calibTtagValid:
            pdict = ubg.UBX_PAYLOADS_GET["ESF-MEAS-CT"]
        else:
            pdict = ubg.UBX_PAYLOADS_GET["ESF-MEAS"]
        return pdict
Esempio n. 4
0
    def config_poll(layer: int, position: int, keys: list) -> object:
        """
        Construct CFG-VALGET message from an array of
        configuration database keys, which can be in int (keyID)
        or str (keyname) format.

        :param int layer: memory layer (0=RAM, 1=BBR, 2=Flash, 7 = Default)
        :param int position: number of keys to skip before returning result
        :param list keys: array of up to 64 keys as int (keyID) or str (keyname)
        :return: UBXMessage CFG-VALGET
        :rtype: UBXMessage
        :raises: UBXMessageError

        """

        num = len(keys)
        if num > 64:
            raise ube.UBXMessageError(
                f"Number of configuration keys {num} exceeds maximum of 64"
            )

        version = UBXMessage.val2bytes(0, ubt.U1)
        layer = UBXMessage.val2bytes(layer, ubt.U1)
        position = UBXMessage.val2bytes(position, ubt.U2)
        payload = version + layer + position
        lis = b""

        for key in keys:
            if isinstance(key, str):  # if keyname as a string
                (key, _) = UBXMessage.cfgname2key(key)  # lookup keyID
            keyb = UBXMessage.val2bytes(key, ubt.U4)
            lis = lis + keyb

        return UBXMessage("CFG", "CFG-VALGET", ubt.POLL, payload=payload + lis)
Esempio n. 5
0
    def config_del(layers: int, transaction: int, keys: list) -> object:
        """
        Construct CFG-VALDEL message from an array of
        configuration database keys, which can be in int (keyID)
        or str (keyname) format.

        :param int layers: memory layer(s) (2=BBR, 4=Flash)
        :param int transaction: 0=no txn, 1=start txn, 2=continue txn, 3=apply txn
        :param list keys: array of up to 64 keys as int (keyID) or string (keyname)
        :return: UBXMessage CFG-VALDEL
        :rtype: UBXMessage
        :raises: UBXMessageError

        """

        num = len(keys)
        if num > 64:
            raise ube.UBXMessageError(
                f"Number of configuration keys {num} exceeds maximum of 64"
            )

        version = UBXMessage.val2bytes(0 if transaction == 0 else 1, ubt.U1)
        layers = UBXMessage.val2bytes(layers, ubt.U1)
        transaction = UBXMessage.val2bytes(transaction, ubt.U1)
        payload = version + layers + transaction + b"\x00"
        lis = b""

        for key in keys:
            if isinstance(key, str):  # if keyname as a string
                (key, _) = UBXMessage.cfgname2key(key)  # lookup keyID
            keyb = UBXMessage.val2bytes(key, ubt.U4)
            lis = lis + keyb

        return UBXMessage("CFG", "CFG-VALDEL", ubt.SET, payload=payload + lis)
Esempio n. 6
0
    def _get_timvcocal_version(self, **kwargs) -> dict:
        """
        Select appropriate TIM-VCOCAL SET payload definition by checking
        the payload length.

        :param kwargs: optional payload key/value pairs
        :return: dictionary representing payload definition
        :rtype: dict
        :raises: UBXMessageError

        """
        # pylint: disable=no-self-use

        lpd = 1
        typ = 0
        if "type" in kwargs:
            typ = kwargs["type"]
        elif "payload" in kwargs:
            lpd = len(kwargs["payload"])
        else:
            raise ube.UBXMessageError(
                "TIM-VCOCAL SET message definitions must include type or payload keyword"
            )
        if lpd == 1 and typ == 0:
            pdict = ubs.UBX_PAYLOADS_SET["TIM-VCOCAL-V0"]  # stop cal
        else:
            pdict = ubs.UBX_PAYLOADS_SET["TIM-VCOCAL"]  # cal
        return pdict
Esempio n. 7
0
    def _set_cfgval_attributes(self, offset: int, **kwargs):
        """
        Parse CFG-VALGET payload to set of configuration
        key value pairs.

        :param int offset: payload offset
        :param **kwargs:  payload key value pairs
        :raise UBXMessageError
        """

        KEYLEN = 4
        if "payload" in kwargs:
            self._payload = kwargs["payload"]
        else:
            raise ube.UBXMessageError(
                "CFG-VALGET message definitions must include payload keyword")
        cfglen = len(self._payload[offset:])

        i = 0
        while offset < cfglen:
            if i == KEYLEN:
                key = int.from_bytes(self._payload[offset:offset + KEYLEN],
                                     "little",
                                     signed=False)
                (keyname, att) = self.cfgkey2name(key)
                atts = attsiz(att)
                valb = self._payload[offset + KEYLEN:offset + KEYLEN + atts]
                val = self.bytes2val(valb, att)
                setattr(self, keyname, val)
                i = 0
                offset += KEYLEN + atts

            else:
                i += 1
Esempio n. 8
0
    def _get_rxmpmreq_version(self, **kwargs) -> dict:
        """
        Select appropriate RXM-PMREQ payload definition by checking
        the 'version' keyword or payload length.

        :param kwargs: optional payload key/value pairs
        :return: dictionary representing payload definition
        :rtype: dict
        :raises: UBXMessageError

        """
        # pylint: disable=no-self-use

        lpd = 0
        if "version" in kwargs:  # assume longer version
            lpd = 16
        elif "payload" in kwargs:
            lpd = len(kwargs["payload"])
        else:
            raise ube.UBXMessageError(
                "RXM-PMREQ message definitions must include version or payload keyword"
            )
        if lpd == 16:
            pdict = ubs.UBX_PAYLOADS_SET["RXM-PMREQ"]  # long
        else:
            pdict = ubs.UBX_PAYLOADS_SET["RXM-PMREQ-S"]  # short
        return pdict
Esempio n. 9
0
    def _get_rxmrlm_version(self, **kwargs) -> dict:
        """
        Select appropriate RXM-PMP payload definition by checking
        value of 'type' attribute (2nd byte of payload).

        :param kwargs: optional payload key/value pairs
        :return: dictionary representing payload definition
        :rtype: dict
        :raises: UBXMessageError

        """
        # pylint: disable=no-self-use

        if "type" in kwargs:
            typ = self.val2bytes(kwargs["type"], ubt.U1)
        elif "payload" in kwargs:
            typ = kwargs["payload"][1:2]
        else:
            raise ube.UBXMessageError(
                "RXM-RLM message definitions must include type or payload keyword"
            )
        if typ == b"\x01":
            pdict = ubg.UBX_PAYLOADS_GET["RXM-RLM-S"]  # short
        else:
            pdict = ubg.UBX_PAYLOADS_GET["RXM-RLM-L"]  # long
        return pdict
Esempio n. 10
0
    def _get_rxmpmp_version(self, **kwargs) -> dict:
        """
        Select appropriate RXM-PMP payload definition by checking
        value of 'version' attribute (1st byte of payload).

        :param kwargs: optional payload key/value pairs
        :return: dictionary representing payload definition
        :rtype: dict
        :raises: UBXMessageError

        """
        # pylint: disable=no-self-use

        if "version" in kwargs:
            ver = self.val2bytes(kwargs["version"], ubt.U1)
        elif "payload" in kwargs:
            ver = kwargs["payload"][0:1]
        else:
            raise ube.UBXMessageError(
                "RXM-PMP message definitions must include version or payload keyword"
            )
        if ver == b"\x00":
            pdict = ubg.UBX_PAYLOADS_GET["RXM-PMP-V0"]
        else:
            pdict = ubg.UBX_PAYLOADS_GET["RXM-PMP-V1"]
        return pdict
Esempio n. 11
0
    def _get_cfgnmea_version(self, **kwargs) -> dict:
        """
        Select appropriate payload definition version for older
        generations of CFG-NMEA message by checking payload length.

        :param kwargs: optional payload key/value pairs
        :return: dictionary representing payload definition
        :rtype: dict
        :raises: UBXMessageError

        """
        # pylint: disable=no-self-use

        if "payload" in kwargs:
            lpd = len(kwargs["payload"])
        else:
            raise ube.UBXMessageError(
                "CFG-NMEA message definitions must include payload keyword"
            )
        if lpd == 4:
            pdict = ubg.UBX_PAYLOADS_GET["CFG-NMEAvX"]
        elif lpd == 12:
            pdict = ubg.UBX_PAYLOADS_GET["CFG-NMEAv0"]
        else:
            pdict = ubg.UBX_PAYLOADS_GET["CFG-NMEA"]
        return pdict
Esempio n. 12
0
    def _get_mga_version(self, mode: int, **kwargs) -> dict:
        """
        Select appropriate MGA payload definition by checking
        value of 'type' attribute (1st byte of payload).

        :param str mode: mode (0=GET, 1=SET, 2=POLL)
        :param kwargs: optional payload key/value pairs
        :return: dictionary representing payload definition
        :rtype: dict
        :raises: UBXMessageError

        """

        if "type" in kwargs:
            typ = self.val2bytes(kwargs["type"], ubt.U1)
        elif "payload" in kwargs:
            typ = kwargs["payload"][0:1]
        else:
            raise ube.UBXMessageError(
                "MGA message definitions must include type or payload keyword"
            )
        identity = ubt.UBX_MSGIDS[self._ubxClass + self._ubxID + typ]
        if mode == ubt.SET:
            pdict = ubs.UBX_PAYLOADS_SET[identity]
        else:
            pdict = ubg.UBX_PAYLOADS_GET[identity]
        return pdict
Esempio n. 13
0
    def _get_esfmeas_version(self, **kwargs) -> dict:
        """
        Select appropriate payload definition version for
        ESF-MEAS message by checking bit 3 (calibTtagValid)
        in the'flags' attribute.

        :param kwargs: optional payload key/value pairs
        :return: dictionary representing payload definition
        :rtype: dict
        :raises: UBXMessageError

        """
        # pylint: disable=no-self-use

        if "flags" in kwargs:
            flags = kwargs["flags"]
        elif "payload" in kwargs:
            flags = kwargs["payload"][4:6]
        else:
            raise ube.UBXMessageError(
                "ESF-MEAS message definitions must include flags or payload keyword"
            )
        calibTtagValid = get_bits(flags, 0b00001000)  # get bit 3 in flags
        if calibTtagValid:
            pdict = ubg.UBX_PAYLOADS_GET["ESF-MEAS-CT"]
        else:
            pdict = ubg.UBX_PAYLOADS_GET["ESF-MEAS"]
        return pdict
Esempio n. 14
0
    def __setattr__(self, name, value):
        """
        Override setattr to make object immutable after instantiation
        """

        if self._immutable:
            raise ube.UBXMessageError(
                f"Object is immutable. Updates to {name} not permitted after initialisation."
            )

        super().__setattr__(name, value)
Esempio n. 15
0
    def key_from_val(dictionary: dict, value) -> str:
        """Helper method - get dictionary key corresponding to (unique) value.

        :param dictionary: dict:
        :param value:
        :return str:

        """

        val = None
        for key, val in dictionary.items():
            if val == value:
                return key
        raise ube.UBXMessageError(f"Undefined message type {value}")
Esempio n. 16
0
    def cfgname2key(name: str) -> tuple:
        """
        Return hexadecimal key and data type for given
        configuration database key name.

        :param str name: config database key name as string
        :return tuple of (key: int, type: str)
        :rtype tuple: (int, str)
        :raise UBXMessageError
        """
        try:
            return ubcdb.UBX_CONFIG_DATABASE[name]
        except KeyError as err:
            raise ube.UBXMessageError(
                f"Undefined configuration database key {name}") from err
Esempio n. 17
0
    def __init__(self, ubxClass, ubxID, msgmode: int, **kwargs):
        """Constructor.

        If no keyword parms are passed, the payload is taken to be empty.

        If 'payload' is passed as a keyword parm, this is taken to contain the complete
        payload as a sequence of bytes; any other keyword parms are ignored.

        Otherwise, any named attributes will be assigned the value given, all others will
        be assigned a nominal value according to type.

        :param object msgClass: message class as str, int or byte
        :param object msgID: message ID as str, int or byte
        :param int msgmode: message mode (0=GET, 1=SET, 2=POLL)
        :param kwargs: optional payload key/value pairs
        :raises: UBXMessageError

        """

        # object is mutable during initialisation only
        super().__setattr__("_immutable", False)
        self._mode = msgmode
        self._payload = b""
        self._length = b""
        self._checksum = b""

        self._parsebf = kwargs.get("parsebitfield", True)  # parsing bitfields Y/N?
        self._decodenavdata = kwargs.get(
            "decodenavdata", True
        )  # decode RXM-SFRBX nav data Y/N? TODO make default False in final

        if msgmode not in (0, 1, 2):
            raise ube.UBXMessageError(f"Invalid msgmode {msgmode} - must be 0, 1 or 2.")

        # accommodate different formats of msgClass and msgID
        if isinstance(ubxClass, str) and isinstance(
            ubxID, str
        ):  # string e.g. 'CFG', 'CFG-PRT'
            (self._ubxClass, self._ubxID) = UBXMessage.msgstr2bytes(ubxClass, ubxID)
        elif isinstance(ubxClass, int) and isinstance(ubxID, int):  # int e.g. 6, 1
            (self._ubxClass, self._ubxID) = UBXMessage.msgclass2bytes(ubxClass, ubxID)
        else:  # bytes e.g. b'\x06', b'\x01'
            self._ubxClass = ubxClass
            self._ubxID = ubxID

        self._do_attributes(**kwargs)

        self._immutable = True  # once initialised, object is immutable
Esempio n. 18
0
    def msgstr2bytes(msgClass: str, msgID: str) -> bytes:
        """Convert plain text UBX message class to bytes
        e.g. 'CFG-MSG' to b'/x06/x01'.

        :param msgClass: str:
        :param msgID: str:

        """

        try:
            clsid = UBXMessage.key_from_val(ubt.UBX_CLASSES, msgClass)
            msgid = UBXMessage.key_from_val(ubt.UBX_MSGIDS, msgID)[1:]
            return (clsid, msgid)
        except ube.UBXMessageError as err:
            raise ube.UBXMessageError(
                f"Undefined message, class {msgClass}, id {msgID}") from err
Esempio n. 19
0
    def cfgkey2name(keyID: int) -> tuple:
        """
        Return key name and data type for given
        configuration database hexadecimal key.

        :param int keyID: config key as integer e.g. 0x20930001
        :return: tuple of (keyname, type)
        :rtype: tuple: (str, str)
        :raises: UBXMessageError

        """

        val = None
        for key, val in ubcdb.UBX_CONFIG_DATABASE.items():
            (kid, typ) = val
            if keyID == kid:
                return (key, typ)
        raise ube.UBXMessageError(f"Undefined configuration database key {hex(keyID)}")
Esempio n. 20
0
    def __init__(self, ubxClass, ubxID, mode: int, **kwargs):
        """Constructor.

        If no keyword parms are passed, the payload is taken to be empty.

        If 'payload' is passed as a keyword parm, this is taken to contain the complete
        payload as a sequence of bytes; any other keyword parms are ignored.

        Otherwise, any named attributes will be assigned the value given, all others will
        be assigned a nominal value according to type.

        :param object msgClass: str, int or byte:
        :param object msgID: str, int or byte:
        :param int mode: SET, GET or POLL
        :param kwargs: payload key value pairs
        :raise UBXMessageError
        """

        # object is mutable during initialisation only
        super().__setattr__("_immutable", False)
        self._mode = mode
        self._payload = b""
        self._length = b""
        self._checksum = b""

        if mode not in (0, 1, 2):
            raise ube.UBXMessageError(
                f"Invalid mode {mode} - must be 0, 1 or 2")

        # accommodate different formats of msgClass and msgID
        if isinstance(ubxClass, str) and isinstance(
                ubxID, str):  # string e.g. 'CFG', 'CFG-PRT'
            (self._ubxClass,
             self._ubxID) = UBXMessage.msgstr2bytes(ubxClass, ubxID)
        elif isinstance(ubxClass, int) and isinstance(ubxID,
                                                      int):  # int e.g. 6, 1
            (self._ubxClass,
             self._ubxID) = UBXMessage.msgclass2bytes(ubxClass, ubxID)
        else:  # bytes e.g. b'\x06', b'\x01'
            self._ubxClass = ubxClass
            self._ubxID = ubxID

        self._do_attributes(**kwargs)
        self._immutable = True  # once initialised, object is immutable
Esempio n. 21
0
    def msgstr2bytes(msgClass: str, msgID: str) -> bytes:
        """
        Convert plain text UBX message class to bytes.

        :param str msgClass: message class as str e.g. 'CFG'
        :param str msgID: message ID as str e.g. 'CFG-MSG'
        :return: message class as bytes e.g. b'/x06/x01'
        :rtype: bytes
        :raises: UBXMessageError

        """

        try:
            clsid = key_from_val(ubt.UBX_CLASSES, msgClass)
            msgid = key_from_val(ubt.UBX_MSGIDS, msgID)[1:2]
            return (clsid, msgid)
        except KeyError as err:
            raise ube.UBXMessageError(
                f"Undefined message, class {msgClass}, id {msgID}") from err
Esempio n. 22
0
    def config_set(layers: int, transaction: int, cfgData: list) -> object:
        """
        Construct CFG-VALSET message from an array of
        configuration database (key, value) tuples. Keys
        can be in int (keyID) or str (keyname) format.

        :param int layers: memory layer(s) (1=RAM, 2=BBR, 4=Flash)
        :param int transaction: 0=no txn, 1=start txn, 2=continue txn, 3=apply txn
        :param list cfgData: list of up to 64 tuples (key, value)
        :return: UBXMessage CFG-VALSET
        :rtype: UBXMessage
        :raises: UBXMessageError

        """

        num = len(cfgData)
        if num > 64:
            raise ube.UBXMessageError(
                f"Number of configuration tuples {num} exceeds maximum of 64"
            )

        version = UBXMessage.val2bytes(0 if transaction == 0 else 1, ubt.U1)
        layers = UBXMessage.val2bytes(layers, ubt.U1)
        transaction = UBXMessage.val2bytes(transaction, ubt.U1)
        payload = version + layers + transaction + b"\x00"
        lis = b""

        for cfgItem in cfgData:
            att = ""
            (key, val) = cfgItem
            if isinstance(key, str):  # if key is a string (keyname)
                (key, att) = UBXMessage.cfgname2key(
                    key
                )  # lookup keyID & attribute type
            else:
                (_, att) = UBXMessage.cfgkey2name(key)  # lookup attribute type
            keyb = UBXMessage.val2bytes(key, ubt.U4)
            valb = UBXMessage.val2bytes(val, att)
            lis = lis + keyb + valb

        return UBXMessage("CFG", "CFG-VALSET", ubt.SET, payload=payload + lis)
Esempio n. 23
0
    def identity(self) -> str:
        """
        Returns identity in plain text form e.g. 'CFG-MSG'.

        :return message identity
        :rtype str
        :raise UBXMessageError
        """

        try:
            # all MGA messages except MGA-DBD need to be identified by the
            # 'type' attribute - the first byte of the payload
            if self._ubxClass == b"\x13" and self._ubxID != b"\x80":
                umsg_name = ubt.UBX_MSGIDS[self._ubxClass + self._ubxID +
                                           self._payload[0:1]]
            else:
                umsg_name = ubt.UBX_MSGIDS[self._ubxClass + self._ubxID]
        except KeyError as err:
            raise ube.UBXMessageError(
                f"Unknown UBX message type class {self._ubxClass} id {self._ubxID}"
            ) from err
        return umsg_name
Esempio n. 24
0
    def identity(self) -> str:
        """Message identity getter.
        Returns identity in plain text form e.g. 'CFG-MSG'.

        :return identity: str:

        """
        # pylint: disable=line-too-long

        try:
            # all MGA messages except MGA-DBD need to be identified by the
            # 'type' attribute - the first byte of the payload
            if self._ubxClass == b'\x13' and self._ubxID != b'\x80':
                umsg_name = ubt.UBX_MSGIDS[self._ubxClass + self._ubxID +
                                           self._payload[0:1]]
            else:
                umsg_name = ubt.UBX_MSGIDS[self._ubxClass + self._ubxID]
        except KeyError as err:
            raise ube.UBXMessageError(
                (f"Message type {self._ubxClass + self._ubxID}"
                 f" not defined")) from err
        return umsg_name
Esempio n. 25
0
    def _get_aopstatus_version(self, **kwargs) -> dict:
        """
        Select appropriate payload definition version for older
        generations of NAV-AOPSTATUS message by checking payload length.

        :param kwargs: optional payload key/value pairs
        :return: dictionary representing payload definition
        :rtype: dict
        :raises: UBXMessageError

        """
        # pylint: disable=no-self-use

        if "payload" in kwargs:
            lpd = len(kwargs["payload"])
        else:
            raise ube.UBXMessageError(
                "NAV-AOPSTATUS message definitions must include payload keyword"
            )
        if lpd == 20:
            pdict = ubg.UBX_PAYLOADS_GET["NAV-AOPSTATUS-L"]
        else:
            pdict = ubg.UBX_PAYLOADS_GET["NAV-AOPSTATUS"]
        return pdict