P E Schoen
2016-08-19 06:19:06 UTC
I have an application that uses a serial port component to read and write
data through a USB serial port at 57.6 kb. Originally I used the SerialNG
component and with some tweaking I was able to get it to work reliably. But
it has problems with Win10, so I changed the code to use ComDrv32, which
works when used in a simple TTY demo.
The SerialNG component uses clusters or packets which can be set to a range
of values. I am communicating with a USB device set up as a CDC serial
emulator using Microchip PIC18F2550. It is basically a data acquisition unit
that samples at 2400 samples/sec with a 10 bit ADC. I am splitting the data
into two 5 bit values in 8 bit data characters, and I'm using the remaining
three to identify the data as a MSB or LSB (using one evem/odd bit), and a
two bit value to determine if the data has been received in proper sequence.
Here is the function that receives the data from the serial port component:
===============================================================
procedure TfmCommLib.CommPortDriver1ReceiveData(Sender: TObject;
DataPtr: Pointer; DataSize: Cardinal);
var
RecdPtr: PChar;
CSize, NCSize : Integer;
n: Integer;
begin
RecdPtr := PChar(DataPtr);
RxDcount := DataSize;
if RxDcount > MaxRxDcount then
MaxRxDcount := RxDcount;
if CommBufferPtr + DataSize >= MAXCOMM then begin
move( DataPtr^, CommBuffer[CommBufferPtr], MAXCOMM-CommBufferPtr );
n := DataSize - (MAXCOMM-CommBufferPtr);
RecdPtr := RecdPtr+n;
DataPtr := RecdPtr;
CommBufferPtr := 0;
move( DataPtr^, CommBuffer[CommBufferPtr], n );
end
else begin
move( DataPtr^, CommBuffer[CommBufferPtr], DataSize );
CommBufferPtr := CommBufferPtr + DataSize; end;
CommCharCount := CommCharCount + DataSize;
if(CommCharCount > MAXCOMM) then
CommCharCount := MAXCOMM+1;
end;
========================================================
It works, but I get errors after running for about 20 seconds. That
corresponds to the point where the CommBuffer will overflow the MAXCOMM
value of 100,000 (4800*20). My previous code for SerialNG used a cluster
size of 2 and a loop to transfer the received data to the buffer one byte at
a time. When I tried that, it seemed to work poorly. So I used a variation
of the method from the ComDrv32 TTY demo using move( DataPtr^,
CommBuffer[CommBufferPtr], DataSize ); But you can see that I had to split
the transfer when near the end of the queue.
I had to use a separate PChar pointer RecdPtr, and I also had to use an
integer for the pointer arithmetic. Apparently Delphi does not allow RecdPtr
:= RecdPtr + (DataSize - (MAXCOMM-CommBufferPtr) ); RecdPtr + n is OK. I'm
not sure if I could just advance the DataPtr in the same way, since it is
declared as a generic Pointer type.
I can't very well use the Delphi debugger to see what's happening, as the
data is received continuously and there is no handshaking.
TIA for any suggestions.
Paul
data through a USB serial port at 57.6 kb. Originally I used the SerialNG
component and with some tweaking I was able to get it to work reliably. But
it has problems with Win10, so I changed the code to use ComDrv32, which
works when used in a simple TTY demo.
The SerialNG component uses clusters or packets which can be set to a range
of values. I am communicating with a USB device set up as a CDC serial
emulator using Microchip PIC18F2550. It is basically a data acquisition unit
that samples at 2400 samples/sec with a 10 bit ADC. I am splitting the data
into two 5 bit values in 8 bit data characters, and I'm using the remaining
three to identify the data as a MSB or LSB (using one evem/odd bit), and a
two bit value to determine if the data has been received in proper sequence.
Here is the function that receives the data from the serial port component:
===============================================================
procedure TfmCommLib.CommPortDriver1ReceiveData(Sender: TObject;
DataPtr: Pointer; DataSize: Cardinal);
var
RecdPtr: PChar;
CSize, NCSize : Integer;
n: Integer;
begin
RecdPtr := PChar(DataPtr);
RxDcount := DataSize;
if RxDcount > MaxRxDcount then
MaxRxDcount := RxDcount;
if CommBufferPtr + DataSize >= MAXCOMM then begin
move( DataPtr^, CommBuffer[CommBufferPtr], MAXCOMM-CommBufferPtr );
n := DataSize - (MAXCOMM-CommBufferPtr);
RecdPtr := RecdPtr+n;
DataPtr := RecdPtr;
CommBufferPtr := 0;
move( DataPtr^, CommBuffer[CommBufferPtr], n );
end
else begin
move( DataPtr^, CommBuffer[CommBufferPtr], DataSize );
CommBufferPtr := CommBufferPtr + DataSize; end;
CommCharCount := CommCharCount + DataSize;
if(CommCharCount > MAXCOMM) then
CommCharCount := MAXCOMM+1;
end;
========================================================
It works, but I get errors after running for about 20 seconds. That
corresponds to the point where the CommBuffer will overflow the MAXCOMM
value of 100,000 (4800*20). My previous code for SerialNG used a cluster
size of 2 and a loop to transfer the received data to the buffer one byte at
a time. When I tried that, it seemed to work poorly. So I used a variation
of the method from the ComDrv32 TTY demo using move( DataPtr^,
CommBuffer[CommBufferPtr], DataSize ); But you can see that I had to split
the transfer when near the end of the queue.
I had to use a separate PChar pointer RecdPtr, and I also had to use an
integer for the pointer arithmetic. Apparently Delphi does not allow RecdPtr
:= RecdPtr + (DataSize - (MAXCOMM-CommBufferPtr) ); RecdPtr + n is OK. I'm
not sure if I could just advance the DataPtr in the same way, since it is
declared as a generic Pointer type.
I can't very well use the Delphi debugger to see what's happening, as the
data is received continuously and there is no handshaking.
TIA for any suggestions.
Paul