-
Notifications
You must be signed in to change notification settings - Fork 1
14 add a class for udp client #20
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
base: main
Are you sure you want to change the base?
Conversation
mod: beginPacket sets remotes' IP/port
feat: implemented remaining methods impr: threading
mod: read stops if no remaining bytes mod: peek works only per-udp-packet impr: stop calls only if connected
…p-client # Conflicts: # src/Arduino_RouterBridge.h # src/tcp_client.h
|
Memory usage change @ 79f5565
Click for full report table
Click for full report CSV |
src/udp_bridge.h
Outdated
| } | ||
|
|
||
| uint8_t beginMulticast(IPAddress ip, uint16_t port) override { | ||
|
|
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.
Why do some methods have this extra blank line at the beginning? Personally, I'd like to remove it because it's really odd to have this double standard; the blanks in the middle of a method may make sense, but at least we could spare the blank at the beginning of the function.
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.
done in:
1037bd9
src/udp_bridge.h
Outdated
| k_mutex_lock(&udp_mutex, K_FOREVER); | ||
|
|
||
| String hostname = ip.toString(); | ||
| const bool ok = _connected || bridge->call(UDP_CONNECT_MULTI_METHOD, hostname, port).result(connection_id); |
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.
Same concerns as for the begin(port)
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.
see
1037bd9
|
|
||
| if (_connected) { | ||
| String msg; | ||
| _connected = !bridge->call(UDP_CLOSE_METHOD, connection_id).result(msg); |
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 udp/close will always close the connection and drop the connection_id on the Linux side.
| _connected = !bridge->call(UDP_CLOSE_METHOD, connection_id).result(msg); | |
| bridge->call(UDP_CLOSE_METHOD, connection_id).result(msg); | |
| _connected = false; |
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.
This is just to make sure the bridge->call went through without errors on the other side
src/udp_bridge.h
Outdated
|
|
||
| if (!connected()) return 0; | ||
|
|
||
| MsgPack::arr_t<uint8_t> payload; | ||
|
|
||
| for (size_t i = 0; i < size; ++i) { | ||
| payload.push_back(buffer[i]); | ||
| } | ||
|
|
||
| size_t written; | ||
| const bool ok = bridge->call(UDP_WRITE_METHOD, connection_id, _targetHost, _targetPort, payload).result(written); | ||
| return ok? written : 0; |
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 believe this isn't the intended use of this API. Once you use beginPacket, all subsequent write calls will add data to that packet, and it will be sent in one go as a single UDP packet when endPacket is called.
The call to udp/write must be done in the endPacket method.
In other words, the following:
udp.beginPacket("1.2.3.4", 1234);
udp.write("hello", 5);
udp.endPacket();must be equivalent to:
udp.beginPacket("1.2.3.4", 1234);
udp.write("hel", 3);
udp.write("l", 1);
udp.write("o", 1);
udp.endPacket();
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.
This depends on how the other side handles the udp/write method (ie always requiring IP and port).
Besides if the udpBridge library is meant to hold the UDP packet in a buffer up until the user is ready to send, then such buffer should be the max size of a UDP packet (64k)
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.
Should we extend the UDP API on the router to handle multiple writes? (as we did for the reading side)
|
|
||
| // if (async_res.error.code > NO_ERR) { | ||
| // _connected = false; | ||
| // } |
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 (async_res.error.code > NO_ERR) { | |
| // _connected = false; | |
| // } |
| k_mutex_lock(&udp_mutex, K_FOREVER); | ||
|
|
||
| String hostname = "0.0.0.0"; | ||
| const bool ok = _connected || bridge->call(UDP_CONNECT_METHOD, hostname, port).result(connection_id); | ||
| _connected = ok; | ||
| if (_connected) _port = port; | ||
|
|
||
| k_mutex_unlock(&udp_mutex); |
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 I read this correctly, a double call to begin(port) will return 1 (aka success) even if the second operation would be a no-op:
udp.begin(3000); // returns 1
udp.begin(4444); // returns 1 as well, but 0 is expected
I would expect a return value of 0 in the second call. Additionally, the internal field _port is updated to the value 4444, while the UDP listener on the Linux side remains unchanged.
| k_mutex_lock(&udp_mutex, K_FOREVER); | |
| String hostname = "0.0.0.0"; | |
| const bool ok = _connected || bridge->call(UDP_CONNECT_METHOD, hostname, port).result(connection_id); | |
| _connected = ok; | |
| if (_connected) _port = port; | |
| k_mutex_unlock(&udp_mutex); | |
| k_mutex_lock(&udp_mutex, K_FOREVER); | |
| bool ok = false; | |
| if (!_connected) { | |
| String hostname = "0.0.0.0"; | |
| ok = bridge->call(UDP_CONNECT_METHOD, hostname, port).result(connection_id); | |
| if (ok) { | |
| _port = port; | |
| _connected = true; | |
| } | |
| } | |
| k_mutex_unlock(&udp_mutex); |
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.
you are right. It should be fixed here:
1037bd9
| int parsePacket() override { | ||
| k_mutex_lock(&udp_mutex, K_FOREVER); | ||
|
|
||
| while (_remaining) read(); // ensure previous packet is read |
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.
This isn't necessary; the RPC API can skip the current UDP packet being read, even if it is not fully consumed.
You can simply set _remaining to 0, with some buffer cleanup if necessary, which should be much quicker than processing the entire packet.
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 call to read() is meant just for flushing in this context.
Again this is a problem of sync between the two sides.
If MCU is not interested in a packet anymore and such packet was not entirely received via RPCs then the MCU should have a method to signal this to the other side.
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.
Calling udp/awaitRead on the router will automatically drop the unread packet on the Linux side.
You can partially read a packet and await the next one; the piece that you didn't read is lost, but this is allowed on the router API.
| RpcResult async_res = bridge->call(UDP_AWAIT_READ_METHOD, connection_id, read_timeout); | ||
| const bool ret = _connected && async_res.result(packet_meta); |
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.
| RpcResult async_res = bridge->call(UDP_AWAIT_READ_METHOD, connection_id, read_timeout); | |
| const bool ret = _connected && async_res.result(packet_meta); | |
| const bool ret = _connected && bridge->call(UDP_AWAIT_READ_METHOD, connection_id, read_timeout).result(packet_meta); |
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.
This makes no difference.
async_res could be used later for error handling
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.
It seems a bit weird to create an async_res object that may not be consumed later, if _connected is false the && operation is short-circuited and the result method is not called.
|
Memory usage change @ 1037bd9
Click for full report table
Click for full report CSV |
UDP class
This PR is also an API proposal of the following CPU-side methods: