Skip to content

Support for Async Ethernet Mode#149

Open
umarbinzahid wants to merge 5 commits into
kaidokert:mainfrom
umarbinzahid:async_ethernet_mode
Open

Support for Async Ethernet Mode#149
umarbinzahid wants to merge 5 commits into
kaidokert:mainfrom
umarbinzahid:async_ethernet_mode

Conversation

@umarbinzahid

@umarbinzahid umarbinzahid commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

This PR adds support for Ethernet mode in async and implements an example using embassy-net to demonstrate the feature.

Summary by Sourcery

Add async Ethernet-mode support with embassy-net integration and refactor PRNG and Ethernet operations into reusable ops, updating both sync and async clients and providing new examples.

New Features:

  • Introduce async Ethernet packet send/receive APIs on AsyncClient, including an embassy-net driver implementation and a feather_async bypass_mode example.

Enhancements:

  • Refactor Ethernet receive and send paths to use new shared op types, modernizing timeouts and buffer handling, and reuse them from smoltcp and async paths.
  • Rename the internal net_ops module to ops and adjust references, and make the MAX_OCTETS_IN_MAC_ADDRESS constant reusable across modules.

Build:

  • Update dependencies in feather_async Cargo.toml and add optional embassy-net feature wiring for external TCP stacks.

Tests:

  • Extend unit tests for Ethernet paths, including Ethernet large buffers, empty buffers, and timeouts.

Summary by CodeRabbit

  • New Features

    • Added Ethernet/networking support for async client builds, including DHCP-based connectivity and packet send/receive capabilities.
    • Added a new embedded “Ethernet bypass mode” ping example with configurable Wi‑Fi credentials, target IP, ping count, and timeouts.
    • Added support for generating random bytes and retrieving the device MAC address in async flows.
  • Bug Fixes

    • Improved Ethernet receive timeout handling and connection/waker behavior for more reliable networking.

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds PRNG byte-generation and Ethernet packet operations to winc-rs's async/sync op framework, refactors the client Ethernet APIs around these operations, implements embassy_net_driver::Driver for AsyncClient with waker deduplication, and adds a feather_async bypass_mode ICMP ping example with embassy-net feature wiring.

Changes

PRNG, Ethernet ops, AsyncClient driver, examples

Layer / File(s) Summary
PrngOp and random-byte APIs
winc-rs/src/async_client/module.rs
Adds get_random_bytes built on PrngOp, changes get_winc_mac_address to take &self, and adds/adjusts tests for MAC address binding and PRNG timeout, success, chunking, and empty-buffer behavior.
Ethernet op primitives and client packet APIs
winc-rs/src/ops/net_ops/ethernet_receive.rs, winc-rs/src/ops/net_ops/mod.rs, winc-rs/src/ops/module/mod.rs, winc-rs/src/client/ethernet.rs, winc-rs/src/async_client/ethernet.rs (tests), winc-rs/src/manager/net_types.rs
Adds RxEthernetPacketInfo for chunked timed Ethernet receive, adds SyncOp::send_ethernet_packet, exports the new op module, and rewrites read_ethernet_packet/send_ethernet_packet/smoltcp receive to use &mut [u8]/Duration and the new ops, with matching tests.
AsyncClient embassy-net driver and wake handling
winc-rs/src/async_client/mod.rs, winc-rs/src/async_client/ethernet.rs, winc-rs/src/manager.rs, winc-rs/src/stack/socket_callbacks.rs, winc-rs/Cargo.toml
Adds async Ethernet read/send helpers, an embassy_net_driver::Driver impl with WincRxToken/WincTxToken, capabilities/link_state/hardware_address reporting, Manager::register_waker_if_new, a public conn_state field, and the embassy-net feature/dependency.
feather_async bypass_mode example
feather_async/Cargo.toml, feather_async/examples/bypass_mode.rs
Adds embassy-net, static_cell, portable-atomic dependencies and the external-tcp-stack feature, and adds a no_std example that waits for DHCP, runs an ICMP ping task, and wires up WiFi connection and the embassy-net stack.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related issues

