Attribute VB_Name = "Module1"
Public Const MAX_DATA_SIZE As Long = 56       ' 单次命令处理的最大数据长度'有效值是1到56
Public Down As USB_DOWN_PKT
Public Up  As USB_UP_PKT
Public Const CONST_CMD_LEN As Long = &H7
Public XRamaStartaddr As Byte
' ****************************************************************************************************
' 计算机接口子程序源程序
''Const MAX_DATA_SIZE As Long = 16                ' 单次命令处理的最大数据长度'有效值是1到56
Type Parastruct
           mByte(3) As Byte                ' 通用参数
          'mWord(2) As Integer              ' 通用参数'低字节在前'Little-Endian
           'mDword As Long                   ' 通用参数'低字节在前'Little-Endian
          'mAddress(1) As Byte               ' 读写操作的起始地址'低字节在前'Little-Endian
End Type

Type USB_DOWN_PKT                      ' 下传的数据包结构'用于命令/写数据
     mCommand As Byte                      ' 命令码'见下面的定义
     mCommandNot As Byte                    ' 命令码的反码'用于校验下传数据包
     'u As Parastruct
     mByte(3) As Byte                ' 通用参数'低字节在前'Little-Endian
     mLength  As Byte                     ' 下面的缓冲区的长度'读写操作的字节数
     mBuffer(MAX_DATA_SIZE) As Byte     ' 数据缓冲区
End Type

Type USB_UP_PKT            ' 上传的数据包结构'用于状态/读数据
    mStatus As Byte                      ' 状态码'见下面的定义
    mCommandNot As Byte                  ' 命令码的反码'用于校验上传数据包
    mReserved(3) As Byte
    mLength As Byte                      ' 下面的缓冲区的长度'读操作的字节数
    mBuffer(MAX_DATA_SIZE) As Byte     ' 数据缓冲区
End Type

' 命令码定义'按位说明
  ' 位7为命令类型:  0=实现特定功能' 1=存储器和SFR读写
   '对于"实现特定功能"命令类型:
    '位6 -位0为定义的具体命令码 ' 命令码为00H-7FH' 其中: 00H-3FH为通用标准命令' 40H-7FH为与应用系统有关的特定命令
'目前版本定义了以下通用标准命令:
'0 H:            获取调试固件程序的版本 ' 并取消未完成的上传数据块
'10 H:           获取当前应用系统的版本和说明字符串
' 对于"存储器和SFR读写"命令类型:
'位6为数据传输方向:      0=读操作/上传' 1=写操作/下传
'位5-位4为数据读写宽度:  00=以字节为单位/8位' 01=以字为单位/16位' 10=以双字为单位/32位' 11=以位为单位/1位
'位1-位0为存储器空间:    00=存取SFR' 01=存取内部RAM' 10=存取外部RAM' 11=存取程序ROM
'例如:        命令码80H为读SFR ' 命令码83H为读程序ROM' 命令码C1H为写内部RAM' 命令码C2H为写外部RAM
'   状态码定义: 00H为操作成功' 080H为命令不支持' 0FFH为未定义的错误

Const USB_CMD_GET_FW_INFO     As Byte = &H0
Const USB_CMD_GET_APP_INFO    As Byte = &H10
Const USB_CMD_MEM_ACCESS      As Byte = &H80
Const USB_CMD_MEM_DIR_WR      As Byte = &H40
Const USB_CMD_MEM_WIDTH       As Byte = &HC
Const USB_CMD_MEM_W_BYTE      As Byte = &H0
Const USB_CMD_MEM_W_WORD      As Byte = &H4
Const USB_CMD_MEM_W_DWORD     As Byte = &H8
Const USB_CMD_MEM_W_BIT       As Byte = &HC
Const USB_CMD_MEM_SPACE       As Byte = &H3
Const USB_CMD_MEM_S_SFR       As Byte = &H0
Const USB_CMD_MEM_S_IRAM      As Byte = &H1
Const USB_CMD_MEM_S_XRAM      As Byte = &H2
Const USB_CMD_MEM_S_ROM       As Byte = &H3
Const ERR_SUCCESS             As Byte = &H0
Const ERR_UNSUPPORT           As Byte = &H80
Const ERR_UNDEFINED           As Byte = &HFF

