Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions lib/exmbus/parser/apl/data_record.ex
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ defmodule Exmbus.Parser.Apl.DataRecord do
@doc """
Decodes a single DataRecord from a binary.
"""
def parse(bin, opts, ctx) do
case Header.parse(bin, opts, ctx) do
def parse(bin, ctx) do
case Header.parse(bin, ctx) do
{:ok, %Header{} = header, rest} ->
case parse_data(header, rest) do
{:ok, data, rest} ->
Expand All @@ -64,8 +64,8 @@ defmodule Exmbus.Parser.Apl.DataRecord do
end
end

def unparse(opts, %__MODULE__{header: h, data: d}) do
with {:ok, h_bytes} <- Header.unparse(opts, h),
def unparse(%__MODULE__{header: h, data: d}) do
with {:ok, h_bytes} <- Header.unparse(h),
{:ok, d_bytes} <- unparse_data(h, d) do
{:ok, <<h_bytes::binary, d_bytes::binary>>}
end
Expand Down
6 changes: 3 additions & 3 deletions lib/exmbus/parser/apl/data_record/data_information_block.ex
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ defmodule Exmbus.Parser.Apl.DataRecord.DataInformationBlock do
size: nil
]

def unparse(_opts, %__MODULE__{device: 0, tariff: 0, storage: s} = dib) when s <= 1 do
def unparse(%__MODULE__{device: 0, tariff: 0, storage: s} = dib) when s <= 1 do
ff_int = encode_function_field(dib.function_field)
df_int = encode_data_field(dib.data_type, dib.size)
{:ok, <<0::1, s::1, ff_int::2, df_int::4>>}
end

def parse(<<special::4, 0b1111::4, rest::binary>>, _opts, _ctx) do
def parse(<<special::4, 0b1111::4, rest::binary>>, _ctx) do
# note that we are effectively stripping the least-significant bits of the dif which is
# always 0b1111 (i.e. 0xF) for special functions, so the following case only checks for the top
# 4 bits. In the manual these are written together (i.e. 0x0F), here we only write the MSB (0x0 instead of 0x0F)
Expand Down Expand Up @@ -64,7 +64,7 @@ defmodule Exmbus.Parser.Apl.DataRecord.DataInformationBlock do
end

# regular DIF parsing:
def parse(<<e::1, lsb_storage::1, ff::2, df::4, rest::binary>>, _opts, _ctx) do
def parse(<<e::1, lsb_storage::1, ff::2, df::4, rest::binary>>, _ctx) do
{:ok, device, tariff, msb_storage, rest} =
case e do
# if extensions, decode dife:
Expand Down
36 changes: 17 additions & 19 deletions lib/exmbus/parser/apl/data_record/header.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ defmodule Exmbus.Parser.Apl.DataRecord.Header do
@moduledoc """
This module represents the header of a DataRecord.
"""
alias Exmbus.Parser.Binary
alias Exmbus.Parser.Apl.DataRecord.DataInformationBlock, as: DIB
alias Exmbus.Parser.Apl.DataRecord.ValueInformationBlock, as: VIB

Expand Down Expand Up @@ -37,28 +36,27 @@ defmodule Exmbus.Parser.Apl.DataRecord.Header do
@doc """
Parses the next DataRecord Header from a binary.
"""
def parse(bin, opts, ctx) do
{:ok, dib_bytes, rest_after_dib} = Binary.collect_by_extension_bit(bin)

case DIB.parse(dib_bytes, opts, ctx) do
{:special_function, type, <<>>} ->
def parse(bin, ctx) do
case DIB.parse(bin, ctx) do
{:special_function, type, rest_after_dib} ->
# we just return the special function. The parser upstream will have to decide what to do,
# but there isn't a real header here. The APL layer knows what to do.
{:special_function, type, rest_after_dib}

{:ok, %DIB{} = dib, <<>>} ->
# {:ok, vib_bytes, rest_after_vib} = Binary.collect_by_extension_bit(rest_after_dib)
{:ok, %DIB{} = dib, rest_after_dib} ->
# We found a DataInformationBlock.
# We now expect a VIB to follow, which needs the context from the DIB to be able to parse
# correctly.
case VIB.parse(rest_after_dib, opts, %{ctx | dib: dib}) do
case VIB.parse(rest_after_dib, %{ctx | dib: dib}) do
{:ok, %VIB{} = vib, rest_after_vib} ->
vib_bytes =
binary_part(
rest_after_dib,
0,
byte_size(rest_after_dib) - byte_size(rest_after_vib)
)
dib_size = byte_size(bin) - byte_size(rest_after_dib)
vib_size = byte_size(rest_after_dib) - byte_size(rest_after_vib)

