初始版本,接近数据不对

This commit is contained in:
jinggaoyang-68
2024-12-09 21:04:49 +08:00
commit 22786992f7
10 changed files with 1341 additions and 0 deletions

41
.gitignore vendored Normal file
View File

@ -0,0 +1,41 @@
# Python 编译产物和临时文件
*.pyc
__pycache__/
*.pyo
*.pyd
*.pyz
*.pyw
# virtualenv / venv / env
env/
venv/
.venv/
# pipenv
.venv
Pipfile.lock
# poetry
.venv
poetry.lock
# PyCharm
.idea/
*.iml
# Visual Studio Code
.vscode/
# 日志和临时文件
*.log
logs/
temp/
Log/
# macOS
.DS_Store
# Windows
Thumbs.db
det_images/*

155
cap_read.py Normal file
View File

@ -0,0 +1,155 @@
from enum import *
import threading
import queue # 导入 queue 模块
from class_ch341 import *
from class_sensorcmd import *
from class_finger import *
from collections import namedtuple
import socket
DEF_CDC_SYNC_MS = 1000 #电容同步间隔
DEF_GET_CAP_MS = (30) #读取电容间隔
DEF_PRO_CYC = 100
# 定义一个全局的队列,用于线程间通信
capReadQueue = queue.Queue()
# 341通信
class EnumCh341ConnectStatus(Enum):
CH341_CONNECT_INIT = 0
CH341_CONNECT_OPEN = 1
CH341_CONNECT_SET_SPEED = 2
CH341_CONNECT_SAMPLE_START = 3
CH341_CONNECT_CHECK = 4
CH341_CONNECT_SAMPLE_STOP = 5
class ClassCapRead:
def __init__(self):
self.ch341 = ClassCh341()
# 最大连接5个手指
self.fingers = list() # 传感器列表
for i in range(5):
self.fingers.append(ClassFinger(2+i, self.ch341))
self.currCh341State = 0 # 当前ch341连接状态
self.prevCh341State = 0 # 上次ch341连接状态
self.ch341CheckTimer = 0
self.mcuInit = 0
self.pcaAddr = 0x70 # iic控制芯片地址
self.ch341Init = 0 # ch341初始化标志位
self.syncTimer = 0
self.connectStatus = EnumCh341ConnectStatus.CH341_CONNECT_INIT
#连接到调试的服务器
self.vofaClient = socket.socket()
addr = ('127.0.0.1', 1347)
try:
self.vofaClient.connect(addr)
# client.send('hello world\r\n'.encode())
self.socketConnected = 1
print('连接服务器成功')
except Exception as e:
self.socketConnected = 0
print('连接服务器失败')
def __del__(self):
if self.vofaClient:
self.vofaClient.close()
self.ch341.disconnect()
print("ch341释放")
pass
def set_sensor_enable(self, idx):
_pack = list()
_pack.append(idx)
self.ch341.write(self.pcaAddr, _pack)
def ch341Connect(self):
if self.connectStatus == EnumCh341ConnectStatus.CH341_CONNECT_INIT:
if(True == self.ch341.init()):
self.connectStatus = EnumCh341ConnectStatus.CH341_CONNECT_OPEN
elif self.connectStatus == EnumCh341ConnectStatus.CH341_CONNECT_OPEN:
if(True == self.ch341.open()):
self.connectStatus = EnumCh341ConnectStatus.CH341_CONNECT_SET_SPEED
else:
self.connectStatus = EnumCh341ConnectStatus.CH341_CONNECT_INIT
elif self.connectStatus == EnumCh341ConnectStatus.CH341_CONNECT_SET_SPEED:
if(True == self.ch341.set_speed(self.ch341.IIC_SPEED_400)):
self.connectStatus = EnumCh341ConnectStatus.CH341_CONNECT_SAMPLE_START
else:
print("set speed err")
self.connectStatus = EnumCh341ConnectStatus.CH341_CONNECT_SAMPLE_START
elif self.connectStatus == EnumCh341ConnectStatus.CH341_CONNECT_SAMPLE_START:
self.connectStatus = EnumCh341ConnectStatus.CH341_CONNECT_CHECK
self.timer = threading.Timer(DEF_GET_CAP_MS/1000, self.capRead)
self.timer.start()
elif self.connectStatus == EnumCh341ConnectStatus.CH341_CONNECT_CHECK:
self.ch341CheckTimer += DEF_PRO_CYC
if(self.ch341CheckTimer >= 1000):
self.ch341CheckTimer = 0
if(False == self.ch341.connectCheck()):
print("ch341 拔出")
self.connectStatus = EnumCh341ConnectStatus.CH341_CONNECT_SAMPLE_STOP
elif self.connectStatus == EnumCh341ConnectStatus.CH341_CONNECT_SAMPLE_STOP:
self.syncTimer = 0
for i in range(0, len(self.fingers)):
self.fingers[i].disconnected()
self.connectStatus = EnumCh341ConnectStatus.CH341_CONNECT_INIT
else:
self.connectStatus = EnumCh341ConnectStatus.CH341_CONNECT_INIT
def capRead(self):
capReadTime = time.time()
ms_capReadTime = capReadTime
connectedSensorChan = 0
connectedSensorCnt = 0
for fingerIndex in range(0, len(self.fingers)):
self.set_sensor_enable(1 << (self.fingers[fingerIndex].pcaIdx))
connectedSensorChan |= 1 << (self.fingers[fingerIndex].pcaIdx)
if self.fingers[fingerIndex].connect == False:
if True == self.fingers[fingerIndex].checkSensor():
print(f"sensor[{fingerIndex}] connected")
else:
print(f"addr = {fingerIndex}, connected false")
else:
self.fingers[fingerIndex].capRead()
connectedSensorCnt += 1
# 大于1个传感器连接需要设置接近采集序列
if connectedSensorCnt > 1 and (time.time() - self.syncTimer) > DEF_CDC_SYNC_MS:
self.syncTimer = time.time()
self.set_sensor_enable(connectedSensorChan)
if self.connectStatus == EnumCh341ConnectStatus.CH341_CONNECT_CHECK:
capReadTime = time.time()
difftime = int(capReadTime*1000-ms_capReadTime*1000)
print(f"diffTime={difftime}")
#定时器在任务完成后重新启动
if(difftime>DEF_GET_CAP_MS):
timer = threading.Timer(DEF_GET_CAP_MS/1000, self.capRead)
else:
timer = threading.Timer((DEF_GET_CAP_MS-difftime)/1000, self.capRead)
timer.start()
def capReadThread():
# 线程的主体功能
cap = ClassCapRead()
while True:
cap.ch341Connect()
time.sleep(DEF_PRO_CYC/1000)
def main():
capReadThread()
if __name__ == "__main__":
main()

265
class_ch341.py Normal file
View File

@ -0,0 +1,265 @@
import time
import os
import sys
from ctypes import *
import ctypes
import glob
# ch341类iic读写int引脚读写速度设置
class ClassCh341:
# 接口固定宏
_mCH341A_CMD_I2C_STREAM = 0xAA # I2C接口的命令包,从次字节开始为I2C命令流
_mCH341A_CMD_I2C_STM_STA = 0x74 # I2C接口的命令流:产生起始位
_mCH341A_CMD_I2C_STM_STO = 0x75 # I2C接口的命令流:产生停止位
_mCH341A_CMD_I2C_STM_OUT = 0x80 # I2C接口的命令流:输出数据,位5-位0为长度,后续字节为数据,0长度则只发送一个字节并返回应答
_mCH341A_CMD_I2C_STM_IN = 0xC0 # I2C接口的命令流:输入数据,位5-位0为长度,0长度则只接收一个字节并发送无应答
_mCH341A_CMD_I2C_STM_MAX = 63 # I2C接口的命令流单个命令输入输出数据的最大长度
_mCH341A_CMD_I2C_STM_SET = 0x60 # I2C接口的命令流:设置参数,位2=SPI的I/O数(0=单入单出,1=双入双出),位1位0=I2C速度(00=低速,01=标准,10=快速,11=高速)
_mCH341A_CMD_I2C_STM_US = 0x40 # I2C接口的命令流:以微秒为单位延时,位3-位0为延时值
_mCH341A_CMD_I2C_STM_MS = 0x50 # I2C接口的命令流:以亳秒为单位延时,位3-位0为延时值
_mCH341A_CMD_I2C_STM_DLY = 0x0F # I2C接口的命令流单个命令延时的最大值
_mCH341A_CMD_I2C_STM_END = 0x00 # I2C接口的命令流:命令包提前结束
_mStateBitINT = 0x00000400
IIC_SPEED_20 = 0
IIC_SPEED_100 = 1
IIC_SPEED_400 = 2
IIC_SPEED_750 = 3
def __init__(self):
self.deviceID = ctypes.c_uint32()
pass
def init(self):
#print('ch341初始化')
addr = os.path.dirname(sys.argv[0]) + r'/lib/ch341/CH341DLLA64.DLL'
print(addr)
dllExist = os.path.exists(addr)
if not dllExist:
print('未找到库文件')
return False
else:
try:
self.ic = windll.LoadLibrary(addr) # ch341接口
print("ch341加载成功")
return True
except Exception as e:
print("ch341加载失败")
return False
def connectCheck(self):
if True == self.ic.CH341GetInput(self.fd, ctypes.byref(self.deviceID)):
return True
else:
return False
# 判断ch341是否插入
# return0未插入1插入
def open(self):
if os.name == 'nt': # Windows 环境
try:
self.fd = self.ic.CH341OpenDevice(0)
if self.fd == -1:
print("CH341 device open failed on Windows.")
return False
else:
print("CH341 device opened successfully on Windows.")
return True
except Exception as e:
print(f"Error occurred while opening CH341 device on Windows: {e}")
return False
elif os.name == 'posix': # Linux 环境
try:
devices = glob.glob('/dev/ch34x_pis*') # 动态查找设备
if devices:
device_path = devices[0].encode()
self.fd = self.ic.CH34xOpenDevice(device_path)
if self.fd == -1:
print("CH341 device open failed on Linux.")
return False
else:
print("CH341 device opened successfully on Linux.")
return True
else:
print("No CH341 device found on Linux.")
return False
except Exception as e:
print(f"Error occurred while opening CH341 device on Linux: {e}")
return False
else:
print("Unsupported operating system.")
return False
def open1(self):
# 查找匹配的设备路径
self.fd = self.ic.CH341OpenDevice(0)
if self.fd == -1:
print("ch341 open false")
return False
else:
print("ch341 open true")
return True
# devices = glob.glob('/dev/ch34x_pis*')
# if devices:
# device_path = devices[0].encode() # 选择第一个找到的设备路径
# self.fd = self.ic.CH34xOpenDevice(device_path)#.encode()"/dev/ch34x_pis1".encode()
# if self.fd == -1:
# print("ch341 open false")
# return False
# else:
# print("ch341 open true")
# return True
# else:
# print("No CH34x device found.")
# return False
def disconnect(self):
self.ic.CH341CloseDevice(0)
# iic写数据
# addr:iic从机地址
# data要写的数据列表
# return写入长度不一定正确
def write(self, addr, data):
sLen = len(data)
tmpData = [] # 临时列表
tmpLen = sLen # 发送数据
pack = [] # 发送列表
cnt = 20 # 每包数量
packNum = sLen // cnt # 拆包数量
sLen %= cnt # 不足字节数
tmpData.extend(data)
pack.append(self._mCH341A_CMD_I2C_STREAM)
pack.append(self._mCH341A_CMD_I2C_STM_STA)
pack.append(self._mCH341A_CMD_I2C_STM_OUT | 1)
pack.append(addr << 1)
for i in range(0, packNum):
pack.append(self._mCH341A_CMD_I2C_STM_OUT | cnt)
pack.extend(tmpData[0:20])
del tmpData[0:20]
pack.append(self._mCH341A_CMD_I2C_STM_END)
sendBuf = (c_byte * len(pack))()
for j in range(0, len(pack)):
sendBuf[j] = pack[j]
sendLen = (c_byte * 1)()
sendLen[0] = len(pack)
if not self.ic.CH341WriteData(0, sendBuf, sendLen):
return 0
if sendLen == 0:
return 0
pack.clear()
pack.append(self._mCH341A_CMD_I2C_STREAM)
if sLen >= 1:
pack.append(self._mCH341A_CMD_I2C_STM_OUT | sLen)
pack.extend(tmpData[0:sLen])
pack.append(self._mCH341A_CMD_I2C_STM_STO)
pack.append(self._mCH341A_CMD_I2C_STM_END)
sendBuf = (c_byte * len(pack))()
for j in range(0, len(pack)):
sendBuf[j] = pack[j]
sendLen = (c_byte * 1)()
sendLen[0] = len(pack)
if not self.ic.CH341WriteData(0, sendBuf, sendLen):
return 0
if sendLen == 0:
return 0
return tmpLen
# iic读数据
# addriic从机地址
# data读取数据列表。根据列表大小确定读取长度
# return读取长度不一定正确
def read(self, addr, data):
if id(data) == 0 or len(data) == 0:
return 0
rLen = len(data)
#print(f"rLen={rLen}")
pack = []
readBuf = []
readLen = 0
packNum = rLen // 30
rLen %= 30
if rLen == 0:
rLen = 30
packNum -= 1
#print(f"packNum={packNum}")
pack.append(self._mCH341A_CMD_I2C_STREAM)
pack.append(self._mCH341A_CMD_I2C_STM_STA)
pack.append(self._mCH341A_CMD_I2C_STM_OUT | 1)
pack.append((addr << 1) | 0x01)
pack.append(self._mCH341A_CMD_I2C_STM_MS | 1)
for i in range(0, packNum):
pack.append(self._mCH341A_CMD_I2C_STM_IN | 30)
pack.append(self._mCH341A_CMD_I2C_STM_END)
sendBuf = (c_byte * len(pack))()
for j in range(0, len(pack)):
sendBuf[j] = pack[j]
recLen = (c_byte * 1)()
recBuf = (c_byte * self._mCH341A_CMD_I2C_STM_MAX)()
if not self.ic.CH341WriteRead(0, len(pack), sendBuf, self._mCH341A_CMD_I2C_STM_MAX, 1, recLen, recBuf):
return 0
if recLen == 0:
return 0
for j in range(0, recLen[0]):
readBuf.append(recBuf[j])
readLen += 30
pack.clear()
pack.append(self._mCH341A_CMD_I2C_STREAM)
if rLen > 1:
pack.append(self._mCH341A_CMD_I2C_STM_IN | (rLen - 1))
pack.append(self._mCH341A_CMD_I2C_STM_IN | 0)
pack.append(self._mCH341A_CMD_I2C_STM_STO)
pack.append(self._mCH341A_CMD_I2C_STM_END)
sendBuf = (c_byte * len(pack))()
for j in range(0, len(pack)):
sendBuf[j] = pack[j]
recLen = (c_byte * 1)()
recBuf = (c_byte * self._mCH341A_CMD_I2C_STM_MAX)()
if not self.ic.CH341WriteRead(0, len(pack), sendBuf, self._mCH341A_CMD_I2C_STM_MAX, 1, recLen, recBuf):
return 0
if recLen[0] == 0:
return 0
for j in range(0, recLen[0]):
readBuf.append(recBuf[j])
data.clear()
data.extend(readBuf)
readLen = len(pack)
#print(f"readLen={len(readBuf)}")
return readLen
# 设置int引脚状态
# lvl高低电平。1高电平0低电平
def set_int(self, lvl):
status = (c_long * 1)()
self.ic.CH341GetInput(0, status)
time.sleep(0.01)
if lvl:
self.ic.CH341SetOutput(0, 0x03, 0xFF00, status[0] | self._mStateBitINT)
else:
self.ic.CH341SetOutput(0, 0x03, 0xFF00, status[0] & (~self._mStateBitINT))
# 读取int引脚状态
# 返回:高低电平
def get_int(self):
status = (c_long * 1)()
self.ic.CH341GetInput(0, status)
return (status[0] & self._mStateBitINT) >> 10
# 设置IIC速度
# return0错误1成功
def set_speed(self, speed):
if speed != self.IIC_SPEED_20 and speed != self.IIC_SPEED_100 and speed != self.IIC_SPEED_400 and speed != self.IIC_SPEED_750:
return False
if False == self.ic.CH341SetStream(0, speed | 0):
print("speed err")
return False
else:
return True

160
class_finger.py Normal file
View File

@ -0,0 +1,160 @@
from class_sensorcmd import *
from sensorPara import *
import struct
# 电容数据存储结构
class capData:
def __init__(self):
self.sensorIndex = 0 # 电容序号与iic addr相同
self.channelCapData = list() # 原始通道数值
self.tf = list() # 切向力数组
self.tfDir = list() # 切向力方向数组
self.nf = list() # 法向力数组
self.sProxCapData = list() # 接近(自电容)数组
self.mProxCapData = list() # 接近(互电容)数组
self.cnt = 0 # 计数,测试用
def init(self, addr, yddsNum, sProxNum, mProxNum, capChannelNum):
self.sensorIndex = addr # 电容序号与iic addr相同
self.channelCapData = list(range(capChannelNum))# 原始通道数值
self.tf = list(range(yddsNum)) # 切向力数组
self.tfDir = list(range(yddsNum)) # 切向力方向数组
self.nf = list(range(yddsNum)) # 法向力数组
self.sProxCapData = list(range(sProxNum)) # 接近(自电容)数组
self.mProxCapData = list(range(mProxNum)) # 接近(互电容)数组
self.cnt = 0 # 计数,测试用
def deinit(self):
self.channelCapData = None
self.tf = None
self.tfDir = None
self.nf = None
self.sProxCapData = None
self.mProxCapData = None
# 传感器类:包换传感器相关参数
class ClassFinger:
def __init__(self, pca_idx, ch341):
self.snsCmd = ClassSensorCmd(ch341)
self.pcaIdx = pca_idx # iic使能芯片序号从2开始
self.readData = capData()
self.disconnected()
# 检查传感器是否连接,如果读写地址正确则认为连接正常
def checkSensor(self):
# 广播的方式读取当前传感器地址并默认将iic地址配置为和pca相同的地址
addrRead = self.snsCmd.getAddr(0)
if addrRead != self.pcaIdx:
if self.pcaIdx != self.snsCmd.setAddr(addrRead, self.pcaIdx):
print(f"set addr false, setaddr={self.pcaIdx}")
return False
else:
addrRead = self.pcaIdx
print(f"update iic addr, new addr ={addrRead}")
# 设置发送数据类型为原始值
if True != self.snsCmd.setSensorSendType(addrRead, 0):
print(f"setSensorSendType err, addr = {addrRead}")
# 设置电容采集序列,这里按照地址来分配采集时序,只要每个传感器不同即可
if self.snsCmd.setSensorCapOffset(addrRead, addrRead) != True:
print(f"setSensorCapOffset err, addr = {addrRead}")
# 实际用户使用中只需要根据使用的传感器来定义参数即可,不需要读取项目号
projectRead = self.snsCmd.getSensorProjectIdex(self.addr)
print(f"project={projectRead}")
findProjectFlg = False
if projectRead > 0:
for pro in finger_params:
if pro.prg == projectRead:
self.projectPara = pro
print(f"finger connected, project = {self.projectPara.name}")
findProjectFlg = True
if findProjectFlg == False:
print("not found vailed project, project para use default")
self.connected(addrRead)
return True
# 传感器连接,初始化参数
def connected(self, addr):
self.addr = addr
self.connect = True
self.connectTimer = time.time()
self.packIdx = 0
self.data = list()
self.data.extend(range(self.projectPara.pack_len))#
self.readData.init(addr, self.projectPara.ydds_num, self.projectPara.s_prox_num, self.projectPara.m_prox_num, self.projectPara.sensor_num)
#print(f"datalen={len(self.data)}")
# 传感器断开,复位参数
def disconnected(self):
self.addr = 0xFF # iic地址
self.connect = False # 连接标志位
self.packIdx = 0 # 采样序号
self.connectTimer = 0 # 连接超时计时
self.projectPara = finger_params[0]
self.readData.deinit()
def capRead(self):
for retry in range(0, 3):
if self.snsCmd.getSensorCapData(self.addr, self.data) == True:
if self.data[5] != self.projectPara.sensor_num:
print(f"cap channel num err, read num = {self.data[5]}, expect num = {self.projectPara.sensor_num}")
if self.data[4] != self.packIdx:
self.packIdx = self.data[4]
self.connectTimer = time.time()
# 根据通道值占用字节大小获取通道数据
if self.projectPara.cap_byte == 4:
for j in range(0, self.projectPara.sensor_num):
self.readData.channelCapData[j] = ((self.data[6 + j * self.projectPara.cap_byte] & 0xFF) +
((self.data[6 + j * self.projectPara.cap_byte + 1] & 0xFF) << 8) +
((self.data[6 + j * self.projectPara.cap_byte + 2] & 0xFF) << 16) +
((self.data[6 + j * 4 + 3] & 0xFF) << 24))
else:
for j in range(0, self.projectPara.sensor_num):
self.readData.channelCapData[j] = ((self.data[6 + j * self.projectPara.cap_byte] & 0xFF) +
((self.data[6 + j * self.projectPara.cap_byte + 1] & 0xFF) << 8) +
((self.data[6 + j * self.projectPara.cap_byte + 2] & 0xFF) << 16))
yddsOffset = 6 + self.projectPara.sensor_num*self.projectPara.cap_byte
if self.projectPara.ydds_type == 2:
struct_size = sizeof(DynamicYddsComTs)
for i in range(self.projectPara.ydds_num):
offset = yddsOffset + i * struct_size
struct_data = self.data[offset : offset + struct_size]
struct_data = [value & 0xFF for value in struct_data]
struct_data = bytes(struct_data) # 转换为 bytes 类型
instance = DynamicYddsComTs.from_buffer_copy(struct_data)
self.readData.nf[i] = instance.nf
self.readData.tf[i] = instance.tf
self.readData.tfDir[i] = instance.tfDir
self.readData.sProxCapData[i] = instance.prox
elif self.projectPara.ydds_type == 4:
pass
print(f"capChannelDat={self.readData.channelCapData}")
for i in range(self.projectPara.ydds_num):
print(f"nf[{i}] = {self.readData.nf[i]}")
print(f"tf[{i}] = {self.readData.tf[i]}")
print(f"tfDir[{i}] = {self.readData.tfDir[i]}")
print(f"sProxCapData[{i}] = {self.readData.sProxCapData[i]}")
break
else:
pass
# 2S未接收到数据超时
if (time.time() - self.connectTimer) > 2:
self.disconnected()

255
class_sensorcmd.py Normal file
View File

@ -0,0 +1,255 @@
import time
from class_ch341 import *
from enum import *
class ClassSensorCmd:
def __init__(self, ch341):
# 命令定义
self.CMD_GET_CHANNEL_NUM = 0x01 # 读取通道数量
self.CMD_GET_SENSOR_CAP_DATA = 0x60 # 读取传感器数据
self.CMD_SET_SENSOR_UART_SEND_TYPE = 0x61 # 设置串口输出模式
self.CMD_GET_SENSOR_CHANNEL = 0x62 # 读取通道数量
self.CMD_SET_SENSOR_AUTO_DAC = 0x63 # 自动dac
self.CMD_GET_SENSOR_ERR_CODE = 0x64 # 读取错误码
self.CMD_SET_SENSOR_CHANNEL_CALIBRATE = 0x65 # 设置通道重量标定
self.CMD_GET_SENSOR_CHANNEL_CALIBRATE = 0x66 # 读取通道重量标定
self.CMD_SET_SENSOR_AUTO_THRESHOLD = 0x67 # 设置自动阈值
self.CMD_GET_SENSOR_THRESHOLD = 0x68 # 读取自动阈值
self.CMD_SET_SENSOR_THRESHOLD = 0x69 # 设置通道阈值
self.CMD_SET_SENSOR_TOUCH_THRESHOLD = 0x6A # 设置压力阈值
self.CMD_SET_SENSOR_CHANNEL_CALIBRATE_QUICK = 0x6B # 最大力快速标定
self.CMD_GET_SENSOR_TEST_HZ = 0x6C # 读取采样率
self.CMD_GET_SENSOR_CALI_N_LIST = 0x6D # 读取标定列表
self.CMD_SET_SENSOR_CHANNEL_GROUP_CALIBRATE = 0x6E # 设置通道组重量标定
self.CMD_SET_SENSOR_IIC_ADDR = 0x70 # 设置传感器IIC地址
self.CMD_GET_SENSOR_IIC_ADDR = 0x71 # 读取传感器IIC地址
self.CMD_SET_SENSOR_CDC_SYNC = 0x72 # 采集停止,用于同步
self.CMD_SET_SENSOR_CDC_START_OFFSET = 0x73 # 设置电容开始偏移
self.CMD_GET_SENSOR_TEMP = 0x74 # 读取温度
self.CMD_SET_SENSOR_CDC_CFG_SAVE = 0x75 # 保存cdc配置
self.CMD_SET_SENSOR_FACTOR = 0x76 # 恢复出厂设置
self.CMD_SET_SENSOR_RESTART = 0x77 # 软件复位
self.CMD_SET_SENSOR_WEIGHT_CALIBRATE = 0x78 # 设置重量标定参数
self.CMD_SET_SENSOR_BASE_RESET = 0x79 # 基线复位
self.CMD_SET_SENSOR_UNIFORMIZATION = 0x7A # 归一化
self.CMD_SET_SENSOR_CHANNEL_ENABLE = 0x7B # 通道使能
self.CMD_SET_SENSOR_CHANNEL_BASE_RESET = 0x7C # 单独通道复位
self.CMD_GET_SENSOR_WEIGHT_CALIBRATE = 0x7D # 读取重量标定参数
self.CMD_GET_SENSOR_CHANNEL_STATE = 0x7E # 读取电容通道状态
self.CMD_SET_SENSOR_SEND_TYPE = 0x7F # 数据传输类型
self.CMD_GET_VERSION = 0xA0 # 读取软件版本
self.CMD_SOFT_RESTART = 0xA1 # 软件复位
self.CMD_GET_TYPE = 0xA2 # 读取设备类型
self.CMD_SET_TYPE = 0xA3 # 设置设备类型
self.CMD_SET_INF = 0xA5 # 设置输出接口
self.CMD_GET_PRG = 0xA6 # 获取项目类型
self._ch341 = ch341
self.sendTimePre = list()
self.sendTimePre.append(time.time())
self.sendTimePre.append(time.time())
self.sendTimeNow = list()
self.sendTimeNow.append(time.time())
self.sendTimeNow.append(time.time())
self.sendCnt = list()
self.sendCnt.append(0)
self.sendCnt.append(0)
# 计算校验和
# pack 数据
def calcSum(self, pack):
if len(pack) <= 5:
return 0
_sum = 0
for i in range(0, len(pack)):
_sum += (pack[i] & 0xFF)
pack.append(_sum & 0xFF)
pack.append(_sum >> 8)
# 检查校验值
# pack要检查的数据
# return 0校验值不一致
# 1:校验值一致
def checkSum(self, pack):
if len(pack) <= 5:
return False
_sum = 0
for i in range(0, len(pack) - 2):
_sum += (pack[i] & 0xFF)
chkL = _sum & 0xFF
chkH = (_sum >> 8) & 0xFF
rchkL = pack[len(pack) - 2] & 0xFF
rchkH = pack[len(pack) - 1] & 0xFF
if chkL == rchkL and chkH == rchkH:
return True
else:
return False
# 设置传感器iic地址
# addr当前地址
# new_addr系地址
# return读取的地址
def setAddr(self, addr, new_addr):
_pack = list()
_pack.append(0xAA)
_pack.append(0x55)
_pack.append(0x03)
_pack.append(self.CMD_SET_SENSOR_IIC_ADDR)
_pack.append(0x00)
_pack.append(0x00)
_pack.append(0x00)
_pack.append(new_addr)
_pack.append(0x00)
self.calcSum(_pack)
self._ch341.write(addr, _pack)
_pack.clear()
_pack.extend(list(range(11)))
time.sleep(0.01)
self._ch341.read(new_addr, _pack)
checksum = self.checkSum(_pack)
if checksum == True and ((self.CMD_SET_SENSOR_IIC_ADDR|0x80) == c_uint8(_pack[3]).value):
return _pack[7] & 0xFF
return 0
def getAddr(self, addr):
_pack = list()
_pack.append(0xAA)
_pack.append(0x55)
_pack.append(0x03)
_pack.append(self.CMD_GET_SENSOR_IIC_ADDR)
_pack.append(0x00)
_pack.append(0x00)
_pack.append(0x00)
_pack.append(0x00)
_pack.append(0x00)
self.calcSum(_pack)
self._ch341.write(addr, _pack)
_pack.clear()
_pack.extend(list(range(11)))
time.sleep(0.01)
self._ch341.read(addr, _pack)
if self.checkSum(_pack) == True:
return _pack[7] & 0xFF
return 0
def getSensorVersion(self, addr):
pass
# 读取电容通道数
# addr传感器地址
def getSensorNum(self, addr):
_pack = list()
_pack.append(0xAA)
_pack.append(0x55)
_pack.append(0x03)
_pack.append(self.CMD_GET_CHANNEL_NUM)
_pack.append(0x00)
_pack.append(0x00)
_pack.append(0x00)
_pack.append(0x00)
_pack.append(0x00)
self.calcSum(_pack)
self._ch341.write(addr, _pack)
_pack.clear()
_pack.extend(list(range(15)))
time.sleep(0.01)
self._ch341.read(addr, _pack)
if self.checkSum(_pack) == True:
return (_pack[5] & 0xFF) + (_pack[6] & 0xFF) * 256
return 0
# 读取项目编号
# addr传感器地址
def getSensorProjectIdex(self, addr):
_pack = list()
_pack.append(0xAA)
_pack.append(0x55)
_pack.append(0x03)
_pack.append(self.CMD_GET_PRG)
_pack.append(0x00)
_pack.append(0x00)
_pack.append(0x00)
_pack.append(0x00)
_pack.append(0x00)
self.calcSum(_pack)
self._ch341.write(addr, _pack)
_pack.clear()
_pack.extend(list(range(11)))
time.sleep(0.01)
self._ch341.read(addr, _pack)
if self.checkSum(_pack) == True:
return (_pack[7] & 0xFF) + (_pack[8] & 0xFF) * 256
return 0
# 设置发送类型
# addr传感器地址
def setSensorSendType(self, addr, sendType):
_pack = list()
_pack.append(0xAA)
_pack.append(0x55)
_pack.append(0x03)
_pack.append(self.CMD_SET_SENSOR_SEND_TYPE)
_pack.append(0x00)
_pack.append(0x00)
_pack.append(0x00)
_pack.append(sendType)
_pack.append(0x00)
self.calcSum(_pack)
self._ch341.write(addr, _pack)
_pack.clear()
_pack.extend(list(range(11)))
time.sleep(0.01)
self._ch341.read(addr, _pack)
if (self.checkSum(_pack) == True) and ((self.CMD_SET_SENSOR_SEND_TYPE|0x80) == c_uint8(_pack[3]).value):
return True
return False
# 设置采集偏置
# addr传感器地址
def setSensorCapOffset(self, addr, offset):
_pack = list()
_pack.append(0xAA)
_pack.append(0x55)
_pack.append(0x03)
_pack.append(self.CMD_SET_SENSOR_CDC_START_OFFSET)
_pack.append(0x00)
_pack.append(0x00)
_pack.append(0x00)
_pack.append(offset)
_pack.append(0x00)
self.calcSum(_pack)
self._ch341.write(addr, _pack)
_pack.clear()
_pack.extend(list(range(6)))
time.sleep(0.01)
self._ch341.read(addr, _pack)
checksum = self.checkSum(_pack)
if (checksum == True) and ((self.CMD_SET_SENSOR_CDC_START_OFFSET|0x80) == c_uint8(_pack[3]).value):
return True
return False
# 读取电容数据
# addr传感器地址
def getSensorCapData(self, addr, buf):
tarLen = len(buf)
err = self._ch341.read(addr, buf)
if(err == 0):
print("get data err")
checkSum = self.checkSum(buf)
if(tarLen != len(buf)):
buf.clear()
buf.extend(range(tarLen))
# try:
if (len(buf) == tarLen and buf[0] & 0xFF) == 0x55 and (buf[1] & 0xFF) == 0xAA and checkSum == True:
return True
else:
#print(f"time={time.time()},len(buf) = {len(buf)}, tarLen={tarLen}, buf[0]={buf[0]}, buf[1]={buf[1]}, sum={checkSum}")
pass
return False

BIN
lib/ch341/CH341DLLA64.DLL Normal file

Binary file not shown.

BIN
lib/ch341/CH341DLLA64.LIB Normal file

Binary file not shown.

399
lib/ch341/ch341_lib.h Normal file
View File

@ -0,0 +1,399 @@
#ifndef _CH341_LIB_H
#define _CH341_LIB_H
typedef enum _EEPROM_TYPE {
ID_24C01,
ID_24C02,
ID_24C04,
ID_24C08,
ID_24C16,
ID_24C32,
ID_24C64,
ID_24C128,
ID_24C256,
ID_24C512,
ID_24C1024,
ID_24C2048,
ID_24C4096
} EEPROM_TYPE;
typedef enum _CHIP_TYPE {
CHIP_CH341 = 0,
CHIP_CH347T = 1,
CHIP_CH347F = 2,
} CHIP_TYPE;
typedef enum {
TYPE_TTY = 0,
TYPE_HID,
TYPE_VCP,
} FUNCTYPE;
#ifdef __cplusplus
extern "C" {
#endif
/**
* CH34XOpenDevice - open device
* @pathname: device path in /dev directory
*
* The function return positive file descriptor if successful, others if fail.
*/
extern int CH34xOpenDevice(const char *pathname);
/**
* CH34XCloseDevice - close device
* @fd: file descriptor of device
*
* The function return true if successful, false if fail.
*/
extern bool CH34xCloseDevice(int fd);
/**
* CH34x_GetDriverVersion - get vendor driver version
* @fd: file descriptor of device
* @Drv_Version: pointer to version string
*
* The function return true if successful, false if fail.
*/
extern bool CH34x_GetDriverVersion(int fd, unsigned char *Drv_Version);
/**
* CH34x_GetChipVersion - get chip version
* @fd: file descriptor of device
* @Version: pointer to version
*
* The function return true if successful, false if fail.
*/
extern bool CH34x_GetChipVersion(int fd, unsigned char *Version);
/**
* CH34x_GetChipType - get chip type
* @fd: file descriptor of device
* @ChipType: pointer to chip type
*
* The function return true if successful, false if fail.
*/
extern bool CH34x_GetChipType(int fd, CHIP_TYPE *ChipType);
/**
* CH34X_GetDeviceID - get device vid and pid
* @fd: file descriptor of device
* @id: pointer to store id which contains vid and pid
*
* The function return true if successful, false if fail.
*/
extern bool CH34X_GetDeviceID(int fd, uint32_t *id);
/**
* CH34xSetParaMode - set chip parrallel work mode
* @fd: file descriptor of device
* @Mode: work mode, 0/1->EPP mode, 2->MEM mode
*
* The function return true if successful, false if fail.
*/
extern bool CH34xSetParaMode(int fd, uint8_t Mode);
/**
* CH34xInitParallel - initial chip parrallel work mode
* @fd: file descriptor of device
* @Mode: work mode, 0/1->EPP mode, 2->MEM mode
*
* The function return true if successful, false if fail.
*/
extern bool CH34xInitParallel(int fd, uint8_t Mode);
/**
* CH34xEppRead - read data or addr in parrallel EPP mode
* @fd: file descriptor of device
* @oBuffer: pointer to read buffer
* @ioLength: read length
* @PipeMode: 0->read pipe0 data, 1->read pipe1 addr
*
* The function return read 0 if successful, others if fail.
*/
extern int CH34xEppRead(int fd, uint8_t *oBuffer, uint32_t ioLength, uint8_t PipeMode);
/**
* CH34xEppWrite - write data or addr in parrallel EPP mode
* @fd: file descriptor of device
* @iBuffer: pointer to write buffer
* @ioLength: write length
* @PipeMode: 0->write pipe0 data, 1->write pipe1 addr
*
* The function return 0 if successful, others if fail.
*/
extern int CH34xEppWrite(int fd, uint8_t *iBuffer, uint32_t ioLength, uint8_t PipeMode);
/**
* CH34xEppWriteData - write data in parrallel EPP mode
* @fd: file descriptor of device
* @iBuffer: pointer to write buffer
* @ioLength: write length
*
* The function return 0 if successful, others if fail.
*/
extern int CH34xEppWriteData(int fd, uint8_t *iBuffer, uint32_t ioLength);
/**
* CH34xEppReadData - read data in parrallel EPP mode
* @fd: file descriptor of device
* @oBuffer: pointer to read buffer
* @ioLength: read length
*
* The function return 0 if successful, others if fail.
*/
extern int CH34xEppReadData(int fd, uint8_t *oBuffer, uint32_t ioLength);
/**
* CH34xEppWriteAddr - write addr in parrallel EPP mode
* @fd: file descriptor of device
* @iBuffer: pointer to write buffer
* @ioLength: write length
*
* The function return 0 if successful, others if fail.
*/
extern int CH34xEppWriteAddr(int fd, uint8_t *iBuffer, uint32_t ioLength);
/**
* CH34xEppReadAddr - read addr in parrallel EPP mode
* @fd: file descriptor of device
* @oBuffer: pointer to read buffer
* @ioLength: read length
*
* The function return 0 if successful, others if fail.
*/
extern int CH34xEppReadAddr(int fd, uint8_t *oBuffer, uint32_t ioLength);
/**
* CH34xEppSetAddr - set addr in parrallel EPP mode
* @fd: file descriptor of device
* @iAddr: addr data
*
* The function return 0 if successful, others if fail.
*/
extern int CH34xEppSetAddr(int fd, uint32_t iAddr);
/**
* CH34xSetTimeout - set USB data read and write timeout
* @fd: file descriptor of device
* @iWriteTimeout: data download timeout in milliseconds
* @iReadTimeout: data upload timeout in milliseconds
*
* The function return true if successful, false if fail.
*/
extern bool CH34xSetTimeout(int fd, uint32_t iWriteTimeout, uint32_t iReadTimeout);
/**
* CH34xInitMEM - initial chip in parrallel MEM mode
* @fd: file descriptor of device
*
* The function return true if successful, false if fail.
*/
extern bool CH34xInitMEM(int fd);
/**
* CH34xMEMReadData - read data in parrallel MEM mode
* @fd: file descriptor of device
* @oBuffer: pointer to read buffer
* @ioLength: read length
* @PipeMode: 0->read pipe0, 1->read pipe1
*
* The function return 0 if successful, others if fail.
*/
extern int CH34xMEMReadData(int fd, uint8_t *oBuffer, uint32_t ioLength, uint8_t PipeMode);
/**
* CH34xMEMWriteData - write data in parrallel MEM mode
* @fd: file descriptor of device
* @iBuffer: pointer to write buffer
* @ioLength: write length
* @PipeMode: 0->write pipe0, 1->write pipe1
*
* The function return 0 if successful, others if fail.
*/
extern int CH34xMEMWriteData(int fd, uint8_t *iBuffer, uint32_t ioLength, uint32_t PipeMode);
/**
* CH34xSetStream - configure spi/i2c interface in stream mode
* @fd: file descriptor of device
* @Mode: stream mode
* ->bit0~1: set I2C SCL rate
* --> 00 : low rate 20KHz
* --> 01 : standard rate 100KHz
* --> 10 : fast rate 400KHz
* --> 11 : high rate 750KHz
* ->bit2: set spi mode
* --> 0 : one in one out(D3: clk, D5: out, D7: in)
* --> 1 : two in two out(D3 :clk, D4/D5: out, D6/D7 :in)
* ->bit7: set spi data mode
* --> 0 : low bit first
* --> 1 : high bit first
* other bits must keep 0
*
* The function return true if successful, false if fail.
*/
extern bool CH34xSetStream(int fd, uint8_t Mode);
/**
* CH34xSetDelaymS - delay operation
* @fd: file descriptor of device
* @iDelay: delay time in millseconds
*
* The function return true if successful, false if fail.
*/
extern bool CH34xSetDelaymS(int fd, uint32_t iDelay);
/**
* CH34xReadData - read for spi/i2c operation
* @fd: file descriptor of device
* @oReadBuffer: pointer to read buffer
* @oReadLength: pointer to read length
*
* The function return true if successful, false if fail.
*/
extern bool CH34xReadData(int fd, void *oReadBuffer, uint32_t *oReadLength);
/**
* CH34xWriteData - write data for spi/i2c operation
* @fd: file descriptor of device
* @iWriteBuffer: pointer to write buffer
* @iWriteLength: pointer to write length
*
* The function return true if successful, false if fail.
*/
extern bool CH34xWriteData(int fd, void *iWriteBuffer, uint32_t *iWriteLength);
/**
* CH34xWriteRead - write data then read for spi/i2c operation
* @fd: file descriptor of device
* @iWriteLength: write length
* @iWriteBuffer: pointer to write buffer
* @iReadStep: per read length
* @iReadTimes: read times
* @oReadLength: pointer to read length
* @oReadBuffer: pointer to read buffer
*
* The function return true if successful, false if fail.
*/
extern bool CH34xWriteRead(int fd, uint32_t iWriteLength, void *iWriteBuffer, uint32_t iReadStep, uint32_t iReadTimes,
uint32_t *oReadLength, void *oReadBuffer);
/**
* CH34xGetInput - get io status of CH341
* @fd: file descriptor of device
* @iStatus: pointer to io status
* Note:
* Bit7~Bit0<==>D7-D0, Bit8<==>ERR#, Bit9<==>PEMP, Bit10<==>INT#
* Bit11<==>SLCT, Bit13<==>WAIT#, Bit14<==>DATAS#/READ#, Bit15<==>ADDRS#/ADDR/ALE, Bit23<==>SDA
*
* The function return true if successful, false if fail.
*/
extern bool CH34xGetInput(int fd, uint32_t *iStatus);
/**
* CH34xSetOutput - set direction and output data of CH341
* @fd: file descriptor of device
* @iEnable: set direction and data enable
* --> Bit16 High : effect on Bit15~8 of iSetDataOut
* --> Bit17 High : effect on Bit15~8 of iSetDirOut
* --> Bit18 High : effect on Bit7~0 of iSetDataOut
* --> Bit19 High : effect on Bit7~0 of iSetDirOut
* --> Bit20 High : effect on Bit23~16 of iSetDataOut
* @iSetDirOut: set io direction
* -- > Bit High : Output
* -- > Bit Low : Input
* @iSetDataOut: set io data
* Output:
* -- > Bit High : High level
* -- > Bit Low : Low level
* Note:
* Bit7~Bit0<==>D7-D0, Bit8<==>ERR#, Bit9<==>PEMP, Bit10<==>INT#
* Bit11<==>SLCT, Bit13<==>WAIT#, Bit14<==>DATAS#/READ#, Bit15<==>ADDRS#/ADDR/ALE
*
* The pins below can only be used in output mode:
* Bit16<==>RESET#, Bit17<==>WRITE#, Bit18<==>SCL, Bit29<==>SDA
*
* The function return true if successful, false if fail.
*/
extern bool CH34xSetOutput(int fd, uint32_t iEnable, uint32_t iSetDirOut, uint32_t iSetDataOut);
/**
* CH34xSet_D5_D0 - set direction and output data of D5-D0 on CH341
* @fd: file descriptor of device
* @iSetDirOut: set io direction
* -- > Bit High : Output
* -- > Bit Low : Input
* @iSetDataOut: set io data
* Output:
* -- > Bit High : High level
* -- > Bit Low : Low level
*
* The function return true if successful, false if fail.
*/
extern bool CH34xSet_D5_D0(int fd, uint8_t iSetDirOut, uint8_t iSetDataOut);
/**
* CH34xStreamI2C - write/read i2c in stream mode
* @fd: file descriptor of device
* @iWriteLength: write length
* @iWriteBuffer: pointer to write buffer
* @iReadLength: read length
* @oReadBuffer: pointer to read buffer
*
* The function return true if successful, false if fail.
*/
extern bool CH34xStreamI2C(int fd, uint32_t iWriteLength, void *iWriteBuffer, uint32_t iReadLength, void *oReadBuffer);
/**
* CH34xReadEEPROM - read data from eeprom
* @fd: file descriptor of device
* @iEepromID: eeprom type
* @iAddr: address of eeprom
* @iLength: read length
* @oBuffer: pointer to read buffer
*
* The function return true if successful, false if fail.
*/
extern bool CH34xReadEEPROM(int fd, EEPROM_TYPE iEepromID, uint32_t iAddr, uint32_t iLength, uint8_t *oBuffer);
/**
* CH34xWriteEEPROM - write data to eeprom
* @fd: file descriptor of device
* @iEepromID: eeprom type
* @iAddr: address of eeprom
* @iLength: write length
* @iBuffer: pointer to write buffer
*
* The function return true if successful, false if fail.
*/
extern bool CH34xWriteEEPROM(int fd, EEPROM_TYPE iEepromID, uint32_t iAddr, uint32_t iLength, uint8_t *iBuffer);
/**
* CH34xStreamSPIx - write/read spi in stream mode
* @fd: file descriptor of device
* @iChipSelect: cs enable
* @iLength: the length of data
* @ioBuffer: one in one out buffer
* @ioBuffer2: two in two out buffer
*
* The function return true if successful, false if fail.
*/
extern bool CH34xStreamSPIx(int fd, uint32_t iChipSelect, uint32_t iLength, void *ioBuffer, void *ioBuffer2);
/**
* CH34xStreamSPI4 - write/read spi in 4-line stream mode
* @fd: file descriptor of device
* @iChipSelect: cs enable
* @iLength: the length of data
* @ioBuffer: one in one out buffer
*
* The function return true if successful, false if fail.
*/
extern bool CH34xStreamSPI4(int fd, uint32_t iChipSelect, uint32_t iLength, void *ioBuffer);
#ifdef __cplusplus
}
#endif
#endif

