Add serial (UART) distribution support#2249
Add serial (UART) distribution support#2249pguyot wants to merge 1 commit intoatomvm:release-0.7from
Conversation
|
CI currently fails on newly merged riscv64 jit builds |
| %% | ||
| %% During the handshake phase, `send/2' and `recv/3' are called | ||
| %% synchronously. Packets are framed with a 2-byte big-endian length | ||
| %% prefix, matching the TCP distribution handshake format. |
There was a problem hiding this comment.
I really suggest adding at the end of a serial frame always a CRC32 at the end.
A more typical scenario is:
Start of Frame byte (like 0x55 or 0xAA) + Length + Payload + CRC32
Implement distributed Erlang over serial/UART connections, enabling disterl between devices connected via serial lines. Also fix net_kernel accept handler to support alternative carriers by wildcarding the family/protocol atoms instead of hardcoding inet/tcp. Also add `os.beam` to `estdlib.avm` fixing dialyzer errors. Signed-off-by: Paul Guyot <pguyot@kallisys.net>
|
usual caveats, pick and choose: PR Review: Add serial (UART) distribution supportCommit: SummaryImplements distributed Erlang over serial/UART connections, enabling disterl between devices connected via serial lines. Also fixes Files changed: 14 files, +1814 / -3 lines 🔴 High Priority Issues1. Simultaneous connect / stale setup race conditionFile: The link manager checks mailbox for Additionally, Suggested fix: Include target node in setup message for tie-breaking, prefer accept if inbound frame data is present, and monitor %% In serial_dist.erl — link_manager/4
link_manager(Kernel, UartPort, UartMod, Buffer) ->
%% Read UART first, then check for setup
UartMod:write(UartPort, ?SYNC_MAGIC),
NewBuffer =
case UartMod:read(UartPort, 500) of
{ok, Data} -> <<Buffer/binary, Data/binary>>;
{error, timeout} -> Buffer;
{error, Reason} -> exit({uart_read_error, Reason})
end,
case serial_dist_controller:scan_frame(NewBuffer, 16) of
{ok, _Payload, _Rest} ->
do_accept_handshake(Kernel, UartPort, UartMod, NewBuffer);
{crc_error, _} ->
link_manager(Kernel, UartPort, UartMod, <<>>);
{need_more, Trimmed} when byte_size(Trimmed) > 4 ->
do_accept_handshake(Kernel, UartPort, UartMod, Trimmed);
{need_more, Trimmed} ->
%% Only check setup AFTER confirming no inbound data
receive
{setup, SetupPid} ->
case is_process_alive(SetupPid) of
true -> do_setup_handshake(Kernel, UartPort, UartMod, SetupPid);
false -> link_manager(Kernel, UartPort, UartMod, Trimmed)
end
after 0 -> ok
end,
link_manager(Kernel, UartPort, UartMod, Trimmed)
end.2. UART write errors silently ignoredFile:
Suggested fix: %% handle_call({send, ...})
handle_call(
{send, Data},
_From,
#state{uart = Uart, uart_module = UartMod, sent = Sent} = State
) ->
DataBin = iolist_to_binary(Data),
DataSize = byte_size(DataBin),
case send_framed(UartMod, Uart, <<DataSize:16, DataBin/binary>>) of
ok ->
{reply, ok, State#state{sent = Sent + 1}};
{error, Reason} ->
{stop, {serial_write_error, Reason}, {error, Reason}, State}
end;
%% handle_cast(tick, ...)
handle_cast(tick, #state{uart = Uart, uart_module = UartMod, sent = Sent} = State) ->
case send_framed(UartMod, Uart, <<0:32>>) of
ok ->
{noreply, State#state{sent = Sent + 1}};
{error, Reason} ->
{stop, {serial_write_error, Reason}, State}
end;
%% send_data_loop/1
send_data_loop(#state{dhandle = DHandle, uart = Uart, uart_module = UartMod, sent = Sent} = State) ->
case erlang:dist_ctrl_get_data(DHandle) of
none ->
ok = erlang:dist_ctrl_get_data_notification(DHandle),
State;
Data ->
DataBin = ?PRE_PROCESS(Data),
DataSize = byte_size(DataBin),
case send_framed(UartMod, Uart, <<DataSize:32, DataBin/binary>>) of
ok ->
send_data_loop(State#state{sent = Sent + 1});
{error, Reason} ->
exit({serial_write_error, Reason})
end
end.3.
|
Implement distributed Erlang over serial/UART connections, enabling disterl between devices connected via serial lines.
Also fix net_kernel accept handler to support alternative carriers by wildcarding the family/protocol atoms instead of hardcoding inet/tcp.
Also add
os.beamtoestdlib.avmfixing dialyzer errors.These changes are made under both the "Apache 2.0" and the "GNU Lesser General
Public License 2.1 or later" license terms (dual license).
SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later