    Function TransferNames(ByRef bw As System.ComponentModel.BackgroundWorker) As Integer

        Dim result As Integer = 0 ' 1 means  success

        Dim CMOSMemoryBytes(192) As Byte
        Dim CMOSMemoryIndex, CMOSMemoryWords(64), SectorBuffer(256 / 3 + 1) As UInt32

        ' DSP clock memory values
        Dim PrintPointer, TestPointer As Integer
        Dim PointerLeft, PointerRight, PrintSaveMode As Integer
        Dim NamesPresent As Boolean

        Dim msg As String
        Dim gInputState As InputState = InputState.Waiting
        CMOSMemoryIndex = 0

        Try
            ' Get data from the COM port.
            Module1.MSComm1.BaudRate = 115200

            IsBluetoothConnection = IsPortBluetooth(Module1.MSComm1.PortName())

            If Not Module1.MSComm1.IsOpen Then Module1.MSComm1.Open()

            'Debug.Print("open in DownloadNamesBinary ")
            Module1.MSComm1.ReadTimeout = 10000
            Module1.MSComm1.WriteTimeout = 500 ' to prevent stalling in Write that causes bw to hang
            Module1.MSComm1.DiscardInBuffer()   ' discard accumulated characters
            Dim UserAborted As Boolean = False

            Do While True
                Dim nextByte As Byte = u.ReadNextByte(Module1.MSComm1, bw)
                'Debug.Print("nextChar: " & String.Format("{0:x}", nextByte))

                Select Case gInputState
                    'Waiting for signal from EROSCAN that it is ready to transmit
                    Case InputState.Waiting
                        If nextByte = 27 Then
                            'Debug.Print("rcvd esc")
                            gInputState = InputState.WaitingGotEscape
                        Else
                            gInputState = InputState.Waiting
                            Debug.Print("expected esc")
                        End If

                    Case InputState.WaitingGotEscape
                        If nextByte = Asc("v") Then
                            'Debug.Print("rcvd v")
                            bw.ReportProgress(0, StringResources.TransferStarted)
                            HandShake(0) = &HF2 ' for getting the DSP into Remote Program Mode
                            Module1.MSComm1.Write(HandShake, 0, 1)

                            Thread.Sleep(2000)   ' wait to avoid DSP hang -  todo review the reason (DSP code) 

                            'Debug.Print("before sendByteWithEcho 32 " + CStr(Now.Second) + " " + CStr(Now.Millisecond))

                            ' get I2C data

                            sendByteWithEcho(0, bw)
                            sendByteWithEcho(32, bw)    ' fun32
                            'Debug.Print("after sendByteWithEcho")
                            For i As Int16 = 0 To 5
                                CMOSMemoryWords(i) = GetWord(bw)
                                'Debug.Print("fun32 location (" & CStr(i) & ") = " & CStr(CMOSMemoryWords(i)))
                            Next

                            ' as per documentation/memory.txt in DSP
                            TestPointer = CMOSMemoryWords(0)
                            PrintPointer = CMOSMemoryWords(1)
                            PointerLeft = CMOSMemoryWords(2)
                            PointerRight = CMOSMemoryWords(3)
                            PrintSaveMode = CMOSMemoryWords(4)
                            NamesPresent = Not CMOSMemoryWords(5)

                            Dim NumberTests As Integer

                            If PrintSaveMode = 1 Then
                                NumberTests = TestPointer - PrintPointer
                                If NumberTests < 0 Then NumberTests = NumberTests + 512 ' this value if hardcoded in Express
                            Else
                                NumberTests = 0
                                If PointerLeft <> &HFFF Then NumberTests += 1
                                If PointerRight <> &HFFF Then NumberTests += 1
                            End If

                            If NumberTests > 0 Then
                                Dim WarnMsg As String = String.Format(StringResources.thereareXtestAreYouSure, CStr(NumberTests))
                                If MsgBox(WarnMsg, vbOKCancel, StringResources.Testswillbedeleted) = vbCancel Then
                                    Debug.Print("download aborted")
                                    UserAborted = True
                                    Exit Do
                                End If
                            End If

                            Thread.Sleep(100)   ' wait 100 ms todo review need for this
                            fun39(bw) ' clear test pointers

                            If Not gClearNames Then
                                fun38(mbytSectorArray, bw)   ' load names
                            End If
                            Exit Do
                        Else
                            gInputState = InputState.Waiting
                            Debug.Print("expected v")
                        End If
                End Select
            Loop
            result = 1

            If UserAborted Then
                msg = StringResources.Operationwascanceled
            Else
                msg = StringResources.TransferCompleted
            End If

            bw.ReportProgress(0, msg)

        Catch cancelEx As CancelledByUserException
            ' catch, but do nothing. 
            'Dim s As String = cancelEx.Message

            Throw cancelEx

        Catch ex As Exception
            bw.ReportProgress(0, ex.Message)
            Throw ex    ' rethrow so caller may display a message box if desired
            Thread.Sleep(1000)
        Finally
            If Module1.MSComm1.IsOpen Then
                Thread.Sleep(100)          ' wait 
                fun21(bw)
                Thread.Sleep(100)          ' wait for the overlay to load
                Module1.MSComm1.Close()
                Debug.Print("closed in downloadnamesbinary - finally")
            End If

        End Try

        Return result

    End Function
	
