Communicating with Codesys

laythea
2010-06-25
2011-02-28
  • laythea - 2010-06-25

    Hello,

    I am trying to communicate between Codesys and my Window application. I have heard of PLCHandler which enables this, but use of this is not an option as its not free.

    The Windows application creates a Windows Shared Memory area, lets say called "DataArea".

    The Codesys application makes use of the SysShm system library.

    In my Codesys application, I am then using the SysSharedMemoryOpen2() function to open this memory area, and then using the SysSharedMemoryRead() and SysSharedMemoryWrite() to get data in and out of the "DataArea" memory block.

    I have read that if I have 2 Windows applications communicating via Windows Shared Memory, then I am supposed to use synchronisation to, for example, avoid one application reading data whilst the other is still writing data.

    I have searched through the Codesys libraries/literature, and cannot find anything that would enable me to "lock" a Windows Shared Memory area whilst I am writing to it in Codesys, so that my Windows app can wait until the lock has been released before reading data from it (and vice-versa)

    I should mention, that I have the setup "working" without any kind of locking mechanisms and it seems to work fine, but having read things about the need for synchronisation between windows applications, I am concerned that I may be missing something here????

    Anyone have any experience of this kind of thing?

    Thanks

    Laythe

     
  • Rolf-Geisler - 2010-06-25

    Hello,

    best way to communicate between CoDeSys and Windows is an OPC connection.

    Shared memory works only, if PLC and Windows are running on the same machine (or at least in the same rack). To have access to the shared memory, you will need a driver running as part of the Windows side of communication. The driver probably has to be a special build for the PLC in use. OPC obviates all these problems.

    Yes, OPC server maybe not free.

    You will need an OPC client running inside the Windows side of communication. OPC is documented pretty well (available in the WWW), any Windows software developer should be able to build such a component. Then, the big advantage is to have a communication method, which works with any PLC, even with remote machines.

    Regards,

    Rolf

     
  • laythea - 2010-07-20

    Hi,

    Thanks for the reply.

    I have wrote my own application that interfaces to the Windows Shared Memory areas which I have setup and populated with data in CodeSys, so this is not a problem. This is not really a 'driver'; its just a normal windows application.

    The PLC is running on top of Windows XPe, so it is not a problem to run my driver program. I don't need them to be seperate. I am familiar with OPC and its advantages, however it is an overkill for my requirements, both in terms of cost and performance overhead.

    I have this setup with my Windows application already working fine. There does not seem to be a problem, however my Windows application will be running for years once deployed (with the occasional restart), and I have not tested it for any great length of time. Therefore, the question was, do I need to protect memory access to the Windows Shared Areas, and if so how?

    I can do this protection in my application via the normal semaphore etc protection mechanisms, but I cannot find anything in CodeSys which will avoid the CodeSys application reading data from a Windows Shared Memory area whilst I am still writing data into the memory block from my Windows application.

    I guess I am looking for a Codesys library that allows me to access the Windows semaphores etc?

    Thanks
    Laythe

     
  • pohg - 2011-02-28

    Hi,

    do you have a runnable application?

     
  • laythea - 2011-02-28

    Can you be a bit more specific?

    Cheers
    Laythe

     
  • pohg - 2011-02-28

    I want to try the following scenario.

    Create a shared memory in a .NET application with the kernel32 function "CreateFileMapping". And now I want to read or write to this memory in CoDeSys.

     
  • laythea - 2011-02-28

    Ok, sounds similar to what I have got setup. In my case I have seperate memory areas, either for reading or writing.

    For Reading data:

       //------------------------------------------------------------------------------------------------------
       // Get a handle to the shared windows memory area
       //------------------------------------------------------------------------------------------------------
       IF (hDriverToCodeSys = RTS_INVALID_HANDLE OR mWindowsShmInitialisationError = TRUE  ) THEN
          hDriverToCodeSys := SysSharedMemoryOpen2(dbName, 0, ADR(dbSizeBytes), ADR(rxResult));   
          IF (hDriverToCodeSys = RTS_INVALID_HANDLE) THEN
             mWindowsShmInitialisationError := TRUE;
          ELSE
             mWindowsShmInitialisationError := FALSE;   
          END_IF
       END_IF
       mTmrWindowsShmInitialisationErrorTimeout(IN := mWindowsShmInitialisationError, PT := MB_TIMEOUT);
       mWindowsShmInitialisationErrorTimeout := mTmrWindowsShmInitialisationErrorTimeout.Q;
       
       //------------------------------------------------------------------------------------------------------
       // If we have got a handle to the shared memory area, then read data from it
       //------------------------------------------------------------------------------------------------------
       IF( mWindowsShmInitialisationError = FALSE ) THEN   
          rxBytesRead := SysSharedMemoryRead ( hDriverToCodeSys, 0, rxBufferPointer, dbSizeBytes, ADR(rxResult));   
          IF (rxBytesRead <> dbSizeBytes) THEN
             mWindowsShmReadError := TRUE;
          ELSIF (rxBytesRead = dbSizeBytes) THEN         
             mWindowsShmReadError := FALSE;
          END_IF
       END_IF
       mTmrWindowsShmReadErrorTimeout(IN := mWindowsShmReadError, PT := MB_TIMEOUT);
       mWindowsShmReadErrorTimeout := mTmrWindowsShmReadErrorTimeout.Q;
       //------------------------------------------------------------------------------------------------------
       // Extract Raw byte buffer data in Data Block word array
       // Note. Do not just do this if rxDataOK = TRUE as then we will not be able to re-establish comms
       // after eg a rolling count timeout!
       //------------------------------------------------------------------------------------------------------
       FOR wordIter:=0 TO (dbSizeBytes/2)-1 BY 1 DO   
          // Get Byte 1 value
          byteValue1 := rxBufferPointer[wordIter*2];
          byteValue2 := rxBufferPointer[(wordIter*2)+1];
          
          // Word value = byteValue1|(byteValue2<<8)
          wordValue := byteValue1;
          wordValue := wordValue OR SHL(byteValue2,8);
          
          // Assign DB word value
          rxDBBufferPointer[wordIter] := wordValue;      
       END_FOR;
       
    

    For writing data:

       //------------------------------------------------------------------------------------------------------
       // Get a handle to the shared windows memory area
       //------------------------------------------------------------------------------------------------------
       IF (hCodeSysToDriver = RTS_INVALID_HANDLE OR mWindowsShmInitialisationError = TRUE) THEN
          hCodeSysToDriver := SysSharedMemoryOpen2(dbName, 0, ADR(dbSizeBytes), ADR(txResult));
          IF (hCodeSysToDriver = RTS_INVALID_HANDLE) THEN
             mWindowsShmInitialisationError := TRUE;
          ELSE
             mWindowsShmInitialisationError := FALSE;   
          END_IF
       END_IF 
       mTmrWindowsShmInitialisationErrorTimeout(IN := mWindowsShmInitialisationError, PT := MB_TIMEOUT);
       mWindowsShmInitialisationErrorTimeout := mTmrWindowsShmInitialisationErrorTimeout.Q;
       
       //------------------------------------------------------------------------------------------------------
       // If we have got a handle to the shared memory area, then write data to it 
       //------------------------------------------------------------------------------------------------------
       IF( mWindowsShmInitialisationError = FALSE ) THEN   
          
          // Copy Block word array into Tx Byte Buffer
          FOR wordIter:=0 TO (dbSizeBytes/2)-1 BY 1 DO   
             
             // Get the value of the current word in the DB
             wordValue := txDBBufferPointer^;
             
             // Extract word value from two consecutive bytes in the tx buffer
             byteValue1 := WORD_TO_BYTE( wordValue AND 255 );
             byteValue2 := WORD_TO_BYTE( SHR(wordValue,8) AND 255);
             
             // Copy the bytes into the tx byte buffer
             txBuffer[(wordIter*2)] := byteValue1;
             txBuffer[(wordIter*2)+1] := byteValue2;
          
             // Next word   
             txDBBufferPointer := txDBBufferPointer +2;
          END_FOR;      
       
          // Write the data
          txBytesWrote := SysSharedMemoryWrite ( hCodeSysToDriver, 0, txBufferPointer, dbSizeBytes, ADR(txResult));   
          IF (txBytesWrote <> dbSizeBytes) THEN
             mWindowsShmWriteError := TRUE;
          ELSIF (txBytesWrote = dbSizeBytes) THEN         
             mWindowsShmWriteError := FALSE;
          END_IF
       END_IF   
       mTmrWindowsShmWriteErrorTimeout(IN := mWindowsShmWriteError, PT := MB_TIMEOUT);
       mWindowsShmWriteErrorTimeout := mTmrWindowsShmWriteErrorTimeout.Q;   
    

    These are just snippets, but should hopefully be helpful.

    Cheers
    Laythe

     

Log in to post a comment.