Building on the ideas suggested by cwal61, one approach could use the following design/implementation strategy:
. Create a user-defined-type (UDT) consisting of three elements: barcode string, time remaining, duplicate count. Let's say they are of types STRING, DINT, and DINT, respectively, where the time remaining is in milliseconds.
. Create an array of these UDTs large enough to hold the maximum number of unique strings (e.g., 20 elements) that could be read within the time frame of interest (e.g., 15 seconds).
. Create a recurring (pulse) timer at the resolution to purge stale barcodes from the tracking array (e.g., every one second).
. Create a single instance of the barcode data UDT as a working unit.
. When a new barcode arrives, first search for it in the UDT array using the FSC instruction. The comparison will look something like 'arrBarcodeData[bcFSCctrl.POS].strBarcode = newBarcode'. For efficiency, set the FSC length equal to the FIFO array position, and RES prior to executing the FSC.
. >> If the barcode is found (i.e. bcFSCctrl.POS.FD is set), increment the duplicate count for that array element. No other action is required.
. >> If the barcode is not found, then copy the newBarcode string into the working UDT instance, and initialize its duplicate count to zero, and time remaining to the time frame of interest (e.g., 15000). Then load this working instance into the FIFO using FFL with the UDT array and the working instance as the source.
. Every time the pulse timer expires, execute a FAL on the UDT array to decrement all the remaining time of all active elements by the pulse timer preset (e.g., 1000). This will look something like 'arrBarcodeData[bcFALctr.POS].RemainTime' as destination with expression 'arrBarcodeData[bcFALctr.POS].RemainTime - 1000'. Again, set the FAL length to the FIFO position for efficiency.
. Also, after the FAL, purge all of the stale barcodes from the UDT array using the FFU to remove the oldest elements whose remaining time has expired. This would be done by testing the remaining time of zero element of the UDT array as less than or equal to zero. If so, execute FFU on the UDT array. The unloaded UDT will indicate how many times it experienced a duplicate read.
. >> Since there could be multiple expired elements, it may be necessary to do more than one FFU after the pulse timer expires. One way is to latch a "purge stale" bit after the FAL. Then unlatch this bit when the remaining time of the zero element is greater than zero or the FIFO is empty. Execute the FFU on every scan while this bit is set.
. Be sure to use the FIFO control.EM bit (i.e., not empty) to precondition the FAL, FSC, and FFU in order to avoid operating on an empty UDT array.
If you want to count active duplicates at any time, you could use an FAL to sum up the duplicate counters in the FIFO. Or if you want to keep track of duplicates over a long period of time, you could sum the duplicate counts of the elements as they are unloaded from the FIFO.
After coding some of this, I did start to wonder it might be easier to read and maintain using loops and routines instead of FAL and FSC. Although the code is quite compact with the traditional FAL/FSC/FFL/FFU approach.