Как использовать последовательный порт в среде приложения-службы, постоянно прослушивая данные
Я написал служебное приложение, которое прослушивает порт для любых коммуникаций, которые могут пройти, наша лаборатория проведет определенный тест, который будет посылать последовательные данные каждые пару часов или около того. служба работает, забирает данные в течение нескольких часов, а затем загадочно останавливается. системный журнал событий сообщает, что служба неожиданно прервана. и в журнале событий приложения есть более описательная ошибка.NET,
Приложение: BondTestService.exe Framework Версия: v4.0.30319 Описание: Процесс был прерван из-за необработанного исключения. Сведения об исключении: System.ObjectDisposedException в System.Runtime.InteropServices.SafeHandle.DangerousAddRef(Boolean ByRef) в System.StubHelpers.StubHelpers.SafeHandleAddRef(System.Runtime.InteropServices.SafeHandNhoef.Og.RegSlayEngRef).Win32.SafeHandles.SafeFileHandle, System.Threading.NativeOverlapped*, Int32 ByRef, Boolean) в System.IO.Ports.SerialStream+EventLoopRunner.WaitForCommEvent() в System.Threading.ThreadHelper.ThreadSystem.Ob.ExecutionContext.RunInternal (System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean) в System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object). в System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object) в System.Threading.ThreadHelper.ThreadStart()
Я читал, как ведут себя сервисы и как ведут себя последовательные порты, так что поправьте меня, если я ошибаюсь, если между тестами есть промежуток в 2 часа или около того, сервис предположит, что он не работает, и остановится сам?
Я также прочитал после чтения буфера из последовательного порта, я добавляю к объекту строителя строки, как показано ниже, и делаю то, что мне нужно со строкой, тогда что происходит с последовательным портом, остается ли он открытым в ожидании следующего значения или мне нужно закрыть и снова открыть, чтобы обновить?
Не уверен, как с этим справиться, так как он должен быть открыт, ожидая, когда тестировщик лаборатории отправит свои данные в любой момент времени.
Imports System
Imports System.Data.SqlClient
Imports System.IO.Ports
Imports System.Net.Mime
Imports Microsoft.Win32
Imports System.IO
Imports System.Text.RegularExpressions
Imports BondTestService.PI
Imports PCA.Core.Configuration
Public Class Bond
Dim WithEvents serialPort As New IO.Ports.SerialPort
Public Delegate Sub myDelegate()
Public RawString As New System.Text.StringBuilder
Public value As String
Public BondTest As Integer = 10
#Region "Commport Traffic and Configuration Validations"
Public Sub StartListening()
If serialPort.IsOpen Then
serialPort.Close()
ErrorLog2(Now.ToString & "Port Closed because StartListening method started over")
End If
Try
With serialPort
.PortName = Registry.LocalMachine.OpenSubKey("SOFTWARE\Wow6432Node\AUTOLABDEVICESERVICE\bondtest", True).GetValue("commport")
.BaudRate = CInt(Registry.LocalMachine.OpenSubKey("SOFTWARE\Wow6432Node\AUTOLABDEVICESERVICE\bondtest", True).GetValue("baudrate"))
If Registry.LocalMachine.OpenSubKey("SOFTWARE\Wow6432Node\AUTOLABDEVICESERVICE\bondtest", True).GetValue("parity") = 0 Then
.Parity = Parity.None
End If
If Registry.LocalMachine.OpenSubKey("SOFTWARE\Wow6432Node\AUTOLABDEVICESERVICE\bondtest", True).GetValue("stopbits") = 1 Then
.StopBits = StopBits.One
End If
.DataBits = CInt(Registry.LocalMachine.OpenSubKey("SOFTWARE\Wow6432Node\AUTOLABDEVICESERVICE\bondtest", True).GetValue("bytesize"))
.Handshake = Handshake.None
If Registry.LocalMachine.OpenSubKey("SOFTWARE\Wow6432Node\AUTOLABDEVICESERVICE\bondtest", True).GetValue("RtsControl") = 1 Then
.RtsEnable = True
Else
.RtsEnable = False
End If
End With
serialPort.Open()
'debug
'ErrorLog2("Listening to COM 19, SerialPort has been Opened")
Catch ex As Exception
ErrorLog2(Now.ToString & ex.tostring)
End Try
End Sub
Public Function Filelocator() As String
' Dim filePath As String = IO.Path.Combine(Application.StartupPath, "bondtest.bat")
Dim filePath As String = IO.Path.Combine("C:\Program Files (x86)\PIPC\Interfaces\Lab", "BondTest.bat")
'Dim reader As New System.IO.StreamReader(filePath)
Dim LineNumber = 4
Using file As New StreamReader(filePath)
' Skip all preceding lines: '
For i As Integer = 1 To LineNumber - 1
If file.ReadLine() Is Nothing Then
ErrorLog2("LineNumber")
End If
Next
' Attempt to read the line you're interested in: '
Dim line As String = file.ReadLine()
If line Is Nothing Then
ErrorLog2("LineNumber")
End If
Return line
End Using
End Function
Private Sub serialPort_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles SerialPort.DataReceived
Try
If GetBondInterfaceStatus = 1 Then
UPdateVariable()
Else
exit Sub
End If
Catch ex As Exception
Errorlog2(Ex.Tostring)
End Try
End Sub
#End Region
#Region "String Handling"
Public Sub UPdateVariable()
With RawString
.Append(serialPort.ReadLine())
End With
try
ErrorLog2(now.ToString & RawString.ToString)
InsertTestDataDEBUG(GetRecordID, BondTest, BondTestType.ToUpper.ToString, GetBondPosition(), StringParser(RawString.ToString()), RawString.tostring)
InsertTestData(GetRecordID, BondTest, BondTestType.ToUpper.ToString, GetBondPosition(), StringParser(RawString.ToString()))
RawString.Clear()
Catch ex As Exception
ErrorLog2(ex.ToString())
End Try
End Sub
Public Function StringParser(RawString As String)As Double ()
Dim Moisture = RawString
Dim pattern As String = "[0-9],"
Dim regex As New Regex(pattern)
Dim Counter As Integer = 0
Dim dblValues(1) As Double
Dim values As String() = Moisture.Split(New Char() {" "c})
for i = 0 to values.Count - 1
if regex.IsMatch(values(i)) Then
dblValues(Counter) = CDbl(values(i).Substring(0,1))
Counter = Counter + 1
Elseif values(i) = "" Then
continue for
else
if Double.TryParse(values(i), dblValues(Counter)) Then
Counter = Counter + 1
End If
End If
Next
Return dblValues
End Function
#End Region
#Region "SQL Statements"
Private Sub InsertTestData(RecordID As Integer, BondTest As Integer, TestType As String, TestPos As Integer, dataArray() As Double)
Dim InsertQuery As String = ""
Dim conn As New BondSQLConnection("PaperTests")
' Dim TestPos = StartingTestPos + (CInt(dataArray(0)) - 1)
conn("@RecordID") = RecordID
conn("@Test") = BondTest
conn("@TestType") = TestType
conn("@TestPos") = TestPos
conn("@TestData") = dataArray(1)
conn("@TestDateTime") = now.tostring
InsertQuery = "INSERT INTO PaperTests.dbo.PaperTestValues(ReelRecordID, Test, TestLocation, TestPosition, TestValue, TestTimeStamp) VALUES (@RecordID, @Test, @TestType, @TestPos, @TestData, @TestDateTime)"
Try
conn.ExecuteNonQuery(InsertQuery)
IncrementTestPosition
Catch ex As Exception
ErrorLog2(ex.ToString())
End Try
End Sub
Private Sub InsertTestDataDEBUG(RecordID As Integer, BondTest As Integer, TestType As String, TestPos As Integer, dataArray() As Double, rawString As String)
Dim InsertQuery As String = ""
Dim conn As New BondSQLConnection("PaperTests")
conn("@RecordID") = RecordID
conn("@Test") = BondTest
conn("@TestType") = TestType
conn("@TestPos") = TestPos
conn("@TestData") = dataArray(1)
conn("@RawString") = rawString
conn("@TestDateTime") = now.tostring
InsertQuery = "INSERT INTO PaperTests.dbo.InterfaceTesting(ReelRecordID, Test, TestLocation, TestPosition, TestValue, TestTimeStamp, RawValue) VALUES (@RecordID, @Test, @TestType, @TestPos, @TestData, @TestDateTime, @RawString)"
Try
conn.ExecuteNonQuery(InsertQuery)
Catch ex As Exception
ErrorLog2(ex.ToString())
End Try
End Sub
Private Sub IncrementTestPosition()
Dim tempPosition As Integer = GetBondPosition()
Dim FrontOriginalMax = 5
Dim CenterOriginalMax = 15
Dim BackOriginalMax = 25
Dim FrontRetestOrWinderMax = 10
Dim CenterRetestOrWinderMax = 20
Dim BackRetestOrWinderMax = 30
If tempPosition = FrontOriginalMax Then
tempPosition = 11
else if tempPosition = CenterOriginalMax Then
tempPosition = 21
else if tempPosition = BackOriginalMax Then
tempPosition = 1
Else If tempPosition = FrontRetestOrWinderMax then
tempPosition = 1
Else If tempPosition = CenterRetestOrWinderMax then
tempPosition = 1
Else If tempPosition = BackRetestOrWinderMax then
tempPosition = 1
else
tempPosition = tempPosition + 1
End If
SetBondPosition(tempPosition.tostring)
End Sub
#End Region
#Region "Get PiValues"
Private Function GetRecordID() As Int64
Dim RecordID As Int32 = 0
Try
Dim piserver As New PIServer("valpi", "piadmin", "fatb0y",True)
RecordID = piserver.GetCurrentValue("PAPERLAB:PaperLabReelSelected")
Catch ex As Exception
ErrorLog2(ex.ToString())
End Try
Return RecordID
End Function
Private Function GetBondPosition() As Int64
Dim BondPos As Int32 = 0
Try
Dim piserver As New PIServer("valpi", "piadmin", "fatb0y",True)
BondPos = CInt(piserver.GetCurrentValue("PAPERLAB:SBOND.POS"))
Catch ex As Exception
ErrorLog2(ex.ToString())
End Try
Return BondPos
End Function
Private Sub SetBondPosition(pos As String)
Try
Dim piserver As New PIServer("valpi", "piadmin", "fatb0y",True)
piserver.WriteValue("PAPERLAB:SBOND.POS", pos)
Catch ex As Exception
ErrorLog2(ex.ToString())
End Try
End Sub
Private Function BondTestType() As String
Dim TestType As String = ""
Try
Dim piserver As New PIServer("valpi", "piadmin", "fatb0y",True)
TestType = piserver.GetCurrentValue("M1:BOND.TYPE")
Catch ex As Exception
ErrorLog2(ex.ToString())
End Try
Return TestType
End Function
Private Function BondReelLoc() As String
Dim ReelLoc As String = ""
Try
Dim piserver As New PIServer("valpi", "piadmin", "fatb0y",True)
ReelLoc = piserver.GetCurrentValue("M1:BOND.ReelLoc")
Catch ex As Exception
ErrorLog2(ex.ToString())
End Try
Return ReelLoc
End Function
Private Function GetBondInterfaceStatus() As Integer
Dim Status As Integer = 0
Try
Dim piserver As New PIServer("valpi", "piadmin", "fatb0y",True)
Status = CInt(piserver.GetCurrentValue("PAPERLAB:BOND_INTERFACE.S"))
Catch ex As Exception
ErrorLog2(ex.ToString())
End Try
Return Status
End Function
#End Region
#Region "Debug"
Private Sub ErrorLog(RecordID As Int32, BondTest As Integer, ReelLoc As String, TestType As String, StartingTestPos As Integer, dataArray() As Double)
Dim SavePath As String = "C:\Program Files (x86)\PIPC\Interfaces\Lab"
Dim NameOfFile As String = "BondTest Debug File"
Dim TestPos = StartingTestPos + (CInt(dataArray(0)) - 1)
If System.IO.File.Exists(SavePath & "\" & NameOfFile & ".txt") Then
Using sw As StreamWriter = New StreamWriter(SavePath & "\" & NameOfFile & ".txt", True)
' For i = 0 To dataArray.Count -1
sw.WriteLine(" ")
sw.WriteLine(RecordID & " " & BondTest & " " & ReelLoc & " " & TestType & " " & TestPos & " " & dataArray(1).ToString)
' TestPos = TestPos + 1
' Next
End Using
else
File.Create(SavePath & "\" & NameOfFile & ".txt").Dispose()
Using sw As StreamWriter = File.CreateText(SavePath & "\" & NameOfFile & ".txt")
'For i = 0 To dataArray.Count -1
sw.WriteLine(" ")
sw.WriteLine(RecordID & " " & BondTest & " " & ReelLoc & " " & TestType & " " & TestPos & " " & dataArray(1).ToString)
' TestPos = TestPos + 1
'Next
End Using
End If
End Sub
Private Sub ErrorLog2(dataArray as string)
Dim SavePath As String = "C:\Program Files (x86)\PIPC\Interfaces\Lab"
Dim NameOfFile As String = "BondTest Debug File"
' Dim TestPos = StartingTestPos
If System.IO.File.Exists(SavePath & "\" & NameOfFile & ".txt") Then
Using sw As StreamWriter = New StreamWriter(SavePath & "\" & NameOfFile & ".txt", True)
sw.WriteLine(" ")
sw.WriteLine(dataArray)
End Using
else
File.Create(SavePath & "\" & NameOfFile & ".txt").Dispose()
Using sw As StreamWriter = File.CreateText(SavePath & "\" & NameOfFile & ".txt")
sw.WriteLine(" ")
sw.WriteLine(dataArray)
End Using
End If
End Sub
#End Region
Это скриншот ошибок:
заранее спасибо
2 ответа
Обновление: так как Тимми говорил, что соединение удаляется сборщиком мусора. поэтому я объявил объект как общую переменную в классе
Shared Dim WithEvents serialPort as IO.Ports.SerialPort
и в методе OnStart я инициировал его как новый последовательный порт и включил его. не выдает никаких ошибок, так как сборка мусора не избавится от него. Надеюсь, что это помогает кому-то, имеющему подобную проблему.
Обычно после открытия последовательного порта в.NET он остается открытым в течение произвольного времени. Я написал несколько приложений.NET, где последовательные порты используются месяцами или годами без перезагрузки приложения или компьютера, и они работают хорошо.
Согласно опубликованной вами информации об исключении, похоже, что этот последовательный порт был удален. Есть несколько возможных причин.
- Использование плохого драйвера или HW, который отключает ваш последовательный порт. Я использовал много преобразователей USB-RS232, и некоторые из них имели плохие драйверы, поэтому иногда порты были случайно отключены и
ObjectDisposedException
был брошен. В более ранних выпусках Windows (XP) ОС даже "сине-экранирована". Вот больше информации о такой ситуации, когдаObjectDisposedException
брошен
Это известная проблема с SerialPort. Удаление устройства вызывает неуловимое исключение в фоновом потоке, которое оно использует (WaitForCommEvent). Единственные решения - не использовать SerialPort или создавать файл.config, который переводит режим обработки необработанных исключений в поведение.NET 1.1.
Кабель USB вашего преобразователя RS232 отключен вручную. Если вы это сделаете, большинство драйверов обычно отключают все дескрипторы вашего последовательного порта и.NET бросков
ObjectDisposedException
,Также проверьте настройки управления питанием на USB-порту, если используется конвертер USB-RS232. Попробуйте снять этот флажок на USB-устройстве, к которому подключен конвертер.
Ошибка SW в вашем коде.
Всегда желательно (особенно если используется конвертер), чтобы попробовать больше типов конвертеров, просто чтобы убедиться, что в устройстве / драйвере HW нет проблем.