Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[QUESTION] Python & groups #391

Open
3 tasks done
kpr-8 opened this issue Oct 31, 2023 · 6 comments
Open
3 tasks done

[QUESTION] Python & groups #391

kpr-8 opened this issue Oct 31, 2023 · 6 comments
Labels

Comments

@kpr-8
Copy link

kpr-8 commented Oct 31, 2023

I want to create a an erpc based project where both ends can send messages to each other (host/target with target able to send asynch messages). To do this I have created the following IDL

program test

@group("targetInterface")
interface Command
{
    start_process() -> void
}

@group("hostInterface")
interface Status
{
    heartbeat() -> void
}

I run the erpcgen and get two directories (test_hostInterface and test_targetInterface)

Now, when I start to write my client code (lives in the parent directory of test_hostInterface and test_targetInterface):

try:
    import erpc
except ImportError:
    print("Could not import erpc.\r\nPlease install it first by running \"python setup.py install\" in folder \"erpc/erpc_python/\".")
    sys.exit()

import test_hostInterface
from test_hostInterface import client

Python throws an error:

$ python ./client.py 
Traceback (most recent call last):
  File "/home/me/simple/./client.py", line 7, in <module>
    import test_hostInterface
  File "/home/me/simple/test_hostInterface/__init__.py", line 17, in <module>
    from . import client
  File "/home/me/simple/test_hostInterface/client.py", line 10, in <module>
    from ..test_targetInterface import interface as interface_targetInterface
ImportError: attempted relative import beyond top-level package

And in the test_hostInterface/client.py file is this:

# import callbacks declaration from other groups
from ..test_targetInterface import interface as interface_targetInterface

Which seems to be the root cause of the problem. Removing that line resolves the issue and it isn't needed as far as I can tell.

What am I missing/doing wrong?

Steps you didn't forgot to do

  • I checked if there is no related issue opened/closed.
  • I checked that there doesn't exist opened/closed PR which is solving this issue.
  • I looked in documentation if there is related information.
@kpr-8 kpr-8 added the question label Oct 31, 2023
Copy link

Hi eRPC user. Thank you for your interest and welcome. We hope you will enjoy this framework well.

@Hadatko
Copy link
Member

Hadatko commented Oct 31, 2023

HI @kpr-8 ,
i made transport arbitrator working here #386 (soon i will add example for that officialy). Could you check it? I know it worked for me.

@kpr-8
Copy link
Author

kpr-8 commented Nov 1, 2023

@Hadatko Thanks but that isn't exactly what I wanted. I did get it working tho, I'll post some code in case it helps others. Unfortunately it will not work with the erpc generated code, two files contain imports that break python

test_hostInterface/client.py line 10

from ..test_targetInterface import interface as interface_targetInterface

test_targetInterface/client.py line 10

from ..test_hostInterface import interface as interface_hostInterface

Removing those imports allows the code to run, maybe this is a bug?

.erpc file

program test

@group("targetInterface")
interface Command
{
    start_process() -> void
}

@group("hostInterface")
interface Status
{
    oneway heartbeat()
}

target.py - the microntroller/server

import time
import threading

try:
    import erpc
except ImportError:
    print("Could not import erpc.\r\nPlease install it first by running \"python setup.py install\" in folder \"erpc/erpc_python/\".")
    sys.exit()

import sys

import test_hostInterface
import test_targetInterface

arbitrator = None

class CommandServiceHandler(test_targetInterface.interface.ICommand):
    def start_process(self):
        print(f'start_process')

def thread_function():
    handler = CommandServiceHandler()
    service = test_targetInterface.server.CommandService(handler)
    server = erpc.simple_server.SimpleServer(arbitrator, erpc.basic_codec.BasicCodec)
    server.add_service(service)
    sys.stdout.flush()
    server.run()


transport = erpc.transport.SerialTransport("/home/user/socatpty2", 115200)
print("arbitrator created")
arbitrator = erpc.arbitrator.TransportArbitrator(transport, erpc.basic_codec.BasicCodec())

thread = threading.Thread(target=thread_function, args=())
thread.start()


clientManager = erpc.client.ClientManager(arbitrator.shared_transport, erpc.basic_codec.BasicCodec)
clientManager.arbitrator = arbitrator
client = test_hostInterface.client.StatusClient(clientManager)

while True:
    res = client.heartbeat()
    time.sleep(3)

host.py - the user end

import time
import sys
import threading

try:
    import erpc
except ImportError:
    print("Could not import erpc.\r\nPlease install it first by running \"python setup.py install\" in folder \"erpc/erpc_python/\".")
    sys.exit()

import test_hostInterface
import test_targetInterface

arbitrator = None

class AsyncStateServiceHandler(test_hostInterface.interface.IStatus):
    def heartbeat(self):
        print(f'heartbeat')


def thread_function():
    # run server
    handler = AsyncStateServiceHandler()
    service = test_hostInterface.server.StatusService(handler)
    server = erpc.simple_server.SimpleServer(arbitrator, erpc.basic_codec.BasicCodec)
    server.add_service(service)
    sys.stdout.flush()
    server.run()


transport = erpc.transport.SerialTransport("/home/user/socatpty1", 115200)
arbitrator = erpc.arbitrator.TransportArbitrator(transport, erpc.basic_codec.BasicCodec())

thread = threading.Thread(target=thread_function, args=())
thread.start()

clientManager = erpc.client.ClientManager(arbitrator.shared_transport, erpc.basic_codec.BasicCodec)
clientManager.arbitrator = arbitrator
client = test_targetInterface.client.CommandClient(clientManager)

while True:
    res = client.start_process()
    time.sleep(1)

@kpr-8
Copy link
Author

kpr-8 commented Nov 1, 2023

Something else I noticed, if I make all the rpc calls "oneway"

program test

@group("targetInterface")
interface Command
{
    oneway start_process()
}

@group("hostInterface")
interface Status
{
    oneway heartbeat()
}

Then I no longer need the arbitrator at either end and it works. Is this expected behaviour?

@Hadatko
Copy link
Member

Hadatko commented Nov 1, 2023

Hi @kpr-8 , i will take a look on your issue later.
Meanwhile related to oneway that make perfect sense. Oneway function means that you are sending data from one side to other side without waiting for answer. If you would expect answer then without arbirator client and server would wait for message and one of them would receive it (who will be first?)

@kpr-8
Copy link
Author

kpr-8 commented Nov 1, 2023

Sorry, I'm not sure I understand you. I think this could be useful in a command/response model, I just thought it was interesting that it worked

I really like erpc, I plan to use it in future projects. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests

2 participants