sjlongland / aioax25

Asynchronous AX.25 library using asyncio
GNU General Public License v2.0
22 stars 8 forks source link

sender header callsign gets a * causes aprslib to fail to decode packet #9

Closed hemna closed 3 years ago

hemna commented 3 years ago

Hello, I am very close to getting aprsd working with aioax25 with direwolf. There is an odd behavior that I am seeing when getting aprs packets from aioax25, which is the sender's callsign gets a * after it, which causes aprslib to fail to decode the packet.

These lines of code are where the * is being added to the sender's callsign. https://github.com/sjlongland/aioax25/blob/master/aioax25/frame.py#L713-L714

Here is a sample packet sent from my Kenwood TH-d74, which direwolf picks up and sends to aioax25

[DEBUG] Got an APRS Frame 'WB4BOR*>APK004,WIDE1-1,WIDE2-1: PID=0xf0 Payload=b':WB4BOR-12:ping{27'' - [/Users/i530566/devel/mine/aprsd/aprsd/threads.py:373]
[09/01/2021 02:15:27 PM] [KISSRX_MSG  ] [DEBUG] Decoding WB4BOR*>APK004,WIDE1-1,WIDE2-1::WB4BOR-12:ping{27 - [/Users/i530566/devel/mine/aprsd/aprsd/threads.py:377]

The direwolf log entry for the packet

WB4BOR audio level = 8(4/2)   [NONE]   ___|||||_                                                                                                 │
[0.5] WB4BOR>APK004,WIDE1-1,WIDE2-1::WB4BOR-12:ping{27<0x0d>                                                                                     │
[0H] WB4BOR>APK004,APPOMX*,WIDE2-1::WB4BOR-12:ping{27<0x0d>

You can see the fail to decode here:

Exception in callback KISSRXThread.process_packet(interface=<aioax25.aprs...t 0x1040a7970>, frame=<aioax25.aprs...t 0x1040b3160>)()
handle: <Handle KISSRXThread.process_packet(interface=<aioax25.aprs...t 0x1040a7970>, frame=<aioax25.aprs...t 0x1040b3160>)()>
Traceback (most recent call last):
  File "/Users/i530566/devel/mine/aprsd/.venv/lib/python3.8/site-packages/aprslib/parsing/__init__.py", line 101, in parse
    parsed.update(parse_header(head))
  File "/Users/i530566/devel/mine/aprsd/.venv/lib/python3.8/site-packages/aprslib/parsing/common.py", line 45, in parse_header
    raise ParseError("fromcallsign is invalid")
aprslib.exceptions.ParseError: fromcallsign is invalid

I've never seen an aprs frame where the fromcallsign gets a * put after it. If I comment those lines 712 and 714 out of the frame.py, then everything works and is happy.

hemna commented 3 years ago

I found a workaround for the time being.

After getting the frame from aioax25, I force the control bit to False for the sender with

frame.header._source._ch = False
hemna commented 3 years ago

For what it's worth, here is my patch on aprsd that uses aioax25. I have it working with tcpkiss and am testing it with serialkiss next.

aprsd <---> aioax25 <-- tcp kiss --> direwolf

sjlongland commented 3 years ago

Okay, so that field marked CH in this code base can mean two different things:

http://web.archive.org/web/20190522033714/https://www.tapr.org/pub_ax25.html#2.4.1.2

I set the bits according to what I understood from that part of the AX.25 2.0 specification. Clearly APRS is special. ;-)

sjlongland commented 3 years ago

http://www.aprs.org/aprs11/C-bits-SSID.txt … took some digging, but this is where I got the idea that the destination call-sign should have a C bit set on the destination and cleared on the source.

Since bit also doubles as the has been digipeated bit when the field is used in a digipeater context, * gets appended anywhere the C/H bit is set.

In the bug report though, one can clearly see it's the source bit that's getting that C bit set… so ch=False is being passed in somewhere. Been a while since I looked at this code, so it might take some digging.

sjlongland commented 3 years ago

@hemna I had a look at the code in aprslib and in aprsd… it would seem the problem is we really need a means of obtaining a frame in "TNC2 format" which could then be passed to aprslib.

Have a look at https://github.com/sjlongland/aioax25/tree/bugfix/issue-9-addr-ch-bit-set and in your code https://github.com/craigerl/aprsd/blob/master/aprsd/threads.py#L374-L375, you should be able to replace that with:

msg = frame.tnc2
hemna commented 3 years ago

https://github.com/craigerl/aprsd/blob/master/aprsd/threads.py#L374-L375

awesome. I'll give that a try!

hemna commented 3 years ago

This is what I got.

Traceback (most recent call last):
  File "/Users/i530566/.pyenv/versions/3.8.5/lib/python3.8/asyncio/events.py", line 81, in _run
    self._context.run(self._callback, *self._args)
  File "/Users/i530566/devel/mine/aprsd/aprsd/threads.py", line 376, in process_packet
    msg = frame.tnc2
AttributeError: 'APRSMessageFrame' object has no attribute 'tnc2'
sjlongland commented 3 years ago

Strange… because APRSMessageFrame is a APRSFrame, which is a AX25UnnumberedInformationFrame

AX25UnnumberedInformationFrame defines the tnc2 property and get_tnc2() method.

Are you sure you pulled the right branch (bugfix/issue-9-addr-ch-bit-set)? Did you symbolically link aioax25's module directory into your project or run setup.py install to install the module in your library path?

hemna commented 3 years ago

ah! I didn't pull the bugfix/issue-9-addr-ch-bit-set. branch. I tried that out and it's working. I just set my message to frame.tnc2 and it's good to get decoded!

sjlongland commented 3 years ago

No worries, I figured I'd try this first before I tried mucking with changing the C bits actually sent over the air. :-)

Half the problem with AX.25 is a lot of the standards were written about the time I was born or a few years after, and so getting documentation on them today can be sketchy. Then you have "de-facto standards" like "TNC2 format", which are seemingly undocumented.

Anyway, if it's working now, I guess we can close this unless we strike issues later. Many thanks.