触摸框串口坐标数据包包的大小基本上都是67 个Byte,但是格式稍有差异。有的6个点,有的10个点,带宽度和不带宽度,某个字节特殊定义等等。
一、串口配置
波特率: 115200
数据位: 8位
停止位: 1 位
奇偶校验: 无
二、触摸框规格
触摸框的分辨率为32767*32767,坐标原点为左上角。当无触摸时,不发送数据,当有触摸时,触摸框通过串口发送一包67 Byte 数据。
三、数据处理
串口工具接触摸框串口,注意接地。将工具中数据拷贝到notepad 或者UE中,通过每67个byte一行,空格隔开。然后处理的文本协议数据拷贝到excel 中,由于一个文本框有67个byte 数据。
A.数据分列
选择单列所有数据,【数据】-【分列】-【设置分隔符号】-【空格】-【完成】,这样单列67个byte 分别分配到67列中。方法链接
B.格式设置
设置数字00 格式显示,保证统一数字宽度
全选后,右键【设置单元格格式】-【数字】-【分类:自定义】-【类型】-【00】
C.表格设置
截取部分头部,尾部和中间一个点的信息,如下
全部梳理清楚后,通过action前后状态判定事件,触控点个数,x,y 坐标等等,非常方便
四、协议格式
其中,data【0】,data【1】 是数据包头,
data【2】是数据包字节长度低字节,固定为67(0x43),
data【3】是数据包字节长度高字节,由于总共为67个低位已经满足,这里默认是00
Data【4】是触控点形状,板擦 或 笔
Data【5 ~ 10】第1个点的状态(Action),ID(0),X的位置的高低字节,Y的位置的高低字节
Data【11 ~ 16】第2个点的状态(Action),ID(1),X的位置的高低字节,Y的位置的高低字节
Data【17 ~ 22】第3个点的状态(Action),ID(2),X的位置的高低字节,Y的位置的高低字节
Data【23 ~ 28】第4个点的状态(Action),ID(3),X的位置的高低字节,Y的位置的高低字节
Data【29 ~ 34】第5个点的状态(Action),ID(4),X的位置的高低字节,Y的位置的高低字节
Data【35 ~ 40】第6个点的状态(Action),ID(5),X的位置的高低字节,Y的位置的高低字节
Data【41 ~ 46】第7个点的状态(Action),ID(6),X的位置的高低字节,Y的位置的高低字节
Data【47 ~ 52】第8个点的状态(Action),ID(7),X的位置的高低字节,Y的位置的高低字节
Data【53 ~ 58】第9个点的状态(Action),ID(8),X的位置的高低字节,Y的位置的高低字节
Data【59 ~ 64】第10个点的状态(Action),ID(9),X的位置的高低字节,Y的位置的高低字节
Data【65】有效触摸点的数量,范围是[1 ~ 10],最多支持10指
Data【66】校验和,求data[0 ~ 65]之和,取低字节
部分数据格式如下:
01 02 03 SUM
index 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 65 66
1F F7 43 00 00 02 00 38 60 08 1E 02 01 30 65 50 1D 00 02 00 00 00 00 02 4C
1F F7 43 00 00 03 00 38 60 08 1E 03 01 30 65 40 1D 00 02 00 00 00 00 02 3E
1F F7 43 00 00 03 00 38 60 08 1E 03 01 30 65 38 1D 00 02 00 00 00 00 02 36
1F F7 43 00 00 03 00 38 60 08 1E 03 01 30 65 38 1D 00 02 00 00 00 00 02 36
1F F7 43 00 00 03 00 40 60 08 1E 03 01 48 65 D0 1D 03 02 A0 6E E0 2D 03 0D
1F F7 43 00 00 03 00 48 60 08 1E 03 01 48 65 D0 1D 02 02 A0 6E E0 2D 03 14
1F F7 43 00 00 03 00 48 60 00 1E 03 01 48 65 D0 1D 00 02 00 00 00 00 02 EE
1F F7 43 00 00 03 00 48 60 00 1E 03 01 48 65 D0 1D 00 02 00 00 00 00 02 EE
1F F7 43 00 00 03 00 48 60 00 1E 03 01 48 65 D0 1D 00 02 00 00 00 00 02 EE
1F F7 43 00 00 03 00 48 60 00 1E 03 01 48 65 D0 1D 00 02 00 00 00 00 02 EE
1F F7 43 00 00 03 00 48 60 00 1E 03 01 48 65 D0 1D 00 02 00 00 00 00 02 EE
1F F7 43 00 00 03 00 40 60 00 1E 03 01 48 65 D0 1D 00 02 00 00 00 00 02 E6
1F F7 43 00 00 03 00 40 60 00 1E 02 01 48 65 D0 1D 00 02 00 00 00 00 02 E5
1F F7 43 00 00 03 00 48 60 00 1E 00 01 00 00 00 00 00 02 00 00 00 00 01 50
1F F7 43 00 00 03 00 50 60 00 1E 00 01 00 00 00 00 00 02 00 00 00 00 01 58
1F F7 43 00 00 02 00 50 60 00 1E 00 01 00 00 00 00 00 02 00 00 00 00 01 57
1.每个点信息起始为:data[i6+5] ; // 其中6表示一个点里面6个byte标记信息,5表示前4个byte 基本为头信息
2.ID 的范围为[0~9],一包数据(67byte)下来,ID 的值都是固定的,从0~9 占用的byte 位为 Byte[6, 12,18,24,30,36,42,48,54,60] = [00,01,02,03,04,05,06,07,08]
3.Byte[65] 为触摸的手指个数,N根手指在屏里面数字就为N,但最后一根手指抬起后,该byte位不会再补发0
4.点的UP,DOWN,MOVE 事件,需要前后两个action状态翻转来判断
// preActionState[0~9], curActionState[0~9] = byte[i6+5], 前置状态触摸前都为00
5.UP,DOWN,MOVE事件处理之后注意前置状态的重新设置,确保前置和当前状态唯一标识一个UP,DOWN,MOVE,ALL_UP 事件,最终的是要避免多发UP/DOWN
6.每个手指的UP/DOWN 事件必须是一一对应, 不能出现count[UP] != count[DOWN]
状态变换
五、触摸事件
上层触摸事件,可以通过USB 触控模拟出来,通过getevent -l 打印出来。
EVENT 分为EV_ABS,EV_KEY,EV_SYN 三种类型
串口触摸事件 与 USB口触摸事件的对比
串口模拟的事件就是协议解析结束之后,需要/dev/uinput发送的事件
六、解析流程图
七、协议解析源码
void sendEvent(unsigned char tmpBuff[])
{
int width = 0;
unsigned char nPosStartIndex = 0;
unsigned int unUsefulDotCnt = tmpBuff[VALID_DOT_NUMBER_IN_EACH_PACKGE];
touchCount = unUsefulDotCnt;
for(int i = 0; i < DOTCNT_OF_PACKAGE; i++){
struct timeval tv;
gettimeofday(&tv,NULL);
nPosStartIndex = i * CNT_OF_DOT + 5;
action = tmpBuff[nPosStartIndex];
id = tmpBuff[nPosStartIndex + 1];
// record the useful dot count
if(unUsefulDotCnt != 0x00){
touchCount = unUsefulDotCnt;
}
if(id > TOUCH_COUNT){ // ID < 12
printf( "\033[1;31;40m Touch data error,id:%d. \n\033[0m", id);
continue;//break;
}
// pos (x,y)
x = tmpBuff[nPosStartIndex+2] + (tmpBuff[nPosStartIndex+3] << 8);
y = tmpBuff[nPosStartIndex+4] + (tmpBuff[nPosStartIndex+5] << 8);
if(!isNoWidth){
// Dot width
width = tmpBuff[nPosStartIndex + 6] + (tmpBuff[nPosStartIndex + 7] << 8);
}
if(action == 0x02){
// printf("[%s][%d] id[%d] preTouchAct[%d] = [0x%02x] action: [0x%02x] touchCount=[%d] count = [%d] unUsefulDotCnt=[%d] \n",__FUNCTION__,__LINE__, id,id,preTouchAct[id],action,touchCount,count,unUsefulDotCnt);
if(preTouchAct[id] == 0x03 || preTouchAct[id] == 0x02){
touchCount--;
write_event_to_device(EV_ABS, ABS_MT_SLOT, id);
write_event_to_device(EV_ABS, ABS_MT_TRACKING_ID, -1);
if(touchCount == 0){
write_event_to_device(EV_KEY, BTN_TOUCH, 0); // UP to Android
printf("[%s][%d]...... id = [%d] ALL UP .\n",__FUNCTION__,__LINE__,id);
}else{
printf("[%s][%d]..... id = [%d]. ONE UP .\n",__FUNCTION__,__LINE__,id);
}
write_event_to_device(EV_SYN, SYN_REPORT, 0);
preTouchAct[id] = 0x00; // set default when dot up
}else if(preTouchAct[id] == 0x00){
printf("[%s][%d]...... id = [%d] DOWN....\n",__FUNCTION__,__LINE__,id);
count++;
trackingId[id] = count;
write_event_to_device(EV_ABS, ABS_MT_SLOT, id);
write_event_to_device(EV_ABS, ABS_MT_TRACKING_ID, count);
write_event_to_device(EV_ABS, ABS_MT_POSITION_X, x);
write_event_to_device(EV_ABS, ABS_MT_POSITION_Y, y);
if(!isNoWidth){
write_event_to_device(EV_ABS, ABS_MT_WIDTH_MAJOR, width);
}
write_event_to_device(EV_KEY, BTN_TOUCH, 1); // DOWN to Android
write_event_to_device(EV_SYN, SYN_REPORT, 0);
preTouchAct[id] = action;
}
}else if(action == 0x03){
// printf("[%s][%d] id[%d] preTouchAct[%d] = [0x%02x] action: [0x%02x] touchCount=[%d] count = [%d] unUsefulDotCnt=[%d] \n",__FUNCTION__,__LINE__, id,id,preTouchAct[id],action,touchCount,count,unUsefulDotCnt);
if(preTouchAct[id] == 0x00){
printf("[%s][%d]...... id = [%d] EXTRA DOWN....\n",__FUNCTION__,__LINE__,id);
count++;
trackingId[id] = count;
write_event_to_device(EV_ABS, ABS_MT_SLOT, id);
write_event_to_device(EV_ABS, ABS_MT_TRACKING_ID, count);
write_event_to_device(EV_ABS, ABS_MT_POSITION_X, x);
write_event_to_device(EV_ABS, ABS_MT_POSITION_Y, y);
if(!isNoWidth){
write_event_to_device(EV_ABS, ABS_MT_WIDTH_MAJOR, width);
}
write_event_to_device(EV_KEY, BTN_TOUCH, 1);
write_event_to_device(EV_SYN, SYN_REPORT, 0);
preTouchAct[id] = action;
//move
write_event_to_device(EV_ABS, ABS_MT_SLOT, id);
write_event_to_device(EV_ABS, ABS_MT_TRACKING_ID, trackingId[id]);
write_event_to_device(EV_ABS, ABS_MT_POSITION_X, x);
write_event_to_device(EV_ABS, ABS_MT_POSITION_Y, y);
#if (TOUCH_HAS_WIDTH == 1)
write_event_to_device(EV_ABS, ABS_MT_WIDTH_MAJOR, width);
#endif
write_event_to_device(EV_SYN, SYN_REPORT, 0);
tmpX[id] = x;
tmpY[id] = y;
}else if((preTouchAct[id] == 0x02)||(abs(tmpX[id] - x) > 17 || abs(tmpY[id] - y) > 30)){//最大坐标除以分辨率,拿到比例
printf("[%s][%d]...... id = [%d] MOVE....\n",__FUNCTION__,__LINE__,id);
write_event_to_device(EV_ABS, ABS_MT_SLOT, id);
write_event_to_device(EV_ABS, ABS_MT_TRACKING_ID, trackingId[id]);
write_event_to_device(EV_ABS, ABS_MT_POSITION_X, x);
write_event_to_device(EV_ABS, ABS_MT_POSITION_Y, y);
if(!isNoWidth){
write_event_to_device(EV_ABS, ABS_MT_WIDTH_MAJOR, width);
}
write_event_to_device(EV_SYN, SYN_REPORT, 0);
tmpX[id] = x;
tmpY[id] = y;
preTouchAct[id] = action;
}
}else if(action == 0x00){
//
}
printf("\n\n\n");
}
}
代码还有待优化。
八、性能优化(后续)