Packages
hl7v2
1.4.3
3.10.1
3.9.0
3.8.0
3.7.0
3.6.0
3.5.0
3.4.0
3.3.6
3.3.5
3.3.4
3.3.3
3.3.2
3.3.1
3.3.0
3.2.0
3.1.1
3.1.0
3.0.2
3.0.1
3.0.0
2.11.0
2.10.0
2.9.1
2.9.0
2.8.2
2.8.1
2.8.0
2.7.1
2.7.0
2.6.0
2.5.0
2.4.0
2.3.0
2.2.0
2.1.3
2.1.2
2.1.1
2.1.0
1.4.6
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.0
1.2.0
1.1.0
1.0.0
0.6.0
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.1.0
Pure Elixir HL7 v2.x toolkit — schema-driven parsing, typed segments, message builder, MLLP transport
Current section
Files
Jump to
Current section
Files
lib/hl7v2/mllp.ex
defmodule HL7v2.MLLP do
@moduledoc """
MLLP (Minimal Lower Layer Protocol) framing for HL7v2 messages.
MLLP wraps each HL7v2 message in a simple frame:
<SB>message<EB><CR>
Where:
- SB (Start Block) = `0x0B`
- EB (End Block) = `0x1C`
- CR (Carriage Return) = `0x0D`
See HL7 Implementation Technology Specification — Minimal Lower Layer Protocol.
"""
@compile {:inline, frame: 1}
@sb 0x0B
@eb 0x1C
@cr 0x0D
@doc """
Wraps a message binary in an MLLP frame.
## Examples
iex> HL7v2.MLLP.frame("MSH|...")
<<0x0B, "MSH|...", 0x1C, 0x0D>>
"""
@spec frame(binary()) :: binary()
def frame(message) when is_binary(message) do
<<@sb, message::binary, @eb, @cr>>
end
@doc """
Extracts the message from an MLLP frame.
Returns `{:ok, message}` when the binary starts with SB and ends with EB+CR.
Returns `{:error, :invalid_frame}` otherwise.
## Examples
iex> HL7v2.MLLP.unframe(<<0x0B, "MSH|...", 0x1C, 0x0D>>)
{:ok, "MSH|..."}
iex> HL7v2.MLLP.unframe("bad")
{:error, :invalid_frame}
"""
@spec unframe(binary()) :: {:ok, binary()} | {:error, :invalid_frame}
def unframe(<<@sb, rest::binary>>) do
case :binary.split(rest, <<@eb, @cr>>) do
[message, <<>>] -> {:ok, message}
_ -> {:error, :invalid_frame}
end
end
def unframe(_), do: {:error, :invalid_frame}
@doc """
Extracts complete MLLP messages from a buffer.
Returns `{messages, remaining_buffer}` where `messages` is a list of
extracted message binaries (without MLLP framing) and `remaining_buffer`
contains any incomplete data that needs more bytes.
## Examples
iex> HL7v2.MLLP.extract_messages(<<0x0B, "MSG1", 0x1C, 0x0D, 0x0B, "MSG2", 0x1C, 0x0D>>)
{["MSG1", "MSG2"], <<>>}
iex> HL7v2.MLLP.extract_messages(<<0x0B, "MSG1", 0x1C, 0x0D, 0x0B, "partial">>)
{["MSG1"], <<0x0B, "partial">>}
"""
@spec extract_messages(binary()) :: {[binary()], binary()}
def extract_messages(buffer) do
extract_messages(buffer, [])
end
defp extract_messages(<<@sb, rest::binary>> = buffer, acc) do
case :binary.split(rest, <<@eb, @cr>>) do
[message, remainder] ->
extract_messages(remainder, [message | acc])
[_incomplete] ->
{Enum.reverse(acc), buffer}
end
end
defp extract_messages(<<>>, acc) do
{Enum.reverse(acc), <<>>}
end
# Data before an SB byte — skip leading garbage
defp extract_messages(buffer, acc) do
case :binary.split(buffer, <<@sb>>) do
[_garbage, rest] ->
extract_messages(<<@sb, rest::binary>>, acc)
[_no_sb] ->
{Enum.reverse(acc), buffer}
end
end
end