<<
dib_bytes::binary-size(dib_size),
vib_bytes::binary-size(vib_size),
_::binary
>> = bin

{:ok, coding} = summarize_coding(dib, vib)

Expand All @@ -84,15 +82,15 @@ defmodule Exmbus.Parser.Apl.DataRecord.Header do
}, rest_after_vib}
end

{:error, reason, <<>>} ->
{:error, reason, rest_after_dib} ->
{:ok, %InvalidHeader{error_message: "Parsing DIB failed: #{inspect(reason)}"},
rest_after_dib}
end
end

def unparse(opts, %__MODULE__{vib: vib, dib: dib}) do
with {:ok, vib_bytes} <- VIB.unparse(opts, vib),
{:ok, dib_bytes} <- DIB.unparse(opts, dib) do
def unparse(%__MODULE__{vib: vib, dib: dib}) do
with {:ok, vib_bytes} <- VIB.unparse(vib),
{:ok, dib_bytes} <- DIB.unparse(dib) do
{:ok, <<dib_bytes::binary, vib_bytes::binary>>}
end
end
Expand Down
10 changes: 5 additions & 5 deletions lib/exmbus/parser/apl/data_record/value_information_block.ex
Original file line number Diff line number Diff line change
Expand Up @@ -52,15 +52,15 @@ defmodule Exmbus.Parser.Apl.DataRecord.ValueInformationBlock do
table: nil
]

@spec parse(binary, opts :: map(), Context.t()) ::
@spec parse(binary, Context.t()) ::
{:ok, VIB.t(), rest :: binary} | {:error, any, binary}
def parse(bin, opts, ctx) do
def parse(bin, ctx) do
# delegate the parsing to the primary table
VifTableMain.parse(bin, opts, ctx)
VifTableMain.parse(bin, ctx)
end

# Basic unparse, main table, no extensions
def unparse(opts, %VIB{table: :main} = vib) do
VifTableMain.unparse(opts, vib)
def unparse(%VIB{table: :main} = vib) do
VifTableMain.unparse(vib)
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -8,38 +8,38 @@ defmodule Exmbus.Parser.Apl.DataRecord.ValueInformationBlock.VifTableFB do
alias Exmbus.Parser.Apl.DataRecord.ValueInformationBlock.Vife

# Table 0xFB from table 14 in EN 13757-3:2018 section 6.4.5
def parse(<<e::1, 0b000000::6, n::1, rest::binary>>, opts, ctx), do: Vife.parse(e, rest, opts, %{ctx| vib: %VIB{table: :fb, description: :energy, multiplier: pow10to(n-1), unit: "MWh"}})
def parse(<<e::1, 0b000001::6, n::1, rest::binary>>, opts, ctx), do: Vife.parse(e, rest, opts, %{ctx| vib: %VIB{table: :fb, description: :reactive_energy, multiplier: pow10to(n), unit: "kVARh"}})
def parse(<<e::1, 0b000010::6, n::1, rest::binary>>, opts, ctx), do: Vife.parse(e, rest, opts, %{ctx| vib: %VIB{table: :fb, description: :apparent_energy, multiplier: pow10to(n), unit: "kVAh"}})
def parse(<<e::1, 0b000011::6, _::1, rest::binary>>, _opts, ctx), do: Vife.error(e, rest, {:reserved, "VIF E000011n reserved"}, ctx)
def parse(<<e::1, 0b000100::6, n::1, rest::binary>>, opts, ctx), do: Vife.parse(e, rest, opts, %{ctx| vib: %VIB{table: :fb, description: :energy, multiplier: pow10to(n-1), unit: "GJ"}})
def parse(<<e::1, 0b000101::6, _::1, rest::binary>>, _opts, ctx), do: Vife.error(e, rest, {:reserved, "VIF E000101n reserved"}, ctx)
def parse(<<e::1, 0b00011::5, nn::2, rest::binary>>, opts, ctx), do: Vife.parse(e, rest, opts, %{ctx| vib: %VIB{table: :fb, description: :energy, multiplier: pow10to(nn-1), unit: "MCal"}})
def parse(<<e::1, 0b001000::6, n::1, rest::binary>>, opts, ctx), do: Vife.parse(e, rest, opts, %{ctx| vib: %VIB{table: :fb, description: :volume, multiplier: pow10to(n+2), unit: "m^3"}})
def parse(<<e::1, 0b001001::6, _::1, rest::binary>>, _opts, ctx), do: Vife.error(e, rest, {:reserved, "VIF E001001n reserved"}, ctx)
def parse(<<e::1, 0b00101::5, nn::2, rest::binary>>, opts, ctx), do: Vife.parse(e, rest, opts, %{ctx| vib: %VIB{table: :fb, description: :reactive_power, multiplier: pow10to(nn-3), unit: "kVAR"}})
def parse(<<e::1, 0b001100::6, n::1, rest::binary>>, opts, ctx), do: Vife.parse(e, rest, opts, %{ctx| vib: %VIB{table: :fb, coding: fb_remark_d(ctx), description: :mass, multiplier: pow10to(n+2), unit: "t"}})
def parse(<<e::1, 0b001101::6, n::1, rest::binary>>, opts, ctx), do: Vife.parse(e, rest, opts, %{ctx| vib: %VIB{table: :fb, coding: fb_remark_d(ctx), description: :relative_humidity, multiplier: pow10to(n-1), unit: "%"}})
def parse(<<e::1, n::7, rest::binary>>, _opts, ctx) when n >= 0b001_1100 and n <= 0b001_1111, do: Vife.error(e, rest, {:reserved, "VIF E0011100 - E0011111 reserved"}, ctx)
def parse(<<e::1, 0b0100000::7, rest::binary>>, opts, ctx), do: Vife.parse(e, rest, opts, %{ctx| vib: %VIB{table: :fb, description: :volume, unit: "ft^3"}})
def parse(<<e::1, 0b0100001::7, rest::binary>>, opts, ctx), do: Vife.parse(e, rest, opts, %{ctx| vib: %VIB{table: :fb, description: :volume, multiplier: 0.1, unit: "ft^3"}})
def parse(<<e::1, n::7, rest::binary>>, _opts, ctx) when n >= 0b010_0010 and n <= 0b010_0111, do: Vife.error(e, rest, {:reserved, "VIF E0100010 - E0100111 were used until 2004, now they are reserved for future use."}, ctx)
def parse(<<e::1, 0b010100::6, n::1, rest::binary>>, opts, ctx), do: Vife.parse(e, rest, opts, %{ctx| vib: %VIB{table: :fb, description: :power, multiplier: pow10to(n-1), unit: "MW"}})
def parse(<<e::1, 0b0101010::7, rest::binary>>, opts, ctx), do: Vife.parse(e, rest, opts, %{ctx| vib: %VIB{table: :fb, description: :phase_volt_to_volt, unit: "°"}})
def parse(<<e::1, 0b0101011::7, rest::binary>>, opts, ctx), do: Vife.parse(e, rest, opts, %{ctx| vib: %VIB{table: :fb, description: :phase_volt_to_current, unit: "°"}})
def parse(<<e::1, 0b01011::5, nn::2, rest::binary>>, opts, ctx), do: Vife.parse(e, rest, opts, %{ctx| vib: %VIB{table: :fb, description: :frequency, multiplier: pow10to(nn-3), unit: "Hz"}})
def parse(<<e::1, 0b011000::6, n::1, rest::binary>>, opts, ctx), do: Vife.parse(e, rest, opts, %{ctx| vib: %VIB{table: :fb, description: :power, multiplier: pow10to(n-1), unit: "GJ/h"}})
def parse(<<e::1, 0b011001::6, _::1, rest::binary>>, _opts, ctx), do: Vife.error(e, rest, {:reserved, "VIF E011001n reserved"}, ctx)
def parse(<<e::1, 0b01101::5, nn::2, rest::binary>>, opts, ctx), do: Vife.parse(e, rest, opts, %{ctx| vib: %VIB{table: :fb, description: :apparent_power, multiplier: pow10to(nn-3), unit: "kVA"}})
def parse(<<e::1, n::7, rest::binary>>, _opts, ctx) when n >= 0b0111000 and n <= 0b1010111, do: Vife.error(e, rest, {:reserved, "E0111000 - E1010111 reserved"}, ctx)
def parse(<<e::1, n::7, rest::binary>>, _opts, ctx) when n >= 0b010_0010 and n <= 0b010_0111, do: Vife.error(e, rest, {:reserved, "VIF E1011000 - E1100111 were used until 2004, now they are reserved for future use."}, ctx)
def parse(<<e::1, 0b11101::5, nn::2, rest::binary>>, opts, ctx), do: Vife.parse(e, rest, opts, %{ctx| vib: %VIB{table: :fb, description: :temperature_limit, multiplier: pow10to(nn-3), unit: "°C"}})
def parse(<<e::1, 0b1111::4, nnn::3, rest::binary>>, opts, ctx), do: Vife.parse(e, rest, opts, %{ctx| vib: %VIB{table: :fb, description: :cumulative_max_active_power, multiplier: pow10to(nnn-3), unit: "W"}})
def parse(<<e::1, 0b1101000::7, rest::binary>>, opts, ctx), do: Vife.parse(e, rest, opts, %{ctx| vib: %VIB{table: :fb, coding: fb_remark_d(ctx), description: :resulting_rating_factor_k, multiplier: pow2to(-12), unit: "units for HCA"}})
def parse(<<e::1, 0b1101001::7, rest::binary>>, opts, ctx), do: Vife.parse(e, rest, opts, %{ctx| vib: %VIB{table: :fb, coding: fb_remark_d(ctx), description: :thermal_output_rating_factor_kq, multiplier: pow2to(-12), unit: "W"}})
def parse(<<e::1, 0b000000::6, n::1, rest::binary>>, ctx), do: Vife.parse(e, rest, %{ctx| vib: %VIB{table: :fb, description: :energy, multiplier: pow10to(n-1), unit: "MWh"}})
def parse(<<e::1, 0b000001::6, n::1, rest::binary>>, ctx), do: Vife.parse(e, rest, %{ctx| vib: %VIB{table: :fb, description: :reactive_energy, multiplier: pow10to(n), unit: "kVARh"}})
def parse(<<e::1, 0b000010::6, n::1, rest::binary>>, ctx), do: Vife.parse(e, rest, %{ctx| vib: %VIB{table: :fb, description: :apparent_energy, multiplier: pow10to(n), unit: "kVAh"}})
def parse(<<e::1, 0b000011::6, _::1, rest::binary>>, ctx), do: Vife.error(e, rest, {:reserved, "VIF E000011n reserved"}, ctx)
def parse(<<e::1, 0b000100::6, n::1, rest::binary>>, ctx), do: Vife.parse(e, rest, %{ctx| vib: %VIB{table: :fb, description: :energy, multiplier: pow10to(n-1), unit: "GJ"}})
def parse(<<e::1, 0b000101::6, _::1, rest::binary>>, ctx), do: Vife.error(e, rest, {:reserved, "VIF E000101n reserved"}, ctx)
def parse(<<e::1, 0b00011::5, nn::2, rest::binary>>, ctx), do: Vife.parse(e, rest, %{ctx| vib: %VIB{table: :fb, description: :energy, multiplier: pow10to(nn-1), unit: "MCal"}})
def parse(<<e::1, 0b001000::6, n::1, rest::binary>>, ctx), do: Vife.parse(e, rest, %{ctx| vib: %VIB{table: :fb, description: :volume, multiplier: pow10to(n+2), unit: "m^3"}})
def parse(<<e::1, 0b001001::6, _::1, rest::binary>>, ctx), do: Vife.error(e, rest, {:reserved, "VIF E001001n reserved"}, ctx)
def parse(<<e::1, 0b00101::5, nn::2, rest::binary>>, ctx), do: Vife.parse(e, rest, %{ctx| vib: %VIB{table: :fb, description: :reactive_power, multiplier: pow10to(nn-3), unit: "kVAR"}})
def parse(<<e::1, 0b001100::6, n::1, rest::binary>>, ctx), do: Vife.parse(e, rest, %{ctx| vib: %VIB{table: :fb, coding: fb_remark_d(ctx), description: :mass, multiplier: pow10to(n+2), unit: "t"}})
def parse(<<e::1, 0b001101::6, n::1, rest::binary>>, ctx), do: Vife.parse(e, rest, %{ctx| vib: %VIB{table: :fb, coding: fb_remark_d(ctx), description: :relative_humidity, multiplier: pow10to(n-1), unit: "%"}})
def parse(<<e::1, n::7, rest::binary>>, ctx) when n >= 0b001_1100 and n <= 0b001_1111, do: Vife.error(e, rest, {:reserved, "VIF E0011100 - E0011111 reserved"}, ctx)
def parse(<<e::1, 0b0100000::7, rest::binary>>, ctx), do: Vife.parse(e, rest, %{ctx| vib: %VIB{table: :fb, description: :volume, unit: "ft^3"}})
def parse(<<e::1, 0b0100001::7, rest::binary>>, ctx), do: Vife.parse(e, rest, %{ctx| vib: %VIB{table: :fb, description: :volume, multiplier: 0.1, unit: "ft^3"}})
def parse(<<e::1, n::7, rest::binary>>, ctx) when n >= 0b010_0010 and n <= 0b010_0111, do: Vife.error(e, rest, {:reserved, "VIF E0100010 - E0100111 were used until 2004, now they are reserved for future use."}, ctx)
def parse(<<e::1, 0b010100::6, n::1, rest::binary>>, ctx), do: Vife.parse(e, rest, %{ctx| vib: %VIB{table: :fb, description: :power, multiplier: pow10to(n-1), unit: "MW"}})
def parse(<<e::1, 0b0101010::7, rest::binary>>, ctx), do: Vife.parse(e, rest, %{ctx| vib: %VIB{table: :fb, description: :phase_volt_to_volt, unit: "°"}})
def parse(<<e::1, 0b0101011::7, rest::binary>>, ctx), do: Vife.parse(e, rest, %{ctx| vib: %VIB{table: :fb, description: :phase_volt_to_current, unit: "°"}})
def parse(<<e::1, 0b01011::5, nn::2, rest::binary>>, ctx), do: Vife.parse(e, rest, %{ctx| vib: %VIB{table: :fb, description: :frequency, multiplier: pow10to(nn-3), unit: "Hz"}})
def parse(<<e::1, 0b011000::6, n::1, rest::binary>>, ctx), do: Vife.parse(e, rest, %{ctx| vib: %VIB{table: :fb, description: :power, multiplier: pow10to(n-1), unit: "GJ/h"}})
def parse(<<e::1, 0b011001::6, _::1, rest::binary>>, ctx), do: Vife.error(e, rest, {:reserved, "VIF E011001n reserved"}, ctx)
def parse(<<e::1, 0b01101::5, nn::2, rest::binary>>, ctx), do: Vife.parse(e, rest, %{ctx| vib: %VIB{table: :fb, description: :apparent_power, multiplier: pow10to(nn-3), unit: "kVA"}})
def parse(<<e::1, n::7, rest::binary>>, ctx) when n >= 0b0111000 and n <= 0b1010111, do: Vife.error(e, rest, {:reserved, "E0111000 - E1010111 reserved"}, ctx)
def parse(<<e::1, n::7, rest::binary>>, ctx) when n >= 0b010_0010 and n <= 0b010_0111, do: Vife.error(e, rest, {:reserved, "VIF E1011000 - E1100111 were used until 2004, now they are reserved for future use."}, ctx)
def parse(<<e::1, 0b11101::5, nn::2, rest::binary>>, ctx), do: Vife.parse(e, rest, %{ctx| vib: %VIB{table: :fb, description: :temperature_limit, multiplier: pow10to(nn-3), unit: "°C"}})
def parse(<<e::1, 0b1111::4, nnn::3, rest::binary>>, ctx), do: Vife.parse(e, rest, %{ctx| vib: %VIB{table: :fb, description: :cumulative_max_active_power, multiplier: pow10to(nnn-3), unit: "W"}})
def parse(<<e::1, 0b1101000::7, rest::binary>>, ctx), do: Vife.parse(e, rest, %{ctx| vib: %VIB{table: :fb, coding: fb_remark_d(ctx), description: :resulting_rating_factor_k, multiplier: pow2to(-12), unit: "units for HCA"}})
def parse(<<e::1, 0b1101001::7, rest::binary>>, ctx), do: Vife.parse(e, rest, %{ctx| vib: %VIB{table: :fb, coding: fb_remark_d(ctx), description: :thermal_output_rating_factor_kq, multiplier: pow2to(-12), unit: "W"}})
# skipping some HCA things here

def parse(<<vif, _rest::binary>>, _opts, ctx) do
def parse(<<vif, _rest::binary>>, ctx) do
raise "decoding from VIF linear extension table 0xFB not implemented. VIFE was: #{Exmbus.Debug.to_bits(vif)}, ctx was: #{inspect ctx}"
end

Expand Down
Loading
Loading