Adding custom functions

Adding a custom functions to the MODBUS MASTER stack if very easy. The recommend layout is to create a new source file, e.h. mbmfunccustom1.c within the directory mbmaster/functions. Or example function code will use the function code 0x32 and will allow us to transmit up to 100 byte of application data. The format of the request is shown below:

Function code Length Payload
0x32 Length (1Byte) Payload (100Bytes max)

A slave device which will receive this request will either acknowledge the data transfer using an ACK (0x00) or will indicate an failure NACK (0xFF).

Function code Status
0x32 ACK(0x00) or NACK(0xFF)

Implementation

The implementation of the custom function is shown below. In the first block the input arguments are checked and then serialized into the MODBUS PDU. The second block deals with the responce and extracts the state returned by the client.

/* ----------------------- Defines ------------------------------------------*/
#define MBM_FUNC_CUSTOM                             ( 0x32 )

/* ----------------------- Type definitions ---------------------------------*/

/* ----------------------- Static variables ---------------------------------*/

/* ----------------------- Static functions ---------------------------------*/

/* ----------------------- Start implementation (Polling functions)----------*/
void
vMBMCustom1Polled( xMBMHandle xHdl, UCHAR ucSlaveAddress, UBYTE ubLength, UBYTE * pubPayload, UBYTE * pubState,
                   /*@out@ */ eMBMQueryState * peState,
                   /*@out@ */ eMBErrorCode * peStatus )
{
    xMBMInternalHandle *pxIntHdl = ( xMBMInternalHandle * ) xHdl;
    UBYTE           ubIdx;

    if( bMBMIsHdlValid( pxIntHdl ) && ( peState != NULL ) && ( peStatus != NULL ) )
    {
        switch ( *peState )
        {
            /* In this state we prepare the frame and send it. */
        case MBM_STATE_NONE:
            /* ----------------------- TO BE CUSTOMIZED BY USER ---------------------------------- */            
            if( ( NULL != pubPayload ) && ( ubLength > 0 ) && ( ubLength <= 100 ) )
            {
                pxIntHdl->usFrameMBPDULength = 0;
                pxIntHdl->pubFrameMBPDUBuffer[pxIntHdl->usFrameMBPDULength++] = MBM_FUNC_CUSTOM;
                pxIntHdl->pubFrameMBPDUBuffer[pxIntHdl->usFrameMBPDULength++] = ubLength;
                for( ubIdx = 0; ubIdx < ubLength; ubIdx++ )
                {
                    pxIntHdl->pubFrameMBPDUBuffer[pxIntHdl->usFrameMBPDULength++] = *pubPayload++;
                }
                /* Frame is assembled. Now send it. */
                *peState = MBM_STATE_SEND;
            }
            else
            {
                *peStatus = MB_EINVAL;
                *peState = MBM_STATE_DONE;
            }
            break;
            /* ----------------------- TO BE CUSTOMIZED BY USER ---------------------------------- */

            /* These states are handled by the common state machine. */
        case MBM_STATE_SEND:
        case MBM_STATE_WAITING:
            vMBMMasterTransactionPolled( pxIntHdl, ucSlaveAddress, peState, peStatus );
            break;

            /* We need to disassemble the response here. */
        case MBM_STATE_DISASSEMBLE:
            *peState = MBM_STATE_DONE;
            /* ----------------------- TO BE CUSTOMIZED BY USER ---------------------------------- */                        
            if( MBM_FUNC_CUSTOM == pxIntHdl->pubFrameMBPDUBuffer[MB_PDU_FUNC_OFF] )
            {
                *pubState = pxIntHdl->pubFrameMBPDUBuffer[MB_PDU_FUNC_OFF];
                *peStatus = MB_ENOERR;
            }
            /* Check for exception frame. */
            else if( ( MB_PDU_EX_RESP_SIZE == pxIntHdl->usFrameMBPDULength ) &&
                     MB_PDU_FUNC_ISEXCEPTION_FOR( pxIntHdl->pubFrameMBPDUBuffer[MB_PDU_FUNC_OFF], MBM_FUNC_CUSTOM ) )
            {
                *peStatus = eMBExceptionToErrorcode( pxIntHdl->pubFrameMBPDUBuffer[MB_PDU_EX_CODE_OFF] );
            }
            else
            {
                *peStatus = MB_EIO;
            }
            /* ----------------------- TO BE CUSTOMIZED BY USER ---------------------------------- */                        
            break;

        case MBM_STATE_ERROR:
            /* No cleanup required. */
            *peState = MBM_STATE_DONE;
            break;

        default:
            *peState = MBM_STATE_DONE;
            *peStatus = MB_EILLSTATE;
        }
    }
    else
    {
        if( NULL != peState )
        {
            *peState = MBM_STATE_DONE;
        }
        if( NULL != peStatus )
        {
            *peStatus = MB_EINVAL;
        }
    }
}

/* ----------------------- Start implementation (Blocking functions) --------*/
eMBErrorCode
eMBMCustom1Polled( xMBMHandle xHdl, UCHAR ucSlaveAddress, UBYTE ubLength, UBYTE * pubPayload, UBYTE * pubState )
{
    eMBErrorCode    eStatus;
    eMBMQueryState  eState = MBM_STATE_NONE;

    do
    {
        vMBMCustom1Polled( xHdl, ucSlaveAddress, ubLength, pubPayload, pubState, &eState, &eStatus );
    }
    while( eState != MBM_STATE_DONE );
    return eStatus;
}

files

As a final step you should create a custom header file for the functions. You can either add them to the file mbmaster/include/mbm.h or to an application specific header file.

(C) 2007 Embedded Solutions. Last updated on 18 Mar 2012.