Private Sub fun38(ByRef mbytSectorArray(,) As Byte, ByRef bw As System.ComponentModel.BackgroundWorker)

        ' downloads names

        Dim msg As String = ""

        sendByteWithEcho(0, bw)
        sendByteWithEcho(38, bw)   ' invoke function 38
        Thread.Sleep(10)

        Dim NumberSectors As Integer
        Dim singleByte(1) As Byte

        ' how many sectors to write?
        For NumberSectors = 0 To NAME_TOTAL_SECTORS - 1
            If mbytSectorArray(NumberSectors, 0) = 0 And _
                mbytSectorArray(NumberSectors, 1) = 0 And _
                mbytSectorArray(NumberSectors, 2) = 0 Then Exit For
        Next NumberSectors

        ' send one empty sector at the end, or TOTAL_SECTORS - 1 max
        NumberSectors = NumberSectors + 1
        singleByte(0) = NumberSectors
        Module1.MSComm1.Write(singleByte, 0, 1)
        Debug.Print("NumberSectors sent: " + CStr(NumberSectors))
        Thread.Sleep(30)
        ' dummy read (should return 0)
        Dim nextByte As Byte = u.ReadNextByte(Module1.MSComm1, bw)


        If 0 <> nextByte Then
            msg = String.Format(StringResources.EOInvalidHandshake, String.Format("{0:x}", nextByte))
            Debug.Print(msg)
            Throw New Exception(msg)
        End If

        Dim readBackBuffer(NAME_BYTES_USED_IN_SECTOR) As Byte
        Dim SectorError As Boolean = False

        Dim indicator1 As String = "??"
        Dim indicator2 As String = "??"
        Dim indicator As String = indicator1

        For i = 0 To NumberSectors - 1
            If (SectorError) Then Exit For

            For j = 0 To NAME_BYTES_USED_IN_SECTOR - 1  ' copy sector data
                mbytSector(j) = mbytSectorArray(i, j)
            Next j

            'Debug.Print("before sending sector " + CStr(i))
            If Not Module1.MSComm1.IsOpen Then Exit Sub

            Module1.MSComm1.Write(mbytSector, 0, NAME_BYTES_USED_IN_SECTOR)

            Debug.Print("after sending sector " + CStr(i))
            Thread.Sleep(200)
            If Module1.MSComm1.BytesToWrite > 0 Then
                Debug.Print("fun38  BytesToWrite expected 0,  is " + CStr(Module1.MSComm1.BytesToWrite))
            End If

            ' read back for verification
            If Not Module1.MSComm1.IsOpen Then Exit Sub

            Module1.MSComm1.Read(readBackBuffer, 0, NAME_BYTES_USED_IN_SECTOR)

            For j = 0 To NAME_BYTES_USED_IN_SECTOR - 1
                If mbytSector(j) <> readBackBuffer(j) Then
                    SectorError = True
                    Debug.Print("readback error, sector " + CStr(i) + " expected " + CStr(mbytSector(j)) +
                                " received " + CStr(readBackBuffer(j)) + ", position " + CStr(j))
                    Exit For
                End If
            Next j
            'Debug.Print("readback OK for sector " + CStr(i))

            bw.ReportProgress(1, indicator)
            'Debug.Print(indicator)

            If indicator.Equals(indicator1) Then
                indicator = indicator2
            Else
                indicator = indicator1
            End If
        Next

        Thread.Sleep(100)

        If (SectorError) Then
            msg = StringResources.EOSectorReadbackFailedNames
            Debug.Print(msg)
            singleByte(0) = 0
        Else
            singleByte(0) = 15
        End If

        If Not Module1.MSComm1.IsOpen Then Exit Sub

        Module1.MSComm1.Write(singleByte, 0, 1)

        If SectorError Then Throw New Exception(msg)

    End Sub	
	
