diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..2f1b6c6
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,394 @@
+root = true
+
+# All files
+[*]
+indent_style = space
+
+# Xml files
+[*.xml]
+indent_size = 2
+
+# C# files
+[*.cs]
+
+#### Core EditorConfig Options ####
+
+# Indentation and spacing
+indent_size = 4
+tab_width = 4
+
+# New line preferences
+end_of_line = crlf
+insert_final_newline = false
+
+#### .NET Coding Conventions ####
+[*.{cs,vb}]
+
+# Organize usings
+dotnet_separate_import_directive_groups = true
+dotnet_sort_system_directives_first = true
+file_header_template = unset
+
+# this. and Me. preferences
+dotnet_style_qualification_for_event = false:warning
+dotnet_style_qualification_for_field = false:warning
+dotnet_style_qualification_for_method = false:silent
+dotnet_style_qualification_for_property = false:warning
+
+# Language keywords vs BCL types preferences
+dotnet_style_predefined_type_for_locals_parameters_members = true:silent
+dotnet_style_predefined_type_for_member_access = true:silent
+
+# Parentheses preferences
+dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent
+dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent
+dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent
+
+# Modifier preferences
+dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
+
+# Expression-level preferences
+dotnet_style_coalesce_expression = true:suggestion
+dotnet_style_collection_initializer = true:suggestion
+dotnet_style_explicit_tuple_names = true:suggestion
+dotnet_style_null_propagation = true:suggestion
+dotnet_style_object_initializer = true:suggestion
+dotnet_style_operator_placement_when_wrapping = beginning_of_line
+dotnet_style_prefer_auto_properties = true:silent
+dotnet_style_prefer_compound_assignment = true:suggestion
+dotnet_style_prefer_conditional_expression_over_assignment = true:silent
+dotnet_style_prefer_conditional_expression_over_return = true:silent
+dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
+dotnet_style_prefer_inferred_tuple_names = true:suggestion
+dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
+dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
+dotnet_style_prefer_simplified_interpolation = true:suggestion
+
+# Field preferences
+dotnet_style_readonly_field = true:warning
+
+# Parameter preferences
+dotnet_code_quality_unused_parameters = all:suggestion
+
+# Suppression preferences
+dotnet_remove_unnecessary_suppression_exclusions = none
+
+#### C# Coding Conventions ####
+[*.cs]
+
+# var preferences
+csharp_style_var_elsewhere = false:silent
+csharp_style_var_for_built_in_types = false:silent
+csharp_style_var_when_type_is_apparent = false:silent
+
+# Expression-bodied members
+csharp_style_expression_bodied_accessors = true:silent
+csharp_style_expression_bodied_constructors = false:silent
+csharp_style_expression_bodied_indexers = true:silent
+csharp_style_expression_bodied_lambdas = true:silent
+csharp_style_expression_bodied_local_functions = false:silent
+csharp_style_expression_bodied_methods = false:silent
+csharp_style_expression_bodied_operators = false:silent
+csharp_style_expression_bodied_properties = true:silent
+
+# Pattern matching preferences
+csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
+csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
+csharp_style_prefer_not_pattern = true:suggestion
+csharp_style_prefer_pattern_matching = true:silent
+csharp_style_prefer_switch_expression = true:suggestion
+
+# Null-checking preferences
+csharp_style_conditional_delegate_call = true:suggestion
+
+# Modifier preferences
+csharp_prefer_static_local_function = true:warning
+csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:silent
+
+# Code-block preferences
+csharp_prefer_braces = true:silent
+csharp_prefer_simple_using_statement = true:suggestion
+
+# Expression-level preferences
+csharp_prefer_simple_default_expression = true:suggestion
+csharp_style_deconstructed_variable_declaration = true:suggestion
+csharp_style_inlined_variable_declaration = true:suggestion
+csharp_style_pattern_local_over_anonymous_function = true:suggestion
+csharp_style_prefer_index_operator = true:suggestion
+csharp_style_prefer_range_operator = true:suggestion
+csharp_style_throw_expression = true:suggestion
+csharp_style_unused_value_assignment_preference = discard_variable:suggestion
+csharp_style_unused_value_expression_statement_preference = discard_variable:silent
+
+# 'using' directive preferences
+csharp_using_directive_placement = outside_namespace:silent
+
+#### C# Formatting Rules ####
+
+# New line preferences
+csharp_new_line_before_catch = true
+csharp_new_line_before_else = true
+csharp_new_line_before_finally = true
+csharp_new_line_before_members_in_anonymous_types = true
+csharp_new_line_before_members_in_object_initializers = true
+csharp_new_line_before_open_brace = all
+csharp_new_line_between_query_expression_clauses = true
+
+# Indentation preferences
+csharp_indent_block_contents = true
+csharp_indent_braces = false
+csharp_indent_case_contents = true
+csharp_indent_case_contents_when_block = true
+csharp_indent_labels = one_less_than_current
+csharp_indent_switch_labels = true
+
+# Space preferences
+csharp_space_after_cast = false
+csharp_space_after_colon_in_inheritance_clause = true
+csharp_space_after_comma = true
+csharp_space_after_dot = false
+csharp_space_after_keywords_in_control_flow_statements = true
+csharp_space_after_semicolon_in_for_statement = true
+csharp_space_around_binary_operators = before_and_after
+csharp_space_around_declaration_statements = false
+csharp_space_before_colon_in_inheritance_clause = true
+csharp_space_before_comma = false
+csharp_space_before_dot = false
+csharp_space_before_open_square_brackets = false
+csharp_space_before_semicolon_in_for_statement = false
+csharp_space_between_empty_square_brackets = false
+csharp_space_between_method_call_empty_parameter_list_parentheses = false
+csharp_space_between_method_call_name_and_opening_parenthesis = false
+csharp_space_between_method_call_parameter_list_parentheses = false
+csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
+csharp_space_between_method_declaration_name_and_open_parenthesis = false
+csharp_space_between_method_declaration_parameter_list_parentheses = false
+csharp_space_between_parentheses = false
+csharp_space_between_square_brackets = false
+
+# Wrapping preferences
+csharp_preserve_single_line_blocks = true
+csharp_preserve_single_line_statements = true
+csharp_style_namespace_declarations = file_scoped:warning
+csharp_style_prefer_method_group_conversion = true:silent
+csharp_style_prefer_top_level_statements = true:silent
+csharp_style_prefer_null_check_over_type_check = true:suggestion
+csharp_style_prefer_local_over_anonymous_function = true:suggestion
+csharp_style_prefer_utf8_string_literals = true:suggestion
+csharp_style_prefer_tuple_swap = true:suggestion
+csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion
+csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent
+csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent
+csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true:silent
+csharp_style_prefer_extended_property_pattern = true:suggestion
+
+#### Naming styles ####
+[*.{cs,vb}]
+
+# Naming rules
+
+dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.severity = warning
+dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.symbols = types_and_namespaces
+dotnet_naming_rule.types_and_namespaces_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.interfaces_should_be_ipascalcase.severity = warning
+dotnet_naming_rule.interfaces_should_be_ipascalcase.symbols = interfaces
+dotnet_naming_rule.interfaces_should_be_ipascalcase.style = ipascalcase
+
+dotnet_naming_rule.type_parameters_should_be_tpascalcase.severity = warning
+dotnet_naming_rule.type_parameters_should_be_tpascalcase.symbols = type_parameters
+dotnet_naming_rule.type_parameters_should_be_tpascalcase.style = tpascalcase
+
+dotnet_naming_rule.methods_should_be_pascalcase.severity = warning
+dotnet_naming_rule.methods_should_be_pascalcase.symbols = methods
+dotnet_naming_rule.methods_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.properties_should_be_pascalcase.severity = warning
+dotnet_naming_rule.properties_should_be_pascalcase.symbols = properties
+dotnet_naming_rule.properties_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.events_should_be_pascalcase.severity = warning
+dotnet_naming_rule.events_should_be_pascalcase.symbols = events
+dotnet_naming_rule.events_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.local_variables_should_be_camelcase.severity = warning
+dotnet_naming_rule.local_variables_should_be_camelcase.symbols = local_variables
+dotnet_naming_rule.local_variables_should_be_camelcase.style = camelcase
+
+dotnet_naming_rule.local_constants_should_be_camelcase.severity = warning
+dotnet_naming_rule.local_constants_should_be_camelcase.symbols = local_constants
+dotnet_naming_rule.local_constants_should_be_camelcase.style = all_caps
+
+dotnet_naming_rule.parameters_should_be_camelcase.severity = warning
+dotnet_naming_rule.parameters_should_be_camelcase.symbols = parameters
+dotnet_naming_rule.parameters_should_be_camelcase.style = camelcase
+
+dotnet_naming_rule.public_fields_should_be_pascalcase.severity = warning
+dotnet_naming_rule.public_fields_should_be_pascalcase.symbols = public_fields
+dotnet_naming_rule.public_fields_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.private_fields_should_be__camelcase.severity = warning
+dotnet_naming_rule.private_fields_should_be__camelcase.symbols = private_fields
+dotnet_naming_rule.private_fields_should_be__camelcase.style = _camelcase
+
+dotnet_naming_rule.private_static_fields_should_be_s_camelcase.severity = warning
+dotnet_naming_rule.private_static_fields_should_be_s_camelcase.symbols = private_static_fields
+dotnet_naming_rule.private_static_fields_should_be_s_camelcase.style = _camelcase
+
+dotnet_naming_rule.public_constant_fields_should_be_pascalcase.severity = warning
+dotnet_naming_rule.public_constant_fields_should_be_pascalcase.symbols = public_constant_fields
+dotnet_naming_rule.public_constant_fields_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.private_constant_fields_should_be_pascalcase.severity = warning
+dotnet_naming_rule.private_constant_fields_should_be_pascalcase.symbols = private_constant_fields
+dotnet_naming_rule.private_constant_fields_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.severity = warning
+dotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.symbols = public_static_readonly_fields
+dotnet_naming_rule.public_static_readonly_fields_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.severity = warning
+dotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.symbols = private_static_readonly_fields
+dotnet_naming_rule.private_static_readonly_fields_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.enums_should_be_pascalcase.severity = warning
+dotnet_naming_rule.enums_should_be_pascalcase.symbols = enums
+dotnet_naming_rule.enums_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.local_functions_should_be_pascalcase.severity = warning
+dotnet_naming_rule.local_functions_should_be_pascalcase.symbols = local_functions
+dotnet_naming_rule.local_functions_should_be_pascalcase.style = pascalcase
+
+dotnet_naming_rule.non_field_members_should_be_pascalcase.severity = warning
+dotnet_naming_rule.non_field_members_should_be_pascalcase.symbols = non_field_members
+dotnet_naming_rule.non_field_members_should_be_pascalcase.style = pascalcase
+
+# Symbol specifications
+
+dotnet_naming_symbols.interfaces.applicable_kinds = interface
+dotnet_naming_symbols.interfaces.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.interfaces.required_modifiers =
+
+dotnet_naming_symbols.enums.applicable_kinds = enum
+dotnet_naming_symbols.enums.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.enums.required_modifiers =
+
+dotnet_naming_symbols.events.applicable_kinds = event
+dotnet_naming_symbols.events.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.events.required_modifiers =
+
+dotnet_naming_symbols.methods.applicable_kinds = method
+dotnet_naming_symbols.methods.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.methods.required_modifiers =
+
+dotnet_naming_symbols.properties.applicable_kinds = property
+dotnet_naming_symbols.properties.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.properties.required_modifiers =
+
+dotnet_naming_symbols.public_fields.applicable_kinds = field
+dotnet_naming_symbols.public_fields.applicable_accessibilities = public, internal
+dotnet_naming_symbols.public_fields.required_modifiers =
+
+dotnet_naming_symbols.private_fields.applicable_kinds = field
+dotnet_naming_symbols.private_fields.applicable_accessibilities = private, protected, protected_internal, private_protected
+dotnet_naming_symbols.private_fields.required_modifiers =
+
+dotnet_naming_symbols.private_static_fields.applicable_kinds = field
+dotnet_naming_symbols.private_static_fields.applicable_accessibilities = private, protected, protected_internal, private_protected
+dotnet_naming_symbols.private_static_fields.required_modifiers = static
+
+dotnet_naming_symbols.types_and_namespaces.applicable_kinds = namespace, class, struct, interface, enum
+dotnet_naming_symbols.types_and_namespaces.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.types_and_namespaces.required_modifiers =
+
+dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
+dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.non_field_members.required_modifiers =
+
+dotnet_naming_symbols.type_parameters.applicable_kinds = namespace
+dotnet_naming_symbols.type_parameters.applicable_accessibilities = *
+dotnet_naming_symbols.type_parameters.required_modifiers =
+
+dotnet_naming_symbols.private_constant_fields.applicable_kinds = field
+dotnet_naming_symbols.private_constant_fields.applicable_accessibilities = private, protected, protected_internal, private_protected
+dotnet_naming_symbols.private_constant_fields.required_modifiers = const
+
+dotnet_naming_symbols.local_variables.applicable_kinds = local
+dotnet_naming_symbols.local_variables.applicable_accessibilities = local
+dotnet_naming_symbols.local_variables.required_modifiers =
+
+dotnet_naming_symbols.local_constants.applicable_kinds = local
+dotnet_naming_symbols.local_constants.applicable_accessibilities = local
+dotnet_naming_symbols.local_constants.required_modifiers = const
+
+dotnet_naming_symbols.parameters.applicable_kinds = parameter
+dotnet_naming_symbols.parameters.applicable_accessibilities = *
+dotnet_naming_symbols.parameters.required_modifiers =
+
+dotnet_naming_symbols.public_constant_fields.applicable_kinds = field
+dotnet_naming_symbols.public_constant_fields.applicable_accessibilities = public, internal
+dotnet_naming_symbols.public_constant_fields.required_modifiers = const
+
+dotnet_naming_symbols.public_static_readonly_fields.applicable_kinds = field
+dotnet_naming_symbols.public_static_readonly_fields.applicable_accessibilities = public, internal
+dotnet_naming_symbols.public_static_readonly_fields.required_modifiers = readonly, static
+
+dotnet_naming_symbols.private_static_readonly_fields.applicable_kinds = field
+dotnet_naming_symbols.private_static_readonly_fields.applicable_accessibilities = private, protected, protected_internal, private_protected
+dotnet_naming_symbols.private_static_readonly_fields.required_modifiers = readonly, static
+
+dotnet_naming_symbols.local_functions.applicable_kinds = local_function
+dotnet_naming_symbols.local_functions.applicable_accessibilities = *
+dotnet_naming_symbols.local_functions.required_modifiers =
+
+# Naming styles
+
+dotnet_naming_style.pascalcase.required_prefix =
+dotnet_naming_style.pascalcase.required_suffix =
+dotnet_naming_style.pascalcase.word_separator =
+dotnet_naming_style.pascalcase.capitalization = pascal_case
+
+dotnet_naming_style.ipascalcase.required_prefix = I
+dotnet_naming_style.ipascalcase.required_suffix =
+dotnet_naming_style.ipascalcase.word_separator =
+dotnet_naming_style.ipascalcase.capitalization = pascal_case
+
+dotnet_naming_style.tpascalcase.required_prefix = T
+dotnet_naming_style.tpascalcase.required_suffix =
+dotnet_naming_style.tpascalcase.word_separator =
+dotnet_naming_style.tpascalcase.capitalization = pascal_case
+
+dotnet_naming_style._camelcase.required_prefix = _
+dotnet_naming_style._camelcase.required_suffix =
+dotnet_naming_style._camelcase.word_separator =
+dotnet_naming_style._camelcase.capitalization = camel_case
+
+dotnet_naming_style.camelcase.required_prefix =
+dotnet_naming_style.camelcase.required_suffix =
+dotnet_naming_style.camelcase.word_separator =
+dotnet_naming_style.camelcase.capitalization = camel_case
+
+dotnet_naming_style.s_camelcase.required_prefix = s_
+dotnet_naming_style.s_camelcase.required_suffix =
+dotnet_naming_style.s_camelcase.word_separator =
+dotnet_naming_style.s_camelcase.capitalization = camel_case
+
+dotnet_naming_style.all_caps.required_prefix =
+dotnet_naming_style.all_caps.required_suffix =
+dotnet_naming_style.all_caps.word_separator = _
+dotnet_naming_style.all_caps.capitalization = all_caps
+
+tab_width = 4
+indent_size = 4
+end_of_line = crlf
+dotnet_style_namespace_match_folder = true:suggestion
+dotnet_style_allow_statement_immediately_after_block_experimental = true:silent
+dotnet_style_allow_multiple_blank_lines_experimental = true:silent
+
+# Unnecessary usings
+dotnet_diagnostic.IDE0005.severity = warning
+
+resharper_csharp_place_attribute_on_same_line = false
+
+csharp_style_prefer_primary_constructors = false
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index af5c6a9..113e3ad 100755
--- a/.gitignore
+++ b/.gitignore
@@ -34,3 +34,4 @@ _ReSharper*/
/.tmp
*.DotSettings
/misc
+/.idea
diff --git a/Nefarius.Peripherals.SerialPort/NativeMethods.txt b/Nefarius.Peripherals.SerialPort/NativeMethods.txt
index e754077..48e53bd 100644
--- a/Nefarius.Peripherals.SerialPort/NativeMethods.txt
+++ b/Nefarius.Peripherals.SerialPort/NativeMethods.txt
@@ -1,17 +1,28 @@
-CreateFile
+CancelIo
+ClearCommError
+EscapeCommFunction
+FILE_ACCESS_RIGHTS
+GetCommModemStatus
+GetCommProperties
GetHandleInformation
+GetOverlappedResult
+MODEM_STATUS_FLAGS
+ReadFile
+SetCommMask
SetCommState
SetCommTimeouts
SetupComm
-WriteFile
-SetCommMask
-WaitCommEvent
-CancelIo
-ReadFile
TransmitCommChar
+WIN32_ERROR
+WaitCommEvent
+WriteFile
+CreateFile
+ESCAPE_COMM_FUNCTION
EscapeCommFunction
-GetCommModemStatus
-GetOverlappedResult
-ClearCommError
-GetCommProperties
-WIN32_ERROR
\ No newline at end of file
+CLEAR_COMM_ERROR_FLAGS
+CE_TXFULL
+CE_PTO
+CE_IOE
+CE_DNS
+CE_OOP
+CE_MODE
\ No newline at end of file
diff --git a/Nefarius.Peripherals.SerialPort/Nefarius.Peripherals.SerialPort.csproj b/Nefarius.Peripherals.SerialPort/Nefarius.Peripherals.SerialPort.csproj
index 370ebf2..91af2d0 100644
--- a/Nefarius.Peripherals.SerialPort/Nefarius.Peripherals.SerialPort.csproj
+++ b/Nefarius.Peripherals.SerialPort/Nefarius.Peripherals.SerialPort.csproj
@@ -31,9 +31,10 @@
-
-
+
all
+
+
\ No newline at end of file
diff --git a/Nefarius.Peripherals.SerialPort/QueueStatus.cs b/Nefarius.Peripherals.SerialPort/QueueStatus.cs
index 63469fd..661b5dc 100644
--- a/Nefarius.Peripherals.SerialPort/QueueStatus.cs
+++ b/Nefarius.Peripherals.SerialPort/QueueStatus.cs
@@ -1,5 +1,5 @@
using System.Text;
-using Nefarius.Peripherals.SerialPort.Win32PInvoke;
+
namespace Nefarius.Peripherals.SerialPort
{
diff --git a/Nefarius.Peripherals.SerialPort/SerialPort.Properties.cs b/Nefarius.Peripherals.SerialPort/SerialPort.Properties.cs
new file mode 100644
index 0000000..55214cf
--- /dev/null
+++ b/Nefarius.Peripherals.SerialPort/SerialPort.Properties.cs
@@ -0,0 +1,278 @@
+using Windows.Win32;
+using Windows.Win32.Devices.Communication;
+
+namespace Nefarius.Peripherals.SerialPort;
+
+public partial class SerialPort
+{
+ ///
+ /// If true, the port will automatically re-open on next send if it was previously closed due
+ /// to an error (default: false)
+ ///
+ public bool AutoReopen { get; set; }
+
+ ///
+ /// Baud Rate (default: 115200)
+ ///
+ /// Unsupported rates will throw "Bad settings".
+ public int BaudRate { get; set; } = 115200;
+
+ ///
+ /// If true, subsequent Send commands wait for completion of earlier ones enabling the results
+ /// to be checked. If false, errors, including timeouts, may not be detected, but performance
+ /// may be better.
+ ///
+ public bool CheckAllSends { get; set; } = true;
+
+ ///
+ /// Number of databits 1..8 (default: 8) unsupported values will throw "Bad settings"
+ ///
+ public int DataBits { get; set; } = 8;
+
+ ///
+ /// The parity checking scheme (default: none)
+ ///
+ public Parity Parity { get; set; } = Parity.None;
+
+ ///
+ /// If true, Xon and Xoff characters are sent to control the data flow from the remote station (default: false)
+ ///
+ public bool RxFlowX { get; set; }
+
+ ///
+ /// If true, received characters are ignored unless DSR is asserted by the remote station (default: false)
+ ///
+ public bool RxGateDsr { get; set; }
+
+ ///
+ /// The number of free bytes in the reception queue at which flow is disabled (default: 2048)
+ ///
+ public int RxHighWater { get; set; } = 2048;
+
+ ///
+ /// The number of bytes in the reception queue at which flow is re-enabled (default: 512)
+ ///
+ public int RxLowWater { get; set; } = 512;
+
+ ///
+ /// Requested size for receive queue (default: 0 = use operating system default)
+ ///
+ public int RxQueue { get; set; }
+
+ ///
+ /// Constant. Max time for Send in ms = (Multiplier * Characters) + Constant (default: 0)
+ ///
+ public int SendTimeoutConstant { get; set; }
+
+ ///
+ /// Multiplier. Max time for Send in ms = (Multiplier * Characters) + Constant
+ /// (default: 0 = No timeout)
+ ///
+ public int SendTimeoutMultiplier { get; set; }
+
+ ///
+ /// Number of stop bits (default: one)
+ ///
+ public StopBits StopBits { get; set; } = StopBits.One;
+
+ ///
+ /// If true, transmission is halted unless CTS is asserted by the remote station (default: false)
+ ///
+ public bool TxFlowCts { get; set; }
+
+ ///
+ /// If true, transmission is halted unless DSR is asserted by the remote station (default: false)
+ ///
+ public bool TxFlowDsr { get; set; }
+
+ ///
+ /// If true, transmission is halted when Xoff is received and restarted when Xon is received (default: false)
+ ///
+ public bool TxFlowX { get; set; }
+
+ ///
+ /// Requested size for transmit queue (default: 0 = use operating system default)
+ ///
+ public int TxQueue { get; set; }
+
+ ///
+ /// If false, transmission is suspended when this station has sent Xoff to the remote station (default: true)
+ /// Set false if the remote station treats any character as an Xon.
+ ///
+ public bool TxWhenRxXoff { get; set; } = true;
+
+ ///
+ /// Specidies the use to which the DTR output is put (default: none)
+ ///
+ public HsOutput UseDtr { get; set; } = HsOutput.None;
+
+ ///
+ /// Specifies the use to which the RTS output is put (default: none)
+ ///
+ public HsOutput UseRts { get; set; } = HsOutput.None;
+
+ ///
+ /// The character used to signal Xoff for X flow control (default: DC3)
+ ///
+ public ASCII XoffChar { get; set; } = ASCII.DC3;
+
+ ///
+ /// The character used to signal Xon for X flow control (default: DC1)
+ ///
+ public ASCII XonChar { get; set; } = ASCII.DC1;
+
+ ///
+ /// True if online.
+ ///
+ public bool Online => _online && CheckOnline();
+
+ ///
+ /// True if the RTS pin is controllable via the RTS property
+ ///
+ protected bool RtSavailable => _stateRts < 2;
+
+ ///
+ /// Set the state of the RTS modem control output
+ ///
+ protected bool Rts
+ {
+ set
+ {
+ if (_stateRts > 1) return;
+ CheckOnline();
+ if (value)
+ {
+ if (PInvoke.EscapeCommFunction(_hPort, ESCAPE_COMM_FUNCTION.SETRTS))
+ _stateRts = 1;
+ else
+ ThrowException("Unexpected Failure");
+ }
+ else
+ {
+ if (PInvoke.EscapeCommFunction(_hPort, ESCAPE_COMM_FUNCTION.CLRRTS))
+ _stateRts = 1;
+ else
+ ThrowException("Unexpected Failure");
+ }
+ }
+ get => _stateRts == 1;
+ }
+
+ ///
+ /// True if the DTR pin is controllable via the DTR property
+ ///
+ protected bool DtrAvailable => _stateDtr < 2;
+
+ ///
+ /// The state of the DTR modem control output
+ ///
+ protected bool Dtr
+ {
+ set
+ {
+ if (_stateDtr > 1) return;
+ CheckOnline();
+ if (value)
+ {
+ if (PInvoke.EscapeCommFunction(_hPort, ESCAPE_COMM_FUNCTION.SETDTR))
+ _stateDtr = 1;
+ else
+ ThrowException("Unexpected Failure");
+ }
+ else
+ {
+ if (PInvoke.EscapeCommFunction(_hPort, ESCAPE_COMM_FUNCTION.CLRDTR))
+ _stateDtr = 0;
+ else
+ ThrowException("Unexpected Failure");
+ }
+ }
+ get => _stateDtr == 1;
+ }
+
+ ///
+ /// Assert or remove a break condition from the transmission line
+ ///
+ protected bool Break
+ {
+ set
+ {
+ if (_stateBrk > 1) return;
+ CheckOnline();
+ if (value)
+ {
+ if (PInvoke.EscapeCommFunction(_hPort, ESCAPE_COMM_FUNCTION.SETBREAK))
+ _stateBrk = 0;
+ else
+ ThrowException("Unexpected Failure");
+ }
+ else
+ {
+ if (PInvoke.EscapeCommFunction(_hPort, ESCAPE_COMM_FUNCTION.CLRBREAK))
+ _stateBrk = 0;
+ else
+ ThrowException("Unexpected Failure");
+ }
+ }
+ get => _stateBrk == 1;
+ }
+
+ ///
+ /// Port Name
+ ///
+ public string PortName { get; set; }
+
+ public Handshake Handshake
+ {
+ get => _handShake;
+ set
+ {
+ _handShake = value;
+ switch (_handShake)
+ {
+ case Handshake.None:
+ TxFlowCts = false;
+ TxFlowDsr = false;
+ TxFlowX = false;
+ RxFlowX = false;
+ UseRts = HsOutput.Online;
+ UseDtr = HsOutput.Online;
+ TxWhenRxXoff = true;
+ RxGateDsr = false;
+ break;
+ case Handshake.XonXoff:
+ TxFlowCts = false;
+ TxFlowDsr = false;
+ TxFlowX = true;
+ RxFlowX = true;
+ UseRts = HsOutput.Online;
+ UseDtr = HsOutput.Online;
+ TxWhenRxXoff = true;
+ RxGateDsr = false;
+ XonChar = ASCII.DC1;
+ XoffChar = ASCII.DC3;
+ break;
+ case Handshake.CtsRts:
+ TxFlowCts = true;
+ TxFlowDsr = false;
+ TxFlowX = false;
+ RxFlowX = false;
+ UseRts = HsOutput.Handshake;
+ UseDtr = HsOutput.Online;
+ TxWhenRxXoff = true;
+ RxGateDsr = false;
+ break;
+ case Handshake.DsrDtr:
+ TxFlowCts = false;
+ TxFlowDsr = true;
+ TxFlowX = false;
+ RxFlowX = false;
+ UseRts = HsOutput.Online;
+ UseDtr = HsOutput.Handshake;
+ TxWhenRxXoff = true;
+ RxGateDsr = false;
+ break;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Nefarius.Peripherals.SerialPort/SerialPort.cs b/Nefarius.Peripherals.SerialPort/SerialPort.cs
index cfddb9a..75114e8 100644
--- a/Nefarius.Peripherals.SerialPort/SerialPort.cs
+++ b/Nefarius.Peripherals.SerialPort/SerialPort.cs
@@ -1,22 +1,57 @@
using System;
+using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
+
using Windows.Win32;
using Windows.Win32.Devices.Communication;
using Windows.Win32.Foundation;
using Windows.Win32.Storage.FileSystem;
+
using Microsoft.Win32.SafeHandles;
-using Nefarius.Peripherals.SerialPort.Win32PInvoke;
namespace Nefarius.Peripherals.SerialPort;
///
-/// PInvokeSerialPort main class.
-/// Borrowed from http://msdn.microsoft.com/en-us/magazine/cc301786.aspx ;)
+/// Wrapper class around a serial (COM, RS-232) port.
///
-public class SerialPort : IDisposable
+[SuppressMessage("ReSharper", "UnusedMember.Global")]
+public partial class SerialPort : IDisposable
{
+ private readonly ManualResetEvent _writeEvent = new(false);
+ private bool _auto;
+ private bool _checkSends = true;
+
+ private Handshake _handShake;
+ private SafeFileHandle _hPort;
+ private bool _online;
+ private NativeOverlapped _ptrUwo;
+ private Exception _rxException;
+ private bool _rxExceptionReported;
+ private Thread _rxThread;
+ private int _stateBrk = 2;
+ private int _stateDtr = 2;
+ private int _stateRts = 2;
+ private int _writeCount;
+
+ ///
+ /// Class constructor
+ ///
+ public SerialPort(string portName)
+ {
+ PortName = portName;
+ }
+
+ ///
+ ///
+ /// Class constructor
+ ///
+ public SerialPort(string portName, int baudRate) : this(portName)
+ {
+ BaudRate = baudRate;
+ }
+
///
///
/// For IDisposable
@@ -32,18 +67,25 @@ public class SerialPort : IDisposable
/// false if the port could not be opened
public bool Open()
{
- var portDcb = new DCB();
- var commTimeouts = new COMMTIMEOUTS();
+ DCB portDcb = new();
+ COMMTIMEOUTS commTimeouts = new();
- if (_online) return false;
+ if (_online)
+ {
+ return false;
+ }
_hPort = PInvoke.CreateFile(PortName,
- FILE_ACCESS_FLAGS.FILE_GENERIC_READ | FILE_ACCESS_FLAGS.FILE_GENERIC_WRITE, 0,
+ (uint)(FILE_ACCESS_RIGHTS.FILE_GENERIC_READ | FILE_ACCESS_RIGHTS.FILE_GENERIC_WRITE), 0,
null, FILE_CREATION_DISPOSITION.OPEN_EXISTING, FILE_FLAGS_AND_ATTRIBUTES.FILE_FLAG_OVERLAPPED, null);
if (_hPort.IsInvalid)
{
- if (Marshal.GetLastWin32Error() == (int)WIN32_ERROR.ERROR_ACCESS_DENIED) return false;
+ if (Marshal.GetLastWin32Error() == (int)WIN32_ERROR.ERROR_ACCESS_DENIED)
+ {
+ return false;
+ }
+
throw new CommPortException("Port Open Failure");
}
@@ -60,20 +102,28 @@ public class SerialPort : IDisposable
portDcb.ByteSize = (byte)DataBits;
portDcb.Parity = (DCB_PARITY)Parity;
portDcb.StopBits = (DCB_STOP_BITS)StopBits;
- portDcb.XoffChar = (CHAR)(byte)XoffChar;
- portDcb.XonChar = (CHAR)(byte)XonChar;
+ portDcb.XoffChar = new CHAR((sbyte)XoffChar);
+ portDcb.XonChar = new CHAR((sbyte)XonChar);
portDcb.XoffLim = (ushort)RxHighWater;
portDcb.XonLim = (ushort)RxLowWater;
if (RxQueue != 0 || TxQueue != 0)
+ {
if (!PInvoke.SetupComm(_hPort, (uint)RxQueue, (uint)TxQueue))
+ {
ThrowException("Bad queue settings");
+ }
+ }
if (!PInvoke.SetCommState(_hPort, portDcb))
+ {
ThrowException("Bad com settings");
+ }
if (!PInvoke.SetCommTimeouts(_hPort, commTimeouts))
+ {
ThrowException("Bad timeout settings");
+ }
_stateBrk = 0;
switch (UseDtr)
@@ -103,12 +153,9 @@ public class SerialPort : IDisposable
_rxException = null;
_rxExceptionReported = false;
- // TODO: utilize Task Parallel Library here
_rxThread = new Thread(ReceiveThread)
{
- Name = "CommBaseRx",
- Priority = ThreadPriority.AboveNormal,
- IsBackground = true
+ Name = "CommBaseRx", Priority = ThreadPriority.AboveNormal, IsBackground = true
};
_rxThread.Start();
@@ -141,7 +188,7 @@ public class SerialPort : IDisposable
private void InternalClose()
{
- Win32Com.CancelIo(_hPort.DangerousGetHandle());
+ PInvoke.CancelIo(_hPort);
if (_rxThread != null)
{
_rxThread.Abort();
@@ -179,14 +226,22 @@ public class SerialPort : IDisposable
/// Description of fault
protected void ThrowException(string reason)
{
- if (Thread.CurrentThread == _rxThread) throw new CommPortException(reason);
+ if (Thread.CurrentThread == _rxThread)
+ {
+ throw new CommPortException(reason);
+ }
+
if (_online)
{
BeforeClose(true);
InternalClose();
}
- if (_rxException == null) throw new CommPortException(reason);
+ if (_rxException == null)
+ {
+ throw new CommPortException(reason);
+ }
+
throw new CommPortException(_rxException);
}
@@ -196,22 +251,23 @@ public class SerialPort : IDisposable
/// Array of bytes to be sent
public unsafe void Write(byte[] toSend)
{
- uint sent;
CheckOnline();
CheckResult();
_writeCount = toSend.GetLength(0);
- fixed (byte* ptr = toSend)
fixed (NativeOverlapped* ptrOl = &_ptrUwo)
{
- if (PInvoke.WriteFile(_hPort, ptr, (uint)_writeCount, &sent, ptrOl))
+ uint sent;
+ if (PInvoke.WriteFile(_hPort, toSend.AsSpan(), &sent, ptrOl))
{
_writeCount -= (int)sent;
}
else
{
- if (Marshal.GetLastWin32Error() != (int)WIN32_ERROR.ERROR_IO_PENDING)
+ if (Marshal.GetLastWin32Error() != (int)WIN32_ERROR.ERROR_IO_PENDING)
+ {
ThrowException("Unexpected failure");
+ }
}
}
}
@@ -231,7 +287,7 @@ public class SerialPort : IDisposable
/// Byte to be sent
public void Write(byte toSend)
{
- var b = new byte[1];
+ byte[] b = new byte[1];
b[0] = toSend;
Write(b);
}
@@ -256,15 +312,25 @@ public class SerialPort : IDisposable
private void CheckResult()
{
- if (_writeCount <= 0) return;
- if (PInvoke.GetOverlappedResult(_hPort, _ptrUwo, out var sent, _checkSends))
+ if (_writeCount <= 0)
+ {
+ return;
+ }
+
+ if (PInvoke.GetOverlappedResult(_hPort, _ptrUwo, out uint sent, _checkSends))
{
_writeCount -= (int)sent;
- if (_writeCount != 0) ThrowException("Send Timeout");
+ if (_writeCount != 0)
+ {
+ ThrowException("Send Timeout");
+ }
}
else
{
- if (Marshal.GetLastWin32Error() != (int)WIN32_ERROR.ERROR_IO_PENDING) ThrowException("Unexpected failure");
+ if (Marshal.GetLastWin32Error() != (int)WIN32_ERROR.ERROR_IO_PENDING)
+ {
+ ThrowException("Unexpected failure");
+ }
}
}
@@ -276,7 +342,10 @@ public class SerialPort : IDisposable
public void SendImmediate(byte tosend)
{
CheckOnline();
- if (!Win32Com.TransmitCommChar(_hPort.DangerousGetHandle(), tosend)) ThrowException("Transmission failure");
+ if (!PInvoke.TransmitCommChar(_hPort, new CHAR((sbyte)tosend)))
+ {
+ ThrowException("Transmission failure");
+ }
}
///
@@ -285,14 +354,15 @@ public class SerialPort : IDisposable
/// Modem status object
protected ModemStatus GetModemStatus()
{
- uint f;
-
CheckOnline();
- if (!Win32Com.GetCommModemStatus(_hPort.DangerousGetHandle(), out f)) ThrowException("Unexpected failure");
+ if (!PInvoke.GetCommModemStatus(_hPort, out MODEM_STATUS_FLAGS f))
+ {
+ ThrowException("Unexpected failure");
+ }
+
return new ModemStatus(f);
}
-
///
/// Get the status of the queues
///
@@ -300,15 +370,19 @@ public class SerialPort : IDisposable
protected unsafe QueueStatus GetQueueStatus()
{
COMSTAT cs;
- var cp = new COMMPROP();
+ COMMPROP cp = new();
CLEAR_COMM_ERROR_FLAGS er;
CheckOnline();
if (!PInvoke.ClearCommError(_hPort, &er, &cs))
+ {
ThrowException("Unexpected failure");
+ }
- if (!PInvoke.GetCommProperties(_hPort, ref cp))
+ if (!PInvoke.GetCommProperties(_hPort, &cp))
+ {
ThrowException("Unexpected failure");
+ }
return new QueueStatus(cs._bitfield, cs.cbInQue, cs.cbOutQue, cp.dwCurrentRxQueue, cp.dwCurrentTxQueue);
}
@@ -383,49 +457,73 @@ public class SerialPort : IDisposable
private unsafe void ReceiveThread()
{
- var buf = new byte[1];
-
- var sg = new AutoResetEvent(false);
- var ov = new OVERLAPPED();
- var unmanagedOv = Marshal.AllocHGlobal(Marshal.SizeOf(ov));
- ov.Offset = 0;
- ov.OffsetHigh = 0;
- ov.hEvent = sg.SafeWaitHandle.DangerousGetHandle();
- Marshal.StructureToPtr(ov, unmanagedOv, true);
-
- uint eventMask = 0;
- var uMask = Marshal.AllocHGlobal(Marshal.SizeOf(eventMask));
+ byte[] buffer = new byte[1];
+ AutoResetEvent sg = new(false);
+ NativeOverlapped ov = new() { EventHandle = sg.SafeWaitHandle.DangerousGetHandle() };
try
{
while (true)
{
- if (!Win32Com.SetCommMask(_hPort.DangerousGetHandle(),
- Win32Com.EV_RXCHAR | Win32Com.EV_TXEMPTY | Win32Com.EV_CTS | Win32Com.EV_DSR
- | Win32Com.EV_BREAK | Win32Com.EV_RLSD | Win32Com.EV_RING | Win32Com.EV_ERR))
- throw new CommPortException("IO Error [001]");
- Marshal.WriteInt32(uMask, 0);
- if (!Win32Com.WaitCommEvent(_hPort.DangerousGetHandle(), uMask, unmanagedOv))
+ COMM_EVENT_MASK eventMask = 0;
+
+ if (!PInvoke.SetCommMask(_hPort,
+ COMM_EVENT_MASK.EV_RXCHAR | COMM_EVENT_MASK.EV_TXEMPTY | COMM_EVENT_MASK.EV_CTS |
+ COMM_EVENT_MASK.EV_DSR
+ | COMM_EVENT_MASK.EV_BREAK | COMM_EVENT_MASK.EV_RLSD | COMM_EVENT_MASK.EV_RING |
+ COMM_EVENT_MASK.EV_ERR))
{
- if (Marshal.GetLastWin32Error() == (int)WIN32_ERROR.ERROR_IO_PENDING)
- sg.WaitOne();
- else
- throw new CommPortException("IO Error [002]");
+ throw new CommPortException("IO Error [001]");
}
- eventMask = (uint)Marshal.ReadInt32(uMask);
- if ((eventMask & Win32Com.EV_ERR) != 0)
+ if (!PInvoke.WaitCommEvent(_hPort, ref eventMask, &ov))
+ {
+ if (Marshal.GetLastWin32Error() == (int)WIN32_ERROR.ERROR_IO_PENDING)
+ {
+ sg.WaitOne();
+ }
+ else
+ {
+ throw new CommPortException("IO Error [002]");
+ }
+ }
+
+ if ((eventMask & COMM_EVENT_MASK.EV_ERR) != 0)
{
CLEAR_COMM_ERROR_FLAGS errs;
if (PInvoke.ClearCommError(_hPort, &errs, null))
{
- var s = new StringBuilder("UART Error: ", 40);
- if (((uint)errs & Win32Com.CE_FRAME) != 0) s = s.Append("Framing,");
- if (((uint)errs & Win32Com.CE_IOE) != 0) s = s.Append("IO,");
- if (((uint)errs & Win32Com.CE_OVERRUN) != 0) s = s.Append("Overrun,");
- if (((uint)errs & Win32Com.CE_RXOVER) != 0) s = s.Append("Receive Overflow,");
- if (((uint)errs & Win32Com.CE_RXPARITY) != 0) s = s.Append("Parity,");
- if (((uint)errs & Win32Com.CE_TXFULL) != 0) s = s.Append("Transmit Overflow,");
+ StringBuilder s = new("UART Error: ", 40);
+ if (((uint)errs & (uint)CLEAR_COMM_ERROR_FLAGS.CE_FRAME) != 0)
+ {
+ s = s.Append("Framing,");
+ }
+
+ if (((uint)errs & PInvoke.CE_IOE) != 0)
+ {
+ s = s.Append("IO,");
+ }
+
+ if (((uint)errs & (uint)CLEAR_COMM_ERROR_FLAGS.CE_OVERRUN) != 0)
+ {
+ s = s.Append("Overrun,");
+ }
+
+ if (((uint)errs & (uint)CLEAR_COMM_ERROR_FLAGS.CE_RXOVER) != 0)
+ {
+ s = s.Append("Receive Overflow,");
+ }
+
+ if (((uint)errs & (uint)CLEAR_COMM_ERROR_FLAGS.CE_RXPARITY) != 0)
+ {
+ s = s.Append("Parity,");
+ }
+
+ if (((uint)errs & PInvoke.CE_TXFULL) != 0)
+ {
+ s = s.Append("Transmit Overflow,");
+ }
+
s.Length -= 1;
throw new CommPortException(s.ToString());
}
@@ -433,17 +531,17 @@ public class SerialPort : IDisposable
throw new CommPortException("IO Error [003]");
}
- if ((eventMask & Win32Com.EV_RXCHAR) != 0)
+ if ((eventMask & COMM_EVENT_MASK.EV_RXCHAR) != 0)
{
- uint gotbytes;
+ uint gotBytes;
do
{
- if (!Win32Com.ReadFile(_hPort.DangerousGetHandle(), buf, 1, out gotbytes, unmanagedOv))
+ if (!PInvoke.ReadFile(_hPort, buffer, &gotBytes, &ov))
{
if (Marshal.GetLastWin32Error() == (int)WIN32_ERROR.ERROR_IO_PENDING)
{
- Win32Com.CancelIo(_hPort.DangerousGetHandle());
- gotbytes = 0;
+ PInvoke.CancelIo(_hPort);
+ gotBytes = 0;
}
else
{
@@ -451,32 +549,58 @@ public class SerialPort : IDisposable
}
}
- if (gotbytes == 1) OnRxChar(buf[0]);
- } while (gotbytes > 0);
+ if (gotBytes == 1)
+ {
+ OnRxChar(buffer[0]);
+ }
+ } while (gotBytes > 0);
}
- if ((eventMask & Win32Com.EV_TXEMPTY) != 0) OnTxDone();
- if ((eventMask & Win32Com.EV_BREAK) != 0) OnBreak();
+ if ((eventMask & COMM_EVENT_MASK.EV_TXEMPTY) != 0)
+ {
+ OnTxDone();
+ }
+
+ if ((eventMask & COMM_EVENT_MASK.EV_BREAK) != 0)
+ {
+ OnBreak();
+ }
+
+ MODEM_STATUS_FLAGS i = 0;
+ if ((eventMask & COMM_EVENT_MASK.EV_CTS) != 0)
+ {
+ i |= MODEM_STATUS_FLAGS.MS_CTS_ON;
+ }
+
+ if ((eventMask & COMM_EVENT_MASK.EV_DSR) != 0)
+ {
+ i |= MODEM_STATUS_FLAGS.MS_DSR_ON;
+ }
+
+ if ((eventMask & COMM_EVENT_MASK.EV_RLSD) != 0)
+ {
+ i |= MODEM_STATUS_FLAGS.MS_RLSD_ON;
+ }
+
+ if ((eventMask & COMM_EVENT_MASK.EV_RING) != 0)
+ {
+ i |= MODEM_STATUS_FLAGS.MS_RING_ON;
+ }
- uint i = 0;
- if ((eventMask & Win32Com.EV_CTS) != 0) i |= Win32Com.MS_CTS_ON;
- if ((eventMask & Win32Com.EV_DSR) != 0) i |= Win32Com.MS_DSR_ON;
- if ((eventMask & Win32Com.EV_RLSD) != 0) i |= Win32Com.MS_RLSD_ON;
- if ((eventMask & Win32Com.EV_RING) != 0) i |= Win32Com.MS_RING_ON;
if (i != 0)
{
- uint f;
- if (!Win32Com.GetCommModemStatus(_hPort.DangerousGetHandle(), out f))
+ if (!PInvoke.GetCommModemStatus(_hPort, out MODEM_STATUS_FLAGS f))
+ {
throw new CommPortException("IO Error [005]");
+ }
+
OnStatusChange(new ModemStatus(i), new ModemStatus(f));
}
}
}
catch (Exception e)
{
- if (uMask != IntPtr.Zero) Marshal.FreeHGlobal(uMask);
- if (unmanagedOv != IntPtr.Zero) Marshal.FreeHGlobal(unmanagedOv);
- if (!(e is ThreadAbortException))
+ if (e is not ThreadAbortException)
{
_rxException = e;
OnRxException(e);
@@ -494,329 +618,24 @@ public class SerialPort : IDisposable
if (_online)
{
- uint f;
- if (Win32Com.GetHandleInformation(_hPort.DangerousGetHandle(), out f)) return true;
+ if (PInvoke.GetHandleInformation(_hPort, out uint _))
+ {
+ return true;
+ }
+
ThrowException("Offline");
return false;
}
if (_auto)
+ {
if (Open())
+ {
return true;
+ }
+ }
+
ThrowException("Offline");
return false;
}
-
- #region Private fields
-
- private readonly ManualResetEvent _writeEvent = new(false);
- private bool _auto;
- private bool _checkSends = true;
-
- private Handshake _handShake;
- private SafeFileHandle _hPort;
- private bool _online;
- private NativeOverlapped _ptrUwo;
- private Exception _rxException;
- private bool _rxExceptionReported;
- private Thread _rxThread;
- private int _stateBrk = 2;
- private int _stateDtr = 2;
- private int _stateRts = 2;
- private int _writeCount;
-
- #endregion
-
- #region Public properties
-
- ///
- /// Class constructor
- ///
- public SerialPort(string portName)
- {
- PortName = portName;
- }
-
- ///
- ///
- /// Class constructor
- ///
- public SerialPort(string portName, int baudRate) : this(portName)
- {
- BaudRate = baudRate;
- }
-
- ///
- /// If true, the port will automatically re-open on next send if it was previously closed due
- /// to an error (default: false)
- ///
- public bool AutoReopen { get; set; }
-
- ///
- /// Baud Rate (default: 115200)
- ///
- /// Unsupported rates will throw "Bad settings".
- public int BaudRate { get; set; } = 115200;
-
- ///
- /// If true, subsequent Send commands wait for completion of earlier ones enabling the results
- /// to be checked. If false, errors, including timeouts, may not be detected, but performance
- /// may be better.
- ///
- public bool CheckAllSends { get; set; } = true;
-
- ///
- /// Number of databits 1..8 (default: 8) unsupported values will throw "Bad settings"
- ///
- public int DataBits { get; set; } = 8;
-
- ///
- /// The parity checking scheme (default: none)
- ///
- public Parity Parity { get; set; } = Parity.None;
-
- ///
- /// If true, Xon and Xoff characters are sent to control the data flow from the remote station (default: false)
- ///
- public bool RxFlowX { get; set; }
-
- ///
- /// If true, received characters are ignored unless DSR is asserted by the remote station (default: false)
- ///
- public bool RxGateDsr { get; set; }
-
- ///
- /// The number of free bytes in the reception queue at which flow is disabled (default: 2048)
- ///
- public int RxHighWater { get; set; } = 2048;
-
- ///
- /// The number of bytes in the reception queue at which flow is re-enabled (default: 512)
- ///
- public int RxLowWater { get; set; } = 512;
-
- ///
- /// Requested size for receive queue (default: 0 = use operating system default)
- ///
- public int RxQueue { get; set; }
-
- ///
- /// Constant. Max time for Send in ms = (Multiplier * Characters) + Constant (default: 0)
- ///
- public int SendTimeoutConstant { get; set; }
-
- ///
- /// Multiplier. Max time for Send in ms = (Multiplier * Characters) + Constant
- /// (default: 0 = No timeout)
- ///
- public int SendTimeoutMultiplier { get; set; }
-
- ///
- /// Number of stop bits (default: one)
- ///
- public StopBits StopBits { get; set; } = StopBits.One;
-
- ///
- /// If true, transmission is halted unless CTS is asserted by the remote station (default: false)
- ///
- public bool TxFlowCts { get; set; }
-
- ///
- /// If true, transmission is halted unless DSR is asserted by the remote station (default: false)
- ///
- public bool TxFlowDsr { get; set; }
-
- ///
- /// If true, transmission is halted when Xoff is received and restarted when Xon is received (default: false)
- ///
- public bool TxFlowX { get; set; }
-
- ///
- /// Requested size for transmit queue (default: 0 = use operating system default)
- ///
- public int TxQueue { get; set; }
-
- ///
- /// If false, transmission is suspended when this station has sent Xoff to the remote station (default: true)
- /// Set false if the remote station treats any character as an Xon.
- ///
- public bool TxWhenRxXoff { get; set; } = true;
-
- ///
- /// Specidies the use to which the DTR output is put (default: none)
- ///
- public HsOutput UseDtr { get; set; } = HsOutput.None;
-
- ///
- /// Specifies the use to which the RTS output is put (default: none)
- ///
- public HsOutput UseRts { get; set; } = HsOutput.None;
-
- ///
- /// The character used to signal Xoff for X flow control (default: DC3)
- ///
- public ASCII XoffChar { get; set; } = ASCII.DC3;
-
- ///
- /// The character used to signal Xon for X flow control (default: DC1)
- ///
- public ASCII XonChar { get; set; } = ASCII.DC1;
-
- ///
- /// True if online.
- ///
- public bool Online => _online && CheckOnline();
-
- ///
- /// True if the RTS pin is controllable via the RTS property
- ///
- protected bool RtSavailable => _stateRts < 2;
-
- ///
- /// Set the state of the RTS modem control output
- ///
- protected bool Rts
- {
- set
- {
- if (_stateRts > 1) return;
- CheckOnline();
- if (value)
- {
- if (Win32Com.EscapeCommFunction(_hPort.DangerousGetHandle(), Win32Com.SETRTS))
- _stateRts = 1;
- else
- ThrowException("Unexpected Failure");
- }
- else
- {
- if (Win32Com.EscapeCommFunction(_hPort.DangerousGetHandle(), Win32Com.CLRRTS))
- _stateRts = 1;
- else
- ThrowException("Unexpected Failure");
- }
- }
- get => _stateRts == 1;
- }
-
- ///
- /// True if the DTR pin is controllable via the DTR property
- ///
- protected bool DtrAvailable => _stateDtr < 2;
-
- ///
- /// The state of the DTR modem control output
- ///
- protected bool Dtr
- {
- set
- {
- if (_stateDtr > 1) return;
- CheckOnline();
- if (value)
- {
- if (Win32Com.EscapeCommFunction(_hPort.DangerousGetHandle(), Win32Com.SETDTR))
- _stateDtr = 1;
- else
- ThrowException("Unexpected Failure");
- }
- else
- {
- if (Win32Com.EscapeCommFunction(_hPort.DangerousGetHandle(), Win32Com.CLRDTR))
- _stateDtr = 0;
- else
- ThrowException("Unexpected Failure");
- }
- }
- get => _stateDtr == 1;
- }
-
- ///
- /// Assert or remove a break condition from the transmission line
- ///
- protected bool Break
- {
- set
- {
- if (_stateBrk > 1) return;
- CheckOnline();
- if (value)
- {
- if (Win32Com.EscapeCommFunction(_hPort.DangerousGetHandle(), Win32Com.SETBREAK))
- _stateBrk = 0;
- else
- ThrowException("Unexpected Failure");
- }
- else
- {
- if (Win32Com.EscapeCommFunction(_hPort.DangerousGetHandle(), Win32Com.CLRBREAK))
- _stateBrk = 0;
- else
- ThrowException("Unexpected Failure");
- }
- }
- get => _stateBrk == 1;
- }
-
-
- ///
- /// Port Name
- ///
- public string PortName { get; set; }
-
- public Handshake Handshake
- {
- get => _handShake;
- set
- {
- _handShake = value;
- switch (_handShake)
- {
- case Handshake.None:
- TxFlowCts = false;
- TxFlowDsr = false;
- TxFlowX = false;
- RxFlowX = false;
- UseRts = HsOutput.Online;
- UseDtr = HsOutput.Online;
- TxWhenRxXoff = true;
- RxGateDsr = false;
- break;
- case Handshake.XonXoff:
- TxFlowCts = false;
- TxFlowDsr = false;
- TxFlowX = true;
- RxFlowX = true;
- UseRts = HsOutput.Online;
- UseDtr = HsOutput.Online;
- TxWhenRxXoff = true;
- RxGateDsr = false;
- XonChar = ASCII.DC1;
- XoffChar = ASCII.DC3;
- break;
- case Handshake.CtsRts:
- TxFlowCts = true;
- TxFlowDsr = false;
- TxFlowX = false;
- RxFlowX = false;
- UseRts = HsOutput.Handshake;
- UseDtr = HsOutput.Online;
- TxWhenRxXoff = true;
- RxGateDsr = false;
- break;
- case Handshake.DsrDtr:
- TxFlowCts = false;
- TxFlowDsr = true;
- TxFlowX = false;
- RxFlowX = false;
- UseRts = HsOutput.Online;
- UseDtr = HsOutput.Handshake;
- TxWhenRxXoff = true;
- RxGateDsr = false;
- break;
- }
- }
- }
-
- #endregion
}
\ No newline at end of file
diff --git a/Nefarius.Peripherals.SerialPort/Win32PInvoke/Win32Com.cs b/Nefarius.Peripherals.SerialPort/Win32PInvoke/Win32Com.cs
deleted file mode 100644
index a8ee677..0000000
--- a/Nefarius.Peripherals.SerialPort/Win32PInvoke/Win32Com.cs
+++ /dev/null
@@ -1,91 +0,0 @@
-using System;
-using System.Runtime.InteropServices;
-
-namespace Nefarius.Peripherals.SerialPort.Win32PInvoke
-{
- internal class Win32Com
- {
-
- [DllImport("kernel32.dll")]
- internal static extern Boolean GetHandleInformation(IntPtr hObject, out UInt32 lpdwFlags);
-
-
- [DllImport("kernel32.dll")]
- internal static extern Boolean SetCommMask(IntPtr hFile, UInt32 dwEvtMask);
-
- // Constants for dwEvtMask:
- internal const UInt32 EV_RXCHAR = 0x0001;
- internal const UInt32 EV_RXFLAG = 0x0002;
- internal const UInt32 EV_TXEMPTY = 0x0004;
- internal const UInt32 EV_CTS = 0x0008;
- internal const UInt32 EV_DSR = 0x0010;
- internal const UInt32 EV_RLSD = 0x0020;
- internal const UInt32 EV_BREAK = 0x0040;
- internal const UInt32 EV_ERR = 0x0080;
- internal const UInt32 EV_RING = 0x0100;
- internal const UInt32 EV_PERR = 0x0200;
- internal const UInt32 EV_RX80FULL = 0x0400;
- internal const UInt32 EV_EVENT1 = 0x0800;
- internal const UInt32 EV_EVENT2 = 0x1000;
-
- [DllImport("kernel32.dll", SetLastError = true)]
- internal static extern Boolean WaitCommEvent(IntPtr hFile, IntPtr lpEvtMask, IntPtr lpOverlapped);
-
- [DllImport("kernel32.dll")]
- internal static extern Boolean CancelIo(IntPtr hFile);
-
- [DllImport("kernel32.dll", SetLastError = true)]
- internal static extern Boolean ReadFile(IntPtr hFile, [Out] Byte[] lpBuffer, UInt32 nNumberOfBytesToRead,
- out UInt32 nNumberOfBytesRead, IntPtr lpOverlapped);
-
- [DllImport("kernel32.dll")]
- internal static extern Boolean TransmitCommChar(IntPtr hFile, Byte cChar);
-
- ///
- /// Control port functions.
- ///
- [DllImport("kernel32.dll")]
- internal static extern Boolean EscapeCommFunction(IntPtr hFile, UInt32 dwFunc);
-
- // Constants for dwFunc:
- internal const UInt32 SETXOFF = 1;
- internal const UInt32 SETXON = 2;
- internal const UInt32 SETRTS = 3;
- internal const UInt32 CLRRTS = 4;
- internal const UInt32 SETDTR = 5;
- internal const UInt32 CLRDTR = 6;
- internal const UInt32 RESETDEV = 7;
- internal const UInt32 SETBREAK = 8;
- internal const UInt32 CLRBREAK = 9;
-
- [DllImport("kernel32.dll")]
- internal static extern Boolean GetCommModemStatus(IntPtr hFile, out UInt32 lpModemStat);
-
- // Constants for lpModemStat:
- internal const UInt32 MS_CTS_ON = 0x0010;
- internal const UInt32 MS_DSR_ON = 0x0020;
- internal const UInt32 MS_RING_ON = 0x0040;
- internal const UInt32 MS_RLSD_ON = 0x0080;
-
- ///
- /// Status Functions.
- ///
- [DllImport("kernel32.dll", SetLastError = true)]
- internal static extern Boolean GetOverlappedResult(IntPtr hFile, IntPtr lpOverlapped,
- out UInt32 nNumberOfBytesTransferred, Boolean bWait);
-
- //Constants for lpErrors:
- internal const UInt32 CE_RXOVER = 0x0001;
- internal const UInt32 CE_OVERRUN = 0x0002;
- internal const UInt32 CE_RXPARITY = 0x0004;
- internal const UInt32 CE_FRAME = 0x0008;
- internal const UInt32 CE_BREAK = 0x0010;
- internal const UInt32 CE_TXFULL = 0x0100;
- internal const UInt32 CE_PTO = 0x0200;
- internal const UInt32 CE_IOE = 0x0400;
- internal const UInt32 CE_DNS = 0x0800;
- internal const UInt32 CE_OOP = 0x1000;
- internal const UInt32 CE_MODE = 0x8000;
-
- }
-}
\ No newline at end of file
diff --git a/nuget.config b/nuget.config
new file mode 100644
index 0000000..223d6b4
--- /dev/null
+++ b/nuget.config
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file