Search code examples
arraysimportvbscripttia-portal

Why do I get a "VBScript runtime error: Overflow" only when writing to a variable?


I need some assistance from any of the VBScript wizards out there.

I'm currently working on Import/Export functions which are capable of moving data between an SD card local to an industrial PLC, and a USB local to an HMI (control panel). This is all being programmed in the Tia-Portal V15.1 programming environment.

When the export function is initiated, the PLC breaks down all 64135 bytes of data from its local SD card into a transfer buffer (ie. multiple arrays of bytes (array[array[bytes]])) in a data block (DB). The transfer buffer is referenced by the HMI, and can be accessed without issue by the VBScripts called within. This is done by referencing the variable USBSD_Interface_TransferBuffer.Datapack_#. Using a FOR-loop, the VBScript counts through each of the elements, and can write them to a log file on the connected USB:

'#############################################################################################
'#                            HANDSHAKE TO WRITE DATA TO FILE                                #
'#-------------------------------------------------------------------------------------------#
Dim LOCAL_BUFFERSIZE : LOCAL_BUFFERSIZE = 1599          ' Array[0..1599] = 1600 entries
Const MAX_ARRAYSIZE = 64135                             ' Max number of elements in array
Const MAX_ARRAYCOUNTER = 40                             ' 40 * 1600 = 64000 values
Dim BUFFER_COUNTER : BUFFER_COUNTER = 0
Dim ARRAY_COUNTER : ARRAY_COUNTER = 0
'#############################################################################################

For ARRAY_COUNTER = 0 To MAX_ARRAYCOUNTER
    If ARRAY_COUNTER = MAX_ARRAYCOUNTER Then
        ' Catch case of final datapack only holding 135 elements
        LOCAL_BUFFERSIZE = 135  
    End If
    
    For BUFFER_COUNTER = 0 To LOCAL_BUFFERSIZE
        FILE.WriteLine SmartTags("USBSD_Interface_TransferBuffer.Datapack_" & ARRAY_COUNTER)(BUFFER_COUNTER)
    Next
Next

Although reading from the array and writing the data to an external file worked without issue, the same cannot be said for the Import function. Here, I attempted to do the exact same thing, yet in reverse. I first load the file and place each entry into a variable (FILEDATA), which is essentially an array of values. These values are then iterated through, and written to the corresponding position in the transfer buffer:

'#############################################################################################
'#                         HANDSHAKE TO WRITE DATA TO TEMP-DB                                #
'#-------------------------------------------------------------------------------------------#
Const MAX_ARRAYSIZE = 40
Const MAX_ELEMENTS = 64135
Dim LOCAL_BUFFERSIZE : LOCAL_BUFFERSIZE = 1599
Dim ARRAY_COUNTER : ARRAY_COUNTER = 0
Dim BUFFER_COUNTER : BUFFER_COUNTER = 0
Dim ELEMENT_COUNTER : ELEMENT_COUNTER = 0
'#############################################################################################

For ARRAY_COUNTER = 0 To MAX_ARRAYSIZE
    If ARRAY_COUNTER = MAX_ARRAYSIZE Then
        LOCAL_BUFFERSIZE = 135
    End If
    
    For BUFFER_COUNTER = 0 To LOCAL_BUFFERSIZE
        SmartTags("USBSD_Interface_TransferBuffer.Datapack_" & ARRAY_COUNTER)(BUFFER_COUNTER) = CByte(FILEDATA(ELEMENT_COUNTER))
        ELEMENT_COUNTER = ELEMENT_COUNTER + 1
    Next
    
    If ELEMENT_COUNTER >= MAX_ELEMENTS Then
        Exit For
    End If
Next

I'm currently getting the following error when running my script:

0x800a0006 - Microsoft VBScript runtime error: Overflow: 'BUFFER_COUNTER'

This only occurs during the Import phase, when the counter reaches BUFFER_COUNTER = 99 of the first datapack (ie. ARRAY_COUNTER = 0).

Out of sheer desperation, I tried brute-forcing the first 100 variables by hand to see if the FOR-loop was causing a problem via:

SmartTags("USBSD_Interface_TransferBuffer.Datapack_0")(0) = CByte(FILEDATA(0))
SmartTags("USBSD_Interface_TransferBuffer.Datapack_0")(1) = CByte(FILEDATA(1))
SmartTags("USBSD_Interface_TransferBuffer.Datapack_0")(2) = CByte(FILEDATA(2))
...
SmartTags("USBSD_Interface_TransferBuffer.Datapack_0")(99) = CByte(FILEDATA(99))
SmartTags("USBSD_Interface_TransferBuffer.Datapack_0")(100) = CByte(FILEDATA(100))

... which resulted in the same overflow error at position 99. I know all of the transfer buffer arrays are instantiated, because I can read/write their values individually. For example, calling:

SmartTags("USBSD_Interface_TransferBuffer.Datapack_0")(99) = CByte(FILEDATA(99))
SmartTags("USBSD_Interface_TransferBuffer.Datapack_0")(100) = CByte(FILEDATA(100))
SmartTags("USBSD_Interface_TransferBuffer.Datapack_0")(101) = CByte(FILEDATA(101))
SmartTags("USBSD_Interface_TransferBuffer.Datapack_0")(102) = CByte(FILEDATA(102))

... results in no error. This error only seems to arise when I attempt to write to more than 98 elements in the array during the VBScript's execution.

I'm really at a loss with this one. If anyone has run into a similar issue before, any tips/tricks/workarounds would be very much appreciated!


Solution

  • Speaking to other professionals on the matter, the reason for this error has been found. The "overflow" is not an overflow of the counter variable, but an overload condition of the processing time/power of the hardware when writing too many variables, in too short of a time (irregardless what the Microsoft error said).

    The recommended solution was to create a pause or time-loop to force the HMI to stop and process the already-called variables, before attempting to write to new ones. The loop would be nestled in the main FOR-loop, and would look something like this:

    If ELEMENT_COUNTER Mod 50 = 0 Then
      Dim WAIT_TIME : WAIT_TIME = Now + 1 / 24 / 3600 ' wait for one second
      Do
      Loop While Now <= WAIT_TIME
    End If
    

    This recommendation unfortunately came too late: I had already created a temporary solution of my own, which inadvertently circumvented the issue, without realizing exactly what the issue was. I created a secondary buffer of 50 bytes in the PLC which is filled by the HMI. Once filled, the HMI sends a signal to the PLC, and the PLC systematically fills the main buffer with the values in the secondary buffer, before sending a signal to the HMI to continue the process. This handshake continues until the main buffer is filled.

    I believe I will make my temporary solution more 'permanent', regardless the fact it is a little slower than the recommended solution. If I'm not mistaken, it is a general rule of thumb in programming to avoid the use of pauses and wait-functions, unless the calling function itself is time-dependent. Even then, they should be treated with caution.