defmodule RtuFramer do
  use ExUnit.Case
  alias Circuits.UART

  @moduledoc """
  These tests only runs if 'tty0tty' is installed in the host computer.
  """
  test "Framer test for fc => [1, 2, 3, 4, 5, 6, 15, 16]" do
    # Raw initialization.
    # RingLogger.attach()
    {:ok, m_pid} = UART.start_link()
    {:ok, s_pid} = UART.start_link()

    UART.open(m_pid, "tnt0", speed: 115_200, framing: {Modbux.Rtu.Framer, behavior: :master})
    UART.open(s_pid, "tnt1", speed: 115_200, framing: {Modbux.Rtu.Framer, behavior: :slave})

    # Master Requests.
    # Read Coil Status (FC=01)
    fc = <<0x11, 0x01, 0x00, 0x13, 0x00, 0x25, 0x0E, 0x84>>
    UART.write(m_pid, fc)
    assert_receive {circuits_uart, "tnt1", fc}

    # Read Input Status (FC=02)
    fc = <<0x11, 0x02, 0x00, 0xC4, 0x00, 0x16, 0xBA, 0xA9>>
    UART.write(m_pid, fc)
    assert_receive {circuits_uart, "tnt1", fc}

    # Read Holding Registers (FC=03)
    fc = <<0x11, 0x03, 0x00, 0x6B, 0x00, 0x03, 0x76, 0x87>>
    UART.write(m_pid, fc)
    assert_receive {circuits_uart, "tnt1", fc}

    # Read Input Registers (FC=04)
    fc = <<0x11, 0x04, 0x00, 0x08, 0x00, 0x01, 0xB2, 0x98>>
    UART.write(m_pid, fc)
    assert_receive {circuits_uart, "tnt1", fc}

    # Force Single Coil (FC=05)
    fc = <<0x11, 0x05, 0x00, 0xAC, 0xFF, 0x00, 0x4E, 0x8B>>
    UART.write(m_pid, fc)
    assert_receive {circuits_uart, "tnt1", fc}

    # Preset Single Register (FC=06)
    fc = <<0x11, 0x06, 0x00, 0x01, 0x00, 0x03, 0x9A, 0x9B>>
    UART.write(m_pid, fc)
    assert_receive {circuits_uart, "tnt1", fc}

    # Force Multiple Coils (FC=15)
    fc = <<0x11, 0x0F, 0x00, 0x13, 0x00, 0x0A, 0x02, 0xCD, 0x01, 0xBF, 0x0B>>
    UART.write(m_pid, fc)
    assert_receive {circuits_uart, "tnt1", fc}

    # Preset Multiple Registers (FC=16)
    fc = <<0x11, 0x10, 0x00, 0x01, 0x00, 0x02, 0x04, 0x00, 0x0A, 0x01, 0x02, 0xC6, 0xF0>>
    UART.write(m_pid, fc)
    assert_receive {circuits_uart, "tnt1", fc}

    # Exception
    excep = <<0x0A, 0x81, 0x02, 0xB0, 0x53>>
    UART.write(m_pid, excep)
    assert_receive {circuits_uart, "tnt1", excep}

    excep = <<0x11, 0x10, 0x00, 0x01, 0x00, 0x02, 0x04, 0x00, 0x0A, 0x01, 0x02, 0xC6, 0x1>>
    UART.write(m_pid, excep)
    assert_receive {:circuits_uart, "tnt1", {:error, :ecrc, "CRC Error"}}

    # Server Response.
    # Read Coil Status (FC=01)
    resp = <<0x11, 0x01, 0x05, 0xCD, 0x6B, 0xB2, 0x0E, 0x1B, 0x45, 0xE6>>
    UART.write(s_pid, resp)
    assert_receive {circuits_uart, "tnt0", resp}

    # Read Input Status (FC=02)
    resp = <<0x11, 0x02, 0x03, 0xAC, 0xDB, 0x35, 0x20, 0x18>>
    UART.write(s_pid, resp)
    assert_receive {circuits_uart, "tnt0", resp}

    # Read Holding Registers (FC=03)
    resp = <<0x11, 0x03, 0x06, 0xAE, 0x41, 0x56, 0x52, 0x43, 0x40, 0x49, 0xAD>>
    UART.write(s_pid, resp)
    assert_receive {circuits_uart, "tnt0", resp}

    # Read Input Registers (FC=04)
    resp = <<0x11, 0x04, 0x02, 0x00, 0x0A, 0xF8, 0xF4>>
    UART.write(s_pid, resp)
    assert_receive {circuits_uart, "tnt0", resp}

    # Force Single Coil (FC=05)
    resp = <<0x11, 0x05, 0x00, 0xAC, 0xFF, 0x00, 0x4E, 0x8B>>
    UART.write(s_pid, resp)
    assert_receive {circuits_uart, "tnt0", resp}

    # Preset Single Register (FC=06)
    resp = <<0x11, 0x06, 0x00, 0x01, 0x00, 0x03, 0x9A, 0x9B>>
    UART.write(s_pid, resp)
    assert_receive {circuits_uart, "tnt0", resp}

    # Force Multiple Coils (FC=15)
    resp = <<0x11, 0x0F, 0x00, 0x13, 0x00, 0x0A, 0x26, 0x99>>
    UART.write(s_pid, resp)
    assert_receive {circuits_uart, "tnt0", resp}

    # Preset Multiple Registers (FC=16)
    resp = <<0x11, 0x10, 0x00, 0x01, 0x00, 0x02, 0x12, 0x98>>
    UART.write(s_pid, resp)
    assert_receive {circuits_uart, "tnt0", resp}
  end
end