Possibly related PRs

  • kaidokert/winc-rs#117: Extends the net_ops/OpImpl framework this PR builds RxEthernetPacketInfo/send_ethernet_packet on.
  • kaidokert/winc-rs#123: Both modify the same Ethernet send/receive plumbing in winc-rs/src/client/ethernet.rs.
  • kaidokert/winc-rs#131: Both touch Manager waker registration logic in winc-rs/src/manager.rs.

Suggested reviewers: kaidokert

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding async Ethernet mode support.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces embassy-net integration for the WINC Wi-Fi driver, adding Ethernet bypass mode and PRNG examples, reorganizing internal operations from net_ops to ops, and implementing the embassy_net_driver::Driver trait. Feedback on these changes highlights several critical issues in the async implementation: an infinite loop {} in the ping task will block the cooperative Embassy executor, and poll-count-based timeouts in both the Ethernet receive and PRNG operations will expire prematurely in tight async polling loops. Additionally, querying the MAC address synchronously on every hardware address request is highly inefficient and risks RefCell borrow panics, and the driver should dynamically report the link state rather than unconditionally returning LinkState::Up.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread feather_async/examples/bypass_mode.rs Outdated
Comment thread winc-rs/src/async_client/ethernet.rs
Comment thread winc-rs/src/async_client/ethernet.rs
Comment thread winc-rs/src/ops/module/prng.rs
Comment thread winc-rs/src/async_client/ethernet.rs
@umarbinzahid umarbinzahid marked this pull request as ready for review June 21, 2026 21:31

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Sorry @umarbinzahid, you have reached your weekly rate limit of 1500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@feather_async/examples/bypass_mode.rs`:
- Around line 101-103: The `loop {}` statement in the error handling block after
the `wait_for_dhcp(&stack).await` call is a busy-spin loop that starves the
cooperative executor. Replace this non-yielding infinite loop with a proper
async construct that yields control back to the executor, such as
`futures::future::pending().await`. Apply the same fix to the other instance of
`loop {}` mentioned at line 145 to ensure the executor can properly schedule
other tasks.
- Around line 166-169: The log statement at lines 166-169 is logging the
plaintext Wi-Fi password in the format string with the password parameter.
Remove the password variable from the log output by deleting the "with password:
{}" portion from the format string and removing the password argument from the
println! macro call. Only log the SSID network name to avoid exposing sensitive
credentials in debug logs and persisted traces.
- Line 63: The code on line 63 uses unwrap() on config.gateway which will panic
if the gateway is not present in the DHCP configuration. Instead of unwrapping,
use a safer approach such as unwrap_or() to provide a default gateway value
(like all zeros), or use an Option pattern to handle the case where gateway is
legitimately missing from the DHCP config. This ensures the code handles missing
gateways gracefully without panicking.
- Line 158: The u16::from_str(test_count).unwrap() call will panic if the input
is invalid, causing a hard crash instead of graceful error handling. Replace the
unwrap() call with the error propagation operator (?) to return the error up the
call stack, allowing the calling function to handle the parsing failure
appropriately. This converts a panic into a recoverable error condition that can
be handled by the caller.

In `@winc-rs/src/async_client/ethernet.rs`:
- Around line 16-18: The documentation for the `read_ethernet_packet` method
currently describes the `buffer` parameter as a required mutable slice, but the
actual function signature defines it as `Option<&mut [u8]>` which is optional.
Update the doc comment for the `buffer` parameter to clarify that it is optional
and describe what happens when `None` is passed (typically using the default
buffer or behavior). Apply the same documentation fix to all other occurrences
of this parameter documentation in the method.
- Around line 103-107: The error handling in the poll_once result block treats
all errors the same by returning None, which masks real module/transport faults
and makes diagnostics difficult. Instead of using a simple else block that
returns None for all errors, match on the specific error types returned from
poll_once: keep GeneralTimeout errors as "no packet" (returning None silently),
but explicitly log any other unexpected errors with their details before
returning None, so real faults are visible in the logs rather than silently
hidden.

In `@winc-rs/src/ops/module/prng.rs`:
- Around line 72-73: The send_prng function calls are passing incorrect pointer
addresses. At line 72, the call passes the address of the temporary Prng struct
itself rather than the actual buffer data it contains, and at line 96 a similar
issue occurs with the slice reference. Instead of using the struct address or
reference address with pointer casts, obtain the actual buffer pointer using
as_ptr() method on the underlying buffer data within the Prng struct, then cast
that address to u32 for both send_prng calls. This ensures the firmware receives
the correct buffer address as expected by the wire protocol.

In `@winc-rs/src/ops/net_ops/ethernet_receive.rs`:
- Around line 57-60: In the timeout conversion calculation on the line with
manager.set_operation_timeout, the expression (timeout_ms * 1000) / 100 can
overflow when timeout_ms is large because the multiplication happens before the
division. Cast timeout_ms to u64 before performing the multiplication to prevent
overflow, ensuring the intermediate result fits safely before the final division
and conversion back to the required type for set_operation_timeout.
- Around line 63-87: When the caller passes an empty buffer (length 0), the code
calculates len_to_read as 0, which leaves rx_done as false (since 0 is not >=
info.packet_size), resulting in no state advancement (data_offset and
packet_size both remain unchanged) while callbacks.eth_rx_info stays active.
This causes the receive operation to get stuck in the same state on the next
call. Add an explicit check after calculating len_to_read to detect when it is 0
and handle this case by clearing callbacks.eth_rx_info to prevent the stuck
receive state, ensuring the operation doesn't loop indefinitely on an empty
buffer scenario.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 15441869-3b2b-4f98-93c6-f7599547af37

📥 Commits

Reviewing files that changed from the base of the PR and between bb6c479 and 0d5d24b.

📒 Files selected for processing (34)
  • feather_async/Cargo.toml
  • feather_async/examples/bypass_mode.rs
  • feather_async/examples/prng.rs
  • winc-rs/Cargo.toml
  • winc-rs/src/async_client/dns.rs
  • winc-rs/src/async_client/ethernet.rs
  • winc-rs/src/async_client/mod.rs
  • winc-rs/src/async_client/module.rs
  • winc-rs/src/async_client/tcp_stack.rs
  • winc-rs/src/async_client/udp_stack.rs
  • winc-rs/src/client.rs
  • winc-rs/src/client/dns.rs
  • winc-rs/src/client/ethernet.rs
  • winc-rs/src/client/prng.rs
  • winc-rs/src/client/tcp_stack.rs
  • winc-rs/src/client/udp_stack.rs
  • winc-rs/src/client/wifi_module.rs
  • winc-rs/src/lib.rs
  • winc-rs/src/manager.rs
  • winc-rs/src/manager/net_types.rs
  • winc-rs/src/ops/mod.rs
  • winc-rs/src/ops/module/mod.rs
  • winc-rs/src/ops/module/prng.rs
  • winc-rs/src/ops/net_ops/dns.rs
  • winc-rs/src/ops/net_ops/ethernet_receive.rs
  • winc-rs/src/ops/net_ops/mod.rs
  • winc-rs/src/ops/net_ops/tcp_accept.rs
  • winc-rs/src/ops/net_ops/tcp_connect.rs
  • winc-rs/src/ops/net_ops/tcp_receive.rs
  • winc-rs/src/ops/net_ops/tcp_send.rs
  • winc-rs/src/ops/net_ops/udp_receive.rs
  • winc-rs/src/ops/net_ops/udp_send.rs
  • winc-rs/src/ops/op.rs
  • winc-rs/src/stack/socket_callbacks.rs

Comment thread feather_async/examples/bypass_mode.rs Outdated
Comment thread feather_async/examples/bypass_mode.rs Outdated
Comment thread feather_async/examples/bypass_mode.rs Outdated
Comment thread feather_async/examples/bypass_mode.rs
Comment thread winc-rs/src/async_client/ethernet.rs
Comment thread winc-rs/src/async_client/ethernet.rs
Comment thread winc-rs/src/ops/module/prng.rs Outdated
Comment thread winc-rs/src/ops/net_ops/ethernet_receive.rs
Comment thread winc-rs/src/ops/net_ops/ethernet_receive.rs
@umarbinzahid umarbinzahid changed the title Suport for Async Ethernet Mode Support for Async Ethernet Mode Jul 5, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
winc-rs/src/async_client/ethernet.rs (2)

96-124: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Register the RX waker before polling

A packet that arrives in the gap between poll_once() and register_waker_if_new() can miss the wakeup, leaving the driver asleep with data ready.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@winc-rs/src/async_client/ethernet.rs` around lines 96 - 124, The RX path in
EthernetAsyncClient::poll_next registers the waker too late, after poll_once(),
which can miss a packet arrival in the gap. Move the
register_waker_if_new(cx.waker().clone()) call to before polling for
RxEthernetPacketInfo, and keep the existing unregister_waker(cx.waker())
handling after a packet is received to preserve wakeup correctness.

