defmodule Modbux.IEEE754 do
@moduledoc """
IEEE754 float helper
Based on https://www.h-schmidt.net/FloatConverter/IEEE754.html.
"""
@doc """
Converts a couple of 16-bit registers to IEEE754 float.
## Example
```elixir
+5.0 = IEEE754.from_2_regs(0x40a0, 0x0000, :be)
```
"""
def from_2_regs(w0, w1, :be) do
<<value::float-32>> = <<w0::16, w1::16>>
value
end
def from_2_regs(w0, w1, :le) do
<<value::float-32>> = <<w1::16, w0::16>>
value
end
@doc """
Converts a couple of 16-bit registers to IEEE754 float.
## Example
```elixir
+5.0 = IEEE754.from_2_regs(0x40a0, 0x0000, :be)
```
"""
def from_2_regs([w0, w1], :be) do
<<f::float-32>> = <<w0::16, w1::16>>
f
end
def from_2_regs([w0, w1], :le) do
<<f::float-32>> = <<w1::16, w0::16>>
f
end
@doc """
Converts a list of 2n 16-bit registers to a IEEE754 floats list.
## Example
```elixir
[-5.0, +5.0] = IEEE754.from_2n_regs([0xc0a0, 0x0000, 0x40a0, 0x0000], :be)
```
"""
def from_2n_regs([], _), do: []
def from_2n_regs([w0, w1 | tail], endianness) do
[from_2_regs(w0, w1, endianness) | from_2n_regs(tail, endianness)]
end
@doc """
Converts a IEEE754 float to a couple of 16-bit registers.
## Example
```elixir
[0xc0a0, 0x0000] = IEEE754.to_2_regs(-5.0)
```
"""
def to_2_regs(f, :be) do
<<w0::16, w1::16>> = <<f::float-32>>
[w0, w1]
end
def to_2_regs(f, :le) do
<<w0::16, w1::16>> = <<f::float-32>>
[w1, w0]
end
@doc """
Converts a list of IEEE754 floats to a list of 2n 16-bit registers.
## Example
```elixir
[0xc0a0, 0x0000, 0x40a0, 0x0000] = IEEE754.to_2n_regs([-5.0, +5.0])
```
"""
def to_2n_regs([], _), do: []
def to_2n_regs([f | tail], endianness) do
[w0, w1] = to_2_regs(f, endianness)
[w0, w1 | to_2n_regs(tail, endianness)]
end
end