Private Sub CreateSectorImage()

        ' create sector images required to write to the instrument

        Dim i, j As Integer
        Dim sectorIndex As Integer, recordindex As Integer

        ' initialize image of sectors to zeroes

        For i = 0 To NAME_TOTAL_SECTORS - 1
            For j = 0 To NAME_BYTES_USED_IN_SECTOR - 1
                mbytSectorArray(i, j) = 0
            Next j
        Next i

        If patientCollection.Count = 0 Then
            gClearNames = True
            Exit Sub
        End If

        gClearNames = False
        sectorIndex = 0
        recordindex = -1

        For Each p As Patient In patientCollection

            ' increment record index, and, if necessary, sector index
            If (recordindex < NAME_TOTAL_RECORDS_PER_SECTOR - 1) Then
                recordindex = recordindex + 1
            Else
                recordindex = 0
                sectorIndex = sectorIndex + 1

                If sectorIndex > NAME_TOTAL_SECTORS - 1 Then
                    Exit Sub ' silently ignore excess names
                End If
            End If

            ' set data
            Dim id1, id2 As String
            id1 = MainForm.GetPatientIdentifier1(p)
            id2 = MainForm.GetPatientIdentifier2(p)

            If String.IsNullOrEmpty(id1) Then id1 = " "

            SetSectorContent(sectorIndex, recordindex, LAST_NAME_OFFSET,
                             id1, LAST_NAME_LEN)
            SetSectorContent(sectorIndex, recordindex, FIRST_NAME_OFFSET,
                             id2, FIRST_NAME_LEN)
            'SetSectorContent(sectorIndex, recordindex, ID_OFFSET, p.Oid.ToString, ID_LEN)
            ' set up ID area
            SetSectorIDContent(sectorIndex, recordindex, GUID_OFFSET_BYTES, p.Oid, MainForm.g_UNIQUE_DATABASE_ID)
        Next

        ' swap byte order - make 2 words from 6 bytes

        Dim b(5) As Byte    ' array of 6 bytes

        For i = 0 To NAME_TOTAL_SECTORS - 1
            For j = 0 To NAME_BYTES_USED_IN_SECTOR - 1 Step 6

                For k = 0 To 5
                    b(k) = mbytSectorArray(i, j + k)
                Next

                ' swap bytes within words 
                mbytSectorArray(i, j) = b(2)
                mbytSectorArray(i, j + 2) = b(0)

                mbytSectorArray(i, j + 3) = b(5)
                mbytSectorArray(i, j + 5) = b(3)

            Next j
        Next i

    End Sub	
	
	Private Sub SetSectorContent(sectorIndex As Integer, recordindex As Integer,
                                 recordOffset As UInt32, theString As String, length As UInt32)

        Dim theStringArray(length) As Char
        If theString Is Nothing Then theString = ""
        Dim lengthToCopy As UInt32 = Math.Min(theString.Length, length)

        theString.CopyTo(0, theStringArray, 0, lengthToCopy)

        Dim k As UInt32 = 0 ' relative offset within the current string
        Dim stringOffset As UInt32

        For Each unicodeChar As Char In theStringArray

            Dim left, right As Byte

            stringOffset = recordOffset * 2 + recordindex * REC_LEN_UNICODE * 2 + k
            left = AscW(unicodeChar) >> 8
            right = AscW(unicodeChar) And &HFF
            mbytSectorArray(sectorIndex, stringOffset) = left
            mbytSectorArray(sectorIndex, stringOffset + 1) = right
            k += 2

        Next
    End Sub