B-One 简化版通信原理 Release:2021.03.04
1.版本记录
整合反馈抑制器说明书, 增加调制器, DELAY+CHORUS+REVERB, TEST MODE
版本V1.4, 发布日期: 2021.02.19
增加DOUBLING, REVERSE
版本V1.3, 发布日期: 2020.10.14
增加直达声音量读写
版本 v1.2, 发布日期: 2020.07.02
增加软件结构, PST,配置信息, 调出预设, PST 下载;
修改参数读写命令;
删除EQ读写指令;
版本v1.1, 发布日期: 2020.3.9
初次发布
版本v1.0, 发布日期: 2020.2.1
2.用前须知
BETFX 主要针对工厂自定义效果板应用, 要求工厂必须具体 MCU 开发能力, 否则将 无法使用该系列模块.
通过外挂 MCU, 工厂能够在 BETFX 的基础上开发出不同效果数量,不同操作风格, 不同显示方式的产品, 例如 320 效果带点阵屏显示, 或者简单到 16 效果无显示屏, 都可以 在 BETFX 上实现, 甚至将 BETFX 嵌入到数字调音台.
应用场景: BETFX 应用场景主要为模拟调音台, 数字调音台, 吉它音箱.
3.描述
主机: 外部MCU/PC等 从机: BETFX
BETFX 模块采用UART 与外部MCU通信, 物理格式为: 115200 - N - 8 - 1 传输采用ASCII, 允许的字符仅有字符0-9, A-Z, $, 以及rn, 其他所有字符都是不合法的. 所有命令都由主机发起, 从机不会主动发送任何数据, 从机在收到完整命令后, 3ms内会对主机作出响应.但主机仍要考虑传输的延迟, 115200BPS 传输一个BYTE需要约0.1ms; 传输中多字节字段,高字节在前.
SOF(1BYTE) |
LEN(1BYTE) |
PAYLOAD(N) |
CS(1BYTE) |
EOF(2BYTE) |
|---|---|---|---|---|
‘$’ |
PAYLOAD长度 |
数据包 |
校验和 SOF,LEN,PAYLOAD3段数据求和 |
rn |
BETFX不带关机保存, 所有操作由主机自行保存参数. 每次开机, BETFX进入DRY模式, 信号直入直出, 不添加任何算法, DRY模式可用于产线FX回路音频指标测试. 此时等待主机指令;
BETFX定位为专业的音效处理模块, 类似于一片专业的音效DSP,内置了常用的效果库, 但这些效果库通常并不能满足所有场景, 需要主机针对不同参数,对同一个效果库写入不同的参数, 例如REVERB库,你可以写入ROOM的参数,也能够写入HALL的参数, 参数不一样, 效果库工作的场景是不一样的. 所有参数的保存UI的操作都由外部MCU来完成, 我们更欢迎工厂自主去开发MCU程序,设计更有创意的产品, 更有个性的UI.
4.软件结构
如图4.1所示, BETFX 向外暴露一组UART接口, 供主机读写BETFX参数, 所有的修改都是即时生效的.
控制BETFX, 我们建议选择以下3种方式之一:
[A]:专业模式, MCU完全控制, BETFX 外部MCU, 所有参数由MCU决定, 参数由64BYTE 长度命令帧直接下载到BETFX, 当然64BYTE的长度是可变的,单个BYTE读写也是支持的. 可以在MCU 这边做一个显示屏, 按键 , 编码器, 将REVERB时间长度,CHORUS 速度等在显示屏上显示出来, 由用户通过编码器修改, MCU负责将用户数据转化成命令通过UART 设置BETFX. 这种操作方式可以简单实现自己的复杂UI, 彩屏, 甚至融入到MP3或数字调音台都是很方便的;
[B]:预设模式, PC配置, MCU载入, BETFX要使用前, 需要将配置文件下载到芯片中. 例如在PC上根据自己的喜好, 先配置出320效果, 保存成一个配置文件, 生产时, 将这个配置文件下载到BETFX中, BETFX 会将这320种效果保存到芯片内部PresetStorage区域, 当要切换效果时, MCU发送切换效果指令, 即可以从PST中加载效果到BETFX Engine. 但这种操作不带参数调节与显示, 只能显示001 -> 320 种效果序号;
[C]:乐器模式, 乐器模式通常是不需要显示的, BETFX 最多提供4个电位器接口控制参数, 这种方式一般用于乐器音箱或 单块效果器. 首先在PC上先配置好自己产品喜好的效果整体参数, 如EQ, 混响类型,CHORUS SPEED/DEPTH等. 在生产时, 将这个文件导入到每片BETFX模块, 然后由电位器来决定个别参数, 例如REVERB DECAY TIME, CHORUS SPEED/DEPTH.
5.设备查询
UART 数据帧格式:
读取数据格式:
说明 |
起始符 |
数据长度[LEN] |
内容[CMD+首地址addr+读取数据长度n] |
校验位 |
结束符 |
|---|---|---|---|---|---|
读命令 |
0x24 |
0x03 CMD(1bytes)+addr(1bytes)+n(1bytes) |
CMD:0x81读取系统信息 |
||
CMD:0x82读取系统配置 |
|||||
CMD:0x83读取当前效果器寄存器 |
|||||
CMD:0x84读取效果器默认参数 |
CS |
0x0d+0x0a |
|||
CMD:0x85读取当前EQ参数 |
|||||
CMD:0x86读取EQ默认参数 |
|||||
首地址:1bytes 查数据结构表 |
|||||
读取数据长度:1bytes 查数据结构表 |
|||||
回复 |
0x24 |
n |
para1+para2…paran |
CS |
0x0d+0x0a |
写数据格式
说明 |
起始符 |
数据长度[LEN] |
内容[CMD+首地址addr+写数据长度n+para1+para2…paran] |
校验位 |
结束符 |
|---|---|---|---|---|---|
写命令 |
0x24 |
0x03+n |
CMD:0x01 保留 |
CS |
0x0d+0x0a |
CMD:0x02 设置系统配置 |
|||||
CMD:0x03 设置效果器寄存器 |
|||||
CMD:0x05 设置EQ寄存器 |
|||||
addr:1bytes 查数据结构表 |
|||||
n:1bytes 查数据结构表 |
|||||
para1+para2…para3:nbytes 设置参数值 |
|||||
回复 |
OK\r\n |
说明: 数据长度+内容 数据必须转义成2个字符 分别转换成16进制 高4位 跟地4位的ASSCII码 例如 0x81 –> 0x38+0x31
CS:是起始符+LEN+内容所有值累加和低8位转换成2个字符
例如: 读取系统信息:制造商名称 占用0x20个字节 地址为0
$03810020B2\\r\\n
起始符:$
LEN:03
CMD:81 addr:00 n:20
CS:B2 (0x24+0x30+0x38+0x31+0x30+0x30+0x32+0x30)%0xFF=0xB2
结束符:\\r\\n
注意事项
UART 物理格式: 115200-8-N-1, 从机响应时间<5mS;
为了将来扩展应用, 不要对所有保留字段进行写操作;
传输采用ASCII, 允许的字符仅有字符0-9, A-Z, $, 以及rn, 其他所有字符都是不合法的.
传输中多字节字段,高字节在前.
数据结构
系统信息(只读, 读): CMD:0x81
首地址 |
长度[字节] |
内容 |
|---|---|---|
0x00 |
0x08 |
H’,’A’,’N’,’M’,’U’,’S’, 0x00, 0x00// 技术供应商名称 |
0x08 |
0x08 |
‘D’,’E’,’1’,’0’,’0’,0x00, 0x00, 0x00 // 主控型号 |
0x10 |
0x04 |
软件发布日期, BCD格式, YYMMDDxx, xx代表当天发布序号 |
0x14 |
0x0C |
保留 |
0x20 |
0x02 |
DELAY最长时间,高字节在前;//应用程序首先要读取当前字段,以确认DELAY数据范围 |
0x22 |
0x01 |
BIT0=1 支持REVERB, 否则不支持; BIT1=1 支持CHORUS, 否则不支持; BIT2=1 支持哇音,否则不支持; BIT3=1 支持颤音, 否则不支持; BIT4=1 支持DELAY, 否则不支持; BIT5=1 支持FBC, 否则不支持; BIT6=1 支持IN EQ, 否则不支持; BIT7=1 支持DRY VOL, 否则不支持; |
0x23 |
0x01 |
EQ 支持最大段数, 一般为6,代表1个HPF, 一个LPF, 4个参量均衡 |
0x24 |
0x02 |
保留 |
例子:读取技术供应商信息
+---------+------+--------+------------------------+
| PageLen | CMD | 首地址 | 读取长度 |
+=========+======+========+========================+
| 0x03 | 0x81 | 0x00 | 0x08[读取全部数据长度] |
+---------+------+--------+------------------------+
起始符 PageLen cmd 首地址 读取长度 校验位 结束符
编码格式如下:字符: $03810008B8\\r\\n
十六进制: 0x24 + 0x30+0x33 + 0x38+0x31 + 0x30+0x30 + 0x30+0x38 + 0x42+0x38 + 0x0D+0x0A
CS:=(0x24+0x30+0x33+0x38+0x31+0x30+030+0x+0x38)%255 =0xB8 转义2位 0x42+0x38
回复:$0848414E4D55530000E0\\r\\n 返回 HANMUS
08: 数据长度为8
48414E4D55530000 数据内容
E0: CS
读取主控型号:DE100 Send:$03810808C0\\r\\n
REV :$084445313030000000A7\r\n
读取发布日期:20120801 2020年12月8号01版本
Send:$03811004B5\r\n
REV :$042012080116\r\n
读取系统DELAY TIME最大值 0x1F4
Send:$03812002B4
REV :$0201F461
读取系统支持配置项
Send:$03812201B5
REV :$01D3FC :读取值为0xD3 :
读取EQ支持最大段数
Send:$03812301B6
REV :$0106EB 读取值为 0x06
系统配置(可读写): CMD: 0x82[读]/ 0x02[写]
首地址 |
长度[字节] |
内容 |
|---|---|---|
0x00 |
0x20 |
‘H’,0x00,’A’,0x00,’N’,0x00,’M’,0x00,’U’,0x00,’S’,0x00, 0x00,0x00, 0x00,0x00, |
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00// 制造商名称, 例如: BMW [unicode编码] |
||
0x20 |
0x20 |
‘A’,0x00,’F’,0x00,’-‘,0x00,’I’,0x00,’I’,0x00,’R’,0x00,‘C’,0x00, 0x00,0x00, |
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, |
||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 // 产品型号, 例如: 740Li [unicode编码] |
||
0x40 |
0x04 |
生产日期, BCD格式, YYMMDDxx, xx代表当天发布序号 |
0x44 |
0x04 |
产品序列号, HEX格式 |
0x48 |
0x01 |
0x55h: 不锁定, 解锁定后, 效果器参数将自动恢复为HANMUS提供的默认参数, |
0xAA 锁定, 锁定后, 效果器参数将不可读出, |
||
其他数据忽略; |
||
0x49 |
0x36 |
保留 |
读取制造商信息:
Send:$03820020B3\\r\\n
REV :$20480041004E004D00550053000000000000000000000000000000000000000000DA\\r\\n
读取产品型号
Send:$03822020B5\\r\\n
REV :$20410046002D00490049002D005200430044000000000000000000000000000000F1\\r\\n
读取生产日期:20120801
Send:$03824004B9
REV :$042012080116
读取产品序列号
Send:$03824404BD
REV :$040000000008
读取锁定参数
Send:$03824801BE
REV :$0100E5
:
写入制造商信息为: 声天下科技有限公司 Send:$23020020F05829590B4ED1798062096750966C51F8530000000000000000000000000000B8 REV :OKrn
效果器参数(可读写): CMD:0x83[读]/0x03[写] / 0x84[读取默认值]
首地址 |
长度[字节] |
内容 |
|---|---|---|
0x00 |
0x01 |
保留 |
0x01 |
0x01 |
[Delay Volume],Type: UINT8, 200: 0dB, 最小值: 0(负无穷大); 最大值:200(0dB), 步进0.5dB |
0x02 |
0x01 |
[Delay Repeat], Type: UINT8, 0-20, Def: 7 |
0x03 |
0x02 |
[Delay Time], Type: UINT16, DEF: 220mS, 高字节在前. |
0x05 |
0x02 |
保留 |
0x07 |
0x01 |
[Reverb Volume], Type: UINT8, 200: 0dB, 最小值: 0(负无穷大); 最大值:200(0dB), 步进0.5dB |
0x08 |
0x01 |
保留 |
0x09 |
0x01 |
[Decay time], Type: UINT8, 0-100, 单位 :% |
0x0A |
0x01 |
[Room Size], Type: UINT8, 0-100, 单位 :% |
0x0B |
0x01 |
[Dramp], Type: UINT8, 0-100, 单位 :% |
0x0C |
0x01 |
[CHORUS Volume], Type: UINT8, 200: 0dB, 最小值: 0(负无穷大); 最大值:200(0dB), 步进0.5dB |
0x0D |
0x01 |
[Chorus speed], Type: UINT8, 0-10HZ, 单位 :0.1HZ |
0x0E |
0x01 |
[Chorus Depth], Type: UINT8, 0-100, 单位 :% |
0x0F |
0x01 |
[Chorus Feedback],Type: UINT8, 0-100, 单位 :% |
0x10 |
0x01 |
[FX volume],总音量, Type: UINT8, 200: 0dB, 最小值: 0(负无穷大); 最大值:200(0dB), 步进0.5dB |
0x11 |
0x02 |
[REVERB HPF FREQ], Type: UINT16, DEF: 20HZ, 范围: 20HZ-20KHZ, 高字节在前. |
0x13 |
0x02 |
[REVERB LPF FREQ], Type: UINT16, DEF: 20000HZ, 范围: 20HZ-20KHZ, 高字节在前. |
0x15 |
0x02 |
[REVERB PEAK FREQ], Type: UINT16, DEF: 20000HZ, 范围: 20HZ-20KHZ, 高字节在前. |
0x17 |
0x01 |
[REVERB PEAK GAIN], Type: UINT8, DEF: 0dB, 范围: 100 +-12dB, 100代表0dB. |
0x18 |
0x01 |
[FBC ENABLE],0: DISABLE, 1:ENABLE |
0x19 |
0x01 |
[DRY volume],总音量, Type: UINT8, 200: 0dB, 最小值: 0(负无穷大); 最大值:200(0dB), 步进0.5dB |
0x1A |
0x02 |
保留 |
读取效果器参数默认值
Send:$0384001CC7\\r\\n
REV :$1C08C80700DC0000C800265D63C8043200C801181F4003E86400C8000057\\r\\n
读取效果器参数 地址0开始到0x1B的值
Send:$0383001CC6\\r\\n
REV :$1C08C80700DC0000C800265D63C8043200A501181F4003E864E8A800006D\\r\\n
设置Delay Volume 音量为-20.5db 设置值为 200-41=159 =0x9F
Send:$040301019F2C\\r\\n
REV :OK\\r\\n
设置Delay time 为200ms 设置值为 0x00C8
$0503030200C88C|\r|\n
REV :OK\r\n
设置混响高通频率 HPF = 1000hz =0x03E8
$0503110203E890\r\n
REV :OK\r\n
EQ寄存器(可读写):CMD :0x85[读]/0x05[写]/0x86[读取默认值]
首地址 |
长度 |
内容 |
|---|---|---|
0x00 |
0x02 |
高通滤波器中心频率, Type: UINT16, DEF: 20HZ, 范围: 20HZ-20KHZ, 高字节在前; 例如:1000hz:0x03E4 |
0x02 |
0x02 |
低通滤波器中心频率, Type: UINT16, DEF: 20HZ, 范围: 20HZ-20KHZ, 高字节在前; |
0x04 |
0x02 |
参量均衡1 中心频率, Type: UINT16, DEF: 20HZ, 范围: 20HZ-20KHZ, 高字节在前; |
0x06 |
0x01 |
参量均衡1 增益,Type: UINT8, DEF:100, 数值100代表0dB, 最小值: 88(-12dB); 最大值:112(12dB), 步进1dB; |
0x07 |
0x01 |
参量均衡1 Q值,Type: UINT8, DEF:10, 最小值: 1(0.1); 最大值:255(25.5), 步进1 |
实际Q值等于该值除以10, 例如数值10代表滤波器Q值为1, 数值50代表Q值为5; |
||
0x08 |
0x02 |
参量均衡2 中心频率,Type: UINT16, DEF: 20HZ, 范围: 20HZ-20KHZ, 高字节在前; |
0x0A |
0x02 |
参量均衡2 增益,Type: UINT8, DEF:100, 数值100代表0dB, 最小值: 88(-12dB); 最大值:112(12dB), 步进1dB; |
0x0B |
0x01 |
参量均衡2 Q值,Type: UINT8, DEF:10, 最小值: 1(0.1); 最大值:255(25.5), 步进1 |
0x0C |
0x02 |
参量均衡3 中心频率, Type: UINT16, DEF: 20HZ, 范围: 20HZ-20KHZ, 高字节在前; |
0x0E |
0x01 |
参量均衡3 增益,Type: UINT8, DEF:100, 数值100代表0dB, 最小值: 88(-12dB); 最大值:112(12dB), 步进1dB; |
0x0F |
0x01 |
参量均衡3 Q值,Type: UINT8, DEF:10, 最小值: 1(0.1); 最大值:255(25.5), 步进1 |
实际Q值等于该值除以10, 例如数值10代表滤波器Q值为1, 数值50代表Q值为5; |
||
0x10 |
0x02 |
参量均衡4 中心频率, Type: UINT16, DEF: 20HZ, 范围: 20HZ-20KHZ, 高字节在前; |
0x12 |
0x01 |
参量均衡4 增益,Type: UINT8, DEF:100, 数值100代表0dB, 最小值: 88(-12dB); 最大值:112(12dB), 步进1dB; |
0x13 |
0x01 |
参量均衡4 Q值,Type: UINT8, DEF:10, 最小值: 1(0.1); 最大值:255(25.5), 步进1 |
实际Q值等于该值除以10, 例如数值10代表滤波器Q值为1, 数值50代表Q值为5; |
||
0x14 |
0x0C |
保留 |
读取EQ寄存器所有参赛的默认值
Send:$0386001ECB\\r\\n
REV :$1E00144E2001F4640A03E8640A0BB8640A1F40640A00000000000000000000E8\\r\\n
读取EQ寄存器所有值
Send:$03850020B6\\r\\n
REV :$2000144E2001F4640A03E8640A0BB8640A1F40640A00000000000000000000000094\\r\\n
设置EQ低通滤波器频率为100 = 0x0064
$0505020200647C\\r\\n
REV :OK\\r\\n
设置均衡2中心频率 为2000 = 0x7D0
$0505080207D093\\r\\n
REV :OK\\r\\n
设置均衡4增益为-5db 设置值为 100-5=95 =0x5F
$050512025F3091\\r\\n
REV :OK\\r\\n
设置均衡1的Q值为 0.9 设置值为 0.9*10 = 0x09
$04050701091E\\r\\n
REV :OK\\r\\n
编解码参考
#define RPC_BUF_MAX 256
#define RPC_BUF_MASK (RPC_BUF_MAX-1)
//RPC 命令集
#define RPC_RESERVE 0x01
#define RPC_WRITE_STSTEM_CONFIG 0x02
#define RPC_WRITE_FX_REG 0x03
#define RPC_WRITE_INEQ_REG 0x05
#define RPC_READ_SYSTEM_INFOR 0x81
#define RPC_READ_SYSTEM_CONFIG 0x82
#define RPC_READ_FX_REG 0x83
#define RPC_READ_FX_DEFAULT_REG 0x84
#define RPC_READ_INEQ_REG 0x85
#define RPC_READ_DEFAULT_INEQ_REG 0x86
typedef struct {
unsigned char rpcPackageLen;
unsigned char cmd,add,len;
unsigned char buf[RPC_BUF_MAX];
}frame_ctrl;
typedef struct {
int fi, fo;
unsigned char buf[RPC_BUF_MAX];
}fifo_t;
unsigned char hex2Assci(unsigned char hc) {
hc = hc & 0x0f;
if ((hc >= 0) && (hc <= 9))return (hc + '0');
return ((hc - 10) + 'A');
}
unsigned char assci2hex(unsigned char a, unsigned char b) {
if (a >= '0' && a <= '9')a = a - '0';
else if (a >= 'a' && a <= 'f') a = a - 'a' + 10;
else if (a >= 'A' && a <= 'F') a = a - 'A' + 10;
if (b >= '0' && b <= '9')b = b - '0';
else if (b >= 'a' && b <= 'f') b = b - 'a' + 10;
else if (b >= 'A' && b <= 'F') b = b - 'A' + 10;
return a * 16 + b;
}
void pushFifo(fifo_t *pfifo, unsigned char *pBuf, int len) {
while (len-- > 0) {
pfifo->buf[pfifo->fi++] = *pBuf++;
pfifo->fi &= RPC_BUF_MASK;
}
/*
编码函数:返回值 pBufOut 发送数据的长度
cmd: 命令
addr :首地址
len:读写数据长度
*pBufIn: 写数据的内容首地址 /读模式为NULL
*PBufOut: 编码后保持数据的首地址
write: false 读 true 写
*/
int encode(unsigned char cmd, unsigned char addr, unsigned char len,
unsigned char *pBufIn, unsigned char *pBufOut, bool write) {
int i;
unsigned char cs, d, d1, d2;
int offset = 0;
pBufOut[offset++&RPC_BUF_MASK] = 0x24;
cs = 0x24;
// pageageLen
d1 = hex2Assci((unsigned char)((write?(len+3):3)>> 4));
pBufOut[offset++&RPC_BUF_MASK] = d1;
cs += d1;
d1 = hex2Assci((unsigned char)((write ? (len + 3) : 3) >>0));
pBufOut[offset++&RPC_BUF_MASK] = d1;
cs += d1;
// cmd
d1 = hex2Assci((unsigned char)(cmd >> 4));
pBufOut[offset++&RPC_BUF_MASK] = d1;
cs += d1;
d1 = hex2Assci((unsigned char)(cmd >> 0));
pBufOut[offset++&RPC_BUF_MASK] = d1;
cs += d1;
// addr
d1 = hex2Assci((unsigned char)(addr >> 4));
pBufOut[offset++&RPC_BUF_MASK] = d1;
cs += d1;
d1 = hex2Assci((unsigned char)(addr >> 0));
pBufOut[offset++&RPC_BUF_MASK] = d1;
cs += d1;
//len
d1 = hex2Assci((unsigned char)(len >> 4));
pBufOut[offset++&RPC_BUF_MASK] = d1;
cs += d1;
d1 = hex2Assci((unsigned char)(len >> 0));
pBufOut[offset++&RPC_BUF_MASK] = d1;
cs += d1;
// date
for (i = 0; i< (write ? len:0); i++) {
d = pBufIn[i];
d1 = hex2Assci((unsigned char)(d >> 4));
d2 = hex2Assci(d);
pBufOut[offset++&RPC_BUF_MASK] = d1;
pBufOut[offset++&RPC_BUF_MASK] = d2;
cs += (d1 + d2);
}
pBufOut[offset++&RPC_BUF_MASK] = hex2Assci((cs >> 4));
pBufOut[offset++&RPC_BUF_MASK] = hex2Assci(cs);
pBufOut[offset++&RPC_BUF_MASK] = 0x0d;
pBufOut[offset++&RPC_BUF_MASK] = 0x0a;
pBufOut[offset&RPC_BUF_MASK] = 0x00; // only for printf.
//pfifo->fi = offset&RPC_BUF_MASK;
return write?(len*2 + 13):13;
}
/*
解码函数:返回值
0:解码成功
-1:
-2:没有新的数据
-3:数据长度不足
fifo_t *pfifo: 接收数据缓存
frame_ctrl *pRpc:解码结构体
*/
int decode(fifo_t *pfifo, frame_ctrl *pRpc)
{
int i, len;
unsigned char d1, d2;
unsigned short d;
unsigned char rpcPackageLen;
int offset;
unsigned char cs;
int ofs1=0;
if (pfifo->fo == pfifo->fi)return -2;
while (pfifo->fo != pfifo->fi) {
if (pfifo->buf[pfifo->fo] == 0x24) {
ofs1 = pfifo->fo;
break;
}
pfifo->fo++;
pfifo->fo &= RPC_BUF_MASK;
}
if (pfifo->buf[pfifo->fo] == 0x24) {
len = ((pfifo->fi + RPC_BUF_MAX) - ofs1)&RPC_BUF_MASK;
if (len<9)return -3;// must wait for "\r\n".
d1 = pfifo->buf[(ofs1 + 1)&RPC_BUF_MASK];
d2 = pfifo->buf[(ofs1 + 2)&RPC_BUF_MASK];
rpcPackageLen = assci2hex(d1, d2);
if (len<(rpcPackageLen * 2 + 7)) return -4;
cs = 0x24 + d1 + d2;
pRpc->len = rpcPackageLen;
offset = (ofs1 + 3)&RPC_BUF_MASK;
for (i = 0; i<rpcPackageLen; i++) {
d1 = pfifo->buf[offset++&RPC_BUF_MASK];
d2 = pfifo->buf[offset++&RPC_BUF_MASK];
pRpc->buf[i&RPC_BUF_MASK] = assci2hex(d1, d2);
cs += (d1 + d2);
}
pfifo->buf[ofs1] |= 0x80;
d1 = pfifo->buf[offset++&RPC_BUF_MASK];
d2 = pfifo->buf[offset++&RPC_BUF_MASK];
if (cs == assci2hex(d1, d2)) {
d1 = pfifo->buf[offset++&RPC_BUF_MASK];
d2 = pfifo->buf[offset++&RPC_BUF_MASK];
if ((d1 == 0x0d) && (d2 == 0x0a)) {
pRpc->len = rpcPackageLen;
return 0;
}
}else {
printf("CS check error:%x,%x", cs, assci2hex(d1, d2)));
}
return -1;
}