Files
2025-12-11 10:59:57 +08:00

1398 lines
43 KiB
VB.net
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Imports System.Threading
Public Class Frm485Update
Implements IModuleForm
#Region "窗体"
''' <summary>
''' 窗体加载函数
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
Private Sub Frm485Update_Load(sender As Object, e As EventArgs) Handles Me.Load
InitDevInfo()
InitTypeGirdInfo()
End Sub
''' <summary>
''' 显示窗体_接口
''' </summary>
''' <param name="parentControl"></param>
Public Sub ShowForm(parentControl As Control) Implements IModuleForm.ShowForm
FormBorderStyle = FormBorderStyle.None '无边框
TopLevel = False
Dock = DockStyle.Fill '填满大小
Parent = parentControl '父容器
Show()
End Sub
''' <summary>
''' 发送函数
''' </summary>
''' <param name="sendPacket"></param>
Public Sub SendData(sendPacket() As Byte)
FrmRCU.SendData(sendPacket) '方法1
End Sub
#End Region
#Region "485升级"
#Region "设备表信息"
''' <summary>
''' 枚举表格设备列信息
''' </summary>
Enum EnTypeColInfo
''' <summary> NULL </summary>
Null
''' <summary> 是否选中 </summary>
Check
''' <summary> 设备地址 </summary>
DevAddr
''' <summary> 设备名称 </summary>
DevName
''' <summary> 状态_区域 </summary>
Status
''' <summary> 结果 </summary>
Result
End Enum
''' <summary> 类型表的列集合 </summary>
Private _typeGirdCols() As String = {"0", "是否选中", "设备地址", "设备名称", "设备分区", "升级结果"}
''' <summary>
''' 初始化设备表格信息
''' </summary>
Private Sub InitTypeGirdInfo()
GrdTypeInfo.DisplayRowNumber = True
GrdTypeInfo.ExtendLastCol = True
GrdTypeInfo.Cols = _typeGirdCols.Length
GrdTypeInfo.Rows = 1
For index = 1 To _typeGirdCols.Length - 1
With GrdTypeInfo.Cell(EnTypeColInfo.Null, index)
.Text = _typeGirdCols(index)
.BackColor = Color.LightGray
.ForeColor = Color.Blue
.Font = New Font("Arial", 8, FontStyle.Bold)
End With
Next
'是否选中_文本对齐单元格宽度
GrdTypeInfo.Column(EnTypeColInfo.Check).CellType = FlexCell.CellTypeEnum.CheckBox
'GrdTypeInfo.Cell(1, EnTypeColInfo.Check).Text = $"0"
GrdTypeInfo.Column(EnTypeColInfo.Check).Alignment = FlexCell.AlignmentEnum.CenterCenter
GrdTypeInfo.Column(EnTypeColInfo.Check).Width = 80
'设备地址_文本对齐单元格宽度
GrdTypeInfo.Column(EnTypeColInfo.DevAddr).Alignment = FlexCell.AlignmentEnum.CenterCenter
GrdTypeInfo.Column(EnTypeColInfo.DevAddr).Width = 80
'设备名称_文本对齐单元格宽度
GrdTypeInfo.Column(EnTypeColInfo.DevName).Alignment = FlexCell.AlignmentEnum.CenterCenter
GrdTypeInfo.Column(EnTypeColInfo.DevName).Width = 180
'设备分区_文本对齐单元格宽度
GrdTypeInfo.Column(EnTypeColInfo.Status).Alignment = FlexCell.AlignmentEnum.CenterCenter
GrdTypeInfo.Column(EnTypeColInfo.Status).Width = 80
End Sub
#End Region
#Region "485升级初始化"
''' <summary> 设备项目列表 </summary>
Private _devNameList() As String = {"None 485", "PB 485", "BLV_C1"}
''' <summary> 单包数据字节长度 </summary>
Private _packagebyte() As String = {"128", "256", "512", "1024", "2048", "4096"}
''' <summary>发送数据序号</summary>
Private _dataNumber As Byte = 0
Const _loadFileSize As Integer = 512 * 1024
Const _loadDataSize As Integer = 512 * 1024
Private _LoadHexFileData(_loadFileSize - 1) As Byte
Private _LoadDataBuff(_loadDataSize - 1) As Byte
Private _LoadEndAddr As Integer
Private _HexStart_C1 As Integer = 0
''' <summary>
''' 初始化设备列表
''' </summary>
Private Sub InitDevInfo()
ComboBox1.Items.Clear()
ComboBox1.Items.AddRange(_devNameList)
If ComboBox1.Items.Count >= 3 Then ComboBox1.SelectedIndex = 2
ComboBox2.Items.Clear()
ComboBox2.Items.AddRange(_packagebyte)
If ComboBox2.Items.Count >= 3 Then ComboBox2.SelectedIndex = 2
End Sub
''' <summary>
''' 设备类型转换
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
Private Sub ComboBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ComboBox1.SelectedIndexChanged
If ComboBox1.SelectedIndex = 0 Or ComboBox1.SelectedIndex = 1 Then
If ComboBox2.Items.Count > 1 Then
ComboBox2.SelectedIndex = 0
End If
End If
End Sub
#End Region
#Region "串口固件升级组包"
''' <summary>
''' 填充串口升级包
''' </summary>
''' <param name="cmd"></param>
''' <param name="data"></param>
''' <returns></returns>
Private Function FillSendPacket(cmd As Byte, data As Byte())
Dim databuff As Byte()
Select Case ComboBox1.Text
Case _devNameList(0), _devNameList(1)
'databuff = FillSendPacket485(cmd, data)
Case _devNameList(2)
databuff = FillSendPacketC1(cmd, data)
Case Else
End Select
Return databuff
End Function
''' <summary>
''' 填充C1发送包
''' </summary>
''' <param name="cmd">命令码</param>
''' <param name="data">Data数组</param>
''' <returns></returns>
Private Function FillSendPacketC1(cmd As Byte, data As Byte())
Dim sendNumber As Byte = GetSendNumber() '发送序号
Dim len(1) As Byte '数据长度占2个字节
Dim dataSum As Byte '校验和
Dim length As Integer = 5 + data.Length
len = IntToByteLB(length)
Dim databuff As New List(Of Byte)
databuff.Add(sendNumber)
databuff.Add(cmd)
databuff.AddRange(len)
databuff.AddRange(data)
dataSum = GetSumCheckMod(databuff.ToArray)
databuff.Insert(4, dataSum)
Return databuff.ToArray
End Function
''' <summary>
''' 获取发送序号
''' </summary>
''' <returns></returns>
Private Function GetSendNumber()
_dataNumber += 1
If _dataNumber > 15 Then
_dataNumber = 1
End If
Return _dataNumber
End Function
#End Region
''' <summary>
''' 判断设备类型
''' </summary>
Private Sub SelectDevice()
If ComboBox1.Text <> _devNameList(2) Then
FrmRCU._isDeviceC1 = True
Else
FrmRCU._isDeviceC1 = False
End If
End Sub
''' <summary>
''' 搜索
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
Private Sub BtnSearch_Click(sender As Object, e As EventArgs) Handles BtnSearch.Click
Dim startValue As Integer = NumericUpDown1.Value
Dim endValue As Integer = NumericUpDown2.Value
SelectDevice()
BtnUpdateFile.Enabled = False
SearchData(startValue, endValue)
BtnUpdateFile.Enabled = True
End Sub
''' <summary>
''' 搜索数据
''' </summary>
''' <param name="startValue"></param>
''' <param name="endValue"></param>
Private Sub SearchData(startValue As Integer, endValue As Integer)
Dim cmd As Byte
For count = 0 To 1
If count = 0 Then
FrmRCU.SerialPort.BaudRate = 2400
PauseWait(1)
cmd = &H63
Else
FrmRCU.SerialPort.BaudRate = CInt(FrmRCU.CboSerialBaud.Text)
PauseWait(1)
cmd = &H1
End If
For index = startValue To endValue
If startValue > endValue Then
index = endValue
End If
Dim indexs(0) As Byte
indexs(0) = index
Dim sendPacket As Byte()
If cmd = &H63 Then 'Boot区搜索
Dim data As Byte() = GetAppSearchData(index)
sendPacket = FillSendPacket(cmd, data)
Console.WriteLine($"Boot区搜索{index}{ByteToString(sendPacket)}")
ElseIf cmd = &H1 Then 'App区搜索
sendPacket = FillSendPacket(cmd, indexs)
Console.WriteLine($"App区搜索{index}{ByteToString(sendPacket)}")
End If
sendPacket = FillPacket(sendPacket) '是否填充透传数据包
SendData(sendPacket) '发送数据包
Next
Next
End Sub
''' <summary>
''' Boot区搜索数据
''' </summary>
''' <param name="index"></param>
''' <returns></returns>
Private Function GetAppSearchData(index As Byte) As Byte()
Dim data As New List(Of Byte)
data.Add(index)
data.Add(&H0) '超时时间H
data.Add(&H14) '超时时间H
Return data.ToArray
End Function
''' <summary>
''' 搜索范围值_委托
''' </summary>
''' <param name="startValue"></param>
''' <param name="endValue"></param>
Delegate Sub Delegate_SearchRangeValue_Change(ByRef startValue As Integer, ByRef endValue As Integer)
''' <summary>
''' 委托搜索范围值
''' </summary>
''' <param name="startValue"></param>
''' <param name="endValue"></param>
Private Sub SearchRangeValue(ByRef startValue As Integer, ByRef endValue As Integer)
If Me.InvokeRequired = True Then
Dim a As New Delegate_SearchRangeValue_Change(AddressOf SearchRangeValue)
Me.Invoke(a, New Object() {startValue, endValue})
Else
startValue = NumericUpDown1.Value
endValue = NumericUpDown2.Value
End If
End Sub
''' <summary>
''' 选择下发文件改变
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
_flashData = Nothing '重新选择,置空
End Sub
''' <summary>
''' 选择文件
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
Private Sub BtnSelectFile_Click(sender As Object, e As EventArgs) Handles BtnSelectFile.Click
_flashData = Nothing '重新选择,置空
Dim dlg As New OpenFileDialog
dlg.InitialDirectory = Application.StartupPath
dlg.Filter = "HEX File|*.hex||"
Dim oldPath As String = TextBox1.Text
If IO.File.Exists(oldPath) Then
dlg.InitialDirectory = IO.Path.GetDirectoryName(oldPath)
dlg.FileName = oldPath
Else
dlg.InitialDirectory = Application.StartupPath
End If
If dlg.ShowDialog() = DialogResult.OK Then
TextBox1.Text = dlg.FileName
'BtnSelectFile.PerformClick()
End If
'Todo:解析Hex文件
Dim path As String = TextBox1.Text
ThreadPool.QueueUserWorkItem(AddressOf DealHexFile path)
End Sub
''' <summary>
''' 状态栏解析文本委托
''' 改变文本和颜色
''' </summary>
''' <param name="text"></param>
''' <param name="color"></param>
''' <param name="flg"></param>
Delegate Sub Delegate_StateLabel_Change(text As String, color As Color, flg As Boolean)
''' <summary>
''' 状态栏解析文本
''' 改变文本和颜色
''' </summary>
''' <param name="text"></param>
''' <param name="color"></param>
''' <param name="flg"></param>
Private Sub StateLabel(text As String, color As Color, flg As Boolean)
If Me.InvokeRequired = True Then
Dim a As New Delegate_StateLabel_Change(AddressOf StateLabel)
Me.Invoke(a, New Object() {text, color, flg})
Else
TSSLbl1.ForeColor = color
TSSLbl1.Text = text
BtnUpdateFile.Enabled = flg
End If
End Sub
#Region "解析Hex文件"
''' <summary>
''' 解析Hex文件
''' </summary>
''' <param name="filePath"></param>
Private Sub DealHexFile(filePath As String)
StateLabel($"正在解析......", Color.Blue, False)
Dim tmpRet As Boolean = LoadDataFromFile(filePath)
Dim checkSum(3) As Byte
Dim tmpStrCks As String = ""
Dim tmpIdx As Integer = 0
Dim tmpLineCnt As Integer = 1
Dim tmpStrBuffer As String = ""
Dim tmpHexValidLenght As Integer = _LoadEndAddr - _HexStart_C1
If tmpRet Then
For tmpIdx = _HexStart_C1 To _LoadEndAddr - 1
tmpStrBuffer = tmpStrBuffer & HexByteStr(_LoadDataBuff(tmpIdx)) & " "
If tmpIdx > 0 And (tmpIdx + 1) Mod 16 = 0 Then
tmpLineCnt = tmpLineCnt + 1
'Todo:加进度条显示
tmpStrBuffer = tmpStrBuffer & vbCrLf
End If
Next
MsgBox("Hex 加载成功!" & vbCrLf &
"起始偏移地址 " & _HexStart_C1 & vbCrLf &
" 结束地址 " & _LoadEndAddr & vbCrLf &
" 文件长度 " & tmpHexValidLenght & vbCrLf
)
StateLabel($"解析完成", Color.Green, True)
_flashData = tmpStrBuffer
Console.WriteLine($"解析出的数据:{vbCrLf}{tmpStrBuffer}")
'GetSumCheck(_LoadDataBuff, _LoadEndAddr, checkSum)
'tmpStrCks = HexByteStr(checkSum(3))
'tmpStrCks = tmpStrCks & " " & HexByteStr(checkSum(2))
'tmpStrCks = tmpStrCks & " " & HexByteStr(checkSum(1))
'tmpStrCks = tmpStrCks & " " & HexByteStr(checkSum(0))
'lab_HexLastModifyDate.Text = IO.File.GetLastWriteTime(Tb_HexFilePath.Text)
'lab_HexDataLenght.Text = Format(tmpHexValidLenght, "###,###") & " Bytes"
'lab_HexDataCks.Text = tmpStrCks
'Me.Text = "Massduino Nano485 Loader(" & Application.ProductVersion & ")" & " - " & Tb_HexFilePath.Text
Else
'lab_HexDataLenght.Text = ""
'lab_HexDataCks.Text = ""
End If
End Sub
''' <summary>
''' 加载hex文件数据
''' </summary>
''' <param name="path"></param>
''' <returns></returns>
Private Function LoadDataFromFile(ByVal path As String) As Boolean
Array.Clear(_LoadHexFileData, 0, _LoadHexFileData.Length)
Try
Dim fs As New IO.FileStream(path, IO.FileMode.Open, IO.FileAccess.Read)
If fs.Length <= _loadFileSize Then
fs.Read(_LoadHexFileData, 0, fs.Length)
Else
Return False
End If
fs.Close()
Catch ex As Exception
Return False
End Try
Return HexFileToData(_LoadHexFileData, _LoadDataBuff, _LoadEndAddr)
End Function
''' <summary>
''' 解析Hex文件到Byte数组
''' </summary>
''' <param name="hexBuffer"></param>
''' <param name="dataBuffer"></param>
''' <param name="endAddr"></param>
''' <returns></returns>
Private Function HexFileToData(ByVal hexBuffer() As Byte, ByVal dataBuffer() As Byte, ByRef endAddr As Integer) As Boolean
Dim i As Integer
'行数
Dim LineCnt As Integer = 0
Dim DataType_00_Idx As Integer = 0
'清空数据缓存区域
For i = 0 To dataBuffer.Length - 1
dataBuffer(i) = &HFF
Next
'本行数据缓存
Dim dataStrBuf(31) As Byte
Dim dataValBuf(15) As Byte
'首地址标记
Dim headAddrFlag As Boolean = True
'本行地址值
Dim tmpLineAdd As Integer = 0
'偏移地址 0x04 数据类型指示偏移地址
Dim LineAddOffestBase As Integer = 0
'结束地址
endAddr = 0
Dim flashAddressBuf(3) As Byte
Dim flashAddress As Integer
'Hex格式解析每一行以0D 0A结束
'文本串::1000000000800020A500010061090100AF0001008F
'分解为20 Bytes Hex数据
'
'--- | ----- | ---| ----------------------------------------------------------|----
'Len | ADD |Type| Data | CKS
'--- | ----- | ---| ----------------------------------------------------------|----
' B0 | B1 B2 | B3 | B4 B5 B6 B7 B8 B9 B10 B11 B12 B13 B14 B15 B16 B17 B18 B19 | B20
':10 | 00 00 | 00 | 00 80 00 20 A5 00 01 00 61 09 01 00 AF 00 01 00 | 8F
' ---| -----| ---| ----------------------------------------------------------|----
'1: 每行固定以“:”开头
'2B0 :数据长度
'3B1~B2 :数据地址 B1为地址高位B2为地址低位
'4B3 :数据类型
' 00' Data Record //数据记录
' 01' End of File Record //文件结束记录
' 02' Extended Segment Address Record //扩展段地址记录
' 03' Start Segment Address Record //开始段地址记录
' 04' Extended Linear Address Record //扩展线性地址记录
' 05' Start Linear Address Record //开始线性地址记录
'5B4~B19 :数据内容
'6B20 :校验码
''''''''''''''
'Hex 数据首地址确认方式将第一个00类型的数据的地址作为起始地址
'因此最低地址必须出现在第一个00类型数据中
For i = 0 To hexBuffer.Length - 1
'首先找到冒号
If hexBuffer(i) = &H3A Then '&H3A = ":"
LineCnt += 1
'B0数据长度
Dim dataLen As Integer = (StrToHex(hexBuffer(i + 1)) * 16 + StrToHex(hexBuffer(i + 2)))
If dataLen > 0 Then
'ByCheckSum
Dim checkSum As Byte = (StrToHex(hexBuffer(i + 9 + dataLen * 2)) * 16 + StrToHex(hexBuffer(i + 10 + dataLen * 2)))
'取出整行数据
Dim rowDataStrBuf(41) As Byte
Dim rowDataValBuf(20) As Byte
Dim rowLen As Integer
Array.Clear(rowDataStrBuf, 0, 42)
Array.Clear(rowDataValBuf, 0, 21)
rowLen = (dataLen * 2) + 10
Array.Copy(hexBuffer, i + 1, rowDataStrBuf, 0, rowLen)
StrToHex(rowDataValBuf, rowDataStrBuf, rowLen / 2)
Dim tempCheckSum As Byte = GetSumChecks(rowDataValBuf, rowLen / 2)
If tempCheckSum <> &HFF Then
Return False 'CheckSum校验不通过返回错误
End If
'B4~Bx数据内容
Array.Clear(dataStrBuf, 0, 32)
Array.Clear(dataValBuf, 0, 16)
Array.Copy(hexBuffer, i + 9, dataStrBuf, 0, dataLen * 2)
StrToHex(dataValBuf, dataStrBuf, dataLen)
End If
'B1~B2取出地址位的值
Array.Copy(hexBuffer, i + 3, flashAddressBuf, 0, 4)
'本行地址取出来放在 flashAddress中
StrToHex(tmpLineAdd, flashAddressBuf)
flashAddress = LineAddOffestBase + tmpLineAdd
'B3数据类型
Dim dataType = StrToHex(hexBuffer(i + 8))
Select Case dataType
Case 0 '数据记录
DataType_00_Idx = DataType_00_Idx + 1
'将第一个00类型数据的地址作为起始地址 保存到 _HexStart_C1
If DataType_00_Idx = 1 Then
_HexStart_C1 = flashAddress
End If
Array.Copy(dataValBuf, 0, dataBuffer, flashAddress, dataLen)
endAddr = flashAddress + dataLen
Case 1 '文件结束
If endAddr = 0 Then
Return False
Else
Return True
End If
Case 2, 3, 5 '扩展段地址, 开始段地址, 开始线性地址’
Continue For
Case 4 '扩展线性地址
If dataLen = 2 Then
LineAddOffestBase = (dataValBuf(0) * 256 + dataValBuf(1)) * 65536
Else
Return False '确认DataLen必须是2否则报错
End If
Case Else
Return False
End Select
End If
Next
Return False
End Function
Private Function HexByteStr(hexByte As Byte) As String
If hexByte < 16 Then
Return "0" & Hex(hexByte)
Else
Return Hex(hexByte)
End If
End Function
''' <summary>
''' 获取和校验
''' </summary>
''' <param name="buf"></param>
''' <param name="len"></param>
''' <param name="resultBuf"></param>
Private Sub GetSumCheck(ByVal buf() As Byte, ByVal len As UInt32, ByRef resultBuf() As Byte)
Dim sum As Integer = 0
Dim i As Integer = 0
Dim j As Integer = 0
Dim retByte As Integer
Do
For j = 0 To 127
sum += buf(i + j)
sum = sum And &HFFFFFFFF
Next
i += 128
Loop Until i >= len
retByte = sum
resultBuf(0) = (retByte \ &H1000000) And &HFF
resultBuf(1) = (retByte \ &H10000) And &HFF
resultBuf(2) = (retByte \ &H100) And &HFF
resultBuf(3) = retByte And &HFF
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 Integer
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
Private Sub StrToHex(ByRef pbDest As UInt16, pbSrc() As Byte)
Dim pBufDest(1) As Byte
Dim h1 As Byte
Dim h2 As Byte
Dim s1 As Byte
Dim s2 As Byte
Dim i As UInt16
For i = 0 To 2 - 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
pBufDest(i) = s1 * 16 + s2
Next
'pbDest = (pBufDest(0) << 8) + pBufDest(1)
pbDest = pBufDest(0) * 256 + pBufDest(1)
End Sub
Private Function StrToHex(ByVal src) As Byte
If src >= &H30 AndAlso src <= &H39 Then
Return (src - &H30)
ElseIf src >= &H41 AndAlso src <= &H46 Then
Return (src - &H41 + 10)
ElseIf src >= &H61 AndAlso src <= &H66 Then
Return (src - &H61 + 10)
Else
Return 0
End If
End Function
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
#End Region
#Region "升级流程"
''' <summary>
''' 升级
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
Private Sub BtnUpdateFile_Click(sender As Object, e As EventArgs) Handles BtnUpdateFile.Click
SelectDevice()
PrepareUpdate485()
End Sub
''' <summary>
''' 获取更新设备类型委托
''' </summary>
''' <returns></returns>
Delegate Function Delegate_GetUpdateDevType_Change()
''' <summary>
''' 获取更新设备类型
''' </summary>
''' <returns></returns>
Public Function GetUpdateDevType()
Dim devType As String
If InvokeRequired = True Then
Dim dev As New Delegate_GetUpdateDevType_Change(AddressOf GetUpdateDevType)
Me.Invoke(dev)
Else
Select Case ComboBox1.Text
Case _devNameList(0)
devType = _devNameList(0)
Case _devNameList(1)
devType = _devNameList(1)
Case _devNameList(2)
devType = _devNameList(2)
End Select
End If
Return devType
End Function
''' <summary> 是否准备升级 </summary>
Public _isPrepareUpdate As Boolean
''' <summary>
''' 准备开始升级485
''' </summary>
Private Sub PrepareUpdate485()
If _isPrepareUpdate = False Then
_isPrepareUpdate = True
BtnUpdateFile.ForeColor = Color.Yellow
BtnUpdateFile.Text = $"停止升级"
TSPBar1.Value = 1
ThreadPool.QueueUserWorkItem(AddressOf StartUpdate)
Else
If MsgBox("当前处于升级状态,确定结束升级?", MsgBoxStyle.YesNo, $"Tip") = MsgBoxResult.Yes Then
_isPrepareUpdate = False
BtnUpdateFile.ForeColor = Color.Green
BtnUpdateFile.Text = $"开始升级"
TSPBar1.Value = 0
AppendTipText($"已终止升级,升级失败!" & vbCrLf, Color.Red)
End If
End If
End Sub
''' <summary>
''' 开始升级
''' </summary>
Private Sub StartUpdate()
_CRC16List.Clear()
'升级流程
Static startValue As Integer
Static endValue As Integer
If GrdTypeInfo.Rows > 0 Then
For index = 1 To GrdTypeInfo.Rows - 1
If GrdTypeInfo.Cell(index, EnTypeColInfo.Check).Text = $"1" Then '选中升级
'开始握手
SearchRangeValue(startValue, endValue)
SearchData(startValue, endValue)
Dim addr As Integer = GrdTypeInfo.Cell(index, EnTypeColInfo.DevAddr).Text
If GrdTypeInfo.Cell(index, EnTypeColInfo.Status).Text = "App" Then '判断分区
FrmRCU.SerialPort.BaudRate = CInt(FrmRCU.CboSerialBaud.Text) '设置波特率
JumpBootPartition(addr) '跳转Boot区
End If
FrmRCU.SerialPort.BaudRate = 2400 '设置波特率
SearchPartition(addr) '再次握手
SetParam(addr) '设置参数
FrmRCU.SerialPort.BaudRate = CInt(FrmRCU.CboSerialBaud.Text) '设置波特率
SearchPartition(addr) '最后握手
EraseFlash(addr) '擦除Flash
ReadFlashData(addr) '写入数据
Dim devType As String = GetUpdateDevType() '委托
Dim burnLen As Integer = GetFlashCheckDataLen(devType) '根据类型确认,单包参与crc16校验数据长度
FlashCheck(addr, burnLen) 'Flash校验
'检验成功后跳转App区
JumpAppPartition(addr)
End If
Next
End If
End Sub
''' <summary>
''' 搜索Boot分区
''' </summary>
''' <param name="Index">485地址</param>
Private Sub SearchPartition(Index As Integer)
Dim cmd As Byte = &H63
Dim data As Byte() = GetAppSearchData(Index)
Dim sendPacket As Byte() = FillSendPacket(cmd, data)
sendPacket = FillPacket(sendPacket) '是否填充透传数据包
Console.WriteLine($"搜索:{Index}-Boot分区{ByteToString(sendPacket)}")
SendData(sendPacket) '发送数据包
End Sub
''' <summary>
''' 跳转BootLoader分区
''' </summary>
''' <param name="Index">485地址</param>
Private Sub JumpBootPartition(Index As Integer)
Dim cmd As Byte = &H68
Dim indexs(0) As Byte
indexs(0) = Index
Dim sendPacket As Byte() = FillSendPacket(cmd, indexs)
sendPacket = FillPacket(sendPacket) '是否填充透传数据包
Console.WriteLine($"跳转{Index}{ByteToString(sendPacket)}")
SendData(sendPacket) '发送数据包
End Sub
''' <summary>
''' 设置参数
''' </summary>
''' <param name="Index">485地址</param>
Private Sub SetParam(Index As Integer)
Dim cmd As Byte = &H69
Dim zero As Byte = &H0
Dim baud() As Byte = IntToByteHB(FrmRCU.CboSerialBaud.Text / 100)
Dim timeout() As Byte = IntToByteLB(10)
Dim type As Byte = GetUpdateType()
Dim databuff As New List(Of Byte)
databuff.Add(Index)
databuff.AddRange(baud)
databuff.AddRange(timeout)
databuff.Add(type)
Dim sendPacket As Byte() = FillSendPacket(cmd, databuff.ToArray)
sendPacket = FillPacket(sendPacket) '是否填充透传数据包
Console.WriteLine($"设置{Index}{ByteToString(sendPacket)}")
SendData(sendPacket) '发送数据包
End Sub
''' <summary>
''' 获取更新设备类型
''' </summary>
''' <returns></returns>
Private Function GetUpdateType()
Dim devType As String = GetUpdateDevType()
Dim type As Byte
Select Case devType
Case _devNameList(0) 'None 485
type = &H0
Case _devNameList(1) 'PB 485
type = &H1
Case _devNameList(2) 'BLV_C1
type = &H2
End Select
Return type
End Function
''' <summary>
''' 擦除Flash
''' </summary>
''' <param name="Index">485地址</param>
Private Sub EraseFlash(Index As Integer)
Dim cmd As Byte = &H62
Dim indexs(0) As Byte
indexs(0) = Index
Dim sendPacket As Byte() = FillSendPacket(cmd, indexs)
sendPacket = FillPacket(sendPacket) '是否填充透传数据包
Console.WriteLine($"擦除{Index}{ByteToString(sendPacket)}")
SendData(sendPacket) '发送数据包
End Sub
''' <summary>
''' 获取Flash数据
''' </summary>
''' <returns></returns>
Private Function GetFlashDataByte()
_flashData = _flashData.Replace($"{vbCrLf}", "").Replace($" ", "")
Dim dataBuff() As Byte = GetStringToDataByte(_flashData)
Return dataBuff
End Function
''' <summary>
''' 写入Flash回复
''' </summary>
Private _isReadFlashRelay As Boolean
''' <summary>
''' 记录重发次数
''' </summary>
Public _retry As Integer = 0
''' <summary>
''' Flash数据
''' </summary>
Private _flashData As String
''' <summary>
''' Flash新数据
''' </summary>
Private _flashNewData As New List(Of Byte)
''' <summary>
''' 写入Flash
''' </summary>
''' <param name="index"></param>
Private Sub ReadFlashData(index As Integer)
'1、根据不同类型选择不同组包方式组包发送
Dim devType As Byte = GetUpdateType()
Dim dataBuff() As Byte = GetFlashDataByte() '数据
Dim blockCount As Integer = SubPackage(devType, dataBuff)
Dim burnPackage() As Byte
Dim packageNumber As Integer
For packageNumber = 1 To blockCount
_isReadFlashRelay = False
burnPackage = FillBurnPackage(index, _flashNewData.ToArray, packageNumber, blockCount)
AppendTipText($"开始发送第{packageNumber}包数据..." & vbCrLf, Color.Blue)
burnPackage = FillPacket(burnPackage) '是否填充透传数据包
SendData(burnPackage)
Console.WriteLine($"第{packageNumber}包:{ByteToString(burnPackage)}")
'ChangePrgValue(packageNumber, blockCount, 0)
WaitReadFlashRelay()
If _isReadFlashRelay = True Then '判断是回复
If packageNumber = blockCount Then
AppendTipText($"写入Flash数据成功!" & vbCrLf, Color.Blue)
'ChangePrgAirBurnValue(0, 1)
Return
End If
Else
_retry += 1
If _retry <= 3 Then
AppendTipText($"开始重发次数:{_retry}次" & vbCrLf, Color.Blue)
packageNumber -= 1
Else
AppendTipText($"已超出最大重发次数!" & vbCrLf, Color.Red)
AppendTipText($"下载失败!" & vbCrLf, Color.Red)
'ChangePrgAirBurnValue(0, 1)
_retry = 0
Return
End If
End If
Next
End Sub
''' <summary>
''' 根据设备地址类型分包
''' </summary>
''' <param name="devType">设备地址类型</param>
''' <param name="dataBuff">数据包</param>
Private Function SubPackage(ByRef devType As Byte, ByRef dataBuff As Byte())
Dim blockCount As Integer
Dim packetCount As Integer = ComboBox2.Text
Select Case devType
Case 0 'None 485
blockCount = GetPacketCount(128, dataBuff)
Case 1 'PB 485
blockCount = GetPacketCount(128, dataBuff)
Case 2 'BLV_C1
blockCount = GetPacketCount(packetCount, dataBuff)
Dim fill(blockCount * packetCount - dataBuff.Length - 1) As Byte
For index = 0 To fill.Length - 1
fill(index) = &HFF
Next
_flashNewData.AddRange(dataBuff)
_flashNewData.AddRange(fill)
End Select
Return blockCount
End Function
''' <summary>
''' 具体分包函数
''' 根据不同类型的包长度分包
''' </summary>
''' <param name="len">不同类型的包长</param>
''' <param name="dataBuff"></param>
Private Function GetPacketCount(len As Integer, dataBuff As Byte())
Dim blockCount As Integer = dataBuff.Length \ len
If dataBuff.Length Mod len > 0 Then
blockCount += 1
End If
Return blockCount
End Function
''' <summary>
''' Flash校验
''' </summary>
Private _CRC16List As New List(Of Byte)
''' <summary>
''' 填充写入Flash数据包
''' </summary>
''' <param name="index">485地址</param>
''' <param name="padData"></param>
''' <param name="blockIndex"></param>
''' <param name="blockCount"></param>
''' <returns></returns>
Private Function FillBurnPackage(index As Integer, padData() As Byte, blockIndex As Integer blockCount As Integer) As Byte()
Dim cmd As Byte = &H60
Dim databuff As Byte() = FillBurnAlonePackage(padData, blockIndex, blockCount)
Dim data As New List(Of Byte)
data.Add(index)
data.AddRange(databuff)
Dim sendPacket As Byte() = FillSendPacket(cmd, data.ToArray)
Return sendPacket
End Function
''' <summary>
''' 填充烧录单包数据
''' </summary>
''' <param name="padData"></param>
''' <param name="blockIndex"></param>
''' <param name="blockCount"></param>
''' <returns></returns>
Private Function FillBurnAlonePackage(padData() As Byte, blockIndex As Integer blockCount As Integer) As Byte()
Dim blockPacket As New List(Of Byte)
Dim count As Integer = ComboBox2.Text
Dim devType As String = GetUpdateDevType()
Select Case devType
Case _devNameList(0), _devNameList(1) 'None 485, 'PB 485
'If blockIndex = blockCount Then
' For index = 128 * (blockIndex - 1) To padData.Length - 1
' blockPacket.Add(padData(index))
' Next
'Else
For index = 128 * (blockIndex - 1) To 128 * blockIndex - 1
blockPacket.Add(padData(index))
Next
'End If
Case _devNameList(2) 'BLV_C1
'If blockIndex = blockCount Then
' For index = count * (blockIndex - 1) To padData.Length - 1
' blockPacket.Add(padData(index))
' Next
'Else
For index = count * (blockIndex - 1) To count * blockIndex - 1
blockPacket.Add(padData(index))
Next
'End If
End Select
Return blockPacket.ToArray
End Function
''' <summary>
''' 获取Flash单包校验数据长度
''' 根据类型判断需要校验的数据长度
''' </summary>
''' <returns></returns>
Private Function GetFlashCheckDataLen(devType As String)
Dim burnLen As Integer
Select Case devType
Case _devNameList(0), _devNameList(1)
burnLen = 512
Case _devNameList(2)
burnLen = 4096
Case Else
End Select
Return burnLen
End Function
''' <summary>
''' Flash校验
''' </summary>
''' <param name="Index"></param>
Private Sub FlashCheck(Index As Integer, burnLen As Integer)
Dim cmd As Byte = &H67
Dim data As Byte() = GetFlashCheck(burnLen)
Console.WriteLine($"Flash-CRC16-{Index}{ByteToString(data)}")
Dim sendPacket As Byte() = FillSendPacket(cmd, data)
sendPacket = FillPacket(sendPacket) '是否填充透传数据包
Console.WriteLine($"校验{Index}{ByteToString(sendPacket)}")
SendData(sendPacket) '发送数据包
End Sub
''' <summary>
''' 获取Flash校验数据
''' </summary>
''' <param name="burnLen">根据类型确认,单包参与crc16校验数据长度burnLen</param>
''' <returns></returns>
Private Function GetFlashCheck(burnLen As Integer)
Dim blockCount As Integer = _flashNewData.ToArray.Length \ burnLen
If _flashNewData.ToArray.Length Mod burnLen > 0 Then
blockCount += 1
End If
For index = 0 To blockCount - 1
Dim burnPack(burnLen - 1) As Byte
Array.Copy(_flashNewData.ToArray, index * burnLen, burnPack, 0, burnPack.Length - 1)
Dim crc16 As Byte() = GetCRC16CheckSum(burnPack, burnPack.Length)
_CRC16List.AddRange(crc16)
Next
Return _CRC16List.ToArray
End Function
''' <summary>
''' 跳转App区
''' </summary>
''' <param name="index"></param>
Private Sub JumpAppPartition(index As Integer)
Dim cmd As Byte = &H68
Dim data(0) As Byte
data(0) = index
Dim sendPacket As Byte() = FillSendPacket(cmd, data)
sendPacket = FillPacket(sendPacket) '是否填充透传数据包
Console.WriteLine($"跳转APP区-{index}{ByteToString(sendPacket)}")
SendData(sendPacket) '发送数据包
End Sub
''' <summary>
''' 回复超时
''' </summary>
Private ReadOnly _RelayTimeout As Integer = 1000
''' <summary>
''' 等待写入Flash数据回复
''' </summary>
Private Sub WaitReadFlashRelay()
Dim tick As Integer
Dim startTick As Integer = My.Computer.Clock.TickCount
_isReadFlashRelay = False
While _isReadFlashRelay = False AndAlso tick <= _RelayTimeout
Thread.Sleep(100)
tick = My.Computer.Clock.TickCount - startTick
Application.DoEvents()
End While
End Sub
''' <summary>
''' 升级设备列表总数
''' </summary>
Public _devUpdateCount As Integer = 1
''' <summary>
''' 搜索分区委托
''' </summary>
Delegate Sub delegate_SearchPartition_Change()
''' <summary>
''' 搜索分区委托
''' 刷新设备列表
''' </summary>
Public Sub SearchPartition()
If InvokeRequired = True Then
Dim dev As New delegate_SearchPartition_Change(AddressOf SearchPartition)
Me.Invoke(dev)
Else
For Each key As String In _upgradeDevList.Keys
GrdTypeInfo.AddItem("")
GrdTypeInfo.Cell(_devUpdateCount, EnTypeColInfo.DevAddr).Text = _upgradeDevList(key).DevAddress
GrdTypeInfo.Cell(_devUpdateCount, EnTypeColInfo.DevName).Text = _upgradeDevList(key).DevName
GrdTypeInfo.Cell(_devUpdateCount, EnTypeColInfo.Status).Text = _upgradeDevList(key).DevPartition
GrdTypeInfo.Cell(_devUpdateCount, EnTypeColInfo.Result).Text = _upgradeDevList(key).DevResult
_devUpdateCount += 1
Next
End If
End Sub
''' <summary>
''' 搜索分区委托
''' 刷新设备列表
''' </summary>
''' <param name="devAddr"></param>
''' <param name="devName"></param>
''' <param name="devPartition"></param>
Delegate Sub delegate_SearchPartitionDevList_Change(devAddr As String, devName As String, devPartition As String)
''' <summary>
''' 刷新设备列表信息
''' 局部刷新_委托
''' </summary>
''' <param name="devAddr"></param>
''' <param name="devName"></param>
''' <param name="devPartition"></param>
Public Sub RefreshSearchPartitionDevList(devAddr As String, devName As String, devPartition As String)
If InvokeRequired = True Then
Dim dev As New delegate_SearchPartitionDevList_Change(AddressOf RefreshSearchPartitionDevList)
Me.Invoke(dev, New Object() {devAddr, devName, devPartition})
Else
GrdTypeInfo.AddItem("")
GrdTypeInfo.Cell(_devUpdateCount, EnTypeColInfo.DevAddr).Text = devName
GrdTypeInfo.Cell(_devUpdateCount, EnTypeColInfo.DevName).Text = devName
GrdTypeInfo.Cell(_devUpdateCount, EnTypeColInfo.Status).Text = devPartition
GrdTypeInfo.Cell(_devUpdateCount, EnTypeColInfo.Result).Text = $"未升级"
_devUpdateCount += 1
End If
End Sub
#End Region
#End Region
#Region "添加记录"
''' <summary>
''' 添加记录
''' </summary>
''' <param name="recordString"></param>
''' <param name="col"></param>
Private Sub AppendTipText(recordString As String, col As Color)
If InvokeRequired Then
Invoke(New Action(Sub()
FrmRCU.AppendTipText(recordString, col)
End Sub))
Else
FrmRCU.AppendTipText(recordString, col)
End If
End Sub
''' <summary>
''' 测试
''' </summary>
''' <param name="sender"></param>
''' <param name="e"></param>
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'GetFlashDataByte()
'JumpBootPartition(&H01)
'SearchPartition(&H01)
'SetParam(&H01)
'EraseFlash(&H01)
'GetFlashDataByte()
'FlashCheck(&H1, 2048)
'JumpAppPartition(&H01)
End Sub
#End Region
End Class