pylessard / python-udsoncan

Python implementation of UDS (ISO-14229) standard.
MIT License
580 stars 197 forks source link

Can I use multiple RX addresses ? #240

Closed ichbinbork closed 3 months ago

ichbinbork commented 3 months ago

Hey,

I want to use multiple rx ids for responding to upcoming frames.

tp_addr = isotp.Address(isotp.AddressingMode.Normal_11bits, txid=0x123, rxid=0x456)

In the above block, the module only filters the 0x456 ID according to gives the response. But I want to filter more than one ID like can module in python. For instance, I want to filter "0x111", "0x222", "0x333" at the same time. Is it possible?

For changing address I created that function but I don't want to call it every process. I need different approach for handling multiple rxids.

    def set_can_addresses(self, physical_can_request_id, physical_can_response_id):
        try:
            txid = int.from_bytes(physical_can_request_id[:-1], 'big')
            rxid = int.from_bytes(physical_can_response_id[:-1], 'big')
            self.tp_addr = isotp.Address(isotp.AddressingMode.Normal_29bits, txid=txid, rxid=rxid)
            self.stack = isotp.NotifierBasedCanStack(bus=self.bus, notifier=self.notifier, address=self.tp_addr, params=isotp_params.isotp_params)
            self.stack.set_sleep_timing(0, 0)
        except Exception as e:
            print(e)

Best regards

pylessard commented 3 months ago

What do you mean exactly? You want to send a request on a given ID then accept and answer from any of the ID in a list? Do you have prior knowledge of which ID will respond? If so, I suggest to simply create 3 instance of the CanStack. You can use 3 UDS clients or create a connection that will put the response of any CanStack into the same queue, then implement a recv function that reads from that Queue. It's not that hard.

Also, you can change the address of a TransportLayer (e.g. the CanStack) by calling set_address instead of creating a new instance each time

ichbinbork commented 3 months ago

"You want to send a request on a given ID then accept and answer from any of the ID in a list": Yes exactly. Also I want to send them request.

"Do you have prior knowledge of which ID will respond?". Yes, I have the response of each ECU ID to answer my request.

I will prefer the creating queue with upcoming responses. Cuz crating 3 different connection is little bit hard to handle (number may increase that's why hard to handle). Also I suspicious that the more than one client crash the stack according to issues of this repo.

Thanks for the advice. Is there a method for change baudrate like set_address?

pylessard commented 3 months ago

Well having 3 full stack (client/connection/TransportLayer/Bus) is the simplest way. You shouldn't encounter any issue doing so. If I were you, I'd make a function that create and configure all these objects and return a working client. Then put those client in a dictionary index by an enum so I can do clients[ECU1].some_request(some_param1, some_param2). If you find it complex to create 3 clients, you will find it more complex to design a custom connection.

If you want to stick with the custom connection option, I suggest you look at how the PythonIsoTPConnectionV2 is designed an do something similar, bu write to a queue instead internally.

To change the baudrate, I am not sure if you are talking about the UDS Baudrate control service or the underlying can bus bitrate. udsoncan supports the baudrate control service. To change the CAN layer, check tyhe python-can documentation.

ichbinbork commented 3 months ago

As I understand I need something like this

def create_client(txid, rxid, bitrate=500000, config=None):
    if config is None:
        config = udsoncan.configs.default_client_config.copy()
    bus = VectorBus(channel=0, bitrate=bitrate)
    tp_addr = isotp.Address(isotp.AddressingMode.Normal_11bits, txid=txid, rxid=rxid)
    stack = isotp.NotifierBasedCanStack(bus=bus, notifier=notifier, address=tp_addr, params=isotp_params)
    conn = PythonIsoTpConnection(stack)
    return Client(conn, config=config)

clients = {
    'ECU1': create_client(txid=0x111, rxid=0x999),
    'ECU2': create_client(txid=0x222, rxid=0x888),
    'ECU3': create_client(txid=0x333, rxid=0x777)
}

with clients['ECU1'] as client_1:
    client_1.change_session(1)
    client_1.some_request(some_param1, some_param2)

with clients['ECU2'] as client_2:
    client_2.change_session(1)
    client_2.some_request(some_param1, some_param2)

with clients['ECU3'] as client_3:
    client_3.change_session(1)
    client_3.some_request(some_param1, some_param2)

Again as I understand when I create three instance of client I can response the (0x999,0x888,0x777) addresses right ?

pylessard commented 3 months ago

yeah. Something like that could do. You don't have to use with absolutely. Might be cleaner like this:


client1.open()
client2.open()
client3.open()

client_1.change_session(1)
client_1.some_request(some_param1, some_param2)

client_2.change_session(1)
client_2.some_request(some_param1, some_param2)

client_3.change_session(1)
client_3.some_request(some_param1, some_param2)

client3.close()
client2.close()
client1.close()

Cheers

ichbinbork commented 3 months ago

Thanks for your attention.

Best regards.

ichbinbork commented 3 months ago

I have tried to call set_address method but I failed. Here is my block

address = isotp.Address(isotp.AddressingMode.Normal_29bits,txid=0x18DDE910 , rxid=0x18DDF3E8)

   isotp.TransportLayerLogic.set_address(address=address)

I know that I need to create instance of TransportLayerLogic class first but when I try to create it according to exception I need to set rxfn and txfn.

Also I want to change my address after connection created is it possible ?

pylessard commented 3 months ago

Just call set_address on your CanStack object. Inheritance hierarchy is as follow: CanStack ==> TransportLayer ==> TransportLayerLogic

ichbinbork commented 3 months ago

Thanks again