Trying to make Modbus code into a lib

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers mbfuncholding.cpp Source File

mbfuncholding.cpp

00001 /* 
00002  * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
00003  * Copyright (c) 2006 Christian Walter <wolti@sil.at>
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  * 1. Redistributions of source code must retain the above copyright
00010  *    notice, this list of conditions and the following disclaimer.
00011  * 2. Redistributions in binary form must reproduce the above copyright
00012  *    notice, this list of conditions and the following disclaimer in the
00013  *    documentation and/or other materials provided with the distribution.
00014  * 3. The name of the author may not be used to endorse or promote products
00015  *    derived from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00019  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00020  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00022  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00023  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00024  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00025  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00026  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  *
00028  * File: $Id: mbfuncholding.c,v 1.12 2007/02/18 23:48:22 wolti Exp $
00029  */
00030 
00031 /* ----------------------- System includes ----------------------------------*/
00032 #include "stdlib.h"
00033 #include "string.h"
00034 
00035 /* ----------------------- Platform includes --------------------------------*/
00036 #include "port.h"
00037 
00038 /* ----------------------- Modbus includes ----------------------------------*/
00039 #include "mb.h"
00040 #include "mbframe.h"
00041 #include "mbproto.h"
00042 #include "mbconfig.h"
00043 
00044 /* ----------------------- Defines ------------------------------------------*/
00045 #define MB_PDU_FUNC_READ_ADDR_OFF               ( MB_PDU_DATA_OFF + 0)
00046 #define MB_PDU_FUNC_READ_REGCNT_OFF             ( MB_PDU_DATA_OFF + 2 )
00047 #define MB_PDU_FUNC_READ_SIZE                   ( 4 )
00048 #define MB_PDU_FUNC_READ_REGCNT_MAX             ( 0x007D )
00049 
00050 #define MB_PDU_FUNC_WRITE_ADDR_OFF              ( MB_PDU_DATA_OFF + 0)
00051 #define MB_PDU_FUNC_WRITE_VALUE_OFF             ( MB_PDU_DATA_OFF + 2 )
00052 #define MB_PDU_FUNC_WRITE_SIZE                  ( 4 )
00053 
00054 #define MB_PDU_FUNC_WRITE_MUL_ADDR_OFF          ( MB_PDU_DATA_OFF + 0 )
00055 #define MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF        ( MB_PDU_DATA_OFF + 2 )
00056 #define MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF       ( MB_PDU_DATA_OFF + 4 )
00057 #define MB_PDU_FUNC_WRITE_MUL_VALUES_OFF        ( MB_PDU_DATA_OFF + 5 )
00058 #define MB_PDU_FUNC_WRITE_MUL_SIZE_MIN          ( 5 )
00059 #define MB_PDU_FUNC_WRITE_MUL_REGCNT_MAX        ( 0x0078 )
00060 
00061 #define MB_PDU_FUNC_READWRITE_READ_ADDR_OFF     ( MB_PDU_DATA_OFF + 0 )
00062 #define MB_PDU_FUNC_READWRITE_READ_REGCNT_OFF   ( MB_PDU_DATA_OFF + 2 )
00063 #define MB_PDU_FUNC_READWRITE_WRITE_ADDR_OFF    ( MB_PDU_DATA_OFF + 4 )
00064 #define MB_PDU_FUNC_READWRITE_WRITE_REGCNT_OFF  ( MB_PDU_DATA_OFF + 6 )
00065 #define MB_PDU_FUNC_READWRITE_BYTECNT_OFF       ( MB_PDU_DATA_OFF + 8 )
00066 #define MB_PDU_FUNC_READWRITE_WRITE_VALUES_OFF  ( MB_PDU_DATA_OFF + 9 )
00067 #define MB_PDU_FUNC_READWRITE_SIZE_MIN          ( 9 )
00068 
00069 /* ----------------------- Static functions ---------------------------------*/
00070 eMBException    prveMBError2Exception( eMBErrorCode eErrorCode );
00071 
00072 /* ----------------------- Start implementation -----------------------------*/
00073 
00074 #if MB_FUNC_WRITE_HOLDING_ENABLED > 0
00075 
00076 eMBException
00077 eMBFuncWriteHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
00078 {
00079     USHORT          usRegAddress;
00080     eMBException    eStatus = MB_EX_NONE;
00081     eMBErrorCode    eRegStatus;
00082 
00083     if( *usLen == ( MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN ) )
00084     {
00085         usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF] << 8 );
00086         usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF + 1] );
00087         usRegAddress++;
00088 
00089         /* Make callback to update the value. */
00090         eRegStatus = eMBRegHoldingCB( &pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF],
00091                                       usRegAddress, 1, MB_REG_WRITE  );
00092 
00093         /* If an error occured convert it into a Modbus exception. */
00094         if( eRegStatus != MB_ENOERR  )
00095         {
00096             eStatus = prveMBError2Exception( eRegStatus );
00097         }
00098     }
00099     else
00100     {
00101         /* Can't be a valid request because the length is incorrect. */
00102         eStatus = MB_EX_ILLEGAL_DATA_VALUE;
00103     }
00104     return eStatus;
00105 }
00106 #endif
00107 
00108 #if MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED > 0
00109 eMBException
00110 eMBFuncWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
00111 {
00112     USHORT          usRegAddress;
00113     USHORT          usRegCount;
00114     UCHAR           ucRegByteCount;
00115 
00116     eMBException    eStatus = MB_EX_NONE;
00117     eMBErrorCode    eRegStatus;
00118 
00119     if( *usLen >= ( MB_PDU_FUNC_WRITE_MUL_SIZE_MIN + MB_PDU_SIZE_MIN ) )
00120     {
00121         usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF] << 8 );
00122         usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF + 1] );
00123         usRegAddress++;
00124 
00125         usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF] << 8 );
00126         usRegCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF + 1] );
00127 
00128         ucRegByteCount = pucFrame[MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF];
00129 
00130         if( ( usRegCount >= 1 ) &&
00131             ( usRegCount <= MB_PDU_FUNC_WRITE_MUL_REGCNT_MAX ) &&
00132             ( ucRegByteCount == ( UCHAR ) ( 2 * usRegCount ) ) )
00133         {
00134             /* Make callback to update the register values. */
00135             eRegStatus =
00136                 eMBRegHoldingCB( &pucFrame[MB_PDU_FUNC_WRITE_MUL_VALUES_OFF],
00137                                  usRegAddress, usRegCount, MB_REG_WRITE  );
00138 
00139             /* If an error occured convert it into a Modbus exception. */
00140             if( eRegStatus != MB_ENOERR  )
00141             {
00142                 eStatus = prveMBError2Exception( eRegStatus );
00143             }
00144             else
00145             {
00146                 /* The response contains the function code, the starting
00147                  * address and the quantity of registers. We reuse the
00148                  * old values in the buffer because they are still valid.
00149                  */
00150                 *usLen = MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF;
00151             }
00152         }
00153         else
00154         {
00155             eStatus = MB_EX_ILLEGAL_DATA_VALUE;
00156         }
00157     }
00158     else
00159     {
00160         /* Can't be a valid request because the length is incorrect. */
00161         eStatus = MB_EX_ILLEGAL_DATA_VALUE;
00162     }
00163     return eStatus;
00164 }
00165 #endif
00166 
00167 #if MB_FUNC_READ_HOLDING_ENABLED > 0
00168 
00169 eMBException
00170 eMBFuncReadHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
00171 {
00172     USHORT          usRegAddress;
00173     USHORT          usRegCount;
00174     UCHAR          *pucFrameCur;
00175 
00176     eMBException    eStatus = MB_EX_NONE;
00177     eMBErrorCode    eRegStatus;
00178 
00179     if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) )
00180     {
00181         usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );
00182         usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );
00183         usRegAddress++;
00184 
00185         usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] << 8 );
00186         usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] );
00187 
00188         /* Check if the number of registers to read is valid. If not
00189          * return Modbus illegal data value exception. 
00190          */
00191         if( ( usRegCount >= 1 ) && ( usRegCount <= MB_PDU_FUNC_READ_REGCNT_MAX ) )
00192         {
00193             /* Set the current PDU data pointer to the beginning. */
00194             pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];
00195             *usLen = MB_PDU_FUNC_OFF;
00196 
00197             /* First byte contains the function code. */
00198             *pucFrameCur++ = MB_FUNC_READ_HOLDING_REGISTER;
00199             *usLen += 1;
00200 
00201             /* Second byte in the response contain the number of bytes. */
00202             *pucFrameCur++ = ( UCHAR ) ( usRegCount * 2 );
00203             *usLen += 1;
00204 
00205             /* Make callback to fill the buffer. */
00206             eRegStatus = eMBRegHoldingCB( pucFrameCur, usRegAddress, usRegCount, MB_REG_READ  );
00207             /* If an error occured convert it into a Modbus exception. */
00208             if( eRegStatus != MB_ENOERR  )
00209             {
00210                 eStatus = prveMBError2Exception( eRegStatus );
00211             }
00212             else
00213             {
00214                 *usLen += usRegCount * 2;
00215             }
00216         }
00217         else
00218         {
00219             eStatus = MB_EX_ILLEGAL_DATA_VALUE;
00220         }
00221     }
00222     else
00223     {
00224         /* Can't be a valid request because the length is incorrect. */
00225         eStatus = MB_EX_ILLEGAL_DATA_VALUE;
00226     }
00227     return eStatus;
00228 }
00229 
00230 #endif
00231 
00232 #if MB_FUNC_READWRITE_HOLDING_ENABLED > 0
00233 
00234 eMBException
00235 eMBFuncReadWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
00236 {
00237     USHORT          usRegReadAddress;
00238     USHORT          usRegReadCount;
00239     USHORT          usRegWriteAddress;
00240     USHORT          usRegWriteCount;
00241     UCHAR           ucRegWriteByteCount;
00242     UCHAR          *pucFrameCur;
00243 
00244     eMBException    eStatus = MB_EX_NONE;
00245     eMBErrorCode    eRegStatus;
00246 
00247     if( *usLen >= ( MB_PDU_FUNC_READWRITE_SIZE_MIN + MB_PDU_SIZE_MIN ) )
00248     {
00249         usRegReadAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_READ_ADDR_OFF] << 8U );
00250         usRegReadAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_READ_ADDR_OFF + 1] );
00251         usRegReadAddress++;
00252 
00253         usRegReadCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_READ_REGCNT_OFF] << 8U );
00254         usRegReadCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_READ_REGCNT_OFF + 1] );
00255 
00256         usRegWriteAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_ADDR_OFF] << 8U );
00257         usRegWriteAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_ADDR_OFF + 1] );
00258         usRegWriteAddress++;
00259 
00260         usRegWriteCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_REGCNT_OFF] << 8U );
00261         usRegWriteCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_REGCNT_OFF + 1] );
00262 
00263         ucRegWriteByteCount = pucFrame[MB_PDU_FUNC_READWRITE_BYTECNT_OFF];
00264 
00265         if( ( usRegReadCount >= 1 ) && ( usRegReadCount <= 0x7D ) &&
00266             ( usRegWriteCount >= 1 ) && ( usRegWriteCount <= 0x79 ) &&
00267             ( ( 2 * usRegWriteCount ) == ucRegWriteByteCount ) )
00268         {
00269             /* Make callback to update the register values. */
00270             eRegStatus = eMBRegHoldingCB( &pucFrame[MB_PDU_FUNC_READWRITE_WRITE_VALUES_OFF],
00271                                           usRegWriteAddress, usRegWriteCount, MB_REG_WRITE  );
00272 
00273             if( eRegStatus == MB_ENOERR  )
00274             {
00275                 /* Set the current PDU data pointer to the beginning. */
00276                 pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];
00277                 *usLen = MB_PDU_FUNC_OFF;
00278 
00279                 /* First byte contains the function code. */
00280                 *pucFrameCur++ = MB_FUNC_READWRITE_MULTIPLE_REGISTERS;
00281                 *usLen += 1;
00282 
00283                 /* Second byte in the response contain the number of bytes. */
00284                 *pucFrameCur++ = ( UCHAR ) ( usRegReadCount * 2 );
00285                 *usLen += 1;
00286 
00287                 /* Make the read callback. */
00288                 eRegStatus =
00289                     eMBRegHoldingCB( pucFrameCur, usRegReadAddress, usRegReadCount, MB_REG_READ  );
00290                 if( eRegStatus == MB_ENOERR  )
00291                 {
00292                     *usLen += 2 * usRegReadCount;
00293                 }
00294             }
00295             if( eRegStatus != MB_ENOERR  )
00296             {
00297                 eStatus = prveMBError2Exception( eRegStatus );
00298             }
00299         }
00300         else
00301         {
00302             eStatus = MB_EX_ILLEGAL_DATA_VALUE;
00303         }
00304     }
00305     return eStatus;
00306 }
00307 
00308 #endif