Place to put your Basic demos and examples

Moderator: Mmiscool

User avatar
By Electroguard
#69441 I created this Circular FIFO buffer for playing sequences of pre-recorded words and numbers on a JQ6500 serial Media Player module, which uses the Busy pin to signal when ready for the next item in the queue, until the queue is empty.

If you have need of such a thing - perhaps slowly feeding out IP address digits for display - then it saves you from having to re-invent that wheel.

It is deceptively simple to use...
1. Set 'qmax' to be more than the max number of entries you will need in the queue at any one time.
2. Push your desired qitem$ strings onto the back of the queue using GOSUB [qpush].
3. Pull the next available item from the front of the queue into qitem$ using GOSUB [qpull].
4. GOSUB [qshow] gives a peek at all items in the queue without affecting them, qsize tells you how many items are in the queue.

The script includes comments with more info, and demo data to show what is happening.


If you care to know how it works:
The FIFO (first in, first out) queue (or buffer) has 2 pointers, one for the front of the queue and one for the back. Initially they both point to array q$(0).
Pushing an item onto the next available location at the back of the queue will store it in the array location pointed to by back, which is then incremented to point to the next available empty location.
Pulling the next item from the front of the queue will free up that front location, and the front pointer is incremented to point to the next available full location.
So pushing and pulling to and from the queue will cause the front and back pointers to keep incrementing upwards.
When a pointer reaches the qmax upper limit it will wrap around and start from q(0) again... hence why it is called circular.
If the queue is empty, both pointers will point to the same location.
Attempting to pull from an empty queue will cause an error.
Attempting to push to a full queue will cause an error.
The script comments show how to trap and avoid those errors, in which case the queue can keep on circulating.

Code: Select all'Circular FIFO queue - qsize shows the number of qitem$ entries up to qmax buffer size (increase qmax to suit)
'[qpull] reads and removes first qitem$ from the front of queue (then increments the qfront pointer)
'[qpush] adds a new qitem$ to the back of the queue (then increments the qback pointer)
'[qpeek] enables queue contents to be viewed without being 'pulled' from queue
'[qshow] does a qpeek of all entries in the queue
'When pointers reach qmax top end they wrap-around to the beginning again forming a continuous circle.
'Pushing to a full queue, or pulling from an empty queue, will terminate on error by default (can be modified)
'Suggest to check qsize (as done in [PUSH] and [PULL]) before attempting to read or write, rather than disable error trapping.
'The FIFO was created for a Voice Announcer to send sequences of individual recorded words via serial2 to a JQ6500 wav/mp3 player.
'The "next" word was pulled from the FIFO queue when the player signaled with its 'busy' pin that the "previous" play was ended.
'So the logic was: While qsize > 0, if Busypin not active then pull next qitem$ from FIFO and send to serial2. 
'Here is just the raw circular FIFO code for including into your own projects for your own purposes.   
'
qmax = 5 'size of fixed circular buffer - arbitrary test size, increase to suit
dim q$(qmax) 'defines a queue for strings
qitem$ = ""  'used for reading and writing string entries to q$
qfront = 0
qback = 0
qsize = 0
'Example for using [qpush], [qpull], [qshow]
html "qmax=" & qmax & " (arbitray maximum Q test size, increase to suit)<BR>"
html "Q starting out empty: size=" & qsize & ", front=" & qfront & ", back=" & qback & "<BR>"
html "Pushing Q almost full (qmax-1)... <BR>"
for count = 1 to qmax - 1
 html count & "<BR>"
 qitem$ = str(count)
 gosub [qpush]
next count
html "Q pushed almost full: size=" & qsize & ", front=" & qfront & ", back=" & qback & "<BR>"
html "Peeking at contents...<BR>"
gosub [qshow]
html "No change after peek: size=" & qsize & ", front=" & qfront & ", back=" & qback & "<BR>"
html "Pushing Q once more to fill it...<BR>"
qitem$ =str(qmax)
gosub [qpush]
html "Q pushed full (to qmax): size=" & qsize & ", front=" & qfront & ", back=" & qback & " note pointer wrapped around to 0<BR>"
html "Pulling Q to empty...<BR>"
for count = 1 to qsize
 gosub [qpull]
 html qitem$ & "<BR>"
next count
html "Q pulled empty: size=" & qsize & ", front=" & qfront & ", back=" & qback & "<BR>"
html "Attempting to pull from empty Q which will cause abort with error...<BR>"
gosub [qpull]
wait


[qpush]
if qsize + 1 > qmax then
 html "ERROR: Queue is full"
 end
else       
 q$(qback) = qitem$   'Add item to back of q 
 qsize = qsize + 1    'Increment qsize
 qback = (qback + 1) % qmax   'Adjust the back pointer
endif
return

[qpull]
if qsize < 1 then
 html "ERROR: Queue is empty"
 end
else
 qitem$ = q$(qfront)   'Remove item from front of q
 qsize = qsize - 1  'Decrement qsize
 qfront = (qfront + 1) % qmax '  Adjust the front pointer
endif
return

[qpeek]  'peeks at item specified by pos(isition) in queue
if pos <= qsize then
 html "qitem " & pos & " = " & q$((qfront + pos - 1) % (qmax)) & "<BR>"
else
 html "ERROR: Peek past end of queue"
endif
return

[qshow]  'peeks at all Q entries
for pos = 1 to qsize
 gosub [qpeek]
next pos
return

'----------- End of Circular FIFO queue -----------