Package: pyrtcm
pyrtcmCurrent Status|Installation|Reading|Parsing|Generating|Serializing|Examples|Extensibility|Command Line Utility|Graphical Client|Author & Licensepyrtcmis an original Python 3 parser for the RTCM3 © GPS/GNSS protocol. RTCM3 is a proprietary GPS/GNSSdifferential correction or DGPSprotocol published by the Radio Technical Commission for Maritime Services.RTCM STANDARD 10403.n DIFFERENTIAL GNSS (GLOBAL NAVIGATION SATELLITE SYSTEMS) SERVICES – VERSION 3.Thepyrtcmhomepage is located athttps://github.com/semuconsulting/pyrtcm.This is an independent project and we have no affiliation whatsoever with the Radio Technical Commission for Maritime Services.FYIThere are companion libraries which handle standard NMEA 0183 © and UBX © (u-blox) GNSS/GPS messages:pyubx2(FYIinstallingpyubx2via pip also installspynmeagpsandpyrtcm)pynmeagpsCurrent StatusParses RTCM3 messages into their constituent data fields. Refer to theRTCM_MSGIDSdictionary inrtcmtypes_core.pyfor a list of message types currently implemented. Additional message types can be readily added - seeExtensibility).Sphinx API Documentation in HTML format is available athttps://www.semuconsulting.com/pyrtcm.Contributions welcome - please refer toCONTRIBUTING.MD.Bug reportsandFeature requests- please use the templates provided. For general queries and advice, post a message to one of thepyrtcm Discussionschannels.Installationpyrtcmis compatible with Python >=3.8 and has no third-party library dependencies.In the following,python3&piprefer to the Python 3 executables. You may need to typepythonorpip3, depending on your particular environment.The recommended way to install the latest version ofpyrtcmis withpip:python3-mpipinstall--upgradepyrtcmIf required,pyrtcmcan also be installed into a virtual environment, e.g.:python3-mpipinstall--user--upgradevirtualenv
python3-mvirtualenvenvsourceenv/bin/activate(orenv\Scripts\activateonWindows)(env)python3-mpipinstall--upgradepyrtcm
...
deactivateForCondausers,pyrtcmis also available fromconda-forge:condainstall-cconda-forgepyrtcmReading (Streaming)class pyrtcm.rtcmreader.RTCMReader(stream, **kwargs)You can create aRTCMReaderobject by calling the constructor with an active stream object.
The stream object can be any data stream which supports aread(n) -> bytesmethod (e.g. File or Serial, with
or without a buffer wrapper).pyrtcmimplements an internalSocketStreamclass to allow sockets to be read in the same way as other streams (see example below).Individual RTCM messages can then be read using theRTCMReader.read()function, which returns both the raw binary data (as bytes) and the parsed data (as aRTCMMessage, via theparse()method). The function is thread-safe in so far as the incoming data stream object is thread-safe.RTCMReaderalso implements an iterator.Example -  Serial input:>>>fromserialimportSerial>>>frompyrtcmimportRTCMReader>>>stream=Serial('/dev/tty.usbmodem14101',9600,timeout=3)>>>rtr=RTCMReader(stream)>>>(raw_data,parsed_data)=rtr.read()>>>print(parsed_data)<RTCM(1077,DF002=1077,DF003=0,GNSSEpoch=204137001,DF393=1,DF409=0,DF001_7=0,DF411=0,DF412=0,DF417=0,DF418=0,DF394=760738918298550272,NSat=10,DF395=1073807360,NSig=2,DF396=1044459,DF397_01(005)=75,DF397_02(007)=75,DF397_03(009)=81,...,DF404_19(030,1C)=0.0,DF404_20(030,2L)=0.0)>,Example - File input (using iterator).>>>frompyrtcmimportRTCMReader>>>stream=open('rtcmdata.log','rb')>>>rtr=RTCMReader(stream)>>>for(raw_data,parsed_data)inrtr:print(parsed_data)...Example - Socket input (using iterator):>>>importsocket>>>frompyrtcmimportRTCMReader>>>stream=socket.socket(socket.AF_INET,socket.SOCK_STREAM):>>>stream.connect(("localhost",50007))>>>rtr=RTCMReader(stream)>>>for(raw_data,parsed_data)inrtr:print(parsed_data)ParsingYou can parse individual RTCM messages using the staticRTCMReader.parse(data)function, which takes a bytes array containing a binary RTCM message and returns aRTCMMessageobject.NB:Once instantiated, anRTCMMessageobject is immutable.Example:>>>frompyrtcmimportRTCMReader>>>msg=RTCMReader.parse(b"\xd3\x00\x13>\xd0\x00\x03\x8aX\xd9I<\x87/4\x10\x9d\x07\xd6\xafH Z\xd7\xf7")>>>print(msg)<RTCM(1005,DF002=1005,DF003=0,DF021=0,DF022=1,DF023=1,DF024=1,DF141=0,DF025=4444030.8028,DF142=1,DF001_1=0,DF026=3085671.2349,DF364=0,DF027=3366658.256)>TheRTCMMessageobject exposes different public attributes depending on its message type or 'identity'. Attributes are defined as data fields ("DF002", "DF003", etc.) e.g. the1005message contains the following data fields:>>>print(msg)<RTCM(1005,DF002=1005,DF003=0,DF021=0,DF022=1,DF023=1,DF024=1,DF141=0,DF025=4444030.8028,DF142=1,DF001_1=0,DF026=3085671.2349,DF364=0,DF027=3366658.256)>>>>msg.identity'1005'>>>msg.DF0241Helper methods are available to interpret the individual datafields:>>>frompyrtcmimportRTCM_DATA_FIELDS,datasiz,datascale,datadesc>>>dfname="DF012">>>RTCM_DATA_FIELDS[dfname](INT20,0.0001,"GPS L1 PhaseRange - L1 Pseudorange")>>>datasiz(dfname)# size in bits20>>>datascale(dfname)# scaling factor0.0001>>>datadesc(dfname)# description'GPS L1 PhaseRange - L1 Pseudorange'Thepayloadattribute always contains the raw payload as bytes.Attributes within repeating groups are parsed with a two-digit suffix ("DF030_01", "DF030_02", etc.).Tip:To iterate through a repeating group of attributes (e.g., DF406 (GNSS signal fine PhaseRange)) as a list, the following construct can be used:df406group = [] # list of DF406 ((GNSS signal fine PhaseRange) values from repeating group in MSM 1077 message
for i in range(msg.NCell):
    df406 = getattr(msg, f"DF406_{i+1:02}")
    df406group.append(df406)Attributes within MSM NSAT and NCELL repeating groups can optionally be labelled with their corresponding satellite PRN and signal ID when the__str__()method is invoked, by setting the keyword argumentlabelmsmto True (e.g.DF405_10(014,2C)signifies that the 10th item in the DF405 group refers to satellite PRN 014, signal ID 2C).Generatingclass pyrtcm.rtcmmessage.RTCMMessage(**kwargs)You can create anRTCMMessageobject by calling the constructor with the following keyword arguments:payload as bytesExample:>>>frompyrtcmimportRTCMMessage>>>msg=RTCMMessage(payload=b">\xd0\x00\x03\x8aX\xd9I<\x87/4\x10\x9d\x07\xd6\xafH ")>>>print(msg)<RTCM(1005,DF002=1005,DF003=0,DF021=0,DF022=1,DF023=1,DF024=1,DF141=0,DF025=4444030.8028,DF142=1,DF001_1=0,DF026=3085671.2349,DF364=0,DF027=3366658.256)>SerializingTheRTCMMessageclass implements aserialize()method to convert aRTCMMessageobject to a bytes array suitable for writing to an output stream.e.g. to create and send a1005message type:>>>fromserialimportSerial>>>serialOut=Serial('COM7',38400,timeout=5)>>>frompyrtcmimportRTCMMessage>>>msg=RTCMMessage(payload=b">\xd0\x00\x03\x8aX\xd9I<\x87/4\x10\x9d\x07\xd6\xafH ")>>>print(msg)<RTCM(1005,DF002=1005,DF003=0,DF021=0,DF022=1,DF023=1,DF024=1,DF141=0,DF025=4444030.8028,DF142=1,DF001_1=0,DF026=3085671.2349,DF364=0,DF027=3366658.256)>>>>output=msg.serialize()>>>outputb'\xd3\x00\x13>\xd0\x00\x03\x8aX\xd9I<\x87/4\x10\x9d\x07\xd6\xafH Z\xd7\xf7'>>>serialOut.write(output)ExamplesThe following examples are available in the /examples folder:rtcmpoller.py- illustrates how to read and display RTCM messages 'concurrently' with other tasks using threads and queues. This represents a useful generic pattern for many end user applications.rtcmfile.py- illustrates how to stream RTCM data from binary log file.rtcmsocket.pyillustrates how to implement a TCP Socket reader for RTCM messages using RTCMReader iterator functionality.ntripclient.py- illustrates a simpleNTRIPclient using pyrtcm to parse the RTCM3 output.ExtensibilityThe RTCM protocol is principally defined in the modulesrtcmtypes_core.pyandrtcmtypes_get.pyas a series of dictionaries. RTCM uses a series of pre-defined data fields ("DF002", DF003" etc.), each of which has a designated data type (UINT32, etc.). Message payload definitions must conform to the following rules:1. datafield names must be unique within each message class
2. datafield types must be one of the valid data fields ("DF026", "DF059", etc.)
3. repeating or bitfield groups must be defined as a tuple ('numr', {dict}), where:
   'numr' is either:
     a. an integer representing a fixed number of repeats e.g. 32
     b. a string representing the name of a preceding attribute containing the number of repeats e.g. 'DF029'
   {dict} is the nested dictionary of repeating items or bitfield groupRepeating attribute names are parsed with a two-digit suffix ("DF030_01", "DF030_02", etc.). Nested repeating groups are supported.Command Line UtilityA command line utilitygnssdumpis available via thepygnssutilspackage. This is capable of reading and parsing NMEA, UBX and RTCM3 data from a variety of input sources (e.g. serial, socket and file) and outputting to a variety of media in a variety of formats. Seehttps://github.com/semuconsulting/pygnssutilsfor further details.To installpygnssutils:python3 -m pip install --upgrade pygnssutilsFor help with thegnssdumputility, type:gnssdump -hGraphical ClientA python/tkinter graphical GPS client which supports NMEA, UBX and RTCM3 protocols is available at:https://github.com/semuconsulting/PyGPSClientAuthor & License Informationsemuadmin@semuconsulting.compyrtcmis maintained entirely by unpaid volunteers. It receives no funding from advertising or corporate sponsorship. If you find the library useful, a small donation would be greatly appreciated!