Todays example uses a dll to access a Barcode Scanner. The used Barcode Scanner is the CS1504 (SDK available here).
The CS1504 has a buffer where it stores all scanned barcodes and this buffer can be accessed via a COM-Port. Luckily, the SDK has a dll which takes care of the communication. The only problem is, that the header is written in C/C++. I translated it (in parts) to Delphi, you can grab the file here.
Now we could just use it as is, but it would be much nicer if we had a class to wrap it all up.
We need some object to store the data, which is really simple:
And now the class that does all the work:
The TScanner class returns a generic TList<TBarcode> with all the Barcodes from the device.
The most important function is of course getBarcodes.
The implementation is pretty much straight forward, the trickiest part was to convert the 4-byte timestamp from each barcode to TDateTime. They crammed the six values for year, month, day, hour, minute and second into 4 bytes. (seriously, a SD Card that has the size of my fingernail can hold easily 4 GB and they worry about 2 bytes per scanned barcode)
This uses T4Bytes which is a packed record.
The bytes are accessible indivudually and as the resulting 4-Byte Cardinal.
Full Sourcecode is available here.
The CS1504 has a buffer where it stores all scanned barcodes and this buffer can be accessed via a COM-Port. Luckily, the SDK has a dll which takes care of the communication. The only problem is, that the header is written in C/C++. I translated it (in parts) to Delphi, you can grab the file here.
Now we could just use it as is, but it would be much nicer if we had a class to wrap it all up.
We need some object to store the data, which is really simple:
TBarcode = class private fTimestamp : TDateTime; fCode : string; public constructor Create(aTimestamp : TDateTime; aCode : string); property TimeStamp : TDateTime read fTimestamp; property Code : string read fCode; end;
And now the class that does all the work:
TScanner = class private fPort : integer; fReady : boolean; fHasData: boolean; function TimestampToDateTime(aTimestamp : Ansistring) : TDateTime; public constructor Create(aPort : integer); destructor Destroy; override; function getBarcodes : TList<TBarcode>; procedure clearBarcodes; property IsReady : boolean read fReady; property HasData : boolean read fHasData; procedure setDateTime(aDateTime : TDateTime); function getDateTime : TDateTime; end;
The TScanner class returns a generic TList<TBarcode> with all the Barcodes from the device.
The most important function is of course getBarcodes.
function TScanner.getBarcodes: TList<TBarcode>; var bc : TBarcode; i, count, pl : integer; buffer : array[0..63] of AnsiChar; dt : TDateTime; s : string; begin result := TList<TBarcode>.Create; begin count := csp2ReadData; for i := 0 to count -1 do begin FillChar(buffer,64,#0); pl := csp2GetPacket(@buffer,i,63); // The Last 4 Bytes hold the timestamp dt := TimestampToDateTime(copy(buffer,pl-3,4)); s := copy(buffer,3,pl-6); bc := TBarcode.Create(dt,s); result.Add(bc); end; end; end;
The implementation is pretty much straight forward, the trickiest part was to convert the 4-byte timestamp from each barcode to TDateTime. They crammed the six values for year, month, day, hour, minute and second into 4 bytes. (seriously, a SD Card that has the size of my fingernail can hold easily 4 GB and they worry about 2 bytes per scanned barcode)
function TScanner.TimestampToDateTime(aTimestamp: Ansistring): TDateTime; var i1,i2,i3,i4,i5,i6 : integer; qb : T4Bytes; y,m,d,h,n,s : word; begin // CharToByte qb.Bytes[3] := Ord(aTimestamp[1]); qb.Bytes[2] := Ord(aTimestamp[2]); qb.Bytes[1] := Ord(aTimestamp[3]); qb.Bytes[0] := Ord(aTimestamp[4]); // split up the bits i1 := qb.Total and $fc000000; // 6 Bit i2 := qb.Total and $03f00000; // 6 Bit i3 := qb.Total and $000f8000; // 5 Bit i4 := qb.Total and $00007c00; // 5 Bit i5 := qb.Total and $000003c0; // 4 Bit i6 := qb.Total and $0000003f; // 6 Bit // Shift right to align the bits s := i1 shr 26; n := i2 shr 20; h := i3 shr 15; d := i4 shr 10; m := i5 shr 6; y := i6; result := EncodeDate(y+2000,m,d) + EncodeTime(h,n,s,0); end;
This uses T4Bytes which is a packed record.
T4Bytes = packed record case Integer of 0: (Bytes: array[0..3] of Byte); 1: (Total: Cardinal); end;
The bytes are accessible indivudually and as the resulting 4-Byte Cardinal.
Full Sourcecode is available here.
Keine Kommentare:
Kommentar veröffentlichen