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

add function for RPC calls #22

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open

add function for RPC calls #22

wants to merge 7 commits into from

Conversation

twendtland
Copy link
Collaborator

@twendtland twendtland commented Nov 14, 2024

I made the params string optional, just because I like being able to omit arguments that are not necessary. If someone's not cool with that, I'm happy to make it a normal parameter

@twendtland twendtland force-pushed the feature/rpc branch 7 times, most recently from 9106616 to 89919b9 Compare November 14, 2024 15:47
@twendtland twendtland marked this pull request as ready for review November 14, 2024 16:13
{
int err;
va_list param;
char params[64];
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We of course don't know how long the parameters list will be but 64 characters seems very short to me. Maybe increase it a bit to 256 or something like that?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, you're right, this was the first thing I used for testing, it might well be too short. I will increase it

@@ -22,6 +24,7 @@ static struct {
K_SEM_DEFINE(time_sem, 0, 1);

static attr_write_callback_t attribute_cb;
static rpc_callback_t rpc_cb;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The callback will be overwritten by another one if the user calls thingsboad_rpc multiple times without waiting for the response. When the response arrives the wrong callback would be called.
Avoiding multiple RPCs in flight with a semaphore approach that you mentioned yesterday would probably solve this. Or just reset rpc_cb to NULL after it was called and return with an error from thingsboad_rpc() if rpc_cb is not NULL?

A nicer solution would be to allow simultaneous RPC calls by using a memory slab to store multiple callbacks (the same way coap_client.c manages multiple requests).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, the limitation is obvious. I will think about a solution, being able to do multiple RPC calls simultaneously seems like something that's not often used, but could come in handy.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would be fine with having this limitations as it is probably okay for most use cases. We should just document this and somehow enforce the "only one rpc at a time" rule to avoid weird behaviour (like wrong callback called) for the user.

* Parameters are an optional string in JSON format as the variadic arguments
* See https://thingsboard.io/docs/reference/coap-api/#client-side-rpc for details.
*/
void thingsboard_rpc(const char *method, rpc_callback_t cb, ...);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you have the time it would be great if you can add a sample for this in samples/, too.

@twendtland twendtland force-pushed the feature/rpc branch 4 times, most recently from 9c084a4 to 6b2062a Compare November 15, 2024 11:13
@twendtland
Copy link
Collaborator Author

I added a sample and changed the RPC function to return an error code.

@twendtland twendtland force-pushed the feature/rpc branch 2 times, most recently from 4043849 to 7dd968c Compare November 15, 2024 11:46
Copy link
Collaborator

@gumulka gumulka left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure, if we should also change our RPC code to already use your code to remove code duplicates and have a seconds example on how to use the RPC callbacks.

src/thingsboard.c Outdated Show resolved Hide resolved
src/thingsboard.c Outdated Show resolved Hide resolved
src/thingsboard.c Show resolved Hide resolved
src/thingsboard.c Show resolved Hide resolved
src/thingsboard.c Show resolved Hide resolved
src/thingsboard.c Outdated Show resolved Hide resolved
Comment on lines 253 to 228
if (k_sem_take(&rpc_sem, K_MSEC(5000)) > 0) {
// in case no response was ever received, reset the semaphore and continue
k_sem_reset(&rpc_sem);
err = k_sem_take(&rpc_sem, K_MSEC(50));
if (err > 0) {
LOG_ERR("failed to take RPC semaphore");
return err;
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if the way you inplemented it in the send routine is the right way to do it.

What I assume you want to do is: If there is no response within 5 seconds of sending, then just assume, that there was never a response and send the next message.

What you achieve: When trying to send a message, wait for 5 seconds before actually sending it, so that the old message is gone.

and if two threads try to send at nearly the same time, then the second thread will overwrite the callback for the first thread.

Copy link
Collaborator Author

@twendtland twendtland Nov 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure I can follow. assuming there is no ongoing request: why would the code wait for 5 seconds? 'take' would return immediately, as the semaphore is free. the second param to 'take' is a timeout, after all, isn't it?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the comparison should be fixed for that, ofc :D

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What I was hinting at was assume the following sequence of Events:
time in minute:seconds

0:00: call to thingsboard_rpc (1)
10:00: call to thingsboard_rpc (2)
10:04: call to thingsboard_rpc (3)

If we assume for 1 to not return, then 2 will wait 5 seconds for the semaphore, and at 10:05 it will reset the semaphore and take it.
Now it will create the request, overwrite the callback and return, making place for other threads to run.
3 will be scheduled to run, because the semaphore it was trying to take was reset, which in turn is an error on taking a semaphore, it will immediately reset the semaphore and take it, then send its own request overwriting the callback.

If we assume the response from 2 at 10:06, it is already to late, as the callback function has been overwritten by 3.

If you instead keep track on when you send out the request at the beginning, then you could reset the semaphore at 10:00, send your request, receive the answer at 10:01 and have no problems or conflicts with 3.

src/thingsboard.c Outdated Show resolved Hide resolved
src/thingsboard.c Outdated Show resolved Hide resolved
@twendtland twendtland force-pushed the feature/rpc branch 3 times, most recently from 72f0946 to 84e562f Compare November 18, 2024 14:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants