PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
dimse_message.h
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2021-2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
19#ifndef PACS_NETWORK_DIMSE_DIMSE_MESSAGE_HPP
20#define PACS_NETWORK_DIMSE_DIMSE_MESSAGE_HPP
21
22#include "command_field.h"
23#include "status_codes.h"
24
29
30#include <cstdint>
31#include <functional>
32#include <optional>
33#include <span>
34#include <string>
35#include <string_view>
36#include <variant>
37#include <vector>
38
40
43
45constexpr core::dicom_tag tag_command_group_length{0x0000, 0x0000};
46
49
52
54constexpr core::dicom_tag tag_command_field{0x0000, 0x0100};
55
57constexpr core::dicom_tag tag_message_id{0x0000, 0x0110};
58
61
63constexpr core::dicom_tag tag_move_destination{0x0000, 0x0600};
64
66constexpr core::dicom_tag tag_priority{0x0000, 0x0700};
67
70
72constexpr core::dicom_tag tag_status{0x0000, 0x0900};
73
75constexpr core::dicom_tag tag_offending_element{0x0000, 0x0901};
76
78constexpr core::dicom_tag tag_error_comment{0x0000, 0x0902};
79
81constexpr core::dicom_tag tag_error_id{0x0000, 0x0903};
82
85
88
90constexpr core::dicom_tag tag_event_type_id{0x0000, 0x1002};
91
94
96constexpr core::dicom_tag tag_action_type_id{0x0000, 0x1008};
97
100
103
106
109
111constexpr core::dicom_tag tag_move_originator_aet{0x0000, 0x1030};
112
115
117
120
122constexpr uint16_t command_data_set_type_null = 0x0101;
123
125constexpr uint16_t command_data_set_type_present = 0x0001;
126
128
131
133constexpr uint16_t priority_low = 0x0002;
134
136constexpr uint16_t priority_medium = 0x0000;
137
139constexpr uint16_t priority_high = 0x0001;
140
142
154
158[[nodiscard]] constexpr std::string_view to_string(dimse_error err) noexcept {
159 switch (err) {
160 case dimse_error::success: return "Success";
161 case dimse_error::invalid_command_set: return "Invalid command set";
162 case dimse_error::missing_required_field: return "Missing required field";
163 case dimse_error::invalid_data_format: return "Invalid data format";
164 case dimse_error::encoding_error: return "Encoding error";
165 case dimse_error::decoding_error: return "Decoding error";
166 default: return "Unknown error";
167 }
168}
169
175template <typename T>
177
203public:
204 // ========================================================================
205 // Construction
206 // ========================================================================
207
214
218 dimse_message() = default;
219
223 dimse_message(const dimse_message&) = default;
224
228 dimse_message(dimse_message&&) noexcept = default;
229
233 auto operator=(const dimse_message&) -> dimse_message& = default;
234
238 auto operator=(dimse_message&&) noexcept -> dimse_message& = default;
239
243 ~dimse_message() = default;
244
245 // ========================================================================
246 // Command Set Access
247 // ========================================================================
248
253 [[nodiscard]] auto command() const noexcept -> command_field;
254
259 [[nodiscard]] auto message_id() const noexcept -> uint16_t;
260
265 [[nodiscard]] auto command_set() noexcept -> core::dicom_dataset&;
266
271 [[nodiscard]] auto command_set() const noexcept -> const core::dicom_dataset&;
272
273 // ========================================================================
274 // Dataset Access
275 // ========================================================================
276
281 [[nodiscard]] auto has_dataset() const noexcept -> bool;
282
287 [[nodiscard]] auto dataset() -> kcenon::pacs::Result<std::reference_wrapper<core::dicom_dataset>>;
288
293 [[nodiscard]] auto dataset() const -> kcenon::pacs::Result<std::reference_wrapper<const core::dicom_dataset>>;
294
299 void set_dataset(core::dicom_dataset ds);
300
304 void clear_dataset() noexcept;
305
306 // ========================================================================
307 // Status (for responses)
308 // ========================================================================
309
314 [[nodiscard]] auto status() const -> status_code;
315
321
322 // ========================================================================
323 // Common Attributes
324 // ========================================================================
325
330 [[nodiscard]] auto affected_sop_class_uid() const -> std::string;
331
336 void set_affected_sop_class_uid(std::string_view uid);
337
342 [[nodiscard]] auto affected_sop_instance_uid() const -> std::string;
343
348 void set_affected_sop_instance_uid(std::string_view uid);
349
354 [[nodiscard]] auto priority() const -> uint16_t;
355
360 void set_priority(uint16_t priority);
361
366 [[nodiscard]] auto message_id_responded_to() const -> uint16_t;
367
372 void set_message_id_responded_to(uint16_t id);
373
374 // ========================================================================
375 // DIMSE-N Specific Attributes
376 // ========================================================================
377
382 [[nodiscard]] auto requested_sop_class_uid() const -> std::string;
383
388 void set_requested_sop_class_uid(std::string_view uid);
389
394 [[nodiscard]] auto requested_sop_instance_uid() const -> std::string;
395
400 void set_requested_sop_instance_uid(std::string_view uid);
401
406 [[nodiscard]] auto event_type_id() const -> std::optional<uint16_t>;
407
412 void set_event_type_id(uint16_t type_id);
413
418 [[nodiscard]] auto action_type_id() const -> std::optional<uint16_t>;
419
424 void set_action_type_id(uint16_t type_id);
425
430 [[nodiscard]] auto attribute_identifier_list() const -> std::vector<core::dicom_tag>;
431
436 void set_attribute_identifier_list(const std::vector<core::dicom_tag>& tags);
437
438 // ========================================================================
439 // Sub-operation Counts (for C-GET/C-MOVE responses)
440 // ========================================================================
441
446 [[nodiscard]] auto remaining_subops() const -> std::optional<uint16_t>;
447
451 void set_remaining_subops(uint16_t count);
452
456 [[nodiscard]] auto completed_subops() const -> std::optional<uint16_t>;
457
461 void set_completed_subops(uint16_t count);
462
466 [[nodiscard]] auto failed_subops() const -> std::optional<uint16_t>;
467
471 void set_failed_subops(uint16_t count);
472
476 [[nodiscard]] auto warning_subops() const -> std::optional<uint16_t>;
477
481 void set_warning_subops(uint16_t count);
482
483 // ========================================================================
484 // Encoding/Decoding
485 // ========================================================================
486
488 using encoded_message = std::pair<std::vector<uint8_t>, std::vector<uint8_t>>;
489
499 [[nodiscard]] static auto encode(
500 const dimse_message& msg,
501 const encoding::transfer_syntax& dataset_ts)
503
511 [[nodiscard]] static auto decode(
512 std::span<const uint8_t> command_data,
513 std::span<const uint8_t> dataset_data,
514 const encoding::transfer_syntax& dataset_ts)
516
517 // ========================================================================
518 // Validation
519 // ========================================================================
520
525 [[nodiscard]] auto is_valid() const noexcept -> bool;
526
531 [[nodiscard]] auto is_request() const noexcept -> bool;
532
537 [[nodiscard]] auto is_response() const noexcept -> bool;
538
539private:
542
545
547 uint16_t message_id_{0};
549 std::optional<core::dicom_dataset> dataset_;
550};
551
552// ============================================================================
553// Factory Functions
554// ============================================================================
555
562[[nodiscard]] auto make_c_echo_rq(
563 uint16_t message_id,
564 std::string_view sop_class_uid = "1.2.840.10008.1.1") -> dimse_message;
565
573[[nodiscard]] auto make_c_echo_rsp(
574 uint16_t message_id_responded_to,
575 status_code status = status_success,
576 std::string_view sop_class_uid = "1.2.840.10008.1.1") -> dimse_message;
577
586[[nodiscard]] auto make_c_store_rq(
587 uint16_t message_id,
588 std::string_view sop_class_uid,
589 std::string_view sop_instance_uid,
590 uint16_t priority = priority_medium) -> dimse_message;
591
600[[nodiscard]] auto make_c_store_rsp(
601 uint16_t message_id_responded_to,
602 std::string_view sop_class_uid,
603 std::string_view sop_instance_uid,
604 status_code status = status_success) -> dimse_message;
605
613[[nodiscard]] auto make_c_find_rq(
614 uint16_t message_id,
615 std::string_view sop_class_uid,
616 uint16_t priority = priority_medium) -> dimse_message;
617
625[[nodiscard]] auto make_c_find_rsp(
626 uint16_t message_id_responded_to,
627 std::string_view sop_class_uid,
628 status_code status) -> dimse_message;
629
630// ============================================================================
631// DIMSE-N Factory Functions
632// ============================================================================
633
641[[nodiscard]] auto make_n_create_rq(
642 uint16_t message_id,
643 std::string_view sop_class_uid,
644 std::string_view sop_instance_uid = "") -> dimse_message;
645
654[[nodiscard]] auto make_n_create_rsp(
655 uint16_t message_id_responded_to,
656 std::string_view sop_class_uid,
657 std::string_view sop_instance_uid,
658 status_code status = status_success) -> dimse_message;
659
667[[nodiscard]] auto make_n_set_rq(
668 uint16_t message_id,
669 std::string_view sop_class_uid,
670 std::string_view sop_instance_uid) -> dimse_message;
671
680[[nodiscard]] auto make_n_set_rsp(
681 uint16_t message_id_responded_to,
682 std::string_view sop_class_uid,
683 std::string_view sop_instance_uid,
684 status_code status = status_success) -> dimse_message;
685
694[[nodiscard]] auto make_n_get_rq(
695 uint16_t message_id,
696 std::string_view sop_class_uid,
697 std::string_view sop_instance_uid,
698 const std::vector<core::dicom_tag>& attribute_tags = {}) -> dimse_message;
699
708[[nodiscard]] auto make_n_get_rsp(
709 uint16_t message_id_responded_to,
710 std::string_view sop_class_uid,
711 std::string_view sop_instance_uid,
712 status_code status = status_success) -> dimse_message;
713
722[[nodiscard]] auto make_n_event_report_rq(
723 uint16_t message_id,
724 std::string_view sop_class_uid,
725 std::string_view sop_instance_uid,
726 uint16_t event_type_id) -> dimse_message;
727
737[[nodiscard]] auto make_n_event_report_rsp(
738 uint16_t message_id_responded_to,
739 std::string_view sop_class_uid,
740 std::string_view sop_instance_uid,
741 uint16_t event_type_id,
742 status_code status = status_success) -> dimse_message;
743
752[[nodiscard]] auto make_n_action_rq(
753 uint16_t message_id,
754 std::string_view sop_class_uid,
755 std::string_view sop_instance_uid,
756 uint16_t action_type_id) -> dimse_message;
757
767[[nodiscard]] auto make_n_action_rsp(
768 uint16_t message_id_responded_to,
769 std::string_view sop_class_uid,
770 std::string_view sop_instance_uid,
771 uint16_t action_type_id,
772 status_code status = status_success) -> dimse_message;
773
781[[nodiscard]] auto make_n_delete_rq(
782 uint16_t message_id,
783 std::string_view sop_class_uid,
784 std::string_view sop_instance_uid) -> dimse_message;
785
794[[nodiscard]] auto make_n_delete_rsp(
795 uint16_t message_id_responded_to,
796 std::string_view sop_class_uid,
797 std::string_view sop_instance_uid,
798 status_code status = status_success) -> dimse_message;
799
800} // namespace kcenon::pacs::network::dimse
801
802#endif // PACS_NETWORK_DIMSE_DIMSE_MESSAGE_HPP
auto message_id() const noexcept -> uint16_t
Get the message ID.
auto status() const -> status_code
Get the status code (for response messages)
std::optional< core::dicom_dataset > dataset_
static auto encode(const dimse_message &msg, const encoding::transfer_syntax &dataset_ts) -> dimse_result< encoded_message >
Encode the DIMSE message to bytes.
void set_requested_sop_instance_uid(std::string_view uid)
Set the Requested SOP Instance UID.
void set_action_type_id(uint16_t type_id)
Set the Action Type ID.
auto affected_sop_class_uid() const -> std::string
Get the Affected SOP Class UID.
auto attribute_identifier_list() const -> std::vector< core::dicom_tag >
Get the Attribute Identifier List (for N-GET)
void set_priority(uint16_t priority)
Set the priority.
static auto decode(std::span< const uint8_t > command_data, std::span< const uint8_t > dataset_data, const encoding::transfer_syntax &dataset_ts) -> dimse_result< dimse_message >
Decode a DIMSE message from bytes.
void set_attribute_identifier_list(const std::vector< core::dicom_tag > &tags)
Set the Attribute Identifier List.
void set_event_type_id(uint16_t type_id)
Set the Event Type ID.
auto command_set() noexcept -> core::dicom_dataset &
Get mutable reference to the command set.
auto is_valid() const noexcept -> bool
Check if the message is valid.
auto message_id_responded_to() const -> uint16_t
Get the Message ID Being Responded To (for responses)
auto remaining_subops() const -> std::optional< uint16_t >
Get the number of remaining sub-operations.
void clear_dataset() noexcept
Remove the data set from this message.
auto warning_subops() const -> std::optional< uint16_t >
Get the number of warning sub-operations.
auto requested_sop_class_uid() const -> std::string
Get the Requested SOP Class UID (for N-SET, N-GET, N-ACTION, N-DELETE)
void set_completed_subops(uint16_t count)
Set the number of completed sub-operations.
auto is_request() const noexcept -> bool
Check if this is a request message.
void update_command_group_length()
Calculate and set CommandGroupLength.
void set_dataset(core::dicom_dataset ds)
Set the data set for this message.
auto requested_sop_instance_uid() const -> std::string
Get the Requested SOP Instance UID (for N-SET, N-GET, N-ACTION, N-DELETE)
void set_status(status_code status)
Set the status code (for response messages)
void set_affected_sop_class_uid(std::string_view uid)
Set the Affected SOP Class UID.
auto is_response() const noexcept -> bool
Check if this is a response message.
auto event_type_id() const -> std::optional< uint16_t >
Get the Event Type ID (for N-EVENT-REPORT)
auto has_dataset() const noexcept -> bool
Check if the message has an associated data set.
void update_data_set_type()
Update the CommandDataSetType field based on dataset presence.
auto failed_subops() const -> std::optional< uint16_t >
Get the number of failed sub-operations.
void set_remaining_subops(uint16_t count)
Set the number of remaining sub-operations.
auto dataset() -> kcenon::pacs::Result< std::reference_wrapper< core::dicom_dataset > >
Get mutable reference to the data set.
auto priority() const -> uint16_t
Get the priority.
dimse_message(dimse_message &&) noexcept=default
Move constructor.
std::pair< std::vector< uint8_t >, std::vector< uint8_t > > encoded_message
Encoded message result type: pair of (command_set_bytes, dataset_bytes)
void set_message_id_responded_to(uint16_t id)
Set the Message ID Being Responded To (for responses)
auto action_type_id() const -> std::optional< uint16_t >
Get the Action Type ID (for N-ACTION)
void set_failed_subops(uint16_t count)
Set the number of failed sub-operations.
auto affected_sop_instance_uid() const -> std::string
Get the Affected SOP Instance UID.
void set_affected_sop_instance_uid(std::string_view uid)
Set the Affected SOP Instance UID.
auto command() const noexcept -> command_field
Get the command field.
dimse_message()=default
Default constructor (creates an invalid message)
dimse_message(const dimse_message &)=default
Copy constructor.
void set_requested_sop_class_uid(std::string_view uid)
Set the Requested SOP Class UID.
auto completed_subops() const -> std::optional< uint16_t >
Get the number of completed sub-operations.
void set_warning_subops(uint16_t count)
Set the number of warning sub-operations.
DIMSE command field enumeration.
DICOM Dataset - ordered collection of Data Elements.
DICOM Tag representation (Group, Element pairs)
constexpr uint16_t priority_low
Low priority.
constexpr core::dicom_tag tag_action_type_id
Action Type ID (0000,1008) - US.
constexpr core::dicom_tag tag_command_field
Command Field (0000,0100) - US.
constexpr core::dicom_tag tag_error_comment
Error Comment (0000,0902) - LO.
constexpr core::dicom_tag tag_number_of_failed_subops
Number of Failed Sub-operations (0000,1022) - US.
constexpr core::dicom_tag tag_message_id
Message ID (0000,0110) - US.
auto make_n_set_rsp(uint16_t message_id_responded_to, std::string_view sop_class_uid, std::string_view sop_instance_uid, status_code status=status_success) -> dimse_message
Create an N-SET response message.
constexpr uint16_t priority_high
High priority.
auto make_n_action_rsp(uint16_t message_id_responded_to, std::string_view sop_class_uid, std::string_view sop_instance_uid, uint16_t action_type_id, status_code status=status_success) -> dimse_message
Create an N-ACTION response message.
constexpr core::dicom_tag tag_number_of_remaining_subops
Number of Remaining Sub-operations (0000,1020) - US.
constexpr core::dicom_tag tag_priority
Priority (0000,0700) - US.
constexpr core::dicom_tag tag_offending_element
Offending Element (0000,0901) - AT.
constexpr core::dicom_tag tag_command_group_length
Command Group Length (0000,0000) - UL.
constexpr std::string_view to_string(command_field cmd) noexcept
Convert command field to string representation.
auto make_n_create_rq(uint16_t message_id, std::string_view sop_class_uid, std::string_view sop_instance_uid="") -> dimse_message
Create an N-CREATE request message.
auto make_n_get_rq(uint16_t message_id, std::string_view sop_class_uid, std::string_view sop_instance_uid, const std::vector< core::dicom_tag > &attribute_tags={}) -> dimse_message
Create an N-GET request message.
constexpr core::dicom_tag tag_affected_sop_instance_uid
Affected SOP Instance UID (0000,1000) - UI.
auto make_n_event_report_rsp(uint16_t message_id_responded_to, std::string_view sop_class_uid, std::string_view sop_instance_uid, uint16_t event_type_id, status_code status=status_success) -> dimse_message
Create an N-EVENT-REPORT response message.
constexpr core::dicom_tag tag_number_of_warning_subops
Number of Warning Sub-operations (0000,1023) - US.
constexpr core::dicom_tag tag_move_originator_message_id
Move Originator Message ID (0000,1031) - US.
constexpr core::dicom_tag tag_attribute_identifier_list
Attribute Identifier List (0000,1005) - AT.
auto make_n_action_rq(uint16_t message_id, std::string_view sop_class_uid, std::string_view sop_instance_uid, uint16_t action_type_id) -> dimse_message
Create an N-ACTION request message.
constexpr core::dicom_tag tag_move_destination
Move Destination (0000,0600) - AE.
auto make_n_set_rq(uint16_t message_id, std::string_view sop_class_uid, std::string_view sop_instance_uid) -> dimse_message
Create an N-SET request message.
constexpr uint16_t command_data_set_type_present
Value indicating data set is present (any value other than 0x0101)
auto make_c_echo_rq(uint16_t message_id, std::string_view sop_class_uid="1.2.840.10008.1.1") -> dimse_message
Create a C-ECHO request message.
auto make_c_find_rsp(uint16_t message_id_responded_to, std::string_view sop_class_uid, status_code status) -> dimse_message
Create a C-FIND response message.
constexpr core::dicom_tag tag_message_id_responded_to
Message ID Being Responded To (0000,0120) - US.
auto make_n_delete_rq(uint16_t message_id, std::string_view sop_class_uid, std::string_view sop_instance_uid) -> dimse_message
Create an N-DELETE request message.
auto make_c_find_rq(uint16_t message_id, std::string_view sop_class_uid, uint16_t priority=priority_medium) -> dimse_message
Create a C-FIND request message.
constexpr core::dicom_tag tag_move_originator_aet
Move Originator Application Entity Title (0000,1030) - AE.
auto make_c_echo_rsp(uint16_t message_id_responded_to, status_code status=status_success, std::string_view sop_class_uid="1.2.840.10008.1.1") -> dimse_message
Create a C-ECHO response message.
constexpr core::dicom_tag tag_error_id
Error ID (0000,0903) - US.
dimse_error
Error codes for DIMSE message operations.
auto make_c_store_rsp(uint16_t message_id_responded_to, std::string_view sop_class_uid, std::string_view sop_instance_uid, status_code status=status_success) -> dimse_message
Create a C-STORE response message.
auto make_n_event_report_rq(uint16_t message_id, std::string_view sop_class_uid, std::string_view sop_instance_uid, uint16_t event_type_id) -> dimse_message
Create an N-EVENT-REPORT request message.
auto make_n_create_rsp(uint16_t message_id_responded_to, std::string_view sop_class_uid, std::string_view sop_instance_uid, status_code status=status_success) -> dimse_message
Create an N-CREATE response message.
command_field
DIMSE command field values.
auto make_c_store_rq(uint16_t message_id, std::string_view sop_class_uid, std::string_view sop_instance_uid, uint16_t priority=priority_medium) -> dimse_message
Create a C-STORE request message.
auto make_n_delete_rsp(uint16_t message_id_responded_to, std::string_view sop_class_uid, std::string_view sop_instance_uid, status_code status=status_success) -> dimse_message
Create an N-DELETE response message.
constexpr uint16_t priority_medium
Medium priority.
constexpr uint16_t command_data_set_type_null
Null value indicating no data set present.
constexpr core::dicom_tag tag_number_of_completed_subops
Number of Completed Sub-operations (0000,1021) - US.
constexpr core::dicom_tag tag_requested_sop_instance_uid
Requested SOP Instance UID (0000,1001) - UI.
constexpr core::dicom_tag tag_event_type_id
Event Type ID (0000,1002) - US.
uint16_t status_code
DIMSE status code type alias.
auto make_n_get_rsp(uint16_t message_id_responded_to, std::string_view sop_class_uid, std::string_view sop_instance_uid, status_code status=status_success) -> dimse_message
Create an N-GET response message.
constexpr core::dicom_tag tag_affected_sop_class_uid
Affected SOP Class UID (0000,0002) - UI.
constexpr core::dicom_tag tag_status
Status (0000,0900) - US.
constexpr core::dicom_tag tag_requested_sop_class_uid
Requested SOP Class UID (0000,0003) - UI.
constexpr core::dicom_tag tag_command_data_set_type
Command Data Set Type (0000,0800) - US.
Result<T> type aliases and helpers for PACS system.
DIMSE status codes.
std::string_view uid