167-173: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Avoid a shared fallback MAC address. On MAC read failure, every affected device still reports DEFAULT_MAC_ADDRESS, which can collide on the network and break DHCP/ARP. Use a device-unique locally administered fallback or keep the interface down until the WINC MAC is available.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@winc-rs/src/async_client/ethernet.rs` around lines 167 - 173, The MAC
fallback in `AsyncEthernetClient::hardware_address`/`get_winc_mac_address`
currently returns `DEFAULT_MAC_ADDRESS` on failure, which can cause multiple
devices to share the same address. Change the failure path to avoid a shared
fallback by generating a device-unique locally administered MAC or by leaving
the interface unavailable until a valid WINC MAC is read, and keep the behavior
localized to the MAC read handling in `ethernet.rs`.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@winc-rs/src/async_client/ethernet.rs`:
- Around line 96-124: The RX path in EthernetAsyncClient::poll_next registers
the waker too late, after poll_once(), which can miss a packet arrival in the
gap. Move the register_waker_if_new(cx.waker().clone()) call to before polling
for RxEthernetPacketInfo, and keep the existing unregister_waker(cx.waker())
handling after a packet is received to preserve wakeup correctness.
- Around line 167-173: The MAC fallback in
`AsyncEthernetClient::hardware_address`/`get_winc_mac_address` currently returns
`DEFAULT_MAC_ADDRESS` on failure, which can cause multiple devices to share the
same address. Change the failure path to avoid a shared fallback by generating a
device-unique locally administered MAC or by leaving the interface unavailable
until a valid WINC MAC is read, and keep the behavior localized to the MAC read
handling in `ethernet.rs`.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8b6aa0c9-7a06-42c4-8c04-20cf19a4a18c

📥 Commits

Reviewing files that changed from the base of the PR and between 0d5d24b and b8def6f.

📒 Files selected for processing (4)
  • feather_async/Cargo.toml
  • feather_async/examples/bypass_mode.rs
  • winc-rs/src/async_client/ethernet.rs
  • winc-rs/src/manager.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • winc-rs/src/manager.rs
  • feather_async/examples/bypass_mode.rs

@umarbinzahid umarbinzahid force-pushed the async_ethernet_mode branch from b8def6f to f800de0 Compare July 5, 2026 21:02
@kaidokert

Copy link
Copy Markdown
Owner

This one also needs a rebase now

@umarbinzahid umarbinzahid force-pushed the async_ethernet_mode branch from f800de0 to d7cc5e2 Compare July 9, 2026 11:19
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.

2 participants