Skip to content
This repository has been archived by the owner on Mar 11, 2024. It is now read-only.

AttributeError: 'Frame' object has no attribute 'encode_kiss' #26

Open
zyphlar opened this issue Oct 31, 2019 · 12 comments
Open

AttributeError: 'Frame' object has no attribute 'encode_kiss' #26

zyphlar opened this issue Oct 31, 2019 · 12 comments

Comments

@zyphlar
Copy link

zyphlar commented Oct 31, 2019

I'm not a python pro, but it seems the serial_write example doesn't work too well.

AttributeError: 'Frame' object has no attribute 'text'

and then

AttributeError: 'Frame' object has no attribute 'encode_kiss'

As far as I can tell, I should be using aprs/kiss_classes.py but seem to be getting aprs/classes.py instead and I'm not experienced enough to know how to make that happen.

@simseve
Copy link

simseve commented Nov 17, 2020

Same issue here.... but also not sure how to make sure aprs/kiss_classes.py are invoked correctly. Is the author still keen to give us an hand? I hope so. thanks for the great work.

@w1oko
Copy link

w1oko commented Dec 1, 2020

Same issue here. I'm trying to use the example to send KISS frames, but receive the same errors. I dug into the code a bit and also noticed that there are two sets of class files - classes.py and kiss_classes.py. The code in the example seems to depend on kiss_classes.py, but the class "Frame" is defined in both files, and only classes.py is called from the init file. I have tried renaming the Frame class in the kiss_classes.py file and added that into the init file, which gets me a bit further, but end up with other errors. Any help / insights from the author would be much appreciated. This will be an awesome piece of code to work on some cool IOT via Radio projects. I'm working on interfacing with an MQTT broker and this is the last piece of the puzzle that I can't figure out.

@KenwoodFox
Copy link

Also the same issue, what could have happened? maybe an issue with the library changing?...

@sticky-tea
Copy link

Same issue

@KenwoodFox
Copy link

Same issue

Any luck on a solution?

@w1oko
Copy link

w1oko commented Aug 30, 2022

It has been a while since I worked on this, but I did get it working a few years ago. Unfortunately I don't have everything in front of me at the moment, and I'm buried with other priorities, but my recollection was that there was a timing issue and by delaying the execution of some piece of code (of course I can't remember what!!) ultimately solved the problem. Hopefully this vague clue helps get you going. When I have more time to return to this, I'm sure it will come back to me, and I will make an effort to document the solution and post here.

@KenwoodFox
Copy link

Still working on this, bleh

@modernham
Copy link

Here I am too now. I've been banging my head against this for a few days. It seems encode_kiss is gone, but there is an encode_ax25 that doesn't seem to work. I even dug up the old code with encode_kiss and couldn't get it to work either. I tried feeding it raw frames from a capture file.

It's a shame when projects like these go unmaintained. It would probably be faster to just build it all form scratch again. Even the test cases in this repository still reference non existent aprs library functions.

I'm not sure the write function works no matter what you feed it. I even tried to just give it the raw kiss frames that is read.

@modernham
Copy link

Figured out a solution fellas, and anyone that comes here in the future. Created an "Encode Packet" class to encode and parse the packet into a an actual KISS / APRS frame before sending it to the write function.


import aprs

def encode_packet(in_frame) -> bytes:
    """
    Encodes an APRS Frame as AX.25.
    """
    frame = aprs.parse_frame(in_frame)
    encoded_frame = []
    encoded_frame.append(frame.destination.encode_ax25())
    encoded_frame.append(frame.source.encode_ax25())
    for path_call in frame.path:
        encoded_frame.append(path_call.encode_ax25())
    encoded_frame[-1] = b'\xae\x92\x88\x8ad@c'
    encoded_frame.append(aprs.ADDR_INFO_DELIM)
    encoded_frame.append(bytes(frame.info))

    fcs = aprs.FCS()
    for bit in encoded_frame:
        fcs.update_bit(bit)

    return b''.join(encoded_frame)

def EncodeKISS(source, destination, message):
    aprs_frame = aprs.parse_frame(source + ">APIN20,WIDE1-1,WIDE2-1::" + destination + " :" + message)
    return(encode_packet(aprs_frame))

The return of "EncodeKISS" which takes a source, destination callsign and a message can be fed directly in your write buffer.

@Smittyman50
Copy link

@modernham Any chance you can show your code in context with a write to a TCP kiss connection? I'm trying to use the socket example and I don't understand how to use your code with that example. I have an instance of direwolf running on my linux machine and I'm wanting to use a python script to connect via kiss, send a frame, then disconnect.

@modernham
Copy link

modernham commented Oct 29, 2023

@modernham Any chance you can show your code in context with a write to a TCP kiss connection? I'm trying to use the socket example and I don't understand how to use your code with that example. I have an instance of direwolf running on my linux machine and I'm wanting to use a python script to connect via kiss, send a frame, then disconnect.

Doing this from my phone, so hopefully turned out okay:


import aprs
Import kiss

"""
Does some voodoo magic to turn an APRS frame into a set of bytes than can be sent over the network to direwolf in 
a way that it's understood. Don't ask me how it works, because even I don't know.
"""
def encode_packet(in_frame) -> bytes:
    """
    Encodes an APRS Frame as AX.25.
    """
    frame = aprs.parse_frame(in_frame)
    encoded_frame = []
    encoded_frame.append(frame.destination.encode_ax25())
    encoded_frame.append(frame.source.encode_ax25())
    for path_call in frame.path:
        encoded_frame.append(path_call.encode_ax25())
    encoded_frame[-1] = b'\xae\x92\x88\x8ad@c'
    encoded_frame.append(aprs.ADDR_INFO_DELIM)
    encoded_frame.append(bytes(frame.info))

    fcs = aprs.FCS()
    for bit in encoded_frame:
        fcs.update_bit(bit)

    return b''.join(encoded_frame)


def EncodeKISSMessage(source, destination, message):
    aprs_frame = aprs.parse_frame(source + ">APIN20,WIDE1-1,WIDE2-1::" + destination + " :" + message)
    kiss_frame = encode_packet(aprs_frame)
    frame_escaped = kiss.escape_special_codes(kiss_frame)

    frame_kiss = b''.join([
        kiss.FEND,
        kiss.DATA_FRAME,
        frame_escaped,
        kiss.FEND
    ])
    return(frame_kiss)


"""
Creates a KISS packet for the TNC
"""
def WriteAPRSMessageFrame(tnc_stream, packet):
    data = packet.split(",")
    sender = data[0]
    receiver = data[1]
    message = data[2]
    if sender and receiver and message:
        frame = EncodeKISSMessage(sender.upper(), receiver.upper(), message)
        tnc_stream._write_handler(frame)
        print("[!] Sent Message to TNC: " + packet)
    return

  
  
  tnc_stream = kiss.TCPKISS(DIREWOLF_IP, DIREWOLF_PORT, False)
  tnc_stream.start()
  
  WriteAPRSMessageFrame(tnc_stream, "mycall,theircall,the message")

You also have to patch the library itself with this method:

This was very much a hack of the authors code to force it to work. There was old code in the library and it looks like some kiss code was in the aprs library itself. Also included was an "encode ax25" function in the aprs module Frame class that was modified to make the above. It took some screwing around with but it is indeed working. I sent a good frame from another application like pinpoint aprs and sniffed the traffic with Wireshark. I then proceeded to try different ways to imitate it over and over again with the kiss python library until I came up with the above.

@modernham
Copy link

Had to edit code to change things a bit. Didn't realize I had made a manual patch.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants