Current section

Files

Jump to
crc lib crc.ex
Raw

lib/crc.ex

defmodule CRC do
@moduledoc """
This module is used to calculate CRC (Cyclic Redundancy Check) values
for binary data. It uses NIF functions written in C to interate over
the given binary calculating the CRC checksum value.
CRC implementations have been tested against these online calculators to
validate their correctness to the best of our ability.
https://www.lammertbies.nl/comm/info/crc-calculation.html
http://www.sunshine2k.de/coding/javascript/crc/crc_js.html
"""
@spec crc(:crc_algorithm.params(), iodata()) :: :crc_algorithm.value()
defdelegate crc(params, input), to: :crc
@spec crc_init(:crc_algorithm.params()) :: :crc_algorithm.resource()
defdelegate crc_init(params), to: :crc
@spec crc_update(:crc_algorithm.resource(), iodata()) :: :crc_algorithm.resource()
defdelegate crc_update(resource, input), to: :crc
@spec crc_final(:crc_algorithm.resource()) :: :crc_algorithm.value()
defdelegate crc_final(resource), to: :crc
@doc """
Returns a list of all the pre-defined CRC models
"""
@spec list() :: [{atom, String.t}]
def list() do
:crc_nif.crc_list()
|> Map.to_list()
|> Enum.map(fn {model, map} -> {model, Map.get(map, model)} end)
end
@doc """
Returns a list of all pre-defined CRC Models that match the filter given.
Filter is compiled into a regular expression and matched against the model name
and description.
"""
@spec list(binary) :: [{atom, String.t}]
def list(filter) do
list()
|> Enum.filter(&(list_filter(&1, filter)))
end
defp list_filter({model_atom, model_name}, filter) do
atom_string = Atom.to_string(model_atom)
{:ok, rfilter} = Regex.compile(filter)
Regex.match?(rfilter, atom_string) or Regex.match?(rfilter, model_name)
end
@doc """
Calculates a 8-bit CRC with polynomial x^8+x^6+x^3+x^2+1, 0x14D.
Chosen based on Koopman, et al. (0xA6 in his notation = 0x14D >> 1):
http://www.ece.cmu.edu/~koopman/roses/dsn04/koopman04_crc_poly_embedded.pdf
seed defaults to 0xFF if one is not given
"""
@spec crc_8(binary, number) :: number
defdelegate crc_8(input, seed \\ 0xFF), to: :crc
@doc """
Calculates a 16-bit ANSI CRC checksum for the provided binary
"""
@spec crc_16(binary) :: number
def crc_16(input), do: :crc_fast.calc(:crc_16, input)
@doc """
Calculates a 16-bit CCITT CRC with the given seed,
seed defaults to 0xFFFF if one is not given.
This CCIT method uses a 0x1021 polynomial.
"""
@spec ccitt_16(binary) :: number
def ccitt_16(input), do: :crc_fast.calc(:crc_16_ccitt_false, input)
@spec ccitt_16(binary, number) :: number
def ccitt_16(input, seed) do
extend_model_seed(:crc_16_ccitt_false, seed)
|> :crc_fast.calc(input)
end
@doc """
Calculates a 16-bit CCITT Kermit CRC
This CCIT method uses a 0x8408 polynomial.
"""
@spec ccitt_16_kermit(binary) :: number
def ccitt_16_kermit(input), do: :crc_fast.calc(:crc_16_kermit, input)
@spec ccitt_16_kermit(binary, number) :: number
def ccitt_16_kermit(input, seed) do
extend_model_seed(:crc_16_kermit, seed)
|> :crc_fast.calc(input)
end
@doc """
Calculates a 16-bit CCITT XMODEM CRC
This CCIT method uses a 0x1021 polynomial.
"""
@spec ccitt_16_xmodem(binary) :: number
def ccitt_16_xmodem(input), do: :crc_fast.calc(:xmodem, input)
@doc """
Calculates a 16-bit CCITT 0x1D0F CRC
This CCIT method uses a 0x1021 polynomial.
"""
@spec ccitt_16_1D0F(binary) :: number
def ccitt_16_1D0F(input) do
extend_model_seed(:crc_16_ccitt_false, 0x1D0F)
|> :crc_fast.calc(input)
end
@doc """
Calculates a 16-bit modbus CRC
"""
@spec crc_16_modbus(binary) :: number
def crc_16_modbus(input), do: :crc_fast.calc(:crc_16_modbus, input)
@doc """
Calculates a 16-bit Sick CRC
"""
@spec crc_16_sick(binary) :: number
def crc_16_sick(input), do: :crc_fast.calc(:crc_16_sick, input)
@doc """
Calculates a 16-bit DNP CRC
"""
@spec crc_16_dnp(binary) :: number
def crc_16_dnp(input), do: :crc_fast.calc(:crc_16_dnp, input)
@doc """
Calculates a 32-bit CRC
"""
@spec crc_32(binary) :: number
def crc_32(input), do: :crc_fast.calc(:crc_32, input)
@doc """
Calculates an XOR checksum for the given binary
"""
@spec checksum_xor(binary) :: number
defdelegate checksum_xor(input), to: :crc
defp extend_model_seed(model, seed), do: %{extend: model, init: seed}
end