PC工具: IC util
手持设备:Dynasty ARM嵌入式设备
通信设备: TTL-USB串口传输器
问题:IC_Util向dynasty传输所需的配置文件,传输速度慢。
传输10k大小的文件
顺利时耗时大约10s,文件分块传输,1k/block or 2k/block。
波特率115200
传输时对于接受和发送的函数需要做适当的延时处理,同时需要对传输时的block大小做一定规定,BLOCK为2k时传输正常,BLOCK为1k时IC_Util将会不时的出现接收超时的问题。
Delphi串口模块使用的是TCOM模块
以下为TCOM模块的配置:
object DtmdComm: TDtmdComm OldCreateOrder = False OnCreate = DataModuleCreate OnDestroy = DataModuleDestroy Left = 415 Top = 275 Height = 225 Width = 314 object cmmMain: TComm CommName = 'COM1' BaudRate = 9600 ParityCheck = False Outx_CtsFlow = False Outx_DsrFlow = False DtrControl = DtrDisable DsrSensitivity = False TxContinueOnXoff = True Outx_XonXoffFlow = False Inx_XonXoffFlow = False ReplaceWhenParityError = False IgnoreNullChar = False RtsControl = RtsDisable XonLimit = 500 XoffLimit = 500 ByteSize = _8 Parity = None StopBits = _1 XonChar = #17 XoffChar = #19 ReplacedChar = #0 ReadIntervalTimeout = 500 ReadTotalTimeoutMultiplier = 0 ReadTotalTimeoutConstant = 0 WriteTotalTimeoutMultiplier = 0 WriteTotalTimeoutConstant = 0 OnReceiveData = cmmMainReceiveData Left = 48 Top = 16 end object tmrPack: TTimer Tag = 20 Enabled = False OnTimer = tmrPackTimer Left = 136 Top = 56 endend
接收函数的对应实现接口为cmmMainReceiveData()
以下为cmmMainReceiveData()的实现:
procedure TDtmdComm.cmmMainReceiveData(Sender: TObject; Buffer: Pointer; BufferLength: Word);var tmpArray:array[1..8096] of Byte; i,DataCount: Integer; tmpRecvStr:string; OneCommand:string;begin //Delay(100); tmpRecvStr := ''; Move(Buffer^,PChar(@tmpArray)^,BufferLength); for i:=1 to BufferLength do tmpRecvStr:=tmpRecvStr+inttohex(tmpArray[i],2); RecvPOSStr := RecvPOSStr +tmpRecvStr; OutputMemo.Lines.Add(FormatDateTime('hh:nn:ss-zzz',now)+'---->[Receive]:'); OutputMemo.Lines.Add(GetBinStrWithSpace(tmpRecvStr)); if Copy(RecvPOSStr,1,2) = '02' then begin CommandType := Copy(RecvPOSStr,3,2); try DataCount := StrToInt('$'+Copy(RecvPOSStr,5,2))*256; DataCount := DataCount +StrToInt('$'+Copy(RecvPOSStr,7,2)); DataCount := DataCount * 2; if Copy(RecvPOSStr,11+DataCount,2) <> '03' then //03开头的数据 begin MoniterMemoAppend(FormatDateTime('yy-mm-dd hh:nn:ss',now)+'---->Data format error,(02,03)。'+Copy(RecvPOSStr,11+DataCount,2),0,0,0); RecvPOSStr := ''; POSCommand := ''; Exit; end; if ((CommandType <> '40') and (CommandType <> '41') and (CommandType <> '42') and (CommandType <> '43') and (CommandType <> '44') and (CommandType <> '45') and (CommandType <> '46') and (CommandType <> '47') and (CommandType <> '48') and (CommandType <> '49') and (CommandType <> '50') and (CommandType <> '51') and (CommandType <> '52') and (CommandType <> '53') and (CommandType <> '54') and (CommandType <> '55') and (CommandType <> '60') and (CommandType <> '61') and (CommandType <> '70') and (CommandType <> '71')) then begin RecvPOSStr := Copy(RecvPOSStr,9,DataCount); if CommandType <> '03' then begin LogOutputMemoAppend(FormatDateTime('yy-mm-dd hh:nn:ss',now)+'-------------------------------->[Transaction Log]:'); OperPackageMessage(RecvPOSStr,tmpRecvStr); LogOutputMemoAppend(FormatDateTime('yy-mm-dd hh:nn:ss',now)+'-------------------------------->[End Log]'); CommandType := IntToHex(StrToInt('$'+Copy(CommandType,1,2)) + 1 ,2); SendHostScript(CommandType); end; end else begin OneCommand := Copy(RecvPOSStr,9,DataCount); POSCommand := OneCommand; RecvPOSStr := ''; if (CommandType = '46') then //请求输入密码 begin SendStringByCom(CommandType,StrToHex('ACK'));//响应ACK ExecInputPin(OneCommand); POSCommand := ''; end else if (CommandType = '47') or (CommandType = '48') or (CommandType = '49') or (CommandType = '50') then begin SendStringByCom(CommandType,StrToHex('ACK')); //响应ACK tmpRecvStr := ''; OperSimulatorMessage(CommandType ,OneCommand, tmpRecvStr ); POSCommand := ''; end else if (CommandType = '51') or (CommandType = '52') or (CommandType = '60') or (CommandType = '61') then begin SendStringByCom(CommandType,StrToHex('ACK')); //响应ACK tmpRecvStr := ''; OperSimulatorMessage(CommandType ,OneCommand, tmpRecvStr ); SendStringByCom(CommandType,tmpRecvStr); POSCommand := ''; end else if(CommandType = '70') then begin //START TEST frmMain.ChangeLedColor(PosCommand); //EMD TEST end else if(CommandType = '71') then begin //START TEST frmMain.BeepSound(PosCommand); //EMD TEST end end; RecvPOSStr := ''; except RecvPOSStr := ''; POSCommand := ''; MoniterMemoAppend(FormatDateTime('yy-mm-dd hh:nn:ss',now)+'---->Data length is not hex',0,0,0); Exit; end; end else if (Copy(RecvPOSStr,1,2) = '0D') or (Copy(RecvPOSStr,1,2) = '0A') then begin MoniterMemoAppend(FormatDateTime('yy-mm-dd hh:nn:ss',now)+'---->Log:'+HexToStr(RecvPOSStr),0,0,0); RecvPOSStr := ''; POSCommand := ''; end else begin MoniterMemoAppend(FormatDateTime('yy-mm-dd hh:nn:ss',now)+'---->Log:'+HexToStr(RecvPOSStr),0,0,0); RecvPOSStr := ''; POSCommand := ''; end;end;procedure TDtmdComm.DataModuleCreate(Sender: TObject);begin bOperPackBusy := False; PosMaxCommLen := 2000; RecvPOSStr := '';end;
以下为文件下载中判断Poscommand是否有数据的函数
function TDtmdComm.ReceACKByComm(SendCommandType:string;TimeOut:Integer): Boolean;var RecvStr:string;begin Result := False; tmrPack.Tag := TimeOut; tmrPack.Enabled := True; while True do begin if POSCommand <> '' then begin RecvStr := POSCommand; tmrPack.Enabled := False; Break; end; if not tmrPack.Enabled then //连接超时 begin Exit; end; if not bComOpened then begin tmrPack.Enabled := False; Exit; end; Application.ProcessMessages; end; if SendCommandType <> CommandType then Exit; UnpackTLV(RecvStr); FindTLV($0,RecvStr); if RecvStr <> 'ACK' then begin Exit; end else begin Result := True; end;end;
超时间为5s
文件传输函数将会对Poscommand的数据进行判断,传输过程中经常出现Poscommand数据为NULL,也就是没有成功获取从ARM设备端获取到数据从而超时的情况。
经过测试发现,在发送和接收之间增加适当的延时或者修改配置文件中ReadIntervalTimeout值对于传输超时现象有很大的改善。(最上面配置文件中红字部分)
1.当将ReadIntervalTimeout从原始的100ms增加为500ms时,无论对于Block为1k或Block为2k的传输单位都不会出现PC接收超时的情况。
2.在PC向ARM设备发送Block数据之间增加500ms的延时,也可以有效的改善PC接收超时的情况。
for j := 0 to 3 do begin Delay(500);//ms SendStringByCom('41',SendStr);//发送连接相应 if not ReceACKByComm('41',5) then//5s超时等待接收数据 begin MoniterMemoAppend(FormatDateTime('yy-mm-dd hh:nn:ss',now)+'------>Download file error['+IntToStr(j+1)+']',0,0,0); Continue; end; Break; end;
但当Delay的时间少于500ms时,每次传输超时现象出现概率大大增加。
注:以上两种方法采用任意一种均可达到消除超时的效果。
================================ 我是分割线 ======================================
分析为什么这两种操作可以改善超时?
尤其是为什么增加ReadIntervalTimeout参数可以改善超时现象?
因为根据ReadInervalTimeout的定义:
来确定所接收到的数据是否属子同一帧数据,其默认值是100ms,也就是说,只要任何两个字节到达的时间间隔小于1OOms,都被认为是属于同一帧数据。
想了半天脑袋都快炸了!!还是没有明白~哪天脑洞一开解决了这个问题再补上,先挖个坑...
就这样,祝您身体健康~