Const ReadSFRCmdCode As Byte = &H80
Const WriteSFRCmdCode As Byte = &HC0
Const ReadIRamCmdCode As Byte = &H81
Const WriteIRamCmdCode As Byte = &HC1
Const ReadXRamCmdCode As Byte = &H82
Const WriteXRamCmdCode As Byte = &HC2
Const ReadRomCmdCode As Byte = &H83
'Const WriteRomCmdCode As Byte = &HC3

Public CH375DBG_Index As Long            ' CH372/CH375设备序号
Public CH375DBG_Opened As Boolean        ' CH372/CH375设备被打开标志


' 应用程序启动后'在所有操作之前'必须首先调用一次下面的CH375DBG_GetFirmwareInfo子程序
 '获取调试固件程序的版本'并取消未完成的上传数据块
Public Function CH375DBG_GetFirmwareInfo(ver As Byte) As Boolean
' 输入参数: ver 指向一个字节变量单元'用于存放获取的版本号
Dim Leng As Long
     CH375DBG_GetFirmwareInfo = False
     If CH375OpenDevice(CH375DBG_Index) <> 0 Then     ' 打开CH375设备
        CH375DBG_Opened = True      ' 打开CH375设备
        GetFirmwareInfo = True
      Else
        CH375DBG_Opened = False   '打开CH375设备失败
        GetFirmwareInfo = False
        Exit Function    '退出
      End If
      Down.mCommand = USB_CMD_GET_FW_INFO
      Down.mCommandNot = Not (Down.mCommand)
      For i = 0 To 3
      Down.mByte(i) = 0
      Next i
      Down.mLength = 1
      'Leng = mOFFSET(USB_DOWN_PKT, mBuffer)
      Leng = CONST_CMD_LEN
      If (CH375Writedata(CH375DBG_Index, Down, Leng)) Then
       ' 写出命令块
        'Leng = Len(Up)
        Leng = Len(Up)
        If (CH375ReadData(CH375DBG_Index, Up, Leng)) Then
          ' 读取应答块
             If ((Up.mStatus = ERR_SUCCESS) And (Up.mCommandNot = Down.mCommandNot) And (Up.mLength >= 1)) Then
              ' 操作成功,并且返回数据
                ver = Up.mBuffer(0)    ' 返回版本号 ''''modi
                CH375DBG_GetFirmwareInfo = True
             End If
        End If
      Else
     GetFirmwareInfo = False
     GetFirmwareInfo = True
    End If
End Function

' 应用程序退出前'在所有操作之后'应该调用一次下面的CH375DBG_CloseExit子程序
Public Function CH375DBG_CloseExit()     '关闭CH372/CH375设备
'   关闭CH372/CH375设备
    CH375DBG_Opened = False
    CH375CloseDevice (CH375DBG_Index)
End Function

 '获取当前应用系统的版本和说明字符串
Public Function CH375DBG_GetAppSysInfo(ver As Byte, StringBuffer() As Byte) As Boolean
' 输入参数: ver 指向一个字节变量单元'用于存放获取的版本号
' StringBuffer 指向一个足够大的字符串缓冲区'用于存放获取的说明字符串
 '获取当前应用系统的版本和说明字符串
'输入参数: ver 指向一个字节变量单元,用于存放获取的版本号
'          StringBuffer 指向一个足够大的字符串缓冲区,用于存放获取的说明字符串
Dim Down As USB_DOWN_PKT
Dim Up  As USB_UP_PKT
Dim Leng As Long
    CH375DBG_GetAppSysInfo = False
    Down.mCommand = USB_CMD_GET_APP_INFO
    Down.mCommandNot = Not Down.mCommand
    For i = 0 To 3
      Down.mByte(i) = 0
      Next i
    Down.mLength = 0
    'len = mOFFSET( USB_DOWN_PKT, mBuffer )
    Leng = CONST_CMD_LEN
    If (CH375Writedata(CH375DBG_Index, Down, Leng)) Then
        '写出命令块
        Leng = Len(Up)
        If (CH375ReadData(CH375DBG_Index, Up, Leng)) Then
            '读取应答块
            'If ((Up.mStatus = ERR_SUCCESS) And (Up.mCommandNot = Down.mCommandNot) And (Up.mLength >= 1)) Then
            If ((Up.mStatus = ERR_SUCCESS) And (Up.mCommandNot = Down.mCommandNot) And (Up.mLength >= 1)) Then
              '操作成功,并且返回数据
                ver = Up.mBuffer(0)    '返回版本号
                For i = 0 To (Up.mLength - 1)
                    StringBuffer(i) = Up.mBuffer(i + 1)     '返回说明字符串
                Next i
                CH375DBG_GetAppSysInfo = True
            End If
        End If
    End If
End Function

Public Function CH375DBG_ReadSFR(Addr As Byte, Data As Byte) As Boolean         '从SFR一个单元读取数据
' 输入参数: addr 指定SFR的地址
'           data 指向一个字节变量单元'用于存放读出的数据
' 从SFR一个单元读取数据
' 输入参数: addr 指定SFR的地址
'           data 指向一个字节变量单元,用于存放读出的数据
Dim Down As USB_DOWN_PKT
Dim Up  As USB_UP_PKT
Dim Leng As Long
     CH375DBG_ReadSFR = False
    'Down.mCommand = hextobcd(Hex(USB_CMD_MEM_ACCESS) & Hex(USB_CMD_MEM_W_BYTE) & Hex(USB_CMD_MEM_S_SFR))
    Down.mCommand = ReadSFRCmdCode
    Down.mCommandNot = Not Down.mCommand
    'Down.mDword = Addr * (256 ^ 3)  '地址低位在前,地址高位在后
    Down.mByte(0) = CByte(Addr)
    For i = 1 To 3
      Down.mByte(i) = 0
    Next i
    Down.mLength = 1
    Leng = CONST_CMD_LEN
    If (CH375Writedata(CH375DBG_Index, Down, Leng)) Then
       ' 写出命令块
        Leng = Len(Up)
        If (CH375ReadData(CH375DBG_Index, Up, Leng)) Then
           ' 读取应答块
            If (((Up.mStatus = ERR_SUCCESS) And (Up.mCommandNot = Down.mCommandNot)) And (Up.mLength >= 1)) Then
               ' 操作成功,并且返回数据
                Data = Up.mBuffer(0)  ' 返回数据   '!date是动态数组
                CH375DBG_ReadSFR = True
            End If
        End If
    End If
End Function

Public Function CH375DBG_WriteSFR(Addr As Long, Data As Byte) As Boolean          '向SFR一个单元写入数据
' 输入参数: addr 指定SFR的地址
'           data 指定准备写入的数据
' 向SFR一个单元写入数据
' 输入参数: addr 指定SFR的地址
'           data 指定准备写入的数据
Dim Down As USB_DOWN_PKT
Dim Up  As USB_UP_PKT
Dim Leng As Long
    CH375DBG_WriteSFR = False
    Down.mCommand = WriteSFRCmdCode
    Down.mCommandNot = Not (Down.mCommand)
    Down.mByte(0) = CByte(Addr)
    For i = 1 To 3
      Down.mByte(i) = 0
    Next i
    Down.mLength = 1
    Down.mBuffer(0) = Data
    Leng = CONST_CMD_LEN + Down.mLength
    If (CH375Writedata(CH375DBG_Index, Down, Leng)) Then
        ' 写出命令块
        Leng = Len(Up)
        If (CH375ReadData(CH375DBG_Index, Up, Leng)) Then
            ' 读取应答块
            If ((Up.mStatus = ERR_SUCCESS) And (Up.mCommandNot = Down.mCommandNot)) Then
              ' 操作成功
                CH375DBG_WriteSFR = True
            End If
        End If
    End If
End Function

Public Function CH375DBG_ReadIRAM(StartAddr As Long, Buffer() As Byte, Count As Byte) As Boolean           '从内部RAM读取数据块
' 输入参数: StartAddr 指定内部RAM的起始地址
'           buffer 指向一个足够大的数据缓冲区'用于存放读出的数据块
'           count 指定读取的字节数
' 从内部RAM读取数据块
' 输入参数: StartAddr 指定内部RAM的起始地址
'           buffer 指向一个足够大的数据缓冲区,用于存放读出的数据块
'           count 指定读取的字节数
Dim Down As USB_DOWN_PKT
Dim Up  As USB_UP_PKT
Dim Leng As Long
    CH375DBG_ReadIRAM = False
    If (Count > MAX_DATA_SIZE) Then
        CH375DBG_ReadIRAM = False  ' 限制单次处理的数据长度,可以与单片机程序的MAX_DATA_SIZE一起同步修改为更大或更小的值
        Exit Function
    End If
    Down.mCommand = ReadIRamCmdCode
    Down.mCommandNot = Not Down.mCommand
    'Down.mDword = StartAddr * (256 ^ 3)
    Down.mByte(0) = CByte(StartAddr)
    For i = 1 To 3
      Down.mByte(i) = 0
    Next i
    Down.mLength = Count
     Leng = CONST_CMD_LEN
    
    If (CH375Writedata(CH375DBG_Index, Down, Leng)) Then
        ' 写出命令块
        Leng = Len(Up)
        If (CH375ReadData(CH375DBG_Index, Up, Leng)) Then
          ' 读取应答块
            If ((Up.mStatus = ERR_SUCCESS) And (Up.mCommandNot = Down.mCommandNot) And (Up.mLength >= Count)) Then
              ' 操作成功,并且返回数据
                For i = 0 To (Count - 1)
                    Buffer(i) = Up.mBuffer(i)  ' 返回数据
                Next i
                CH375DBG_ReadIRAM = True
                
            End If
        End If
    End If
End Function

Public Function CH375DBG_WriteIRAM(StartAddr As Long, Buffer() As Byte, Count As Byte) As Boolean       '向内部RAM写入数据块
' 输入参数: StartAddr 指定内部RAM的起始地址
'           buffer 指向一个数据缓冲区'存放准备写入的数据块
'           count 指定写入的字节数
' 向内部RAM写入数据块
' 输入参数: StartAddr 指定内部RAM的起始地址
'           buffer 指向一个数据缓冲区,存放准备写入的数据块
'           count 指定写入的字节数
Dim Down As USB_DOWN_PKT
Dim Up  As USB_UP_PKT
Dim Leng As Long
    CH375DBG_WriteIRAM = False
    If (Count > MAX_DATA_SIZE) Then
        CH375DBG_WriteIRAM = False        ' 限制单次处理的数据长度,可以与单片机程序的MAX_DATA_SIZE一起同步修改为更大或更小的值
        Exit Function
    End If
    Down.mCommand = WriteIRamCmdCode
    Down.mCommandNot = Not (Down.mCommand)
    Down.mByte(0) = CByte(StartAddr)
    For i = 1 To 3
      Down.mByte(i) = 0
    Next i
    Down.mLength = Count
    For i = 0 To (Count - 1)
        Down.mBuffer(i) = Buffer(i)
    Next i
    Leng = CONST_CMD_LEN + Down.mLength

    If (CH375Writedata(CH375DBG_Index, Down, Leng)) Then      ' 写出命令块
        Leng = Len(Up)
        If (CH375ReadData(CH375DBG_Index, Up, Leng)) Then
           ' 读取应答块
            If ((Up.mStatus = ERR_SUCCESS) And (Up.mCommandNot = Down.mCommandNot)) Then
              ' 操作成功
                CH375DBG_WriteIRAM = True
            End If
        End If
    End If
End Function

Public Function CH375DBG_ReadXRAM(StartAddr As Long, Buffer() As Byte, Count As Byte) As Boolean         '从外部RAM读取数据块
' 输入参数: StartAddr 指定外部RAM的起始地址
'           buffer 指向一个足够大的数据缓冲区'用于存放读出的数据块
'           count 指定读取的字节数
' 从外部RAM读取数据块
' 输入参数: StartAddr 指定外部RAM的起始地址
'           buffer 指向一个足够大的数据缓冲区,用于存放读出的数据块
'           count 指定读取的字节数
Dim Down As USB_DOWN_PKT
Dim Up  As USB_UP_PKT
Dim Leng As Long
    CH375DBG_ReadXRAM = False
    If (Count > MAX_DATA_SIZE) Then
        CH375DBG_ReadXRAM = False    ' 限制单次处理的数据长度,可以与单片机程序的MAX_DATA_SIZE一起同步修改为更大或更小的值
        Exit Function
    End If
    Down.mCommand = ReadXRamCmdCode
    Down.mCommandNot = Not (Down.mCommand)
    Down.mByte(0) = CByte(StartAddr Mod 256)
    Down.mByte(1) = CByte(StartAddr \ 256)
    Down.mByte(2) = 0
    Down.mByte(3) = 0
    Down.mLength = Count
    Leng = CONST_CMD_LEN
    If (CH375Writedata(CH375DBG_Index, Down, Leng)) Then
       ' 写出命令块
        Leng = Len(Up)
        If (CH375ReadData(CH375DBG_Index, Up, Leng)) Then
            ' 读取应答块
            If ((Up.mStatus = ERR_SUCCESS) And (Up.mCommandNot = Down.mCommandNot) And (Up.mLength >= Count)) Then
              ' 操作成功,并且返回数据
                For i = 0 To (Up.mLength - 1)
                    Buffer(i) = Up.mBuffer(i)  ' 返回数据
                Next i
                CH375DBG_ReadXRAM = True
               
            End If
        End If
    End If
End Function

Public Function CH375DBG_WriteXRAM(StartAddr As Long, Buffer() As Byte, Count As Byte) As Boolean           '向外部RAM写入数据块
' 输入参数: StartAddr 指定外部RAM的起始地址
'           buffer 指向一个数据缓冲区'存放准备写入的数据块
'           count 指定写入的字节数
 ' 向外部RAM写入数据块
' 输入参数: StartAddr 指定外部RAM的起始地址
'           buffer 指向一个数据缓冲区,存放准备写入的数据块
'           count 指定写入的字节数
Dim Down As USB_DOWN_PKT
Dim Up  As USB_UP_PKT
Dim Leng As Long
    CH375DBG_WriteXRAM = False
    If (Count > MAX_DATA_SIZE) Then
        CH375DBG_WriteXRAM = False    ' 限制单次处理的数据长度,可以与单片机程序的MAX_DATA_SIZE一起同步修改为更大或更小的值
        Exit Function
    End If
    Down.mCommand = WriteXRamCmdCode
    Down.mCommandNot = Not (Down.mCommand)
    Down.mByte(0) = CByte(StartAddr Mod 256)
    Down.mByte(1) = CByte(StartAddr \ 256)
    Down.mByte(2) = 0
    Down.mByte(3) = 0
    Down.mLength = Count
    For i = 0 To (Count - 1)
       Down.mBuffer(i) = Buffer(i)
    Next i
    Leng = CONST_CMD_LEN + Down.mLength
    If (CH375Writedata(CH375DBG_Index, Down, Leng)) Then
        ' 写出命令块
        Leng = Len(Up)
        If (CH375ReadData(CH375DBG_Index, Up, Leng)) Then
            ' 读取应答块
            If ((Up.mStatus = ERR_SUCCESS) And (Up.mCommandNot = Down.mCommandNot)) Then
              ' 操作成功
                CH375DBG_WriteXRAM = True
            End If
        End If
    End If
End Function

Public Function CH375DBG_ReadROM(StartAddr As Long, Buffer() As Byte, Count As Byte) As Boolean      '从程序ROM读取数据块
' 输入参数: StartAddr 指定程序ROM的起始地址
'           buffer 指向一个足够大的数据缓冲区'用于存放读出的数据块
'           count 指定读取的字节数
 ' 从程序ROM读取数据块
' 输入参数: StartAddr 指定程序ROM的起始地址
'           buffer 指向一个足够大的数据缓冲区,用于存放读出的数据块
'           count 指定读取的字节数
Dim Down As USB_DOWN_PKT
Dim Up  As USB_UP_PKT
Dim Leng As Long
    CH375DBG_ReadROM = False
    If (Count > MAX_DATA_SIZE) Then     ' 限制单次处理的数据长度,可以与单片机程序的MAX_DATA_SIZE一起同步修改为更大或更小的值
      CH375DBG_ReadROM = False
      Exit Function
    End If
    Down.mCommand = ReadRomCmdCode
    Down.mCommandNot = Not Down.mCommand
    Down.mByte(0) = CByte(StartAddr Mod 256)
    Down.mByte(1) = CByte(StartAddr \ 256)
    Down.mByte(2) = 0
    Down.mByte(3) = 0
    Down.mLength = Count
    Leng = CONST_CMD_LEN
    If (CH375Writedata(CH375DBG_Index, Down, Leng)) Then
       ' 写出命令块
        Leng = Len(Up)
        If (CH375ReadData(CH375DBG_Index, Up, Leng)) Then
           ' 读取应答块
            If ((Up.mStatus = ERR_SUCCESS) And (Up.mCommandNot = Down.mCommandNot) And (Up.mLength >= Count)) Then
              ' 操作成功,并且返回数据
                For i = 0 To (Count - 1)
                   Buffer(i) = Up.mBuffer(i)  ' 返回数据
                Next i
                CH375DBG_ReadROM = True
            End If
        End If
    End If
End Function

Function hextobcd(str As String) As Byte                 '将文本框中输入的十六进制值转换成BCD码
Dim Length As Integer
Dim x As String
Length = Len(str)
For i = 0 To Length - 1
x = Mid(str, Length - i, 1)
Select Case x
       Case "a", "A"
         hextobcd = hextobcd + 10 * (16 ^ i)
       Case "b", "B"
         hextobcd = hextobcd + 11 * (16 ^ i)
       Case "c", "C"
         hextobcd = hextobcd + 12 * (16 ^ i)
       Case "d", "D"
         hextobcd = hextobcd + 13 * (16 ^ i)
       Case "e", "E"
         hextobcd = hextobcd + 14 * (16 ^ i)
       Case "f", "F"
         hextobcd = hextobcd + 15 * (16 ^ i)
       Case "0" To "9"
         hextobcd = hextobcd + val(x) * 16 ^ i
       Case Else
       'MsgBox "非十六进制数", vbCritical, "信息提示"
       hextobcd = 0
End Select
Next i
End Function

Function hex2bit(var As Byte) As String
If var < 16 Then
   hex2bit = "0" & Hex(var)
 Else
   hex2bit = Hex(var)
End If
End Function

Public Function HexKeyAscii(KeyAscii As Integer) '屏蔽非十六进制位键值
  If KeyAscii > 96 And KeyAscii < 123 Then
     KeyAscii = KeyAscii - 32  '字母小写转成大写
  End If
  If KeyAscii > 70 And KeyAscii < 91 Or (KeyAscii >= 0 And KeyAscii <= 7) Or (KeyAscii >= 11 And KeyAscii <= 12) _
      Or (KeyAscii >= 14 And KeyAscii <= 47) Or (KeyAscii >= 58 And KeyAscii <= 64) Or (KeyAscii >= 91 And KeyAscii <= 96) _
     Or (KeyAscii >= 123 And KeyAscii <= 127) Then   '非有效进制值为0
     KeyAscii = 48
  End If
  HexKeyAscii = KeyAscii
End Function

Public Function SFR_ADDR(x As String) As Byte                   'SFR地址函数：根据TEXT3的内容返回其值
Select Case x
Case "P0"
SFR_ADDR = &H80
Case "SP"
SFR_ADDR = &H81
Case "DPL"
SFR_ADDR = &H82
Case "DPH"
SFR_ADDR = &H83
Case "PCON"
SFR_ADDR = &H87
Case "TCON"
SFR_ADDR = &H88
Case "TMOD"
SFR_ADDR = &H89
Case "TL0"
SFR_ADDR = &H8A
Case "TL1"
SFR_ADDR = &H8B
Case "TH0"
SFR_ADDR = &H8C
Case "TH1"
SFR_ADDR = &H8D
Case "P1"
SFR_ADDR = &H90
Case "SCON"
SFR_ADDR = &H98
Case "SBUF"
SFR_ADDR = &H99
Case "P2"
SFR_ADDR = &HA0
Case "IE"
SFR_ADDR = &HA8
Case "P3"
SFR_ADDR = &HB0
Case "IP"
SFR_ADDR = &HB8
Case "T2CON"
SFR_ADDR = &HC8
Case "PSW"
SFR_ADDR = &HD0
Case "ACC"
SFR_ADDR = &HE0
Case "B"
SFR_ADDR = &HF0
Case "TL2"
SFR_ADDR = &HCC
Case "TH2"
SFR_ADDR = &HCD
Case Else
SFR_ADDR = 0
End Select
End Function


