Re: [fpc-pascal] Reading Serial Hex Data
El 28/12/2020 a las 2:02, James Richters via fpc-pascal escribió: I think I figured out why my writeln's are causing an issue.. they are introducing a delay between the SerWrite and SerRead... and the device I am reading is timing out and sending it's response a second time. Hello, None of the serial devices I have seen do something like that, in fact usually they do exactly the opposite, fire and forget, or in other words send a message and do not check for errors unless they wait for an answer from the host. Your problem seems to be or a documentation misinterpretation or the connection or the device is not using any kind of flow control. I was under the impression that there was a hardware buffer on the serial ports, my packets are very small, some only a few bytes, but even those are not going into any kind of a hardware buffer. Hardware buffers in serial device is 16 bytes (In fact 14 for receive) at most and it is managed by the Windows serial driver to garantee no byte is lost. The operation scheme is something like: 1- Serial byte received 2- IRQ signal issued 3- Windows serial driver read serial port and copy byte(s) to driver buffer. 4- Signal IRQ as handled. The 16 bytes hardware (FIFO) buffer is present to garantee that if steps between 2 and 4 takes too much time (this is time scaled in 1990's CPU power) no byte is lost. If an Intel 8088 can read 115200bps without any byte lost think what a today computer can read. In order to perform tests there are programs where you create an hex string to be sent and inspect the answer from the device. Read documentation about how to open the port, specially about the flow control sync. XOn/XOff, RTS/CTS. In example some need that you raise the RTS line and wait for CTS line to be high before write, if you do not wait the device can misinterpret your request and hang or answer something stupid, this is automatically done by the Windows serial driver if you select the RTS/CTS flow control when open the port. Have a nice 2021! -- ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Reading Serial Hex Data
On Mon, 28 Dec 2020 14:12:02 +0100, Jean SUZINEAU via fpc-pascal wrote: >Le 28/12/2020 à 13:16, Bo Berglund via fpc-pascal a écrit : >> Synchronize(CallEvent); //Supply received data in FBuffer to >> caller > >You are using TThread.Synchronize. > >In a console app, it's likely that somewhere else in your main thread >you'll need to call regularly Classes.CheckSynchronize to allow the >actual execution of CallEvent. > >In my case, linux server dll called by a 4js 4GL console program (no GUI >on linux server), I need to call regurlarly Classes.CheckSynchronize >froml 4gl through function exported by the pascal code. >If I don't do this, the CallEvent is nether called. > Where I use the fpserial class for communications over RS232 there is an "eternal" loop in the main program, which for a console program is what is really running: {$IFDEF UNIX} //What to do for system messages procedure handleSignal(signum: CInt); cdecl; begin case signum of SIGHUP : bSHup := true; SIGTERM : bSTerm := true; SIGINT : bSInt := true end; end; {$ENDIF} program //Create all objects and start processes {$IFDEF UNIX} //Make sure there is a signal handler fpSignal(SigTerm, SignalHandler(@handleSignal)); fpSignal(SigInt, SignalHandler(@handleSignal)); fpSignal(SigHup, SignalHandler(@handleSignal)); {$ENDIF} //Now wait for signals: While not (bSTerm or bSInt or bsHup) do //React to system signals begin //Here is where the server runs as defined elsewhere //Eternal loop to wait for system messages Sleep(1); //To not hog the CPU CheckSynchronize; //Enable events to fire off handlers end; //cleanup and exit ... end. The program is intended to run as a Linux service and so it reacts to the service manager's messages which are coming in via the handleSignal procedure. The main action is controlled by socket handlers started by the preliminaries in the main program and which are triggered by events from various sources like TCP/IP connections, timers etc. -- Bo Berglund Developer in Sweden ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Reading Serial Hex Data
Le 28/12/2020 à 13:16, Bo Berglund via fpc-pascal a écrit : Synchronize(CallEvent); //Supply received data in FBuffer to caller You are using TThread.Synchronize. In a console app, it's likely that somewhere else in your main thread you'll need to call regularly Classes.CheckSynchronize to allow the actual execution of CallEvent. In my case, linux server dll called by a 4js 4GL console program (no GUI on linux server), I need to call regurlarly Classes.CheckSynchronize froml 4gl through function exported by the pascal code. If I don't do this, the CallEvent is nether called. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Reading Serial Hex Data
On Sun, 27 Dec 2020 18:20:32 -0500, James Richters via fpc-pascal wrote: >>On Sun, 27 Dec 2020 10:47:59 -0500, James Richters via fpc-pascal >> wrote: >> >>>I'm trying to figure out how to read a packet of HEX Bytes of an >>>unknown length that have no specific termination character over a >>>serial port as efficiently as practical. >> >>What exactly do you mean by HEX Bytes? >>Hex transfers using two characters for each byte? like 1F A4 etc? > >What I meant by 'Hex Data' is that I am reading data in the form of bytes but >they do not represent ASCII characters. >So if I read a $0D, it's just a byte $0D, it doesn't represent a carriage >return. There is no specific code for end of line, >the last two bytes are a checksum, but I won't know they are the last ones >until I'm done reading. >I'm reading all the data available, then analyzing it. > This is NOT wahat is generally meant by hex data, hex data means bytes are encoded using the ASCII characters 0..9, A..F thus expanding data size by x2 while making it possible to send over channels that use control characters to handle transfer details such as line feeds, start of text and end of text etc. What you have is straight binary data >> >>Is your program a console or GUI program? > >This is a console application. I suspected as much. Many of the serial components available are geared towards GUI apps and so for instance LazSerial links in stuff like Forms and menus and the like, which causes exceptrions when running in a straight GUI-less environment like a Linux server. So I created a class named fpserial where I packaged the functions I needed and used the built-in Serial unit as the basic execution handler. This class uses an event model to supply incoming data, which are received inside a thread and supplied via a synchronized call to the event function in the main thread of the program. Being a console program it has a loop which includes CheckSynchronize to handle this. After I did that I have had no problems talking to external hardware sending and receiving data in binary streams. But there is a "protocol" for the transfers implemented to allow some control. It looks something like this: Where length is a 4-byte integer containing the length of the transfer body and checksum is a 16 bit sum over all of the bytes inside the body (excluding the checksum). The messages are sent following a handshake between the two sides. My thread code looks like this: { TComPortReadThread } TComPortReadThread=class(TThread) private FBuffer: TBytes; FReadPacketSize: integer; FReadTimeout: integer; public MustDie: boolean; Owner: TFpSerialPort; property ReadPacketSize: integer read FReadPacketSize write FReadPacketSize; //How many bytes to read in each operation property ReadTimeout: integer read FReadTimeout write FReadTimeout;//Max time to wait for data in thread protected procedure CallEvent; procedure Execute; override; published property Terminated; end; implementation { TComPortReadThread } procedure TComPortReadThread.CallEvent; begin if Assigned(Owner.FOnRxData) then begin Owner.FOnRxData(Owner, FBuffer); end; end; procedure TComPortReadThread.Execute; var Cnt: integer; begin try SetLength(FBuffer, BUFFERSIZE); //Set buffer size to 8192 bytes. while not MustDie do begin cnt := SerReadTimeout(Owner.FHandle, FBuffer[0], FReadPacketSize, FReadTimeout); //Read FReadPacketSize bytes with timeout of FReadTimeout ms if cnt > 0 then begin SetLength(FBuffer, cnt); //Reduce size to fit received data Synchronize(CallEvent); //Supply received data in FBuffer to caller SetLength(FBuffer, BUFFERSIZE); //Reset buffer size to 8192 bytes. end; end; finally Terminate; end; end; HTH -- Bo Berglund Developer in Sweden ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal
Re: [fpc-pascal] Reading Serial Hex Data
Op 12/27/2020 om 4:47 PM schreef James Richters via fpc-pascal: I'm trying to figure out how to read a packet of HEX Bytes of an unknown length that have no specific termination character over a serial port as efficiently as practical. The packet ends when there is just no more data to read. I have something that is working that I wrote using SerRead from the Serial unit in FPC, and it works at 9600bps, but the method I am using will not work well at anything higher unless I can figure out how to a very accurate very short delay. At 9600, I need a delay just a little less than 1ms, so I use Sleep(1) for my delay, but since 1ms is the minimum for sleep, and sleep itself is not really that accurate, I am doing a lot more delay than I need to in order to make sure it works. You don't mention OS, but for Windows no sleep should not be necessary, and is unnecessarily delaying. Look at delphi tcomport which has a waitforevent based solution. ___ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal