# SPDX-FileCopyrightText: 2016 Frank Hunleth # SPDX-FileCopyrightText: 2018 Adam Kohring # SPDX-FileCopyrightText: 2018 Jon Carstens # SPDX-FileCopyrightText: 2021 Chris D'Ambrosio # # SPDX-License-Identifier: Apache-2.0 # Code.require_file("uart_test.exs", __DIR__) defmodule FramingTest do use ExUnit.Case alias Circuits.UART @moduledoc """ These tests are high level framing tests. See `framing_*_test.exs` for unit tests. """ setup do UARTTest.common_setup() end @tag skip: "Fix test on Windows" test "receive a line in passive mode", %{uart1: uart1, uart2: uart2} do assert :ok = UART.open(uart1, UARTTest.port1()) assert :ok = UART.open( uart2, UARTTest.port2(), active: false, framing: { UART.Framing.Line, max_length: 4 } ) # Send something that's not a line and check that we don't receive it assert :ok = UART.write(uart1, "A") assert {:ok, <<>>} = UART.read(uart2, 500) # Terminate the line and check that receive gets it assert :ok = UART.write(uart1, "\n") assert {:ok, "A"} = UART.read(uart2) # Send two lines assert :ok = UART.write(uart1, "B\nC\n") assert {:ok, "B"} = UART.read(uart2, 500) assert {:ok, "C"} = UART.read(uart2, 500) # Handle a line that's too long assert :ok = UART.write(uart1, "DEFGHIJK\n") assert {:ok, {:partial, "DEFG"}} = UART.read(uart2, 500) assert {:ok, "HIJK"} = UART.read(uart2, 500) UART.close(uart1) UART.close(uart2) end test "framing gets applied when transmitting", %{uart1: uart1, uart2: uart2} do assert :ok = UART.open(uart1, UARTTest.port1(), framing: UART.Framing.Line) assert :ok = UART.open(uart2, UARTTest.port2(), active: false) # Transmit something and check that a linefeed gets applied assert :ok = UART.write(uart1, "A") :timer.sleep(100) assert {:ok, "A\n"} = UART.read(uart2) UART.close(uart1) UART.close(uart2) end test "multiple read polls do not elapse the specified read timeout", %{ uart1: uart1, uart2: uart2 } do assert :ok = UART.open(uart1, UARTTest.port1()) assert :ok = UART.open( uart2, UARTTest.port2(), active: false, framing: { UART.Framing.Line, max_length: 4 } ) spawn(fn -> # Sleep to allow the UART.read some time to begin reading :timer.sleep(100) # Send something that's not a line assert :ok = UART.write(uart1, "A") end) assert {:ok, <<>>} = UART.read(uart2, 500) end test "framing timeouts in passive mode", %{uart1: uart1, uart2: uart2} do assert :ok = UART.open(uart1, UARTTest.port1()) assert :ok = UART.open( uart2, UARTTest.port2(), active: false, framing: {UART.Framing.Line, max_length: 10}, rx_framing_timeout: 100 ) # Send something that's not a line and check that it times out assert :ok = UART.write(uart1, "A") # Initial read will timeout and the partial read will be queued in the uart state assert {:ok, <<>>} = UART.read(uart2, 200) # Call read again to fetch the queued data assert {:ok, {:partial, "A"}} = UART.read(uart2, 200) UART.close(uart1) UART.close(uart2) end test "receive a line in active mode", %{uart1: uart1, uart2: uart2} do assert :ok = UART.open(uart1, UARTTest.port1()) assert :ok = UART.open( uart2, UARTTest.port2(), active: true, framing: { UART.Framing.Line, max_length: 4 } ) port2 = UARTTest.port2() # Send something that's not a line and check that we don't receive it assert :ok = UART.write(uart1, "A") refute_receive {:circuits_uart, _, _} # Terminate the line and check that receive gets it assert :ok = UART.write(uart1, "\n") # QUESTION: Trim the framing or not? # Argument to trim: 1. the framing is at a lower level # 2. framing could contain stuffing, compression, etc. # that would need to be undone anyway. not removing # the framing would effectively mean that the # framing gets removed twice. # 3. Erlang ports remove their framing # Argument not to trim: 1. most framing is easy to trim anyway # 2. easier to debug? assert_receive {:circuits_uart, ^port2, "A"} # Send two lines assert :ok = UART.write(uart1, "B\nC\n") assert_receive {:circuits_uart, ^port2, "B"} assert_receive {:circuits_uart, ^port2, "C"} # Handle a line that's too long assert :ok = UART.write(uart1, "DEFGHIJK\n") assert_receive {:circuits_uart, ^port2, {:partial, "DEFG"}} assert_receive {:circuits_uart, ^port2, "HIJK"} UART.close(uart1) UART.close(uart2) end test "framing timeouts in active mode", %{uart1: uart1, uart2: uart2} do assert :ok = UART.open(uart1, UARTTest.port1()) assert :ok = UART.open( uart2, UARTTest.port2(), active: true, framing: {UART.Framing.Line, max_length: 10}, rx_framing_timeout: 500 ) port2 = UARTTest.port2() # Send something that's not a line and check that it times out assert :ok = UART.write(uart1, "A") assert_receive {:circuits_uart, ^port2, {:partial, "A"}}, 1000 UART.close(uart1) UART.close(uart2) end test "active mode gets error when write fails", %{uart1: uart1} do # This only works with tty0tty since it fails write operations if no # receiver. if String.starts_with?(UARTTest.port1(), "tnt") do assert :ok = UART.open(uart1, UARTTest.port1(), active: true, framing: UART.Framing.Line) port1 = UARTTest.port1() assert {:error, errno} = UART.write(uart1, "a", 0) assert errno in [:einval, :eagain] assert_receive {:circuits_uart, ^port1, {:error, _einval_or_eagain}} UART.close(uart1) end end end