BIN
lib/ch341/libch347.so Normal file

Binary file not shown.

66
sensorPara.py Normal file
View File

@ -0,0 +1,66 @@
from typing import List, Optional
from ctypes import Structure, sizeof, c_float, c_uint32, c_uint16
class DynamicYddsComTs(Structure):
_fields_ = [
("nf", c_float),
("nfCap", c_uint32),
("tf", c_float),
("tfCap", c_uint32),
("tfDir", c_uint16),
("prox", c_uint32),
]
#todo 其他三维力类型待补充
class FingerHeatMap:
def __init__(self, rows: int, cols: int, file_path: str, cap_count: int, cap_indices: List[int]):
self.rows = rows
self.cols = cols
self.file_path = file_path
self.cap_count = cap_count
self.cap_indices = cap_indices
class FingerParamTS:
def __init__(self, prg: int, pack_len: int, sensor_num: int, touch_num: int, ydds_num: int,
s_prox_num: int, m_prox_num: int, cap_byte: int, ydds_type: int, had_err: int,
cali_num: int, name: str, display_type_para: str, p_heat_map: Optional[List[FingerHeatMap]]):
self.prg = prg
self.pack_len = pack_len
self.sensor_num = sensor_num
self.touch_num = touch_num
self.ydds_num = ydds_num
self.s_prox_num = s_prox_num
self.m_prox_num = m_prox_num
self.cap_byte = cap_byte
self.ydds_type = ydds_type
self.had_err = had_err
self.cali_num = cali_num
self.name = name
self.display_type_para = display_type_para
self.p_heat_map = p_heat_map
# 定义 fingerHeatMap 数据
finger2_power_cap_index = [
FingerHeatMap(16, 8, "TS-F-A/heatMapPara16_8.dat", 7, [0, 1, 2, 3, 4, 5, 6, 255, 255, 255, 255, 255, 255, 255, 255, 255])
]
finger17_power_cap_index = [
FingerHeatMap(6, 7, "TS-T-A/weight6X7X6.dat", 6, [0, 1, 4, 5, 6, 7, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255]),
FingerHeatMap(6, 7, "TS-T-A/weight6X7X6.dat", 6, [2, 3, 8, 9, 10, 11, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255])
]
# 定义 fingerParams 数据
finger_params = [
FingerParamTS(2, 62, 8, 7, 1, 1, 0, 4, 2, 0, 22, "通用手指", "TypeA", finger2_power_cap_index),
FingerParamTS(17, 78, 16, 13, 2, 2, 1, 3, 4, 1, 22, "两指-大包", "TypeB", finger17_power_cap_index),
FingerParamTS(18, 462, 50, 49, 50, 1, 0, 3, 4, 1, 22, "两指-阵列", "TypeC", finger2_power_cap_index),
FingerParamTS(19, 62, 8, 7, 1, 0, 0, 4, 2, 0, 22, "通用手指New", "TypeA", finger2_power_cap_index),
FingerParamTS(20, 45, 7, 6, 2, 1, 0, 3, 4, 1, 27, "强脑-大拇指(量)", "TypeD", finger2_power_cap_index),
FingerParamTS(21, 69, 11, 8, 3, 2, 1, 3, 4, 1, 27, "强脑-食指(量)", "TypeE", finger2_power_cap_index),
FingerParamTS(22, 69, 11, 8, 3, 2, 1, 3, 4, 1, 27, "强脑-中指(量)", "TypeE", finger2_power_cap_index),
FingerParamTS(23, 69, 11, 8, 3, 2, 1, 3, 4, 1, 27, "强脑-无名指(量)", "TypeE", finger2_power_cap_index),
FingerParamTS(24, 45, 7, 6, 2, 1, 0, 3, 4, 1, 27, "强脑-小拇指(量)", "TypeD", finger2_power_cap_index),
]