如何正确显示解压缩的UDP数据

时间:2019-07-14 00:03:30

标签: python-3.x udp

我正在尝试编写一个小代码,以显示通过UDP从游戏(F1 2019)接收的数据。

F1 2019游戏通过UDP发送数据。我已经能够接收数据包,并且已经分离了标头和数据,现在根据使用rawutil模块发送数据的结构来解压缩数据。

发送数据包的结构可以在这里找到: https://forums.codemasters.com/topic/38920-f1-2019-udp-specification/

我只对遥测数据包感兴趣。

import socket
import cdp
import struct
import array
import rawutil
from pprint import pprint

# settings
ip = '0.0.0.0'
port = 20777

# listen for packets
listen_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
listen_socket.bind((ip, port))

while True:
  # Receiving data
  data, address = listen_socket.recvfrom(65536)
  header = data[:20]
  telemetry = data[20:]

  # decode the header
  packetFormat, = rawutil.unpack('<H', header[:2])
  gameMajorVersion, = rawutil.unpack('<B', header[2:3])
  gameMinorVersion, = rawutil.unpack('<B', header[3:4])
  packetVersion, = rawutil.unpack('<B', header[4:5])
  packetId, = rawutil.unpack('<B', header[5:6])
  sessionUID, = rawutil.unpack('<Q', header[6:14])
  sessionTime, = rawutil.unpack('<f', header[14:18])
  frameIdentifier, = rawutil.unpack('<B', header[18:19])
  playerCarIndex, = rawutil.unpack('<B', header[19:20])

  # print all info (just for now)

##  print('Packet Format : ',packetFormat)
##  print('Game Major Version : ',gameMajorVersion)
##  print('Game Minor Version : ',gameMinorVersion)
##  print('Packet Version : ',packetVersion)
##  print('Packet ID : ', packetId)
##  print('Unique Session ID : ',sessionUID)
##  print('Session Time : ',sessionTime)
##  print('Frame Number : ',frameIdentifier)
##  print('Player Car Index : ',playerCarIndex)
##  print('\n\n')

#start getting the packet data for each packet starting with telemetry data

  if (packetId == 6):
    speed, = rawutil.unpack('<H' , telemetry[2:4])
    throttle, = rawutil.unpack('<f' , telemetry[4:8])
    steer, = rawutil.unpack('<f' , telemetry[8:12])
    brake, = rawutil.unpack('<f' , telemetry[12:16])
    gear, = rawutil.unpack('<b' , telemetry[17:18])
    rpm, = rawutil.unpack('<H' , telemetry[18:20])

    print (speed)

UDP规范指出,汽车的速度以km / h为单位发送。但是,当我打开包装袋时,速度是256的倍数,因此10 km / h是2560。

我想知道我是否以错误的方式解压缩数据?还是其他原因导致了这种情况。

例如转向也存在问题。规范说应该在-1.0到1.0之间,但实际值可能很大或很小。

此处抓取屏幕:https://imgur.com/a/PHgdNrx

对此表示感谢。 谢谢。

2 个答案:

答案 0 :(得分:1)

我建议您不要使用unpack方法,因为对于大型结构(例如MotionPacket具有1343字节),您的代码会立即变得非常混乱。 但是,如果您非常想使用它,请仅调用unpack,例如:

fmt = "<HBBBBQfBB"
size = struct.calcsize(fmt)
arr = struct.unpack("<HBBBBQfBB", header[:size])

或者,查看ctypes库,尤其是ctypes.LittleEndianStructure库,您可以在其中将_fields_属性设置为ctypes的序列(例如uint8等等,而不必像解压缩一样将它们翻译成相关符号)。 https://docs.python.org/3.8/library/ctypes.html#ctypes.LittleEndianStructure

或者,看看namedtuples

另外,也有很多python二进制IO库,例如binio,您可以在其中声明ctypes的结构,因为无论如何它都是一个薄包装器。

要完全回答您的问题,结构似乎是:

struct PacketHeader
{
    uint16    m_packetFormat;         // 2019
    uint8     m_gameMajorVersion;     // Game major version - "X.00"
    uint8     m_gameMinorVersion;     // Game minor version - "1.XX"
    uint8     m_packetVersion;        // Version of this packet type, all start from 1
    uint8     m_packetId;             // Identifier for the packet type, see below
    uint64    m_sessionUID;           // Unique identifier for the session
    float     m_sessionTime;          // Session timestamp
    uint      m_frameIdentifier;      // Identifier for the frame the data was retrieved on
    uint8     m_playerCarIndex;       // Index of player's car in the array
};

意味着unpack的符号序列应为:<H4BQfLB,因为uint中的ctypes实际上是uint32,您在{{1 }}。 我还用uint8替换了BBBB。希望这可以帮助。

答案 1 :(得分:0)

海德我也想从Formula 1 2019中读取车速。我找到了您的问题,从您的问题中得到了一些提示,并解决了我的问题。现在我想我必须还钱。速度乘以256的原因是您从错误的字节开始,并且此数据的格式为little endian。您共享的代码从第22个字节开始读取速度,如果从第23个字节开始读取,则将获得正确的速度数据。