>Bo, > >Most of the users on this forum have never interfaced with hardware , as you >can see from the responses. Those who have interfaced with hardware have >developed circular buffers which they know work , and they reuse them again >and again.
I did this about 10 years ago when working on a PIC project with serial data coming in from sensors and such, using Ansi-C. And the buffer was just an array of char (byte in pascal) and there was a read and a write index. The read index was only ever changed by the consumer and the write index by the interrupt routine when adding data. The data reception was done in the interrupt and the code stuffed the data into the array using ++ syntax for the index, with a check for overflowing the array and then setting the index back to zero. There was probably also an overrun detection and action if the consumer is not fast enough, but I do not remember now... > >The following assumes you are receiving data from a sender , and in this >case the sender and receiver are connected via 1Gbps Ethernet using Synapse >(works really well). > > >A thread receives data into an array of byte. RxBuffer : Array[0..1500] of >byte ... and copies the number of bytes received into a circular buffer , >which is an array of RxBuffer. This is where I lose you, are you saying the circular buffer is not individual bytes but something larger? What is the size of RxBuffer? Looks like it is an array of byte, can you then make an array of such arrays? ... The CicBuffer is an array of N RxBuffer , which is an array of byte. The main loop extracts the byte array and either decodes them or type casts them into a record structure if it is compatible with the contents of the byte array, Type RxBufferType = array[0..1500] of byte; Var CirBuffer : array[0..N] of RxBufferType; > >In pseudo code it looks like this ... >CircularBuffer : Array[0..N] of RxBuffer >There is a ReadIndex and a WriteIndex , both longword or longint. > >The thread moves the data into the circular buffer continuously increase >the WriteIndex each write of RxBuffer data. If the WriteIndex > N then >WriteIndex := 0 , otherwise it is increased by 1. > >The main loop (below) moves the byte data using MOVE from CircBuffer to >whatever structure it represents , increase the ReadIndex by one and decodes >the data as needed. Looks like an array of some bigger datatype then. But if so then one needs to be able to detect in the receiver that enough data has arrived to make one such object to put onto the next buffer... ... you appear to be thinking of a asynchronous serial (RS-232 / 422) with no delimiters to indicate when a complete message is received. ... think of the byte array as an Ethernet packet of any length data of which the data structure is known. This is received using Synapse (UDP in this case) and copied into RxBuffer byte array by a thread which is always running until the main program is shut down. Whenever the thread receives a "complete" packet from Synapse (it signals a complete packket) , the thread code then puts it into RxBuffer and then copies RxBuffer into CircBuffer[WriteIndex] and increments the WriteIndex. If the WriteIndex < N then WriteIndex := WriteIndex +1 else WriteIndex := 0 // wraps The ReadIndex is incremented similar to the WriteIndex, if ReadIndex < N then ReadIndex := ReadIndex +1 else ReadIndex := 0; The circular buffer can be made as large as you need to "absorb" incoming data while the main loop is busy doing something else. The "nice" aspect of a circular buffer is that if the main loop is very slow and the incoming data stream is very fast , the WriteIndex will eventually overrun the ReadIndex and data is lost but nothing chokes or crashes , and eventually the ReadIndex will catch up. BTW : There are enough things that can go wrong implementing a circular buffer , and while it should be possible (and very nice) to implement it as an object , it may not be worth the effort. At least get it working as non-object code , then decide. > > If ReadIndex <> WriteIndex then > .. do the work as described above and increment the ReadIndex > >I use the Free Pascal unit which allows suspending the thread while the >ReadIndex is being increased. In the old DOS/DPMI days we would disable >interrupts briefly. Do you use CriticalSection for this? No . .. I started to originally but found it wasn't necessary as it uses a semaphore to prevent a Write occurring when the ReadIndex is being incremented. The FPC unit syncobjs is used the create a semaphore which is RESET before incrementing the ReadIndex and SET immediately after. This prevents a potential race condition where data could be written to CircBuffer at the exact time the ReadIndex is being incremented. >If you are innterested I can send you code snippets showing exactly how to >implement the circular buffer. > BTW : The circular buffer approach can also be used when transmitting data. For example Synapse maintains its own transmit buffers , which signal when you can send more data. -- Sent from: http://free-pascal-general.1045716.n5.nabble.com/ _______________________________________________ fpc-pascal maillist - fpc-pascal@lists.freepascal.org https://lists.freepascal.org/cgi-bin/mailman/listinfo/fpc-pascal