#1 IoDrvFB: Error in Logger after download

1.0
open
nobody
None
2024-11-12
2019-01-03
Ingo
No

Missing UpdateMapping in IoDrvFB leads to error in logger.

1 Attachments

Discussion

  • Strucc.c

    Strucc.c - 2024-11-10

    Hmmmm... After messing some hours with that error message, I finally found this ticket - and yes, the solution is suggested in the title.

    So the module, inputs, outputs were working OK, just this stupid message in the PLC Log.

    Seems like, in order to implement ICmpIoDrv one have to say something about Module Mapping. Looking at the Parameters for the call, I assume It has stg to do with the possible mapping of parameters to different tasks... Has stg to do with this:

    As all this was working OK, I assume (maybe incorrectly) that it is not necessary to do anything in this call, unless you really want to do so... So, - assuming again - that these things were taken care of already somewhere high in the IoDrv, I just set the status to ERR_OK in the call.

    This seems to fix the issue. Let me know if I am wrong...

     

    Last edit: Strucc.c 2024-11-10
  • Strucc.c

    Strucc.c - 2024-11-12

    Update:

    Meanwhile I understood the meaning of this call. At least I think I did. Roughly:

    PLEASE FEEL FREE TO CORRECT ME IF I AM WRONG, I AM STILL JUST EXPLORING

    IoDrvUpdateMapping is not needed, if you take care all of your input / output parameters at IoDrvUpdateConfigurtion, by providing a memory location, where the IoDrv should read/write the parameters from.

    This is done by assigning a pointer to memory location, probably to a variable instance with the proper type and size the parameter.dwDriverSpecific value. This is the value, what the default IoDrvReadInputs / IoDrvWriteOutputs are looking for.

    For a practical reason there is no built in safety in these calls - so you just get an Exception - access violation, when the RT / IoDrv finds a blank value here. This happens, if you have defined Input/Output parameters in the XML Device Description, but you did not set their .dwDriverSpecific member to a valid pointer. It's actually very practical for a developer... Naturally, can go around and avoid the Exception:

    {attribute 'conditionalshow'}
    METHOD IoDrvReadInputs : UDINT
    VAR_INPUT
        pConnectorMapList : POINTER TO IoConfigConnectorMap;
        nCount : DINT;
    END_VAR
    VAR
        i, j : DINT;
        pParam : POINTER TO IoConfigParameter;
        pChannel : POINTER TO IoConfigChannelMap;
    END_VAR
    
    // Returns if parameter error
    IF pConnectorMapList = 0 OR nCount = 0 THEN
        IoDrvReadInputs := Errors.ERR_PARAMETER;
        RETURN;
    END_IF
    
    // Go trough _all_ the channels of _all_ connectors, and copy the input parameters from the area specified by dwDriverSpecific
    FOR i:=0 TO nCount - 1 DO
        IF (pConnectorMapList[i].dwNumOfChannels = 0) THEN
            CONTINUE;
        END_IF
        FOR j:= 0 TO TO_UINT(pConnectorMapList[i].dwNumOfChannels) - 1 DO   
            pChannel := ADR( pConnectorMapList[i].pChannelMapList[j] );
            pParam := pChannel^.pParameter;
    
            IF (pParam <> 0) AND_THEN ( pParam^.dwDriverSpecific <> 0 ) THEN
                IoMgrCopyInputLE ( pChannel, pParam^.dwDriverSpecific );    
            END_IF
    //      IoMgrCopyInputLE(
    //          pChannel := ADR( pConnectorMapList[i].pChannelMapList[j] ), 
    //          pAddress := pConnectorMapList[i].pChannelMapList[j].pParameter^.dwDriverSpecific);
        END_FOR
    END_FOR
    
    IoDrvReadInputs := Errors.ERR_OK;
    

    Maybe, this small additional code explains a little bit better, what is IoDrvBase doing for us, and how IoDrvReadInputs / IoDrvWriteOutputs are actually working: They look for for dwDriverSpecific, as a default "mapping", and if they don't find, just throw up.

    This is not the end of the World, you can just implement these calls according to your needs. But... be careful, there are many tricky things are taken care of in the background: especially when it comes to tasks, multicore, memory allocation, etc....

    (By the way, it would be nice someone could react, what might be an issue with the above modification ... - because I see some :) )

    IoDrvUpdateMapping can be practical, if you don't want to bind the input / output process data to a pre-determined, fixed, hard-coded variable. For example, you would like to "map" the process data of all your modules ("sub devices") in a continuous memory area... for some reason... maybe package them for network transfer? Or you just don't want to implement a special function block for each of your modules? Who knows... Life is dangerous.

    The big advantage is, that at the point when this call is initiated, all connectors are already initialized and configured, so you can traverse the complete device tree... Like:

    FOR I:= 0 TO nCount -1 DO
        MyTaskMap := pTaskMapList[I];
        IF MyTaskMap.pConnectorMapList <> 0 AND MyTaskMap.wNumOfConnectorMap <> 0 THEN
            FOR J := 0 TO MyTaskMap.wNumOfConnectorMap - 1 DO
                MyConnMap := MyTaskMap.pConnectorMapList[J];
                IF myConnMap.pChannelMapList <> 0 AND MyConnMap.dwNumOfChannels <> 0 THEN
                    FOR K := 0 TO MyConnMap.dwNumOfChannels - 1 DO
                        pMyChannelMap := ADR (myConnMap.pChannelMapList[K]);
    
                        // ...  
                    END_FOR
                END_IF
            END_FOR
        END_IF
    END_FOR
    

    But once again - it is not necessary to set all the .dwDriverSpecific pointers. Just deal with the consequences.

    One example is, if you prepare a driver for a modular device - you can not predict the number of inputs / outputs, not even the structure of the configuration data - all this happens ad-hoc, when the station is assembled and configured in the device editor...

     

Log in to post a comment.