Python
Python loads the shared library from the AMMC zip directly. The zip also
contains lib_test.py, a working script that does exactly what is below.
pip install cffifrom cffi import FFI
ffi = FFI()
ffi.cdef("""
char *p3_to_json(const char *msg);
void p3_free_string(char *ptr);
""")
lib = "windows64\\libammc.dll"
print(f"Trying to open AMMC lib from path: {lib}")
C = ffi.dlopen(lib)
p3_msg = "8e023300e5630000010001047a00000003041fd855000408589514394cd8040005026d0006025000080200008104501304008f"
result = C.p3_to_json(p3_msg.encode('ascii'))
assert result != ffi.NULL
json = ffi.string(result).decode('ascii')
C.p3_free_string(result) # the caller owns the string and must free it
assert 'PASSING' in json
Use linux_x86-64/libammc.so or apple_m/libammc.dylib instead of the .dll
on other platforms.
A small helper
Wrapping the two calls keeps the free where it belongs and gives you real Python objects:
import json as jsonlib
from cffi import FFI
ffi = FFI()
ffi.cdef("""
char *p3_to_json(const char *msg);
void p3_free_string(char *ptr);
""")
C = ffi.dlopen("apple_m/libammc.dylib")
def to_json(p3_hex: str) -> list:
"""Converts hex-encoded decoder bytes into a list of messages."""
result = C.p3_to_json(p3_hex.encode("ascii"))
if result == ffi.NULL:
return []
try:
return jsonlib.loads(ffi.string(result).decode("ascii"))
finally:
C.p3_free_string(result)
for passing in to_json("8e023300e5630000010001047a000000030"
"41fd855000408589514394cd80400050"
"26d0006025000080200008104501304008f"):
print(passing["passing_number"], passing["transponder"], passing["rtc_time"])122 5625887 2013-03-19 21:36:33.607 +02:00
The try/finally matters: without p3_free_string every converted message
leaks, which adds up quickly on a busy timing loop.
Reading a decoder
The library does no networking, so the socket is yours:
import socket
sock = socket.create_connection(("10.0.11.10", 5403))
while True:
data = sock.recv(4096)
if not data:
break
for passing in to_json(data.hex()):
print(passing)
Each call parses independently and keeps nothing between calls, so a message
split across two recv calls is lost by both. If you need every passing without
gaps, do not parse the socket yourself — run ammc-amb -w 9000 and read its
WebSocket, which handles the framing for you.