The “shift string element” example I mentioned here was part of a request I had for a little OptoScript to make a note if a certain tag changed.
For example, we’re working on some new interactive demos (be sure to sign up on groov.com for updates) that involve a “your name in lights” sign where you can change a text string and it shows up “in lights” (visible via a webcam). But we’d like to make a note when someone types in their name or other message.
I wanted to make this code a little generic/reusable since a couple of coworkers of mine wanted to add some similar logic to the controllers in their homes.
Here’s what I came up with (no pointers involved!) -- do share if you have questions or other ideas. In the attached chart, which you can import into your own 9.3 Basic or better strategy, I give 2 options for the “make a note” part:
1) You can write it to a file to get a log like the one shown below (I prefer Firefox for easy reading of a text file on your PAC):
2) You can store this info a string table, where element  has the most recent entry.
(Or you can do both, which is what the attached chart currently does – adjust as needed.)
In the first OptoScript block, I initialize a list of the names of the tags I want to monitor. (Optional comment/label in the second column of string table initializations here.) I also open the local log file.
// Create a list of the values to log when they change
// Optional label (if you want more info than just the tag name)
stTagList = "fFloat"; stLabels = "My test float";
stTagList = "nInt32"; stLabels = "An int 32";
stTagList = "di_R1_0000"; stLabels = "digital input";
stTagList = "sSignString"; stLabels = "here's your sign";
// Open file to log to
nCHResult = OpenOutgoingCommunication(chLogFile);
In the “Check variables for changes” OptoScript block, I use the handy command GetValueFromName to grab the current value of each tag in my list (as a string) and compare it with the previous value:
// Initialize loop variables
nTableIndex = 0;
// Loop through all the tags to check, see if they're different, and make a note if they are
while ( IsVariableFalse( nDone ) )
// See if we've reached the end of the list (the first blank or bad tag name)
if ( GetValueFromName(stTagList[nTableIndex], stCurrentValue[nTableIndex]) <> 0 ) then
else // we need to compare this value to the last one
// see if it's changed
if ( 0 == CompareStrings(stCurrentValue[nTableIndex],
stLastValue[nTableIndex] ) ) then
// the value hasn't changed
// the value has changed, made a note, starting w/a date/timestamp
sLogMessage = sDate + " " + sTime + " " + stTagList[nTableIndex] + " '" +
stLabels[nTableIndex] + "' changed to: '" +
stCurrentValue[nTableIndex] + "'" + chr(0xD) + chr(0xA);
// MAKE A NOTE HERE
// update "last value"
stLastValue[nTableIndex] = stCurrentValue[nTableIndex];
if (nTableIndex >= GetLengthOfTable(stTagList)) then
In the “MAKE A NOTE” part, I give two options, shown below. But you could also send an email or something else if you’d like.
// MAKE A NOTE HERE
/** "make a note" Option #1: write to file *****/
nCHResult = TransmitString(sLogMessage, chLogFile);
// Check number of bytes left for RAM filespace
nResultRAMbytes = GetAvailableFileSpace(0);
// Check to see how much room we have for the log file
if (nResultRAMbytes < 100) then // put a warning in the queue
AddMessageToQueue(16, "chLogFile out of file space.");
elseif (nResultRAMbytes < 1000) then // put a warning in the queue
AddMessageToQueue(8, "chLogFile running low on filespace");
/** end option 1 */
/*** option 2 (Ben's choice) - string table w/most recent entry at the top */
// Read what's currently in the SP strings (so we can shift them down one)
//GetIoUnitScratchPadStringTable(I/O Unit, Length, From Index, To Index, To Table)
nSPResult = GetIoUnitScratchPadStringTable(R1, 63, 0, 1, stEventLog);
// Load element  of the table
stEventLog = sLogMessage;
// Write the updated log list to the scratch pad
//SetIoUnitScratchPadStringTable(I/O Unit, Length, To Index, From Index, From Table)
nSPResult = SetIoUnitScratchPadStringTable(R1, 64, 0, 0, stEventLog);
/** end option 2 */
Of course, this will miss any changes that happen inside the scanning interval. But for a simple event log, I thought this might be handy to others out there!
ChangeLogChart.zip (3.09 KB)