Pure Elixir DICOM DIMSE networking library.
Provides the DICOM Upper Layer Protocol (PS3.8), DIMSE-C message services (PS3.7 Chapter 9) and DIMSE-N notification/management services (PS3.7 Chapter 10) for building DICOM SCP (server) and SCU (client) applications on the BEAM.
Public API
Listener (SCP)
Dimse.start_listener(port: 11112, handler: MyApp.DicomHandler)
Dimse.stop_listener(ref)Client (SCU) — DIMSE-C
{:ok, assoc} = Dimse.connect("192.168.1.10", 11112, calling_ae: "MY_SCU", called_ae: "REMOTE_SCP")
:ok = Dimse.echo(assoc)
:ok = Dimse.store(assoc, sop_class_uid, sop_instance_uid, data_set)
{:ok, results} = Dimse.find(assoc, :study, query_data, timeout: 30_000)
:ok = Dimse.cancel(assoc, message_id)
{:ok, result} = Dimse.move(assoc, :study, query, dest_ae: "DEST_AE")
{:ok, data_sets} = Dimse.get(assoc, :study, query)Client (SCU) — DIMSE-N
{:ok, status, data} = Dimse.n_get(assoc, sop_class_uid, sop_instance_uid)
{:ok, status, data} = Dimse.n_set(assoc, sop_class_uid, sop_instance_uid, modifications)
{:ok, status, data} = Dimse.n_action(assoc, sop_class_uid, sop_instance_uid, action_type_id, action_info)
{:ok, status, created_sop_instance_uid, data} = Dimse.n_create(assoc, sop_class_uid, attributes)
{:ok, status, nil} = Dimse.n_delete(assoc, sop_class_uid, sop_instance_uid)
{:ok, status, data} = Dimse.n_event_report(assoc, sop_class_uid, sop_instance_uid, event_type_id, event_info)Connection management
:ok = Dimse.release(assoc)
:ok = Dimse.abort(assoc)Architecture
Each DICOM association is a dedicated GenServer process (Dimse.Association)
supervised under a DynamicSupervisor. Ranch handles TCP acceptance. This gives
fault isolation per-association and natural backpressure via max_children.
Dependencies
dicom— command set encoding (Implicit VR Little Endian), UID generation, transfer syntax registry, SOP class lookupranch— TCP acceptor pooltelemetry— observability events
Summary
Functions
Sends an A-ABORT to forcefully terminate the association.
Sends a C-CANCEL-RQ to cancel a pending C-FIND operation.
Opens an association to a remote DICOM AE (SCU client).
Sends a C-ECHO request on an established association.
Sends a C-FIND request and returns matching data sets.
Sends a C-GET request to retrieve instances on the same association.
Sends a C-MOVE request to retrieve instances to a destination AE.
Sends an N-ACTION-RQ to request an action on a managed SOP Instance.
Sends an N-CREATE-RQ to create a new managed SOP Instance.
Sends an N-DELETE-RQ to delete a managed SOP Instance.
Sends an N-EVENT-REPORT-RQ to notify the SCP of an event.
Sends an N-GET-RQ to retrieve attributes from a managed SOP Instance.
Sends an N-SET-RQ to modify attributes on a managed SOP Instance.
Sends an A-RELEASE-RQ to gracefully close the association.
Starts a DIMSE listener on the given port.
Stops a running DIMSE listener.
Sends a C-STORE request with the given data set.
Opens an association, executes a function, and releases gracefully.
Functions
@spec abort(pid()) :: :ok
Sends an A-ABORT to forcefully terminate the association.
Sends a C-CANCEL-RQ to cancel a pending C-FIND operation.
The message_id should be the MessageID of the original C-FIND-RQ.
@spec connect(String.t(), pos_integer(), keyword()) :: {:ok, pid()} | {:error, term()}
Opens an association to a remote DICOM AE (SCU client).
Options
:calling_ae— local AE title (default:"DIMSE"):called_ae— remote AE title (default:"ANY-SCP"):abstract_syntaxes— list of SOP Class UIDs to propose:transfer_syntaxes— list of Transfer Syntax UIDs to propose:max_pdu_length— max PDU length (default:16_384):timeout— total association establishment timeout in ms (default:30_000):tls— TLS options (keyword list). When present, the SCU connects via TLS instead of plain TCP. Accepts standard:ssloptions such as:cacertfile,:verify,:certfile, and:keyfile.:role_selections— list ofDimse.Pdu.RoleSelectionstructs proposing SCU/SCP roles per SOP class (PS3.7 Annex D.3.3.4):user_identity—Dimse.Pdu.UserIdentitystruct for SCU authentication (PS3.7 Annex D.3.3.7)
Returns {:ok, association_pid} or {:error, reason}.
Sends a C-ECHO request on an established association.
@spec find(pid(), String.t() | atom(), binary(), keyword()) :: {:ok, [binary()]} | {:error, {:cancelled, [binary()]} | term()}
Sends a C-FIND request and returns matching data sets.
Parameters
assoc— association pid fromDimse.connect/3sop_class_or_level— SOP Class UID string, or query level atom (:patient,:study,:worklist)query_data— encoded query identifier data set
Options
:priority— request priority (default:0x0000medium):timeout— response timeout in ms (default:30_000)
Sends a C-GET request to retrieve instances on the same association.
The SCP sends matching instances back as C-STORE sub-operations on the same association. The SCU auto-accepts and returns the data sets.
Parameters
assoc— association pid fromDimse.connect/3sop_class_or_level— SOP Class UID string, or query level atom (:patient,:study)query_data— encoded query identifier data set
Options
:priority— request priority (default:0x0000medium):timeout— response timeout in ms (default:30_000)
Returns {:ok, [binary()]} with the received data sets.
Sends a C-MOVE request to retrieve instances to a destination AE.
The SCP pushes matching instances to the destination AE via C-STORE sub-operations and reports sub-operation counts in the response.
Parameters
assoc— association pid fromDimse.connect/3sop_class_or_level— SOP Class UID string, or query level atom (:patient,:study)query_data— encoded query identifier data set
Options
:dest_ae— destination AE title (required):priority— request priority (default:0x0000medium):timeout— response timeout in ms (default:30_000)
Returns {:ok, %{completed: n, failed: n, warning: n}} on success.
@spec n_action(pid(), String.t(), String.t(), integer(), binary() | nil, keyword()) :: {:ok, integer(), binary() | nil} | {:error, {:status, integer(), binary() | nil} | term()}
Sends an N-ACTION-RQ to request an action on a managed SOP Instance.
Returns {:ok, status, data} or {:error, reason}.
@spec n_create(pid(), String.t(), binary() | nil, keyword()) :: {:ok, integer(), String.t() | nil, binary() | nil} | {:error, {:status, integer(), binary() | nil} | term()}
Sends an N-CREATE-RQ to create a new managed SOP Instance.
Options
:sop_instance_uid— optional proposed SOP Instance UID:timeout— response timeout in ms (default:30_000)
Returns {:ok, status, created_sop_instance_uid, data} or {:error, reason}.
@spec n_delete(pid(), String.t(), String.t(), keyword()) :: {:ok, integer(), nil} | {:error, {:status, integer(), nil} | term()}
Sends an N-DELETE-RQ to delete a managed SOP Instance.
Returns {:ok, status, nil} or {:error, reason}.
@spec n_event_report( pid(), String.t(), String.t(), integer(), binary() | nil, keyword() ) :: {:ok, integer(), binary() | nil} | {:error, {:status, integer(), binary() | nil} | term()}
Sends an N-EVENT-REPORT-RQ to notify the SCP of an event.
Returns {:ok, status, data} or {:error, reason}.
@spec n_get(pid(), String.t(), String.t(), keyword()) :: {:ok, integer(), binary() | nil} | {:error, {:status, integer(), binary() | nil} | term()}
Sends an N-GET-RQ to retrieve attributes from a managed SOP Instance.
Options
:attribute_identifier_list— list of{group, element}tags to retrieve:timeout— response timeout in ms (default:30_000)
Returns {:ok, status, data} or {:error, reason}.
@spec n_set(pid(), String.t(), String.t(), binary(), keyword()) :: {:ok, integer(), binary() | nil} | {:error, {:status, integer(), binary() | nil} | term()}
Sends an N-SET-RQ to modify attributes on a managed SOP Instance.
Returns {:ok, status, data} or {:error, reason}.
Sends an A-RELEASE-RQ to gracefully close the association.
Starts a DIMSE listener on the given port.
Options
:port— TCP port to listen on (default:11112):handler— module implementingDimse.Handlerbehaviour (required):ae_title— local AE title (default:"DIMSE"):max_associations— max concurrent associations (default:200):num_acceptors— Ranch acceptor pool size (default:10):max_pdu_length— max PDU length in bytes (default:16_384):tls— TLS options (keyword list). When present, the listener uses TLS (:ranch_ssl) instead of plain TCP. Accepts standard:ssloptions such as:certfile,:keyfile,:cacertfile,:verify, and:fail_if_no_peer_cert. PS3.15 Annex B recommends port 2762 for DICOM-TLS.
Returns {:ok, listener_ref} or {:error, reason}.
Stops a running DIMSE listener.
Sends a C-STORE request with the given data set.
Parameters
assoc— association pid fromDimse.connect/3sop_class_uid— SOP Class UID of the instancesop_instance_uid— SOP Instance UID of the instancedata— encoded data set binary
Options
:priority— request priority (default:0x0000medium):move_originator_ae— AE title of the C-MOVE originator:move_originator_message_id— message ID from the C-MOVE request:timeout— response timeout in ms (default:30_000)
@spec with_connection(String.t(), pos_integer(), keyword(), (pid() -> term())) :: {:ok, term()} | {:error, term()}
Opens an association, executes a function, and releases gracefully.
Handles the full connection lifecycle: connect, execute, release. If the function raises or the association fails, the connection is aborted to ensure cleanup.
Parameters
host— remote hostname or IPport— remote portopts— connection options (same asconnect/3)fun— function receiving the association pid
Examples
Dimse.with_connection("192.168.1.10", 11112, [calling_ae: "SCU"], fn assoc ->
:ok = Dimse.echo(assoc)
{:ok, results} = Dimse.find(assoc, :study, query)
results
end)Returns {:ok, fun_result} or {:error, reason}.