-
Notifications
You must be signed in to change notification settings - Fork 0
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
base: main
Are you sure you want to change the base?
Conversation
9106616
to
89919b9
Compare
89919b9
to
519954d
Compare
src/thingsboard.c
Outdated
{ | ||
int err; | ||
va_list param; | ||
char params[64]; |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
include/thingsboard.h
Outdated
* 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, ...); |
There was a problem hiding this comment.
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.
9c084a4
to
6b2062a
Compare
I added a sample and changed the RPC function to return an error code. |
4043849
to
7dd968c
Compare
There was a problem hiding this 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
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; | ||
} | ||
} |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
72f0946
to
84e562f
Compare
84e562f
to
e9c2e9d
Compare
a9de50a
to
06dd351
Compare
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