0

I tried to receive data from medical 'Mindray bs 200' device through serial port. data received but is unreadable. Unable to find the kind of data encryption.

Here is the code that receives the data

Private Sub comPort_DataReceived(ByVal sender As Object, ByVal e As System.IO.Ports.SerialDataReceivedEventArgs) Handles comPort.DataReceived
    Dim str As String = ""
    If e.EventType = SerialData.Chars Then
        Do
            Dim bytecount As Integer = comPort.BytesToRead
            If bytecount = 0 Then
                Exit Do
            End If
            Dim byteBuffer(bytecount) As Byte

            comPort.Encoding = Encoding.GetEncoding(28591)
            ' comPort.Encoding = Encoding.GetEncoding(1252)
            'comPort.Encoding = Encoding.GetEncoding("Windows-1252")
            comPort.Read(byteBuffer, 0, bytecount)
            str = str & System.Text.Encoding.ASCII.GetString(byteBuffer, 0, 1)
            ' The str looks like
        Loop
    End If
    RaiseEvent ScanDataRecieved(str)
End Sub

Here is the data received ??????????????????????????????????????????????????????????????????????????????????????????????????????????????????X???????????????????

Tu deschizi eu inchid
  • 4,117
  • 3
  • 13
  • 24
Reagan
  • 71
  • 5
  • 1
    The following may be helpful: https://pdfcoffee.com/bs-200-host-interface-manual-v12-pdf-free.html and https://www.mindraynorthamerica.com/cmsAdmin/uploads/h-046-004990-00-a-series-communication-protocol-interface-guide-v2-0_004.pdf – Tu deschizi eu inchid Nov 12 '21 at 16:03
  • 1
    Make sure the baud rate, word length and parity you are opening the serial port with match those of the device. This looks very much like you would expect with incorrect serial speed/format mismatch. – JcMaltaDev Nov 12 '21 at 16:09
  • 1
    Ref the comment above ... nothing specific for BS-200 byt the serial baud/word-lengths on other Mindray serial interfaces is 115,000 baud, 8 databits, 1 stop bit, no parity, no handshaking. – JcMaltaDev Nov 12 '21 at 16:31
  • I tried your comments. No result. Just the same junk data is received. The only diffrence happens. when i change these encodings 'comPort.Encoding = Encoding.GetEncoding(28591) ' comPort.Encoding = Encoding.GetEncoding(1252) comPort.Encoding = Encoding.GetEncoding("Windows-1252") – Reagan Nov 12 '21 at 17:43
  • Do you have any documentation that states to use `Encoding.GetEncoding` ? Is the machine configured for a different language than the language that you're trying to write the program in? You should probably refer to the documentation for the machine in the language that the machine is configured for. Where are you viewing the data that you've shown? In the Output window for Visual Studio? You may want to write the data to a file instead and open it in Wordpad/Notepad. – Tu deschizi eu inchid Nov 12 '21 at 17:48
  • Dear that is a great comment let me give it a try. I will directly write it to file. – Reagan Nov 12 '21 at 17:55
  • It was rich textbox control. When i refer some documents i found it is advisable to do it in C++ or visual basic. Since i did it for humacount Blood count machine i didn't expect it this hard. – Reagan Nov 12 '21 at 18:02
  • The kind of data i am receiving now. is 18 60 00 06 78 00 86 78 E0 06 78 00 9E E0 66 7E 00 06 78 00 06 78 00 06 78 00 06 78 06 E6 78 7E 66 9E 00 66 78 06 66 78 1E 86 78 00 86 78 06 06 78 1E 06 78 7E 06 78 00 86 9E 60 06 78 00 86 78 06 06 78 00 66 78 60 06 78 00 86 78 86 E6 78 1E 66 78 18 86 78 00 06 9E 60 66 7E 66 86 78 7E 66 – Reagan Nov 12 '21 at 18:22
  • Software from the manufacturer may contain drivers. Have you installed any software that exists for the machine? – Tu deschizi eu inchid Nov 12 '21 at 18:29
  • I'm not familiar with your particular device. You're more likely to receive help for C#. You may want to create a post for C# and once you receive an answer that works, you can convert it to VB.NET. For C#, the following may be helpful: https://stackoverflow.com/questions/65957066/serial-to-usb-cable-from-a-scale-to-pc-some-values-are-just-question-marks/65971845#65971845 and https://stackoverflow.com/questions/67409850/cant-show-data-received-from-serial-port-on-c-sharp-richtextbox/67410160#67410160 – Tu deschizi eu inchid Nov 12 '21 at 18:47
  • According to the "host interface manual" (2 Communication and HL7 Protocol), _There are two types of transmission: real-time and batch...Real-time mode can be achieved only if a sample bar code reader is equipped. Batch-mode downloading refers to retrieving samples in certain period of the day...Transmission of calibration results is not allowed on the BS-200._ Please update your post to add clarification as to what type of transmission you are attempting - real time or batch. – Tu deschizi eu inchid Nov 14 '21 at 16:36
  • Sorry, It is mindray bc3000. It allows transmission of calibration. I am trying batch mode. – Reagan Nov 14 '21 at 23:23
  • Looks like "BS" indicates a Chemistry Analyzer while "BC" indicates a Hematology Analyzer. In your OP, you stated that it was a BS-200. It seems that you should first figure out the model number of the machine your working with. My (limited) research doesn't show a "BC-3000", but rather a "BC-3000 Plus". – Tu deschizi eu inchid Nov 15 '21 at 00:45
  • If you're using a BC-3000 Plus, the following may be helpful: https://www.manualslib.com/manual/1981843/Mindray-Bc-3000-Plus.html . It looks like the BC-3000 Plus supports both handshaking and without handshaking - the serial port settings need to be configured in the machine in the Setup screen (Setup => Transmission) - under "5.5 Transmission". [This post](https://www.dreamincode.net/forums/topic/207372-reading-data-from-mindray-bc-2800/) may be helpful as well. You should be able to get all of the manuals from the manufacturer. – Tu deschizi eu inchid Nov 15 '21 at 00:59
  • It looks like five baud rates are supported: 19200, 9600 (default), 4800, 2400, and 1200. The following Parity options are available: Odd, Even, None (default). The following options are available for Handshake: No (default), Yes. The following options are available for "Auto Transmission": Off, On. (Auto Trans: whether the analyzer will automatically transmit the results to the host when analysis is finished). – Tu deschizi eu inchid Nov 15 '21 at 01:00
  • Here are some `SerialPort` URLs which may be helpful: [DSR](https://learn.microsoft.com/en-us/dotnet/api/system.io.ports.serialport.dsrholding?view=dotnet-plat-ext-5.0) - used during DSR/DTR handshaking, [DtrEnable](https://learn.microsoft.com/en-us/dotnet/api/system.io.ports.serialport.dtrenable?view=dotnet-plat-ext-5.0) , [Handshake](https://learn.microsoft.com/en-us/dotnet/api/system.io.ports.serialport.handshake?view=dotnet-plat-ext-5.0) , and [Handshake enum](https://learn.microsoft.com/en-us/dotnet/api/system.io.ports.handshake?view=dotnet-plat-ext-5.0) . – Tu deschizi eu inchid Nov 15 '21 at 01:23

1 Answers1

0

While not for this particular device, this document discusses a device that uses the same RS232 communication protocol and recommends the following SerialPort settings:

  • Baud rate: 115200
  • DataBits: 8
  • StopBits: 1
  • Parity: None
  • No flow control

Note: Minimum baud rate is 57600.

According to this document

2.1 Message Grammar:

Each HL7 message is composed of segments that end with <CR>

3 Communication Process and Message Example:

A message of HL7 protocol is the format of: <SB> ddddd <EB><CR>

                                   ASCII value (HEX)

<SB> (start of message):           0B  (VT - vertical tab)
<EB> (end of message):             1C  (FS - file separator)
<CR> (carriage return)             0D  (carriage return)

In the code below, I'll show how to use a buffer to collect data when "start of message" is received (HEX: 0B) and fill the buffer until "end of message" (HEX: 1C) followed by a carriage return (HEX: 0D) is received - at which point we'll raise an event and/or output the data.

For testing, we'll also write the data to a file in the Documents folder - this file is deleted each time the program starts so that only data from the current execution of the program is contained in the file. Each byte of data is output as a 2-digit hexadecimal value which allows us to see if a value is a control character.

The following may be helpful for interpreting the values:


Create a class (name: HelperSerialPort.vb)

HelperSerialPort.vb

Note: The code in method Port_DataReceived (within the if-elseif statements) is untested - I don't have the particular device that you're using to be able to test it.

'(.NET Framework) - Add reference: Project => Add Reference => Assemblies => System.Management

'add using statement: Using System.Management;
'
'For >= .NET 5, install NuGet Package: System.IO.Ports and System.Management
'add Imports statements: Imports System.IO.Ports; Imports System.Management;
'
'

Imports System.Management
Imports System.IO.Ports

'specify valid baud rates
Public Enum PortBaudRate As Integer
    Baud57600 = 57600
    Baud76800 = 76800
    Baud115200 = 115200
End Enum

Public Class HelperSerialPort
    Implements IDisposable

    Private Const BufferSize As Integer = 4096 'this value may need to be changed
    Private Port As SerialPort = Nothing
    Private BytesReadMessage As Integer = 0 'used to hold message bytes read
    Private Buffer(BufferSize) As Byte 'used to hold data
    Private Filename As String = Nothing
    Private IsMessage As Boolean = False

    'events that can be subscribed to
    Public Event DataReceived(ByVal sender As Object, ByVal data As String)
    Public Event ErrorReceived(ByVal sender As Object, ByVal errMsg As String)

    Sub New()
        'set value
        'data will be written to this file for testing
        Filename = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Mindray BS200.txt")

        If Not String.IsNullOrEmpty(Filename) AndAlso System.IO.File.Exists(Filename) Then
            'delete existing file
            System.IO.File.Delete(Filename)
        End If

        System.Diagnostics.Debug.WriteLine("Filename: '" & Filename & "'")
    End Sub

    Public Function Connect(ByVal comPort As String, ByVal Optional baudRate As PortBaudRate = PortBaudRate.Baud115200) As String
        Dim errMsg As String = String.Empty
        Dim portName As String = String.Empty
        Dim result As String = String.Empty

        If String.IsNullOrEmpty(comPort) Then
            errMsg = "COM port not selected"
            Throw New Exception(errMsg)
        End If

        Try
            If Port Is Nothing Then

                'create new instance
                Port = New SerialPort(comPort)

                'subscribe to events (add event handlers)
                AddHandler Port.DataReceived, AddressOf Port_DataReceived
                AddHandler Port.ErrorReceived, AddressOf Port_ErrorReceived

            End If

            If Not Port.IsOpen Then

                'set properties
                Port.BaudRate = baudRate
                Port.Handshake = Handshake.None

                'if parity is even or odd, then set DataBits = 7
                'if parity is none, set DataBits = 8
                Port.Parity = Parity.None
                Port.DataBits = 8

                Port.StopBits = StopBits.One
                'Port.ReadTimeout = 500 'this value may need to be adjusted
                Port.WriteTimeout = 500 'this value may need to be adjusted
                Port.DtrEnable = True 'enable Data Terminal Ready
                'Port.RtsEnable = True 'enable Request to Send
                'Port.DiscardNull = True
                'Port.ReceivedBytesThreshold = 1 'number of bytes that causes 'DataReceived' event to be raised; default is 1

                'open port
                Port.Open()

                result = "Status: Connected"
            Else
                result = "Status: Already Connected"
            End If

        Catch ex As System.IO.IOException
            errMsg = "Error: " & ex.Message
            result = errMsg 'set value
            Debug.WriteLine(errMsg)

            Dispose()

        Catch ex As Exception
            errMsg = "Error: " & ex.Message
            result = errMsg 'set value
            Debug.WriteLine(errMsg)
            Throw ex
        End Try

        Debug.WriteLine(result)

        Return result
    End Function

    Public Function Disconnect() As String
        Dispose()

        Return "Status: Disconnected"
    End Function

    Public Sub Dispose() Implements System.IDisposable.Dispose
        If Port IsNot Nothing Then

            'unsubscribe from events (remove event handlers)
            RemoveHandler Port.DataReceived, AddressOf Port_DataReceived
            RemoveHandler Port.ErrorReceived, AddressOf Port_ErrorReceived

            Port.Dispose()
            Port = Nothing
        Else
            Debug.WriteLine("Info: Port is null")
        End If
    End Sub

    Public Function IsPortOpen() As Boolean
        If Port IsNot Nothing Then
            If Port.IsOpen Then
                Return True
            Else
                Try
                    Port.Dispose()
                Catch ex As Exception
                    'do nothing
                    Debug.WriteLine("Error (IsPortOpen): " & ex.Message)
                End Try
            End If

            Port = Nothing
            System.GC.Collect()
            System.GC.Collect()
        End If

        Return False
    End Function

    Private Sub Port_DataReceived(ByVal sender As Object, ByVal e As SerialDataReceivedEventArgs)
        'ToDo: add desired code

        Dim bytesRead As Integer = 0
        Dim bytesToRead As Integer = 1
        Dim errMsg As String = String.Empty

        'read SerialPort data
        Do
            'read 1 byte at a time
            bytesRead = Port.Read(Buffer, BytesReadMessage, bytesToRead)

            'when <SB> (HEX: 0B) is received, remove all existing data from buffer
            'this will result in the buffer only containing our desired data.
            'when <EB> (HEX: 1C) is received followed by <CR> (HEX: 0D), 
            'this is the end of the message, so we'll send the message and/or display it.
            'Buffer(BytesReadMessage) contains the last byte of data that was read
            '

            If Buffer(BytesReadMessage) = &HB Then
                '0x0B - VT (vertical tab); in the documentation this is '<SB>' - start of message

                System.Diagnostics.Debug.WriteLine("<SB> (start of message)")

                'remove existing data (get ready for new message)
                Array.Clear(Buffer, 0, Buffer.Length)

                're-initialize to -1. It's incremented below which will result in the value being 0
                BytesReadMessage = -1

                'set value - start saving data to the buffer
                IsMessage = True

            ElseIf IsMessage AndAlso Buffer(BytesReadMessage) = &HD AndAlso Buffer(BytesReadMessage - 1) = &H1C Then
                '0x1C - FS (file separator); in the documentation this is '<EB>' - end of message
                '0x0D - CR (carriage return); in the documentation this is '<CR>' 

                System.Diagnostics.Debug.WriteLine("<EB> (end of message)")

                'raise event to send data
                SendData(Buffer)

                'set value - stop saving data to the buffer
                IsMessage = False

            ElseIf Not IsMessage Then
                'for debugging/testing, display non-message data
                System.Diagnostics.Debug.WriteLine("Non-message data: " & Buffer(BytesReadMessage).ToString("X2"))
            End If

            'set value
            BytesReadMessage += bytesRead

            Debug.WriteLine("Info: BytesReadMessage: " & BytesReadMessage.ToString() & " bytesRead: " & bytesRead.ToString() & " Port.BytesToRead: " & Port.BytesToRead.ToString())

        Loop While (Port.BytesToRead > 0)

        Debug.WriteLine(String.Format("{0}---------------------------{0}", System.Environment.NewLine))
    End Sub

    Private Sub Port_ErrorReceived(ByVal sender As Object, ByVal e As SerialErrorReceivedEventArgs)
        'ToDo: add desired code

        Dim errMsg As String = e.EventType.ToString()

        Debug.WriteLine("Port_ErrorReceived: " & errMsg)

        'raise event
        RaiseEvent ErrorReceived(Me, errMsg)
    End Sub

    Public Sub SendData(buffer() As Byte)
        'ToDo: modify the code below and/or add desired code

        'convert to a string that's human-readable

        Dim data As String = String.Empty
        If buffer IsNot Nothing Then
            For i As Integer = 0 To BytesReadMessage Step 1
                If Not String.IsNullOrEmpty(data) Then
                    data += " " 'append space
                End If

                'for testing, convert to a 2-digit HEX value
                data += buffer(i).ToString("X2")
            Next

            'add newline
            data += System.Environment.NewLine
        End If

        System.Diagnostics.Debug.WriteLine("data: " & data)

        'for testing save to file
        If Not String.IsNullOrEmpty(Filename) Then
            'append data to file
            System.IO.File.AppendAllText(Filename, data)
        End If

        'raise event
        RaiseEvent DataReceived(Me, data)

        'Note: "When receiving the message, the LIS (Laboratory Information Management System) host first judges the legality and type of the message and then replies accordingly."
        'ToDo: A response needs to be sent for each message received (see documentation for information on how to create the appropriate message - "3 Communication Process and Message Example")

    End Sub

    Public Sub WriteToSerialPort(ByVal data As String)
        Dim errMsg As String = String.Empty

        Try
            If Port.IsOpen Then

                'convert string to Byte array
                Dim hexArr As Byte() = System.Text.Encoding.ASCII.GetBytes(data)

                For Each hexVal As Byte In hexArr

                    'convert byte to byte array
                    Dim tempArr As Byte() = New Byte() {hexVal}

                    'write 
                    Port.Write(tempArr, 0, 1)

                    'add 1 ms delay before writing next byte
                    System.Threading.Thread.Sleep(1)
                Next
            Else
                errMsg = "Error: Port is not open. Please open the connection and try again."
                Debug.WriteLine(errMsg)
                Throw New Exception(errMsg)
            End If
        Catch ex As Exception
            errMsg = "Error: " & ex.Message
            Debug.WriteLine(errMsg)
            Throw ex
        End Try
    End Sub
End Class

Below is an alternative version of method Port_DataReceived that uses ReadExisting() instead - however, it may not work in your situation.

Port_DataReceived (version that uses ReadExisting):

Private Sub Port_DataReceived(ByVal sender As Object, ByVal e As SerialDataReceivedEventArgs)
    'ToDo: add desired code

    'read SerialPort data
    Dim data As String = String.Empty

    data = Port.ReadExisting()
    'data = Port.ReadLine

    Debug.WriteLine("Port_DataReceived: " & data)

    'raise event
    RaiseEvent DataReceived(Me, data)
End Sub

Form1:

  • Add a Button (name: btnConnectDisconnect)
  • Double-click the button to add the event handler
  • Add a RichTextBox (name: RichTextBox1)

enter image description here

Form1.vb

Note: In the code below, you'll need to update helper.Connect("COM1") with the correct COM port.

Public Class Form1
    Private helper As HelperSerialPort = New HelperSerialPort()
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

    End Sub

    Private Sub Disconnect()
        If helper IsNot Nothing Then
            'unsubscribe from event(s)
            RemoveHandler helper.DataReceived, AddressOf Helper_DataReceived
            RemoveHandler helper.ErrorReceived, AddressOf Helper_ErrorReceived

            helper.Dispose()
            helper = Nothing
        End If
    End Sub

    Private Sub btnConnectDisconnect_Click(sender As Object, e As EventArgs) Handles btnConnectDisconnect.Click
        If helper Is Nothing Then
            'create new instance
            helper = New HelperSerialPort()
        End If

        If btnConnectDisconnect.Text = "Connect" Then
            'clear existing data
            RichTextBox1.Clear()

            'ToDo: change to your desired COM port
            helper.Connect("COM1")

            'subscribe to event(s)
            AddHandler helper.DataReceived, AddressOf Helper_DataReceived
            AddHandler helper.ErrorReceived, AddressOf Helper_ErrorReceived

            'set text
            btnConnectDisconnect.Text = "Disconnect"
            btnConnectDisconnect.Refresh()
        Else
            Disconnect()

            'set text
            btnConnectDisconnect.Text = "Connect"
            btnConnectDisconnect.Refresh()
        End If
    End Sub

    Private Sub Helper_DataReceived(ByVal sender As Object, ByVal data As String)
        'ToDo: add desired code
        System.Diagnostics.Debug.WriteLine(DateTime.Now.ToString("HH:mm:ss") & " - Helper_DataReceived: " & data)

        'append data to RichTextBox
        RichTextBox1.Invoke(New MethodInvoker(Sub()
                                                  RichTextBox1.AppendText(DateTime.Now.ToString("yyyy/MM/dd HH:mm:ss.fff") & " - " & data)
                                              End Sub))
    End Sub

    Private Sub Helper_ErrorReceived(ByVal sender As Object, ByVal errMsg As String)
        'ToDo: add desired code
        System.Diagnostics.Debug.WriteLine(DateTime.Now.ToString("HH:mm:ss") & " - Helper_ErrorReceived: " & errMsg)

        'append error message to RichTextBox
        RichTextBox1.Invoke(New MethodInvoker(Sub()
                                                  RichTextBox1.AppendText(errMsg)
                                              End Sub))
    End Sub

    Private Sub Form1_FormClosed(sender As Object, e As FormClosedEventArgs) Handles MyBase.FormClosed
        Disconnect()
    End Sub
End Class

Resources:

Tu deschizi eu inchid
  • 4,117
  • 3
  • 13
  • 24
  • Thanks for your response bro, still unable to decode the data sent. – Reagan Nov 13 '21 at 06:50
  • 1
    I've updated the post. The code now logs the data to a file in the Documents folder, as well as outputs it to a RichTextBox. Each byte of data is shown as a 2-digit hexadecimal value (the values are separated by a space) - this should be useful for testing/debugging. – Tu deschizi eu inchid Nov 13 '21 at 21:29
  • That is same problem. Which means unexpected data. with your code the result is "Non-message data". The message start or end are not received. just some binary from the very beginning. – Reagan Nov 18 '21 at 07:49
  • We are going to re-install the windows and try it. because there was similar software before our serial reader. – Reagan Nov 18 '21 at 08:13
  • It is all about HL7 Protocol – Reagan Nov 22 '21 at 18:12