  Function TransferResults(ByRef bw As System.ComponentModel.BackgroundWorker) As Integer
        ' reads DSP sectors containing test results
        ' notifies user of progress of DSP sector retrieval
        ' creates a TestResult object for each sector
        ' reports error condition or success
        Dim result As Integer = 0 ' 1 means test successfully uploaded

        CountOfParsedTestResults = 0
        Dim CMOSMemoryBytes(192) As Byte
        Dim CMOSMemoryIndex, CMOSMemoryWords(64), SectorBuffer(512 / 3 + 1) As UInt32

        ' DSP clock memory values
        Dim PointerRead, PointerWrite As Integer
        Dim PointerLeft, PointerRight, PrintSaveMode As Integer
        Dim NamesPresent As Boolean

        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 uploadbintests ")
            Module1.MSComm1.ReadTimeout = 10000
            Module1.MSComm1.WriteTimeout = 500 ' to prevent stalling in Write that causes bw to hang
            Module1.MSComm1.DiscardInBuffer()   ' discard accumulated characters

            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(1, 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 - less than 2 secs may not work on all devices!
                            u.DetermineFimwareVersions(Module1.MSComm1, bw, MSP_FW_Version, MSP_HW_Version, DSPFirmwareVersion)

                            Support12Frequencies = IIf(MSP_HW_Version >= DISPLAY_BOARD_HW_12_FREQ_VERSION, True, False)

                            Support12Frequencies = u.fun50_is12freq(Module1.MSComm1, bw)
                            SectorLength = IIf(Support12Frequencies, 512, 256)
                            TestStartSector = IIf(Support12Frequencies, EXPRESS_TEST_START_SECTOR_12FREQ, EXPRESS_TEST_START_SECTOR_6FREQ)

                            Debug.Print("before sendByteWithEcho 32 " + CStr(Now.Second) + " " + CStr(Now.Millisecond))
                            sendByteWithEcho(0, bw)
                            sendByteWithEcho(32, bw)    ' fun32
                            Debug.Print("after sendByteWithEcho fun32")
                            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
                            PointerWrite = CMOSMemoryWords(0)
                            PointerRead = CMOSMemoryWords(1)
                            PointerLeft = CMOSMemoryWords(2)
                            PointerRight = CMOSMemoryWords(3)
                            PrintSaveMode = CMOSMemoryWords(4)
                            NamesPresent = (CMOSMemoryWords(5) = 0)

                            Thread.Sleep(100)   ' wait 100 ms todo review need for this

                            'Debug.Print("GettingCMOSMemory: PointerRead " & CStr(PointerRead) & ", PointerWrite" & CStr(PointerWrite))
                            If PointerRead = PointerWrite Then
                                'Debug.Print("No Results")
                                bw.ReportProgress(0, StringResources.Therearenoresults & vbCrLf)
                                Exit Do
                            End If

                            ' Find out if there are names

                            SectorBuffer(0) = 0 ' assume no names

                            FirstNameArray = Nothing
                            LastNameArray = Nothing
                            DateOfBirthArray = Nothing
                            PatientOidArray = Nothing

                            If NamesPresent Then

                                ' Debug.Print("Names detected")
                                Dim NameListAddress As Int32
                                NameListAddress = 7 * 256 * 256 ' see common\express_equates.inc NAME_SECTOR
                                Dim NameIndex As UInt16 = 0
                                Dim SectorIndex As UInt16 = 0
                                Dim RawNames(REC_LEN_UNICODE) As Byte
                                FirstNameArray = New String(MAX_NAMES) {}
                                LastNameArray = New String(MAX_NAMES) {}
                                DateOfBirthArray = New String(MAX_NAMES) {}
                                PatientOidArray = New Integer(MAX_NAMES) {}

                                Do While True
                                    'Debug.Print("Getting names sector " & CStr(SectorIndex))
                                    fun15(NameListAddress + SectorIndex, SectorBuffer, bw) ' get next name sector
                                    If SectorBuffer(0) = 0 Or SectorBuffer(0) = &HFFFFFF Then Exit Do ' no more names
                                    SectorIndex = SectorIndex + 256
                                    bw.ReportProgress(1, StringResources.StatusObtainingpatientidentification + " " + CStr(SectorIndex / 256)) ' 

                                    ' initialize values
                                    FirstNameArray(NameIndex) = New String("")
                                    LastNameArray(NameIndex) = New String("")
                                    DateOfBirthArray(NameIndex) = New String("")

                                    ' revert bytes in SectorBuffer
                                    Dim a, b, c As UInt32

                                    For i = 0 To SectorBuffer.Length - 1
                                        a = SectorBuffer(i) >> 16
                                        b = (SectorBuffer(i) >> 8) And &HFF
                                        c = SectorBuffer(i) And &HFF
                                        'SectorBuffer(i) = (c << 16) + (b << 8) + a
                                    Next

                                    ' transfer first name record info
                                    'Debug.Print("calling ExtractIdentificationData 1")
                                    ExtractIdentificationData(SectorBuffer, 0, FirstNameArray(NameIndex),
                                        LastNameArray(NameIndex), DateOfBirthArray(NameIndex), PatientOidArray(NameIndex), DatabaseGuidArray(NameIndex))

                                    If SectorBuffer(REC_LEN_UNICODE / 3 * 2) = 0 Then Exit Do ' no more names
                                    NameIndex = NameIndex + 1
                                    ' transfer second name record info
                                    'Debug.Print("calling ExtractIdentificationData 2")
                                    ExtractIdentificationData(SectorBuffer, REC_LEN_UNICODE / 3 * 2, FirstNameArray(NameIndex),
                                        LastNameArray(NameIndex), DateOfBirthArray(NameIndex), PatientOidArray(NameIndex), DatabaseGuidArray(NameIndex))
                                    NameIndex = NameIndex + 1
                                Loop

                            End If

                            Dim NoResults As UInt32 = EXPRESS_NO_RESULTS

                            Dim msg As String

getResults:
                            If (PrintSaveMode = 1) Then
                                'Debug.Print("PrintSaveMode = 1, Save All Mode")

                                If PointerWrite > PointerRead Then
                                    msg = String.Format(StringResources.StartingtotransferXResults, PointerWrite - PointerRead) & vbCrLf & vbCrLf
                                    Debug.Print(msg)
                                    bw.ReportProgress(0, msg)

                                    For sector As Int16 = PointerRead To PointerWrite - 1
                                        RetrieveAndParseTestSector(sector, SectorBuffer, bw)
                                    Next

                                    Exit Do
                                Else
                                    Dim TestCount As Integer = IIf(Support12Frequencies, 384 + PointerWrite - PointerRead, 512 + PointerWrite - PointerRead)
                                    Dim LastSector As Integer = IIf(Support12Frequencies, 383, 511)
                                    msg = String.Format(StringResources.StartingtotransferXResults, TestCount) & vbCrLf
                                    Debug.Print(msg)
                                    bw.ReportProgress(0, msg)

                                    For sector As Int16 = PointerRead To LastSector
                                        RetrieveAndParseTestSector(sector, SectorBuffer, bw)
                                    Next
                                    For sector As Int16 = 0 To PointerWrite - 1
                                        RetrieveAndParseTestSector(sector, SectorBuffer, bw)
                                    Next
                                    Exit Do
                                End If
                            Else

                                ' only 0, 1 or 2 tests
                                Debug.Print("PrintSaveMode = 0, Save Last Mode")
                                Dim Totalresults As Integer = 0
                                ' pointer with value NO_RESULTS means "no results"
                                If (PointerLeft <> NoResults) Then Totalresults = Totalresults + 1
                                If (PointerRight <> NoResults) Then Totalresults = Totalresults + 1

                                If (Totalresults > 0) Then
                                    msg = String.Format(StringResources.StartingtotransferXResults, Totalresults) & vbCrLf
                                    bw.ReportProgress(0, msg)
                                End If

                                If (PointerLeft <> NoResults) Then
                                    RetrieveAndParseTestSector(PointerLeft, SectorBuffer, bw)
                                End If

                                If (PointerRight <> NoResults) Then
                                    RetrieveAndParseTestSector(PointerRight, SectorBuffer, bw)

                                End If
                                Exit Do
                            End If

                        Else
                            gInputState = InputState.Waiting
                            Debug.Print("expected v")
                        End If
                End Select
            Loop
            result = 1
        Catch cancelEx As CancelledByUserException
            Throw New CancelledByUserException
            ' catch, but do nothing. Backgroundworker will issue the appropriate message


        Catch ex As Exception

            bw.ReportProgress(0, StringResources.AnError)
            bw.ReportProgress(0, ex.Message)
            If Not TryCast(ex, IOException) Is Nothing Then
                bw.ReportProgress(0, StringResources.MakeSureIinstrumentIsPluggedIn)
            End If

        Finally
            If Module1.MSComm1.IsOpen Then
                sendByteWithEcho(0, bw)
                sendByteWithEcho(21, bw)    ' function 21 - return to scanb
                Module1.MSComm1.Close()
                Thread.Sleep(1000)          ' wait for the overlay to load
                'Debug.Print("closed in uploadbintests - finally")
            End If
        End Try

        Return result
    End Function
	
 Private Function RetrieveAndParseTestSector(sector As Short, SectorBuffer As UInteger(), bw As BackgroundWorker) As Short

        ' sector is a relative "sector". Its length will depend on the DSP system. fun15 and fun14 use byte address.
        If Not Support12Frequencies Then
            fun15(TestStartSector + sector * 256, SectorBuffer, bw)
            If ParseSector6Freq(SectorBuffer) Then ReportTestDetails(bw, TestResults(CountOfParsedTestResults - 1))
        Else
            fun45(TestStartSector + sector * 512, SectorBuffer, bw)
            If ParseSector12Freq(SectorBuffer) Then ReportTestDetails(bw, TestResults(CountOfParsedTestResults - 1))
        End If
    End Function
	
	Private Sub fun45(ByVal StartSector As UInt32, ByRef SectorBuffer As UInt32(), ByRef bw As System.ComponentModel.BackgroundWorker)

        ' Reads flash storage from DSP. 

        Dim SectorBytes(510) As Byte
       
        For i As Integer = 0 To UBound(SectorBytes) - 1 ' zero out the bytes
            SectorBytes(i) = 0
        Next

        sendByteWithEcho(0, bw)
        sendByteWithEcho(45, bw)   ' function number

        SendWordWithEcho(StartSector, bw)

        For ByteIndex As Integer = 0 To 509 ' must read 510 bytes
            SectorBytes(ByteIndex) = u.ReadNextByte(Module1.MSComm1, bw)
        Next

        ConvertToWords(SectorBytes, SectorBuffer)

    End Sub
	
    Private Sub ConvertToWords(ByRef theBytes As Byte(), ByRef theWords As UInt32())
        ' prepare stream of bytes to send to DSP as 3-byte words
        For i As Int16 = 0 To UBound(theBytes) - 4 Step 3
            Dim x As UInt32 = (theBytes(i) << 16)
            x = x + (theBytes(i + 1) << 8)
            x = x + theBytes(i + 2)
            theWords(i / 3) = theBytes(i + 2) * 256 * 256 + (theBytes(i + 1) * 256) + theBytes(i)
        Next
    End Sub	
	
	Private Sub SendWordWithEcho(ByVal word As UInteger, ByRef bw As System.ComponentModel.BackgroundWorker)

        Dim theBytes(3) As Byte

        theBytes(0) = word And &HFF
        theBytes(1) = (word And &HFF00) >> 8
        theBytes(2) = (word And &HFF0000) >> 16
        sendByteWithEcho(theBytes(0), bw)
        sendByteWithEcho(theBytes(1), bw)
        sendByteWithEcho(theBytes(2), bw)
    End Sub
	
Private Function ParseSector12Freq(ByRef SectorBuffer As UInt32()) As Boolean
        ' Converts raw DSP sector data to an object of TestResult class
        'Debug.Print("ParseSector +++++++++++++++++++++++++ ")
        ' NOTE: offsets within the sector can best be seen by inspecting DSP tesdata.lst 
        Dim ts As TestResult
        If SectorBuffer(0) = &HFFFFFF Then 'todo review
            Return False
        End If

        Dim upper, middle, lower As Byte

        TestResults(CountOfParsedTestResults) = New TestResult
        ts = TestResults(CountOfParsedTestResults)
        ts.RecordVersion = SectorBuffer(&H99)

        If ts.RecordVersion <> 200 Then ' todo avoid harcoding
            Throw New ArgumentException( _
                String.Format(StringResources.IncompatibleRecordVersion + vbCrLf, ts.RecordVersion, 200))
            Return False
        End If

        CountOfParsedTestResults = CountOfParsedTestResults + 1

        ts.TestType = SectorBuffer(&H88)
        If (ts.TestType And &H800000) <> 0 Then
            ' adjustment for 3-byte negative DSP numbers
            ts.TestType = ts.TestType Or &HFF000000
        End If

        If ts.TestType < -1 Or ts.TestType = 0 Then
            Throw New ArgumentException( _
                String.Format(StringResources.InvalidTestType + vbCrLf, ts.TestType))
        End If

        ts.NumberFrequencies = SectorBuffer(&H8E)

        Dim ind As Int16 = 0
        Dim result As UInt32
        For k = 0 To ts.NumberFrequencies - 1
            ts.TestArray(k).NF = convert1(SectorBuffer(ind))
            result = SectorBuffer(ind + 6) And &HFF
            If ts.TestType >= 0 Then ' DP test 
                ts.TestArray(k).P1 = convert1(SectorBuffer(ind + 1))
                ts.TestArray(k).P2 = convert1(SectorBuffer(ind + 2))
            Else    ' TE test
                If ind = 0 Then
                    ts.TEpeak = convert1(SectorBuffer(ind + 2)) '  % actual stimulus peak value (float dB)
                    ts.TestArray(k).P2 = ts.TEpeak
                ElseIf ind = 7 Then
                    ts.TEtesttime = convert1(SectorBuffer(ind + 2)) '  actual test time in seconds?
                End If
            End If
            ts.TestArray(k).DP = convert1(SectorBuffer(ind + 3))
            ts.TestArray(k).NumberOfBlockAcceptedPercent = SectorBuffer(ind + 4) / &H8000
            ts.TestArray(k).NumberOfBlockAcceptedPercent = SectorBuffer(ind + 4) * (2 ^ -15)
            ts.TestArray(k).SNR = convert1(SectorBuffer(ind + 5))

            If result = Asc(" ") Then
                ts.TestArray(k).TestSummary = " "  ' no result
            ElseIf result = Asc("F") Then
                ts.TestArray(k).TestSummary = "F" ' FAIL
            ElseIf result = Asc("P") Then
                ts.TestArray(k).TestSummary = "P" ' PASS
            Else : ts.TestArray(k).TestSummary = "E" ' Error
            End If
            ind = ind + 7   ' point to the next array
        Next

        ts.test_timestamp_sec = (SectorBuffer(&H54) And &HF) + _
            (SectorBuffer(&H54) And &HF00) / 256 * 10
        ts.test_timestamp_min = (SectorBuffer(&H55) And &HF) + _
            (SectorBuffer(&H55) And &HF00) / 256 * 10
        ts.test_timestamp_hour_24 = (SectorBuffer(&H56) And &HF) + _
            (SectorBuffer(&H56) And &HF00) / 256 * 10

        ts.test_timestamp_day = (SectorBuffer(&H58) And &HF00) / 256 + _
        (SectorBuffer(&H58) And &HF0000) / 256 * 10 / 256
        ts.test_timestamp_month = SectorBuffer(&H93)
        ts.test_timestamp_year = (SectorBuffer(&H5A) And &HF) + _
            (SectorBuffer(&H5A) And &HF00) / 256 * 10 + 2000


        If (SectorBuffer(&H5B) And &HFF00) / 256 = Asc("P") Then
            ts.test_timestamp_hour_24 = ts.test_timestamp_hour_24 + 12
            If ts.test_timestamp_hour_24 = 24 Then
                ts.test_timestamp_hour_24 = 0
            End If
        End If

        ts.id_num = SectorBuffer(&H86)

        For i = &H76 To &H79
            upper = (SectorBuffer(i) >> 16) And &HFF
            middle = (SectorBuffer(i) >> 8) And &HFF
            lower = (SectorBuffer(i)) And &HFF
            ts.ProtocolName = ts.ProtocolName + ChrW(upper) + ChrW(middle) + ChrW(lower)
        Next

        If ts.ProtocolName.Length > 10 Then ts.ProtocolName = ts.ProtocolName.Substring(0, 10)

        For i = 0 To ts.NumberFrequencies - 1
            Dim offset As Int16 = &H7A + i
            upper = (SectorBuffer(offset) >> 16) And &HFF
            middle = (SectorBuffer(offset) >> 8) And &HFF
            lower = (SectorBuffer(offset)) And &HFF
            ts.FrequencyLabels(i) = ChrW(upper) + ChrW(middle) + ChrW(lower)
        Next

        Dim ear As UInt32 = (SectorBuffer(&H87) And &HFF00) / 256

        ts.ear = ChrW(ear)

        If ts.TestType > 0 Then  ' values only have meaning for DP test
            ts.TargetP1 = 20 * Math.Log(SectorBuffer(&H89) / 2 ^ 23, 10) + 92 ' target P1 (dB) 
            ts.TargetP2 = 20 * Math.Log(SectorBuffer(&H8A) / 2 ^ 23, 10) + 92 ' target P1 (dB) 
            ts.Blocks = SectorBuffer(&H8B) / (31250 / 1024)
        Else ' TE
            ts.TargetP = 20 * Math.Log(SectorBuffer(&H89) / 2 ^ 23, 10) + 92 ' target P (dB) 
            ts.Blocks = SectorBuffer(&H8B)
        End If

        ts.TAvg = ts.Blocks

        ts.pass_SNR = SectorBuffer(&H8C) * (2 ^ -15)
        ts.save_setting = SectorBuffer(&H8D)
        ts.pass_FREQ = SectorBuffer(&H8F)
        ts.pass_test = SectorBuffer(&H90)
        If (ts.pass_test And &H800000) Then ' adjust negative 24-bit numbers
            ts.pass_test = ts.pass_test Or &HFF000000
        End If

        ts.FrequencySet = SectorBuffer(&H91)
        ts.NamePointer = SectorBuffer(&H92)   ' 255 means no name

        If Not IsNothing(FirstNameArray) And Not ts.NamePointer = 255 Then
            If IsNothing(FirstNameArray(ts.NamePointer)) Then
                FirstNameArray(ts.NamePointer) = "" ' first name is missing, that's OK
            End If

            If FirstNameArray(ts.NamePointer).Length > 0 Then ts.PatientIdentifier2 = FirstNameArray(ts.NamePointer)
            If LastNameArray(ts.NamePointer).Length > 0 Then ts.PatientIdentifier1 = LastNameArray(ts.NamePointer)
            If Not DateOfBirthArray(ts.NamePointer) Is Nothing Then
                If DateOfBirthArray(ts.NamePointer).Length > 0 And IsDate(DateOfBirthArray(ts.NamePointer)) Then
                    ts.DateOfBirth = DateOfBirthArray(ts.NamePointer)
                End If
            End If

            ts.PatientOID = PatientOidArray(ts.NamePointer)
            ts.DatabaseGUID = DatabaseGuidArray(ts.NamePointer)
        End If

        ' obtain probe serial (9 ASCII characters) 

        If SectorBuffer(&H94) <> 0 Then ' ignore if serial was never written (all one bits)
            For i As UInt16 = &H94 To &H96
                upper = (SectorBuffer(i) >> 16) And &HFF
                middle = (SectorBuffer(i) >> 8) And &HFF
                lower = (SectorBuffer(i)) And &HFF
                ts.ProbeSerial = ts.ProbeSerial + ChrW(lower) + ChrW(middle) + ChrW(upper)
            Next i
        End If

        ts.ProbeSerial = ts.ProbeSerial.Trim

        ' obtain instrument serial (3 ASCII character prefix and a binary number) 
        If SectorBuffer(&H98) <> 0 Then    ' ignore if serial number (integer) was never written (all one bits)
            Dim Prefix1, Prefix2, Prefix3 As Char
            Prefix1 = ChrW((SectorBuffer(&H97) >> 16) And &HFF)
            Prefix2 = ChrW((SectorBuffer(&H97) >> 8) And &HFF)
            Prefix3 = ChrW((SectorBuffer(&H97)) And &HFF)

            If Not Char.IsLetter(Prefix1) Then Prefix1 = " "
            If Not Char.IsLetter(Prefix2) Then Prefix2 = " "
            If Not Char.IsLetter(Prefix3) Then Prefix3 = " "

            ts.InstrumentSerial = ts.InstrumentSerial + Prefix1 + Prefix2 + Prefix3 + SectorBuffer(&H98).ToString().PadLeft(7, "0")
            ts.InstrumentSerial = ts.InstrumentSerial.Trim()
        End If

        Return True

    End Function	
	
    Private Function convert1(ByVal value As UInteger) As Integer
        If value > (2 ^ 23) Then
            convert1 = (value - (2 ^ 24)) / 256 / 128
        Else
            convert1 = value * (2 ^ -15)
        End If
    End Function	
	
	Private Sub ExtractIdentificationData(ByRef SectorWordData As UInt32(), ByVal offset As UInt16,
            ByRef FirstName As String, ByRef LastName As String, ByRef DOB As String,
            ByRef PatienOID As Integer, ByRef DatBaseGuid As Guid)

        ' extracts patient identification data from the sector / offset within sector
        ' There are two sets of id data per sector, but this routine is not aware of that
        Dim RawNameInfo(REC_LEN_UNICODE) As Char
        Dim RawByteInfo(REC_LEN_UNICODE * 2) As Byte

        UnpackDSPData(SectorWordData, offset, RawNameInfo, RawByteInfo)

        For i As UInt16 = LAST_NAME_OFFSET To LAST_NAME_LEN - 1
            If RawNameInfo(i) = ChrW(0) Then Exit For
            LastName = LastName & RawNameInfo(i)
        Next

        For i As UInt16 = FIRST_NAME_OFFSET To FIRST_NAME_OFFSET + FIRST_NAME_LEN - 1
            If RawNameInfo(i) = ChrW(0) Then Exit For
            FirstName = FirstName & RawNameInfo(i)
        Next

        For i As UInt16 = DOB_OFFSET To DOB_OFFSET + DOB_LEN - 1
            If RawNameInfo(i) = ChrW(0) Then Exit For
            DOB = DOB & RawNameInfo(i)
        Next

        Dim GuidBytes(15), UnicodeBytes(), PatientOIDBytes(4) As Byte

        UnicodeBytes = Nothing

        For i As UInt16 = 0 To 15
            GuidBytes(i) = RawByteInfo(GUID_OFFSET_BYTES + i)
        Next

        DatBaseGuid = New Guid(GuidBytes)

        PatienOID = BitConverter.ToInt32(RawByteInfo, GUID_OFFSET_BYTES + 16)

    End Sub
	
    Private Sub UnpackDSPData(SectorWordData As UInt32(), ByVal offset As UInt16,
                ByRef RawNameInfo As Char(), ByRef RawByteInfo As Byte())

        Dim CharIndex As UInt16 = 0
        Dim b1, b2, b3, b4, b5, b6 As Byte
        Dim ByteIndex = 0

        ' unpack 3-byte-per-word data as appropriate

        For i As UInt16 = offset To (offset + REC_LEN_UNICODE / 3 * 2) - 2 Step 2

            ' 2 words (6 bytes or 3 Unicode characters) at a time)

            b1 = (SectorWordData(i) >> 16) And &HFF
            b2 = (SectorWordData(i) >> 8) And &HFF
            RawNameInfo(CharIndex) = ChrW((b1 * 256) + b2)

            b3 = SectorWordData(i) And &HFF
            b4 = (SectorWordData(i + 1) >> 16) And &HFF
            RawNameInfo(CharIndex + 1) = ChrW((b3 * 256) + b4)

            b5 = (SectorWordData(i + 1) >> 8) And &HFF
            b6 = SectorWordData(i + 1) And &HFF
            RawNameInfo(CharIndex + 2) = ChrW((b5 * 256) + b6)

            ' store raw bytes

            RawByteInfo(ByteIndex) = b1
            RawByteInfo(ByteIndex + 1) = b2
            RawByteInfo(ByteIndex + 2) = b3
            RawByteInfo(ByteIndex + 3) = b4
            RawByteInfo(ByteIndex + 4) = b5
            RawByteInfo(ByteIndex + 5) = b6

            ByteIndex += 6

            CharIndex = CharIndex + 3
        Next
    End Sub	
	
   ''' <summary>
    ''' Receives a byte from a serial port
    ''' </summary>
    ''' <param name="Port">Reference to a previously opened serial port</param>
    ''' <param name="bw">The background worker that initiated the process</param>
    ''' <returns>The next byte read from the given port</returns>
    ''' <remarks></remarks>
    Public Function ReadNextByte(ByRef Port As SerialPort, ByRef bw As System.ComponentModel.BackgroundWorker) As Byte
        ' This function does not block. Instead, it returns when user issues a Cancel command, or
        ' a byte is received on the serial port
        Do While Not bw.CancellationPending ' wait for next character or user cancel command
            If Port.BytesToRead < 1 Then
                Thread.Sleep(10)
            Else
                Exit Do
            End If
        Loop

        ' careful: this must be removed for packet I/O, but what about the rest?
        If bw.CancellationPending Then Throw New CancelledByUserException

        Dim byteRead As Byte

        Try
            byteRead = Port.ReadByte()
        Catch ex As Exception
            Dim q As String = ex.Message
        End Try
        Return byteRead
    End Function

    Sub DetermineFimwareVersions(ByRef Port As SerialPort,
                                         ByRef bw As System.ComponentModel.BackgroundWorker,
                                       ByRef MSP_FW_Version As UInt32,
                                       ByRef MSP_HW_Version As UInt32,
                                       ByRef DSP_FW_Version As UInt32)
        ' determine DSP and MSP versions
        Thread.Sleep(100)
        Debug.Print("DetermineFimwareVersions: enter fun 9")
        sendByteWithEcho(Port, 0, bw)
        sendByteWithEcho(Port, 9, bw)    ' DSP version
        DSP_FW_Version = GetWord(Port, bw)

        Debug.Print("DetermineFimwareVersions: received DSP_FW_Version " + CStr(DSP_FW_Version) + "  - enter fun 34")

        Thread.Sleep(100)

        sendByteWithEcho(Port, 0, bw)
        sendByteWithEcho(Port, 34, bw) ' MSP version
        MSP_HW_Version = ReadNextByte(Port, bw)
        Debug.Print("DetermineFimwareVersions: received MSP_HW_Version " + CStr(MSP_HW_Version))

        MSP_FW_Version = GetWord(Port, bw)
        Debug.Print("DetermineFimwareVersions: received MSP_FW_Version " + CStr(MSP_FW_Version))
    End Sub
	
	Public Sub sendByteWithEcho(ByRef Port As SerialPort, ByVal value As Integer, ByRef bw As System.ComponentModel.BackgroundWorker)
        Handshake(0) = value
        Port.Write(Handshake, 0, 1)
        Dim echo As Byte
        echo = ReadNextByte(Port, bw)
        If echo <> value Then
            Dim msg As String
            msg = "Echo test failed - sent hex " & Hex(value) & _
                  " received hex:" & Hex(echo)
            Debug.Print(msg)
            bw.ReportProgress(0, New WorkerNotificationType(ControlCode.Log, msg))
        Else
            'Debug.Print("Echo test OK for " + Hex(echo))
        End If

    End Sub	