我有这个PCB用 ATMEL-microcontroller通过 TCP 通信 Lantronix Xport .它使用 30 字节长的 asci 字符串发送一些继电器和传感器的状态报告,格式如下:
400000000000000000414243303031303030303030303030303030303339
| | | |
| byte[0] = $40 | | |
| | |- byte[11] = $43 // 'C' Always
| |--- byte[10] = $42 // 'B' Always
|----- byte[9] = $41 // 'A' Always
byte[1..8] = boolean values := Bool(byte[x]);
byte[12..29] = 6 different numbers as string, 3 chars long each, range 0..999
我对数据包的加载状态做了一个简单的验证:
procedure Load(iData: TBytes);
const vsp = 9; //Validation String Postition
buflen = 30;
begin
If (Length(iData) = buflen) And (iData[0] = $40) And (iData[vsp] = $41) And (iData[vsp + 1] = $42) And (iData[vsp + 2] = $43) Then
SetStatus(iData) //Function for loading validated packet
Else Begin
DoError(1, 'Invalid packet. Length = ' + IntToStr(Length(iData)) + #13#10 +
'iData[0] = ' + String(ByteToHex(iData[0])) + #13#10 +
'iData[vsp] = ' + String(ByteToHex(iData[vsp])) + #13#10 +
'iData[vsp + 1] = ' + String(ByteToHex(iData[vsp + 1])) + #13#10 +
'iData[vsp + 2] = ' + String(ByteToHex(iData[vsp + 2]))
);
End;
End;
问题是有时 asci 字符串被拆分成几个数据包或连接成一个数据包(第一个数字是 tickcount):
4239483 4000 // Could be missing in case of disconnect-reconnect.
4239514 00000000000000414243303030303030303030303030303030303338400000000000000000414243
4239545 303031303030303030303030303030303339
4239576 400000000000000000414243303031303030303030303030303030303339400000000000000000414243303031303030303030303030303030303338
4239670 40000000000000000041424330303130
4239701 3030303030303030303030303339
在断开连接-重新连接的情况下,部分状态信息将丢失。
我如何利用 TMemoryStream 或 Move 来读取收到的每个数据包而不丢弃任何信息?
编辑: SetStatus 看起来像这样,所以我想避免将状态报告移植到字符串:
Procedure TTractor.SetStatus(AData: TBytes);
begin
StatusStream := AData;
pStatus.HighSpeed := Bool(AData[1]);
pStatus.RevDir := Bool(AData[2]);
pStatus.FwdDir := Bool(AData[3]);
pStatus.FrontExpanded := Bool(AData[4]);
pStatus.RearExpanded := Bool(AData[5]);
pStatus.AntiSpin := Bool(AData[6]);
pStatus.Unknown1 := DecodePCBNumber(AData[12], AData[13], AData[14]);
pStatus.PumpPressureVoltage := DecodePCBNumber(AData[15], AData[16], AData[17]);
pStatus.Unknown2 := DecodePCBNumber(AData[18], AData[19], AData[20]);
pStatus.WheelPressureVoltage := DecodePCBNumber(AData[21], AData[22], AData[23]);
pStatus.OilTemperatureVoltage := DecodePCBNumber(AData[24], AData[25], AData[26]);
pStatus.PCBTemperatureVoltage := DecodePCBNumber(AData[27], AData[28], AData[29]);
End;
阅读代码:
procedure TForm1.FormCreate(Sender: TObject);
begin
If Traktor = nil Then Traktor := TTractor.Create(500);
//...
End;
// TidConnectionIntercept
procedure TForm1.trCItcReceive(ASender: TIdConnectionIntercept; var ABuffer: TArray<System.Byte>);
Var
tmpList: TList;
i: Integer;
Begin
If Traktor <> nil Then Traktor.StatusTBytes := ABuffer;
AppendConLog(TraktorReceive, False, False, BytesToHexStr(ABuffer) );
End;
procedure TForm1.AppendConLog(LogTyp: TLogType; ShowInConsole, PlainText: Boolean; Text: String);
begin
If ShowInConsole Or (PlainText And DebugMode) Then Begin
MemoConsole.Lines.Add(FormatDateTime('[hh:nn:ss] ', Now) + Text);
Text := String2Hex(AnsiString(Text));
End;
LogFile.Add(IntToHex(DateTimeToUNIXTimeFAST(Now()), 8) + ' ' + IntToHex(GetTickCount, 8) + ' ' +
IntToHex(Word(ShowInConsole), 1) + IntToHex(Word(PlainText), 1) + ' ' +
IntToHex( Ord(LogTyp), 2) + ' ' + Text);
end;
Type TTractor = class
constructor Create(LoadInterval: Cardinal; SyncInterval: Cardinal = 25);
//....
public
property StatusTBytes: TBytes read StatusStream write Load;
//...
End;
最佳答案
Intercept.OnReceive 事件不会自行触发,它是在另一个读取操作的上下文中触发的。您显示的代码中没有任何内容执行任何读取,因此永远不会触发 OnReceive 事件。
Intercept 用于操作数据(压缩、加密等),而不是用于检测何时读取数据。请改用 IOHandler 方法,例如 ReadBytes()。 TIdIOHandler 有自己的内部缓冲区来为您处理拆分/连接的数据包。这让您可以专注于更高级别的逻辑(读取 30 字节的消息),而 Indy 处理较低级别的细节(循环读取直到 30 字节可用,缓存未使用的数据以供后续读取等)。
完全去掉Intercept,然后在需要的时候调用TIdTCPClient.IOHandler.ReadBytes(),例如:
在计时器中:
procedure TForm1.IdTCPClient1Connected(Sender: TObject);
begin
ReadTimer.Enabled := True;
end;
procedure TForm1.IdTCPClient1Disconnected(Sender: TObject);
begin
ReadTimer.Enabled := False;
end;
procedure TForm1.ReadTimerElapsed(ASender: TObject);
var
Buffer: TIdBytes;
Begin
try
if IdTCPClient1.IOHandler.InputBufferIsEmpty then
begin
IdTCPClient1.IOHandler.CheckForDataOnSource(10);
IdTCPClient1.IOHandler.CheckForDisconnect;
if IdTCPClient1.IOHandler.InputBufferIsEmpty then Exit;
end;
IdTCPClient1.IOHandler.ReadBytes(Buffer, 30);
except
IdTCPClient1.Disconnect;
Exit;
end;
If Traktor <> nil Then Traktor.StatusTBytes := Buffer;
AppendConLog(TraktorReceive, False, False, BytesToHexStr(Buffer) );
End;
或者在工作线程中:
type
TDataEvent = procedure(const Data: TIdBytes) of object;
TReadingThread = class(TThread)
private
FBuffer: TIdBytes;
FClient: TIdTCPClient;
FOnData: TDataEvent;
procedure DoData;
protected
procedure Execute; override;
public
constructor Create(AClient: TIdTCPClient; AOnData: TDataEvent); reintroduce;
end;
constructor TReadingThread.Create(AClient: TIdTCPClient; AOnData: TDataEvent);
begin
inherited Create(False);
FClient := AClient;
FOnData := AOnData;
end;
procedure TReadingThread.Execute;
begin
while not Terminated do
begin
FClient.IOHandler.ReadBytes(FBuffer, 30);
Synchronize(DoData);
end;
end;
procedure TReadingThread.DoData;
begin
if Assigned(FOnData) then FOnData(FBuffer);
end;
var
ReadThread: TReadingThread = nil;
procedure TForm1.IdTCPClient1Connected(Sender: TObject);
begin
ReadThread := TReadingThread.Create(IdTCPClient1, DataAvailable);
end;
procedure TForm1.IdTCPClient1Disconnected(Sender: TObject);
begin
if Assigned(ReadThread) then
begin
ReadThread.Terminate;
ReadThread.WaitFor;
FreeAndNil(ReadThread);
end;
end;
procedure TForm1.DataAvailable(const Data: TIdBytes);
begin
If Traktor <> nil Then Traktor.StatusTBytes := Data;
AppendConLog(TraktorReceive, False, False, BytesToHexStr(Data) );
end;
关于Delphi 将数据包附加到 TBytes,验证并读取,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22436523/
给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru
我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val
我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss
好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信
我有一些非常大的模型,我必须将它们迁移到最新版本的Rails。这些模型有相当多的验证(User有大约50个验证)。是否可以将所有这些验证移动到另一个文件中?说app/models/validations/user_validations.rb。如果可以,有人可以提供示例吗? 最佳答案 您可以为此使用关注点:#app/models/validations/user_validations.rbrequire'active_support/concern'moduleUserValidationsextendActiveSupport:
当我的预订模型通过rake任务在状态机上转换时,我试图找出如何跳过对ActiveRecord对象的特定实例的验证。我想在reservation.close时跳过所有验证!叫做。希望调用reservation.close!(:validate=>false)之类的东西。仅供引用,我们正在使用https://github.com/pluginaweek/state_machine用于状态机。这是我的预订模型的示例。classReservation["requested","negotiating","approved"])}state_machine:initial=>'requested
我有一个服务模型/表及其注册表。在表单中,我几乎拥有服务的所有字段,但我想在验证服务对象之前自动设置其中一些值。示例:--服务Controller#创建Action:defcreate@service=Service.new@service_form=ServiceFormObject.new(@service)@service_form.validate(params[:service_form_object])and@service_form.saverespond_with(@service_form,location:admin_services_path)end在验证@ser