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