semuconsulting / pygnssutils

Python GNSS CLI utility library for reading, parsing and broadcasting NMEA, UBX, RTCM3, NTRIP and SPARTN protocols
BSD 3-Clause "New" or "Revised" License
87 stars 27 forks source link

gnssserver - nmea message communication bug #14

Closed sergiobellido closed 1 year ago

sergiobellido commented 1 year ago

Describe the bug

I am trying to communicate gps data serial port through TCP/IP with gnsserver CLI. when I try to connect to server socket, this error is raised: "TypeError: a bytes-like object is required, not 'NMEAMessage'" Traceback:

Exception occurred during processing of request from ('127.0.0.1', 61299)
Traceback (most recent call last):
  File "C:\Users\g512\anaconda3\envs\generic\lib\socketserver.py", line 683, in process_request_thread
    self.finish_request(request, client_address)
  File "C:\Users\g512\anaconda3\envs\generic\lib\socketserver.py", line 360, in finish_request
    self.RequestHandlerClass(request, client_address, self)
  File "C:\Users\g512\anaconda3\envs\generic\lib\site-packages\pygnssutils\socket_server.py", line 220, in __init__
    super().__init__(*args, **kwargs)
  File "C:\Users\g512\anaconda3\envs\generic\lib\socketserver.py", line 747, in __init__
    self.handle()
  File "C:\Users\g512\anaconda3\envs\generic\lib\site-packages\pygnssutils\socket_server.py", line 291, in handle
    self._write_from_mq()
  File "C:\Users\g512\anaconda3\envs\generic\lib\site-packages\pygnssutils\socket_server.py", line 409, in _write_from_mq
    self.wfile.write(raw)
  File "C:\Users\g512\anaconda3\envs\generic\lib\socketserver.py", line 826, in write
    self._sock.sendall(b)
TypeError: a bytes-like object is required, not 'NMEAMessage'

pygnssutils version: 1.01

To Reproduce

Open anaconda prompt terminal and type this command: gnssserver ntripmode=0 inport=COM5 baudrate=38400 hostip=127.0.0.1 outport=50010 limit=0 format=1 verbosity=2

On the other hand, when the socket is already created, open a jupyter notebook and run this code:

import socket
host = "127.0.0.1"
port = 50010
gps_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
gps_socket.connect((host, port))
response = gps_socket.recv(1024).decode('latin')
print(response)

Expected Behaviour

I suppose I will be reading gps data (nmea messages) through the socket like I did working with the graphical interface PyGPSClient.

Desktop (please complete the following information):

GNSS/GPS Device (please complete the following information as best you can):

Additional context

I solved the problem by identifying if the message socket server is sending is a NMEA msg and then serializing it. Modified __write_from_mq()_ function on socket_server.py script. Captura

I would like you to fix the bug. Thanks,

semuadmin commented 1 year ago

Hi @sergiobellido

Sorry you're having difficulties.

So to clarify, the gnssserver utility is designed to transmit data from a GNSS receiver in a variety of formats. The default is binary (format=2), but it can also transmit in parsed (NMEAMessage, UBXMessage or RTCMMessage object), JSON, hex or simple string formats.

BUT the client you're using to read from the socket must be capable of parsing data in whatever format you're transmitting it in. If you're using format=1, you'll need a client which is capable of parsing NMEAMessage objects.

e.g. here's a log on the server side using the default format=2:

➜  ~ gnssserver inport=/dev/tty.usbmodem1101
2023-01-31 14:11:45.651873: Starting server (type CTRL-C to stop)...
2023-01-31 14:11:45.651902: Starting input thread, reading from /dev/tty.usbmodem1101...
2023-01-31 14:11:45.655540: Parsing GNSS data stream from: Serial<id=0x105505f60, open=True>(port='/dev/tty.usbmodem1101', baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=3, xonxoff=False, rtscts=False, dsrdtr=False)...

2023-01-31 14:11:46.157229: Starting output thread, broadcasting on 0.0.0.0:50010...
2023-01-31 14:12:04.558185: Client ('127.0.0.1', 52133) has connected. Total clients: 1
2023-01-31 14:12:29.027703: Client ('127.0.0.1', 52133) has disconnected. Total clients: 0

and here's a log on the client side using the gnssdump CLI utility, which is capable of parsing binary GNSS data in either NMEA, UBX or RTCM3 formats:

➜  ~ gnssdump socket=localhost:50010
2023-01-31 14:53:21.037663: Parsing GNSS data stream from: <socket.socket fd=3, family=2, type=1, proto=0, laddr=('127.0.0.1', 52566), raddr=('127.0.0.1', 50010)>...

<NMEA(GNRMC, time=14:53:21, status=A, lat=50.7363436667, NS=N, lon=-1.9737508333, EW=W, spd=0.013, cog=, date=2023-01-31, mv=, mvEW=, posMode=A, navStatus=V)>
<NMEA(GNVTG, cogt=, cogtUnit=T, cogm=, cogmUnit=M, sogn=0.013, sognUnit=N, sogk=0.023, sogkUnit=K, posMode=A)>
...
<NMEA(GQGSV, numMsg=1, msgNum=1, numSV=0, signalID=0)>
<NMEA(GNGLL, lat=50.7363436667, NS=N, lon=-1.9737506667, EW=W, time=14:53:22, status=A, posMode=A)>
^C2023-01-31 14:53:22.077004: Streaming terminated, 62 messages processed with 0 errors.

As you can see, this combination of server and client is transmitting and receiving raw NMEA data OK.

So you either need to change the server format to match your client, or update your client to handle the server format. Unless you have a particular reason to use format=1, I suggest you simply use the default format=2.

Hope this helps. Any queries, please get back to me.

semuadmin commented 1 year ago

Hi @sergiobellido

Did this help at all?

FYI the pygnssutils library is being updated shortly to use the standard Python argparse argument parser library, so the CLI command arguments will change to the new format, e.g.

gnssserver ntripmode=0 inport=COM5 baudrate=38400 hostip=127.0.0.1 outport=50010 limit=0 format=2 verbosity=2

will change in pygnssutils>=1.0.2 to:

gnssserver --ntripmode 0 --inport COM5 --baudrate 38400 --hostip 127.0.0.1 --outport 50010 --limit 0 --format 2 --verbosity 2

But, as I say, if you use the default gnssserver format (2 = binary), you should find your server-client combination works OK.

I'll close this issue for now but if you're still having difficulties, please get back to me.