请吕雪松老师帮助解决一个问题 ( 积分: 100 )

  • 主题发起人 主题发起人 liuql188
  • 开始时间 开始时间
L

liuql188

Unregistered / Unconfirmed
GUEST, unregistred user!
这是我的garmin手持机接收程序,后面是运行结果,
为什么接受的长度多数是64,极少数是63,并且长度是63的,解析后的name少一个字符,alt,dpth也不正确。
程序源码:
====================
type
TGPSWayPoint = class
Name : string;
comment : string;
wpt_class : byte;
color : byte;
dspl : byte;
Alt : single;
dpth : single;
Dist : single;
attr : byte;
smbl : word;

X : single;
Y : single;
private


public
{ Public declarations }
end;


Packet_t = record
mPacketType:char;
mReserved1:char;
mReserved2:word;
mPacketId:word;
mReserved3:word;
mDataSize:Longword ;
mData: array of byte;
end;


TGarminGPSForm = class(TForm)
Comm1: TComm;
Dbf1: TDbf;
DataSource1: TDataSource;
DBGrid1: TDBGrid;
Memo1: TMemo;
Panel1: TPanel;
open: TButton;
close: TButton;
Button1: TButton;
Button2: TButton;
Splitter1: TSplitter;
procedure SendACK(RecByte : Byte);
function CalcCheckSum(var sPack : string) : integer;
function GetCoordinate(Semicircle : string) :do
uble;
//4 char
procedure Translate_D108_Wpt_type(Package : string);
function GetIntData(strData: string;
nbegin
Pos, nLength: integer): integer;
function FixPackage(var sPack:string ):integer
function unFixPackage(var sPack : string) : integer;
function GetSingleData(sPack:string;pos,len:integer):single;
procedure openClick(Sender: TObject);
procedure closeClick(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Comm1ReceiveData(Sender: TObject;
Buffer: Pointer;
BufferLength: Word);
procedure Button2Click(Sender: TObject);
procedure showmsg(fx,str:string);
private
{ Private declarations }
public
{ Public declarations }
end;


var
GarminGPSForm: TGarminGPSForm;

implementation

{$R *.dfm}

procedure TGarminGPSForm.showmsg(fx,str:string);
var str1:string;
i:integer;
begin

str1:=fx;
for i:= 1 to length(str)do

str1:=str1+inttohex(ord(str),1);
memo1.Lines.Append(str1);

end;



function TGarminGPSForm.GetSingleData(sPack:string;pos,len:integer):single;

var
buf : array[0..3] of byte;
begin

buf[0] := ord(sPack[pos]);
Buf[1] := ord(sPack[pos+1]);
Buf[2] := ord(sPack[pos+2]);
Buf[3] := ord(sPack[pos+3]);
Move(Buf, result, 4);
end;



procedure TGarminGPSForm.Translate_D108_Wpt_type(Package : string);
var
XX,YY :do
uble;
WPt : TGPSWayPoint;
//航点类,没什么特别的,你可以设计你自己的。
szSubPack : string;
maxID:integer;
begin

WPt := TGPSWayPoint.Create;//建一个航点实例

szSubPack:=Copy(Package,52,length(Package)-48);//取航点名称,可以是中文,注意有可能有很多空格,早期etrex大概只有5个汉字,而后期的和航海GPS可能有很长的中文名
Wpt.Name := Copy(szSubPack, 1, Pos(#0, szSubPack) - 1);

Wpt.Name := Trim(Wpt.Name);
Delete(szSubPack, 1, Pos(#0, szSubPack));
wpt.comment := Copy(szSubPack, 1, Pos(#0, szSubPack) - 1);//取其中的备注部分,一般是空的,Vista可能会把建立航点的时间写在这里。
Wpt.wpt_class := Ord(Package[4]);
wpt.color := Ord(Package[5]);
wpt.dspl := Ord(Package[6]);
wpt.Alt := GetSingleData(Package,36,4);
if Wpt.Alt > 10E10 then
Wpt.Alt := 0;
wpt.dpth := GetSingleData(Package,40,4);
if Wpt.Dpth > 10E10 then
Wpt.Dpth := 0;
wpt.Dist := GetSingleData(Package,44,4);
if Wpt.Dist > 10E10 then
Wpt.Dist := 0;
{
dspl_name = 0, /* Display symbol with waypoint name */
dspl_none = 1, /* Display symbol by itself */
dspl_cmnt = 2 /* Display symbol with comment */
}
wpt.attr := Ord(Package[7]);
{ The "attr"
member should be set to a value of 0x60.}
wpt.smbl := GetIntData(Package,8,2);

YY := GetCoordinate(Copy(Package,28,4));
XX := GetCoordinate(Copy(Package,32,4));


//WPt.AddPt(XX,YY);
dbf1.Append;

dbf1.FieldByName('id').AsInteger:=1;
dbf1.FieldByName('name').asstring:=wpt.Name;
dbf1.FieldByName('comment').AsString:=wpt.comment;
dbf1.FieldByName('wpt_class').AsInteger:=wpt.wpt_class;
dbf1.FieldByName('color').asinteger:=wpt.color;
dbf1.FieldByName('dspl').AsInteger:=wpt.dspl;
dbf1.FieldByName('alt').AsFloat:=wpt.Alt;
dbf1.FieldByName('dpth').AsFloat:=wpt.dpth;
dbf1.FieldByName('dist').AsFloat:=wpt.dist;
dbf1.FieldByName('attr').AsInteger:=wpt.attr;
dbf1.FieldByName('xx').asfloat:=xx;
dbf1.FieldByName('yy').asfloat:=yy;
dbf1.Post;
end;


//从报文中解析坐标
function TGarminGPSForm.GetCoordinate(Semicircle : string) :do
uble;
//4 char
begin

if semicircle='' then

result:=0
else

result := (Ord(SemiCircle[1]) + Ord(SemiCircle[2]) * Power(2,8) + Ord(SemiCircle[3]) * Power(2,16) + Ord(SemiCircle[4]) * Power(2,24)) * 180/Power(2,31);
end;

//根据字节计算出整数来
function TGarminGPSForm.GetIntData(strData: string;
nbegin
Pos, nLength: integer): integer;
var
I : integer;
begin

result := 0;
for I := 1 to nLengthdo
begin

result := result + Round(Ord(StrData[nbegin
Pos + (I - 1)]) * Power(2,8 * (I - 1)));
end;

end;

procedure TGarminGPSForm.SendACK(RecByte : Byte);
var
sPack : string;
begin

sPack := #16;
sPack := sPack + Chr(Pid_Ack_Byte);
sPack := sPack + #2;
sPack := sPack + Chr(RecByte);
sPack := sPack + #0#0#16#3;
CalcCheckSum(sPack);
comm1.WriteCommData(pchar(sPack),length(sPack));

end;


function TGarminGPSForm.CalcCheckSum(var sPack : string) : integer;
var
nCheckByte : Byte;
I : integer;
begin

try
nCheckByte := 0;
for I := 0 to Ord(sPack[3])do
begin

nCheckByte := nCheckByte + Ord(sPack[I + 2]);
end;

sPack[4 + Ord(sPack[3])] := Chr(256 - nCheckByte);
result := Ord(sPack[4 + Ord(sPack[2])]);
//#16->#16#16
FixPackage(sPack);
except

end;

end;


function TGarminGPSForm.FixPackage(var sPack : string) : integer;
//#16->#16#16
var
n:integer;
I : integer;
str1:string;
begin

try
n:=0;
str1:=sPack;
sPack:=#16;
for I := 2 to length(str1)-2do

begin

if str1=#16 then

begin
//若是#16,则先插入一个
sPack:=sPack+#16;
n:=n+1;
end;

sPack:=sPack+str1;
end;

sPack:=sPack+#16#3;
result := n;
except
end;

end;


function TGarminGPSForm.unFixPackage(var sPack : string) : integer;
//#16#16->#16
var
n:integer;
I : integer;
str1:string;
begin

try
n:=0;
str1:=sPack;
sPack:=#16;
for I := 2 to length(str1)-2do

begin

if (str1=#16) and (str1[i+1]=#16) then

begin
//若是连续两个#16,则放弃第一个
n:=n+1;
end
else

sPack:=sPack+str1;
end;

sPack:=sPack+#16#3;
result := n;
except
end;

end;




procedure TGarminGPSForm.openClick(Sender: TObject);
begin

comm1.StartComm;
end;


procedure TGarminGPSForm.closeClick(Sender: TObject);
begin

comm1.StopComm;
end;


procedure TGarminGPSForm.Button1Click(Sender: TObject);
var
i: integer;
cmd:string;
begin

cmd:=#16;
cmd:=cmd+chr(Pid_Command_Data);
cmd := cmd + #2;
cmd := cmd + Chr(Cmnd_Transfer_Wpt);
cmd := cmd + #0#0#16#3;
calcCheckSum(cmd);
showmsg('W:',cmd);
comm1.WriteCommData(pansichar(cmd),length(cmd));
end;


procedure TGarminGPSForm.Comm1ReceiveData(Sender: TObject;
Buffer: Pointer;
BufferLength: Word);
var
frambuf:string;
pp:pchar;
i: integer;
begin

frambuf:='';
// memo1.Lines.Append('正在接收串口数据...');
pp:=buffer;
for i:=1 to bufferlengthdo

begin

frambuf:=frambuf+pp^;
pp:=pp+1;
end;

unFixPackage(frambuf);
showmsg('R:<'+inttostr(bufferlength)+'-'+inttostr(length(frambuf))+'> ',frambuf);
showmsg('W:',frambuf[2]);

sendAck(ord(frambuf[2]));
if frambuf[2]=#35 then

begin

Translate_D108_Wpt_type(frambuf);
end;

end;


====================================
运行结果:
R:<64-64> 10233A0FF060120000000FFFFFFFFFFFFFFFFFFFFFFFF6718621BD20A2510CB71425159469515946920202020303133320000008B103
W:23
R:<64-64> 10233A0FF060120000000FFFFFFFFFFFFFFFFFFFFFFFF72FA611BA8E9A151E0677B425159469515946920202020303133330000005A103
W:23
R:<64-64> 10233A0FF060120000000FFFFFFFFFFFFFFFFFFFFFFFFB5D1611B8D3A151E02D684251594695159469202020203031333400000042103
W:23
R:<64-64> 10233A0FF060120000000FFFFFFFFFFFFFFFFFFFFFFFFEFAA611BE5C4A1510CB714251594695159469202020203031333500000099103
W:23
R:<64-64> 10233A0FF060120000000FFFFFFFFFFFFFFFFFFFFFFFF3888611BD1AEA1510CB71425159469515946920202020303133360000009B103
W:23
R:<63-63> 10233A0FF060120000000FFFFFFFFFFFFFFFFFFFFFFFF5560611B3C97A151408142515946951594692020202030313337000000BB103
W:23
R:<64-64> 10233A0FF060120000000FFFFFFFFFFFFFFFFFFFFFFFF862E611B387BA151D0ED904251594695159469202020203031333800000060103
W:23
 
我一般不会像你这样来充分信任COM口的缓冲,也就是说串口通讯不一定能一次读出来完整的报文,有可能会截断报文的。所以我会设一个缓冲区,简单地说就是设一个string变量buf,从串口读出来的报文拼在buf变量后面,然后从头检查buf,看是否存在一个以上的完整报文(#16->#16#3),有的话就取走,并处理。这样我能保证要处理的报文肯定是完整的,而你这样的处理方式,有可能会有不完整的报文进入处理流程,一方面会读错,另一方面也会丢失报文。
 
原来大虾还在!
 
我做了多次试验,每次都是在相同的位置出现错误,不知道是否是你说的原因,
我有点怀疑是fixpackage和unfixpackage函数有错误,我写得对吗?能把你的两个函数贴出来吗?
能否把你从COM口接收和处理数据的过程贴出来?

已经分析了四天,头都大了。万望吕老师慷慨帮忙!
 
又试验了几天,还是找不到任何规律。

自己顶一下,请吕老师快乐帮忙。
 
顶一下!
 
procedure TForm1.Comm1ReceiveData(Sender: TObject;
Buffer: Pointer;
BufferLength: Word);
var
CurCommData,S: string;
i: integer;
begin

SetLength(CurCommData,BufferLength);
Move(Buffer^, PChar(CurCommData)^, BufferLength);
Edt1.Text := CurCommData;

S := '';
for i := 1 to Length(CurCommData)do

S := S + CurCommData+ ' ';
Memo1.Lines.Add(S);
end;
 
后退
顶部