Imports System.Text
Public Class ReadFlash

    Private Sub TextBox1_KeyDown(sender As Object, e As KeyEventArgs) Handles tb_Address.KeyDown
        If e.KeyCode = Keys.Enter Then
            If tb_Address.Text = "" Then MsgBox("请输入地址")

            Dim adressStr As String
            Dim rows As UInt16
            If InStr(tb_Address.Text, "0X") OrElse InStr(tb_Address.Text, "0x") Then
                adressStr = tb_Address.Text.Substring(2)
                If adressStr = "" Then MsgBox("请输入地址") : Exit Sub

                rows = CInt("&H" & adressStr)       '字符串转十六进制

                rows = rows / 16
                If DataGridView1.Rows.Count > rows Then
                    DataGridView1.FirstDisplayedScrollingRowIndex = rows         '将内容滚动的作用
                Else
                    MsgBox("输入地址不存在")
                End If

            End If
        End If
    End Sub

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim dlg As New SaveFileDialog

        dlg.Filter = "HEX File|*.hex||"

        If dlg.ShowDialog() = Windows.Forms.DialogResult.OK Then
            SaveHexFileData(DataGridView1, dlg.FileName)
        End If
    End Sub

    Private Function GetRowsVaildDataNum(rows As DataGridViewRow) As Byte
        Dim vaildDataNum As Byte = 0
        Dim i As Byte

        For i = 0 To 15
            If rows.Cells(i).Value <> "--" Then
                vaildDataNum += 1
            End If
        Next
        Return vaildDataNum
    End Function

    ''' <summary>
    ''' 保存HEX文件数据
    ''' </summary>
    ''' <param name="prth"></param>保存的文件路径名
    ''' <param name="pSaveHex"></param>
    Private Sub SaveHexFileData(dataGridView As DataGridView, prth As String)
        If dataGridView.Rows.Count = 0 Then MsgBox("表格没有数据，无法保存") : Exit Sub

        Dim bufIndex As UInt32 = 0
        Dim bufIndexHead As UInt32 = 0
        Dim rowsIndex As UInt16
        Dim i As UInt16

        Dim dataLen As Byte
        Dim dataLenBuf(1) As Byte
        Dim flashAddress As String
        Dim flashAddressBuf(5) As Byte
        Dim dataValStr As String
        Dim dataStrBuf() As Byte
        Dim checkSum As Byte
        Dim checkSumBuf(1) As Byte
        Dim rowsDataValBuf(19) As Byte
        Dim rowsDataStrBuf(39) As Byte
        Dim pSaveHexBuf(1000 * 1024 - 1) As Byte

        Array.Clear(pSaveHexBuf, 0, pSaveHexBuf.Length)

        For rowsIndex = 0 To dataGridView.Rows.Count - 1
            dataLen = GetRowsVaildDataNum(dataGridView.Rows(rowsIndex))     '得到当前行的有效数据的长度
            HexToStr(dataLenBuf, dataLen)
            If dataLen = 0 Then
                Continue For         '结束当次循环
            End If

            pSaveHexBuf(bufIndex) = &H3A                            '头
            bufIndex += 1
            bufIndexHead = bufIndex                         '标记头开始

            Array.Copy(dataLenBuf, 0, pSaveHexBuf, bufIndex, 2)     '得到数据长度
            bufIndex += 2

            flashAddress = dataGridView.Rows(rowsIndex).HeaderCell.Value
            flashAddressBuf = Encoding.ASCII.GetBytes(flashAddress)         '字符串转字节数组
            Array.Copy(flashAddressBuf, 0, pSaveHexBuf, bufIndex, 4)     '得到数据地址
            bufIndex += 4

            pSaveHexBuf(bufIndex) = &H30                            '数据类型
            bufIndex += 1
            pSaveHexBuf(bufIndex) = &H30                            '数据类型
            bufIndex += 1

            dataValStr = ""
            For i = 0 To dataLen - 1
                dataValStr += dataGridView.Rows(rowsIndex).Cells(i).Value
            Next
            dataStrBuf = Encoding.ASCII.GetBytes(dataValStr)         '字符串转字节数组
            Array.Copy(dataStrBuf, 0, pSaveHexBuf, bufIndex, dataLen * 2)     '得到数据
            bufIndex += (dataLen * 2)

            Array.Clear(rowsDataValBuf, 0, 20)
            Array.Clear(rowsDataStrBuf, 0, 40)
            Array.Copy(pSaveHexBuf, bufIndexHead, rowsDataStrBuf, 0, bufIndex - bufIndexHead)
            StrToHex(rowsDataValBuf, rowsDataStrBuf, (bufIndex - bufIndexHead) / 2)
            checkSum = CalcCheckSum(rowsDataValBuf, (bufIndex - bufIndexHead) / 2)
            HexToStr(checkSumBuf, checkSum)
            Array.Copy(checkSumBuf, 0, pSaveHexBuf, bufIndex, 2)     '得到校验和
            bufIndex += 2

            pSaveHexBuf(bufIndex) = &HD                            '数据类型
            bufIndex += 1
            pSaveHexBuf(bufIndex) = &HA                            '数据类型
            bufIndex += 1
        Next
        Array.Copy(Encoding.ASCII.GetBytes(":00000001FF"), 0, pSaveHexBuf, bufIndex, 11)       '结尾的
        bufIndex += 11
        pSaveHexBuf(bufIndex) = &HD                            '数据类型
        bufIndex += 1
        pSaveHexBuf(bufIndex) = &HA                            '数据类型
        bufIndex += 1
        Try
            Dim fs As New System.IO.FileStream(prth, IO.FileMode.Create, IO.FileAccess.Write)
            fs.Write(pSaveHexBuf, 0, bufIndex)
            fs.Close()
        Catch ex As Exception
            MsgBox("文件写入失败失败，可能的原因" & vbNewLine & ex.Message)
        End Try
    End Sub

    Private Function CalcCheckSum(buf() As Byte, len As UInt16) As UInt64
        Dim sum As Int64
        Dim i As UInt16

        For i = 0 To len - 1
            sum += buf(i)
            sum = sum And &HFF
        Next
        sum = ((Not sum) + 1) And &HFF
        Return sum
    End Function

    ''' <summary>
    ''' 将小写转成大写字母
    ''' </summary>
    ''' <param name="val"></param>
    ''' <returns></returns>
    Private Function toupper(val As Byte) As Byte
        If val >= &H61 AndAlso val <= &H7A Then
            Return (val - &H20)
        Else
            Return val
        End If
    End Function

    ''' <summary>
    ''' 16进制转字符串，输入一个字节，输出两个字节
    ''' </summary>
    ''' <param name="pbDest"></param>
    ''' <param name="pbSrc"></param>
    Private Sub HexToStr(pbDest() As Byte, pbSrc As Byte)
        Dim ddl As Byte
        Dim ddh As Byte
        Dim i As UInt16

        ddh = 48 + pbSrc \ 16
        ddl = 48 + pbSrc Mod 16
        If ddh > 57 Then ddh += 7
        If ddl > 57 Then ddl += 7
        pbDest(i * 2) = toupper(ddh)
        pbDest(i * 2 + 1) = toupper(ddl)
    End Sub

    Private Sub StrToHex(pbDest() As Byte, pbSrc() As Byte, nLen As UInt16)
        Dim h1 As Byte
        Dim h2 As Byte
        Dim s1 As Byte
        Dim s2 As Byte
        Dim i As UInt16

        For i = 0 To nLen - 1
            h1 = pbSrc(2 * i)
            h2 = pbSrc(2 * i + 1)

            s1 = toupper(h1) - &H30
            If s1 > 9 Then
                s1 -= 7
            End If

            s2 = toupper(h2) - &H30
            If s2 > 9 Then
                s2 -= 7
            End If

            pbDest(i) = s1 * 16 + s2
        Next
    End Sub
End Class