Revision 20e5429c

View differences:

Makefile
1
PART=t1634
2
MCU=attiny1634
3
#MCU=atmega2560
4
F_CPU=1000000
5
SRC=main.c serial.c \
6
		freemodbus/port/*.c \
7
		freemodbus/modbus/mb.c \
8
		freemodbus/modbus/rtu/mbrtu.c \
9
		freemodbus/modbus/ascii/mbascii.c \
10
		freemodbus/modbus/functions/*.c
11
HDR=tooltron_mb.h serial.h freemodbus/port/*.h
12

  
13
# TODO we can exclude modbus functions we don't need if the generated hex file
14
# ends up too large
15

  
16
FLAGS=-Os -Wall -mmcu=$(MCU) -DF_CPU=$(F_CPU) \
17
			-Ifreemodbus/port \
18
			-Ifreemodbus/modbus/rtu \
19
			-Ifreemodbus/modbus/ascii \
20
			-Ifreemodbus/modbus/include
21

  
22
PROG=avrispMKII
23

  
24
all: toolbox.hex
25

  
26
%.hex: %.elf
27
	avr-objcopy -j .text -j .data -O ihex $< $@
28

  
29
toolbox.elf: $(SRC) $(HDR)
30
	avr-gcc $(FLAGS) $(SRC) -o $@
31

  
32
%.asm: %.c
33
	avr-gcc -S $(FLAGS) $< -o $@
34

  
35
program: toolbox.hex
36
	avrdude -p $(PART) -c $(PROG) -P usb -B 1 -F -U flash:w:toolbox.hex
37

  
38
clean:
39
	rm -f *.elf *.hex
freemodbus/modbus/ascii/mbascii.c
1
/* 
2
 * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
3
 * Copyright (c) 2006 Christian Walter <wolti@sil.at>
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 * 1. Redistributions of source code must retain the above copyright
10
 *    notice, this list of conditions and the following disclaimer.
11
 * 2. Redistributions in binary form must reproduce the above copyright
12
 *    notice, this list of conditions and the following disclaimer in the
13
 *    documentation and/or other materials provided with the distribution.
14
 * 3. The name of the author may not be used to endorse or promote products
15
 *    derived from this software without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 *
28
 * File: $Id: mbascii.c,v 1.17 2010/06/06 13:47:07 wolti Exp $
29
 */
30

  
31
/* ----------------------- System includes ----------------------------------*/
32
#include "stdlib.h"
33
#include "string.h"
34

  
35
/* ----------------------- Platform includes --------------------------------*/
36
#include "port.h"
37

  
38
/* ----------------------- Modbus includes ----------------------------------*/
39
#include "mb.h"
40
#include "mbconfig.h"
41
#include "mbascii.h"
42
#include "mbframe.h"
43

  
44
#include "mbcrc.h"
45
#include "mbport.h"
46

  
47
#if MB_ASCII_ENABLED > 0
48

  
49
/* ----------------------- Defines ------------------------------------------*/
50
#define MB_ASCII_DEFAULT_CR     '\r'    /*!< Default CR character for Modbus ASCII. */
51
#define MB_ASCII_DEFAULT_LF     '\n'    /*!< Default LF character for Modbus ASCII. */
52
#define MB_SER_PDU_SIZE_MIN     3       /*!< Minimum size of a Modbus ASCII frame. */
53
#define MB_SER_PDU_SIZE_MAX     256     /*!< Maximum size of a Modbus ASCII frame. */
54
#define MB_SER_PDU_SIZE_LRC     1       /*!< Size of LRC field in PDU. */
55
#define MB_SER_PDU_ADDR_OFF     0       /*!< Offset of slave address in Ser-PDU. */
56
#define MB_SER_PDU_PDU_OFF      1       /*!< Offset of Modbus-PDU in Ser-PDU. */
57

  
58
/* ----------------------- Type definitions ---------------------------------*/
59
typedef enum
60
{
61
    STATE_RX_IDLE,              /*!< Receiver is in idle state. */
62
    STATE_RX_RCV,               /*!< Frame is beeing received. */
63
    STATE_RX_WAIT_EOF           /*!< Wait for End of Frame. */
64
} eMBRcvState;
65

  
66
typedef enum
67
{
68
    STATE_TX_IDLE,              /*!< Transmitter is in idle state. */
69
    STATE_TX_START,             /*!< Starting transmission (':' sent). */
70
    STATE_TX_DATA,              /*!< Sending of data (Address, Data, LRC). */
71
    STATE_TX_END,               /*!< End of transmission. */
72
    STATE_TX_NOTIFY             /*!< Notify sender that the frame has been sent. */
73
} eMBSndState;
74

  
75
typedef enum
76
{
77
    BYTE_HIGH_NIBBLE,           /*!< Character for high nibble of byte. */
78
    BYTE_LOW_NIBBLE             /*!< Character for low nibble of byte. */
79
} eMBBytePos;
80

  
81
/* ----------------------- Static functions ---------------------------------*/
82
static UCHAR    prvucMBCHAR2BIN( UCHAR ucCharacter );
83

  
84
static UCHAR    prvucMBBIN2CHAR( UCHAR ucByte );
85

  
86
static UCHAR    prvucMBLRC( UCHAR * pucFrame, USHORT usLen );
87

  
88
/* ----------------------- Static variables ---------------------------------*/
89
static volatile eMBSndState eSndState;
90
static volatile eMBRcvState eRcvState;
91

  
92
/* We reuse the Modbus RTU buffer because only one buffer is needed and the
93
 * RTU buffer is bigger. */
94
extern volatile UCHAR ucRTUBuf[];
95
static volatile UCHAR *ucASCIIBuf = ucRTUBuf;
96

  
97
static volatile USHORT usRcvBufferPos;
98
static volatile eMBBytePos eBytePos;
99

  
100
static volatile UCHAR *pucSndBufferCur;
101
static volatile USHORT usSndBufferCount;
102

  
103
static volatile UCHAR ucLRC;
104
static volatile UCHAR ucMBLFCharacter;
105

  
106
/* ----------------------- Start implementation -----------------------------*/
107
eMBErrorCode
108
eMBASCIIInit( UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity )
109
{
110
    eMBErrorCode    eStatus = MB_ENOERR;
111
    ( void )ucSlaveAddress;
112
    
113
    ENTER_CRITICAL_SECTION(  );
114
    ucMBLFCharacter = MB_ASCII_DEFAULT_LF;
115

  
116
    if( xMBPortSerialInit( ucPort, ulBaudRate, 7, eParity ) != TRUE )
117
    {
118
        eStatus = MB_EPORTERR;
119
    }
120
    else if( xMBPortTimersInit( MB_ASCII_TIMEOUT_SEC * 20000UL ) != TRUE )
121
    {
122
        eStatus = MB_EPORTERR;
123
    }
124

  
125
    EXIT_CRITICAL_SECTION(  );
126

  
127
    return eStatus;
128
}
129

  
130
void
131
eMBASCIIStart( void )
132
{
133
    ENTER_CRITICAL_SECTION(  );
134
    vMBPortSerialEnable( TRUE, FALSE );
135
    eRcvState = STATE_RX_IDLE;
136
    EXIT_CRITICAL_SECTION(  );
137

  
138
    /* No special startup required for ASCII. */
139
    ( void )xMBPortEventPost( EV_READY );
140
}
141

  
142
void
143
eMBASCIIStop( void )
144
{
145
    ENTER_CRITICAL_SECTION(  );
146
    vMBPortSerialEnable( FALSE, FALSE );
147
    vMBPortTimersDisable(  );
148
    EXIT_CRITICAL_SECTION(  );
149
}
150

  
151
eMBErrorCode
152
eMBASCIIReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength )
153
{
154
    eMBErrorCode    eStatus = MB_ENOERR;
155

  
156
    ENTER_CRITICAL_SECTION(  );
157
    assert( usRcvBufferPos < MB_SER_PDU_SIZE_MAX );
158

  
159
    /* Length and CRC check */
160
    if( ( usRcvBufferPos >= MB_SER_PDU_SIZE_MIN )
161
        && ( prvucMBLRC( ( UCHAR * ) ucASCIIBuf, usRcvBufferPos ) == 0 ) )
162
    {
163
        /* Save the address field. All frames are passed to the upper layed
164
         * and the decision if a frame is used is done there.
165
         */
166
        *pucRcvAddress = ucASCIIBuf[MB_SER_PDU_ADDR_OFF];
167

  
168
        /* Total length of Modbus-PDU is Modbus-Serial-Line-PDU minus
169
         * size of address field and CRC checksum.
170
         */
171
        *pusLength = ( USHORT )( usRcvBufferPos - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_LRC );
172

  
173
        /* Return the start of the Modbus PDU to the caller. */
174
        *pucFrame = ( UCHAR * ) & ucASCIIBuf[MB_SER_PDU_PDU_OFF];
175
    }
176
    else
177
    {
178
        eStatus = MB_EIO;
179
    }
180
    EXIT_CRITICAL_SECTION(  );
181
    return eStatus;
182
}
183

  
184
eMBErrorCode
185
eMBASCIISend( UCHAR ucSlaveAddress, const UCHAR * pucFrame, USHORT usLength )
186
{
187
    eMBErrorCode    eStatus = MB_ENOERR;
188
    UCHAR           usLRC;
189

  
190
    ENTER_CRITICAL_SECTION(  );
191
    /* Check if the receiver is still in idle state. If not we where too
192
     * slow with processing the received frame and the master sent another
193
     * frame on the network. We have to abort sending the frame.
194
     */
195
    if( eRcvState == STATE_RX_IDLE )
196
    {
197
        /* First byte before the Modbus-PDU is the slave address. */
198
        pucSndBufferCur = ( UCHAR * ) pucFrame - 1;
199
        usSndBufferCount = 1;
200

  
201
        /* Now copy the Modbus-PDU into the Modbus-Serial-Line-PDU. */
202
        pucSndBufferCur[MB_SER_PDU_ADDR_OFF] = ucSlaveAddress;
203
        usSndBufferCount += usLength;
204

  
205
        /* Calculate LRC checksum for Modbus-Serial-Line-PDU. */
206
        usLRC = prvucMBLRC( ( UCHAR * ) pucSndBufferCur, usSndBufferCount );
207
        ucASCIIBuf[usSndBufferCount++] = usLRC;
208

  
209
        /* Activate the transmitter. */
210
        eSndState = STATE_TX_START;
211
        vMBPortSerialEnable( FALSE, TRUE );
212
    }
213
    else
214
    {
215
        eStatus = MB_EIO;
216
    }
217
    EXIT_CRITICAL_SECTION(  );
218
    return eStatus;
219
}
220

  
221
BOOL
222
xMBASCIIReceiveFSM( void )
223
{
224
    BOOL            xNeedPoll = FALSE;
225
    UCHAR           ucByte;
226
    UCHAR           ucResult;
227

  
228
    assert( eSndState == STATE_TX_IDLE );
229

  
230
    ( void )xMBPortSerialGetByte( ( CHAR * ) & ucByte );
231
    switch ( eRcvState )
232
    {
233
        /* A new character is received. If the character is a ':' the input
234
         * buffer is cleared. A CR-character signals the end of the data
235
         * block. Other characters are part of the data block and their
236
         * ASCII value is converted back to a binary representation.
237
         */
238
    case STATE_RX_RCV:
239
        /* Enable timer for character timeout. */
240
        vMBPortTimersEnable(  );
241
        if( ucByte == ':' )
242
        {
243
            /* Empty receive buffer. */
244
            eBytePos = BYTE_HIGH_NIBBLE;
245
            usRcvBufferPos = 0;
246
        }
247
        else if( ucByte == MB_ASCII_DEFAULT_CR )
248
        {
249
            eRcvState = STATE_RX_WAIT_EOF;
250
        }
251
        else
252
        {
253
            ucResult = prvucMBCHAR2BIN( ucByte );
254
            switch ( eBytePos )
255
            {
256
                /* High nibble of the byte comes first. We check for
257
                 * a buffer overflow here. */
258
            case BYTE_HIGH_NIBBLE:
259
                if( usRcvBufferPos < MB_SER_PDU_SIZE_MAX )
260
                {
261
                    ucASCIIBuf[usRcvBufferPos] = ( UCHAR )( ucResult << 4 );
262
                    eBytePos = BYTE_LOW_NIBBLE;
263
                    break;
264
                }
265
                else
266
                {
267
                    /* not handled in Modbus specification but seems
268
                     * a resonable implementation. */
269
                    eRcvState = STATE_RX_IDLE;
270
                    /* Disable previously activated timer because of error state. */
271
                    vMBPortTimersDisable(  );
272
                }
273
                break;
274

  
275
            case BYTE_LOW_NIBBLE:
276
                ucASCIIBuf[usRcvBufferPos] |= ucResult;
277
                usRcvBufferPos++;
278
                eBytePos = BYTE_HIGH_NIBBLE;
279
                break;
280
            }
281
        }
282
        break;
283

  
284
    case STATE_RX_WAIT_EOF:
285
        if( ucByte == ucMBLFCharacter )
286
        {
287
            /* Disable character timeout timer because all characters are
288
             * received. */
289
            vMBPortTimersDisable(  );
290
            /* Receiver is again in idle state. */
291
            eRcvState = STATE_RX_IDLE;
292

  
293
            /* Notify the caller of eMBASCIIReceive that a new frame
294
             * was received. */
295
            xNeedPoll = xMBPortEventPost( EV_FRAME_RECEIVED );
296
        }
297
        else if( ucByte == ':' )
298
        {
299
            /* Empty receive buffer and back to receive state. */
300
            eBytePos = BYTE_HIGH_NIBBLE;
301
            usRcvBufferPos = 0;
302
            eRcvState = STATE_RX_RCV;
303

  
304
            /* Enable timer for character timeout. */
305
            vMBPortTimersEnable(  );
306
        }
307
        else
308
        {
309
            /* Frame is not okay. Delete entire frame. */
310
            eRcvState = STATE_RX_IDLE;
311
        }
312
        break;
313

  
314
    case STATE_RX_IDLE:
315
        if( ucByte == ':' )
316
        {
317
            /* Enable timer for character timeout. */
318
            vMBPortTimersEnable(  );
319
            /* Reset the input buffers to store the frame. */
320
            usRcvBufferPos = 0;;
321
            eBytePos = BYTE_HIGH_NIBBLE;
322
            eRcvState = STATE_RX_RCV;
323
        }
324
        break;
325
    }
326

  
327
    return xNeedPoll;
328
}
329

  
330
BOOL
331
xMBASCIITransmitFSM( void )
332
{
333
    BOOL            xNeedPoll = FALSE;
334
    UCHAR           ucByte;
335

  
336
    assert( eRcvState == STATE_RX_IDLE );
337
    switch ( eSndState )
338
    {
339
        /* Start of transmission. The start of a frame is defined by sending
340
         * the character ':'. */
341
    case STATE_TX_START:
342
        ucByte = ':';
343
        xMBPortSerialPutByte( ( CHAR )ucByte );
344
        eSndState = STATE_TX_DATA;
345
        eBytePos = BYTE_HIGH_NIBBLE;
346
        break;
347

  
348
        /* Send the data block. Each data byte is encoded as a character hex
349
         * stream with the high nibble sent first and the low nibble sent
350
         * last. If all data bytes are exhausted we send a '\r' character
351
         * to end the transmission. */
352
    case STATE_TX_DATA:
353
        if( usSndBufferCount > 0 )
354
        {
355
            switch ( eBytePos )
356
            {
357
            case BYTE_HIGH_NIBBLE:
358
                ucByte = prvucMBBIN2CHAR( ( UCHAR )( *pucSndBufferCur >> 4 ) );
359
                xMBPortSerialPutByte( ( CHAR ) ucByte );
360
                eBytePos = BYTE_LOW_NIBBLE;
361
                break;
362

  
363
            case BYTE_LOW_NIBBLE:
364
                ucByte = prvucMBBIN2CHAR( ( UCHAR )( *pucSndBufferCur & 0x0F ) );
365
                xMBPortSerialPutByte( ( CHAR )ucByte );
366
                pucSndBufferCur++;
367
                eBytePos = BYTE_HIGH_NIBBLE;
368
                usSndBufferCount--;
369
                break;
370
            }
371
        }
372
        else
373
        {
374
            xMBPortSerialPutByte( MB_ASCII_DEFAULT_CR );
375
            eSndState = STATE_TX_END;
376
        }
377
        break;
378

  
379
        /* Finish the frame by sending a LF character. */
380
    case STATE_TX_END:
381
        xMBPortSerialPutByte( ( CHAR )ucMBLFCharacter );
382
        /* We need another state to make sure that the CR character has
383
         * been sent. */
384
        eSndState = STATE_TX_NOTIFY;
385
        break;
386

  
387
        /* Notify the task which called eMBASCIISend that the frame has
388
         * been sent. */
389
    case STATE_TX_NOTIFY:
390
        eSndState = STATE_TX_IDLE;
391
        xNeedPoll = xMBPortEventPost( EV_FRAME_SENT );
392

  
393
        /* Disable transmitter. This prevents another transmit buffer
394
         * empty interrupt. */
395
        vMBPortSerialEnable( TRUE, FALSE );
396
        eSndState = STATE_TX_IDLE;
397
        break;
398

  
399
        /* We should not get a transmitter event if the transmitter is in
400
         * idle state.  */
401
    case STATE_TX_IDLE:
402
        /* enable receiver/disable transmitter. */
403
        vMBPortSerialEnable( TRUE, FALSE );
404
        break;
405
    }
406

  
407
    return xNeedPoll;
408
}
409

  
410
BOOL
411
xMBASCIITimerT1SExpired( void )
412
{
413
    switch ( eRcvState )
414
    {
415
        /* If we have a timeout we go back to the idle state and wait for
416
         * the next frame.
417
         */
418
    case STATE_RX_RCV:
419
    case STATE_RX_WAIT_EOF:
420
        eRcvState = STATE_RX_IDLE;
421
        break;
422

  
423
    default:
424
        assert( ( eRcvState == STATE_RX_RCV ) || ( eRcvState == STATE_RX_WAIT_EOF ) );
425
        break;
426
    }
427
    vMBPortTimersDisable(  );
428

  
429
    /* no context switch required. */
430
    return FALSE;
431
}
432

  
433

  
434
static          UCHAR
435
prvucMBCHAR2BIN( UCHAR ucCharacter )
436
{
437
    if( ( ucCharacter >= '0' ) && ( ucCharacter <= '9' ) )
438
    {
439
        return ( UCHAR )( ucCharacter - '0' );
440
    }
441
    else if( ( ucCharacter >= 'A' ) && ( ucCharacter <= 'F' ) )
442
    {
443
        return ( UCHAR )( ucCharacter - 'A' + 0x0A );
444
    }
445
    else
446
    {
447
        return 0xFF;
448
    }
449
}
450

  
451
static          UCHAR
452
prvucMBBIN2CHAR( UCHAR ucByte )
453
{
454
    if( ucByte <= 0x09 )
455
    {
456
        return ( UCHAR )( '0' + ucByte );
457
    }
458
    else if( ( ucByte >= 0x0A ) && ( ucByte <= 0x0F ) )
459
    {
460
        return ( UCHAR )( ucByte - 0x0A + 'A' );
461
    }
462
    else
463
    {
464
        /* Programming error. */
465
        assert( 0 );
466
    }
467
    return '0';
468
}
469

  
470

  
471
static          UCHAR
472
prvucMBLRC( UCHAR * pucFrame, USHORT usLen )
473
{
474
    UCHAR           ucLRC = 0;  /* LRC char initialized */
475

  
476
    while( usLen-- )
477
    {
478
        ucLRC += *pucFrame++;   /* Add buffer byte without carry */
479
    }
480

  
481
    /* Return twos complement */
482
    ucLRC = ( UCHAR ) ( -( ( CHAR ) ucLRC ) );
483
    return ucLRC;
484
}
485

  
486
#endif
freemodbus/modbus/ascii/mbascii.h
1
/* 
2
 * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
3
 * Copyright (c) 2006 Christian Walter <wolti@sil.at>
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 * 1. Redistributions of source code must retain the above copyright
10
 *    notice, this list of conditions and the following disclaimer.
11
 * 2. Redistributions in binary form must reproduce the above copyright
12
 *    notice, this list of conditions and the following disclaimer in the
13
 *    documentation and/or other materials provided with the distribution.
14
 * 3. The name of the author may not be used to endorse or promote products
15
 *    derived from this software without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 *
28
 * File: $Id: mbascii.h,v 1.8 2006/12/07 22:10:34 wolti Exp $
29
 */
30

  
31
#ifndef _MB_ASCII_H
32
#define _MB_ASCII_H
33

  
34
#ifdef __cplusplus
35
PR_BEGIN_EXTERN_C
36
#endif
37

  
38
#if MB_ASCII_ENABLED > 0
39
eMBErrorCode    eMBASCIIInit( UCHAR slaveAddress, UCHAR ucPort,
40
                              ULONG ulBaudRate, eMBParity eParity );
41
void            eMBASCIIStart( void );
42
void            eMBASCIIStop( void );
43

  
44
eMBErrorCode    eMBASCIIReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame,
45
                                 USHORT * pusLength );
46
eMBErrorCode    eMBASCIISend( UCHAR slaveAddress, const UCHAR * pucFrame,
47
                              USHORT usLength );
48
BOOL            xMBASCIIReceiveFSM( void );
49
BOOL            xMBASCIITransmitFSM( void );
50
BOOL            xMBASCIITimerT1SExpired( void );
51
#endif
52

  
53
#ifdef __cplusplus
54
PR_END_EXTERN_C
55
#endif
56
#endif
freemodbus/modbus/functions/mbfunccoils.c
1
/* 
2
 * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
3
 * Copyright (c) 2006 Christian Walter <wolti@sil.at>
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 * 1. Redistributions of source code must retain the above copyright
10
 *    notice, this list of conditions and the following disclaimer.
11
 * 2. Redistributions in binary form must reproduce the above copyright
12
 *    notice, this list of conditions and the following disclaimer in the
13
 *    documentation and/or other materials provided with the distribution.
14
 * 3. The name of the author may not be used to endorse or promote products
15
 *    derived from this software without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 *
28
 * File: $Id: mbfunccoils.c,v 1.8 2007/02/18 23:47:16 wolti Exp $
29
 */
30

  
31
/* ----------------------- System includes ----------------------------------*/
32
#include "stdlib.h"
33
#include "string.h"
34

  
35
/* ----------------------- Platform includes --------------------------------*/
36
#include "port.h"
37

  
38
/* ----------------------- Modbus includes ----------------------------------*/
39
#include "mb.h"
40
#include "mbframe.h"
41
#include "mbproto.h"
42
#include "mbconfig.h"
43

  
44
/* ----------------------- Defines ------------------------------------------*/
45
#define MB_PDU_FUNC_READ_ADDR_OFF           ( MB_PDU_DATA_OFF )
46
#define MB_PDU_FUNC_READ_COILCNT_OFF        ( MB_PDU_DATA_OFF + 2 )
47
#define MB_PDU_FUNC_READ_SIZE               ( 4 )
48
#define MB_PDU_FUNC_READ_COILCNT_MAX        ( 0x07D0 )
49

  
50
#define MB_PDU_FUNC_WRITE_ADDR_OFF          ( MB_PDU_DATA_OFF )
51
#define MB_PDU_FUNC_WRITE_VALUE_OFF         ( MB_PDU_DATA_OFF + 2 )
52
#define MB_PDU_FUNC_WRITE_SIZE              ( 4 )
53

  
54
#define MB_PDU_FUNC_WRITE_MUL_ADDR_OFF      ( MB_PDU_DATA_OFF )
55
#define MB_PDU_FUNC_WRITE_MUL_COILCNT_OFF   ( MB_PDU_DATA_OFF + 2 )
56
#define MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF   ( MB_PDU_DATA_OFF + 4 )
57
#define MB_PDU_FUNC_WRITE_MUL_VALUES_OFF    ( MB_PDU_DATA_OFF + 5 )
58
#define MB_PDU_FUNC_WRITE_MUL_SIZE_MIN      ( 5 )
59
#define MB_PDU_FUNC_WRITE_MUL_COILCNT_MAX   ( 0x07B0 )
60

  
61
/* ----------------------- Static functions ---------------------------------*/
62
eMBException    prveMBError2Exception( eMBErrorCode eErrorCode );
63

  
64
/* ----------------------- Start implementation -----------------------------*/
65

  
66
#if MB_FUNC_READ_COILS_ENABLED > 0
67

  
68
eMBException
69
eMBFuncReadCoils( UCHAR * pucFrame, USHORT * usLen )
70
{
71
    USHORT          usRegAddress;
72
    USHORT          usCoilCount;
73
    UCHAR           ucNBytes;
74
    UCHAR          *pucFrameCur;
75

  
76
    eMBException    eStatus = MB_EX_NONE;
77
    eMBErrorCode    eRegStatus;
78

  
79
    if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) )
80
    {
81
        usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );
82
        usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );
83
        usRegAddress++;
84

  
85
        usCoilCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_COILCNT_OFF] << 8 );
86
        usCoilCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_COILCNT_OFF + 1] );
87

  
88
        /* Check if the number of registers to read is valid. If not
89
         * return Modbus illegal data value exception. 
90
         */
91
        if( ( usCoilCount >= 1 ) &&
92
            ( usCoilCount < MB_PDU_FUNC_READ_COILCNT_MAX ) )
93
        {
94
            /* Set the current PDU data pointer to the beginning. */
95
            pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];
96
            *usLen = MB_PDU_FUNC_OFF;
97

  
98
            /* First byte contains the function code. */
99
            *pucFrameCur++ = MB_FUNC_READ_COILS;
100
            *usLen += 1;
101

  
102
            /* Test if the quantity of coils is a multiple of 8. If not last
103
             * byte is only partially field with unused coils set to zero. */
104
            if( ( usCoilCount & 0x0007 ) != 0 )
105
            {
106
                ucNBytes = ( UCHAR )( usCoilCount / 8 + 1 );
107
            }
108
            else
109
            {
110
                ucNBytes = ( UCHAR )( usCoilCount / 8 );
111
            }
112
            *pucFrameCur++ = ucNBytes;
113
            *usLen += 1;
114

  
115
            eRegStatus =
116
                eMBRegCoilsCB( pucFrameCur, usRegAddress, usCoilCount,
117
                               MB_REG_READ );
118

  
119
            /* If an error occured convert it into a Modbus exception. */
120
            if( eRegStatus != MB_ENOERR )
121
            {
122
                eStatus = prveMBError2Exception( eRegStatus );
123
            }
124
            else
125
            {
126
                /* The response contains the function code, the starting address
127
                 * and the quantity of registers. We reuse the old values in the 
128
                 * buffer because they are still valid. */
129
                *usLen += ucNBytes;;
130
            }
131
        }
132
        else
133
        {
134
            eStatus = MB_EX_ILLEGAL_DATA_VALUE;
135
        }
136
    }
137
    else
138
    {
139
        /* Can't be a valid read coil register request because the length
140
         * is incorrect. */
141
        eStatus = MB_EX_ILLEGAL_DATA_VALUE;
142
    }
143
    return eStatus;
144
}
145

  
146
#if MB_FUNC_WRITE_COIL_ENABLED > 0
147
eMBException
148
eMBFuncWriteCoil( UCHAR * pucFrame, USHORT * usLen )
149
{
150
    USHORT          usRegAddress;
151
    UCHAR           ucBuf[2];
152

  
153
    eMBException    eStatus = MB_EX_NONE;
154
    eMBErrorCode    eRegStatus;
155

  
156
    if( *usLen == ( MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN ) )
157
    {
158
        usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF] << 8 );
159
        usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF + 1] );
160
        usRegAddress++;
161

  
162
        if( ( pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF + 1] == 0x00 ) &&
163
            ( ( pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF] == 0xFF ) ||
164
              ( pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF] == 0x00 ) ) )
165
        {
166
            ucBuf[1] = 0;
167
            if( pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF] == 0xFF )
168
            {
169
                ucBuf[0] = 1;
170
            }
171
            else
172
            {
173
                ucBuf[0] = 0;
174
            }
175
            eRegStatus =
176
                eMBRegCoilsCB( &ucBuf[0], usRegAddress, 1, MB_REG_WRITE );
177

  
178
            /* If an error occured convert it into a Modbus exception. */
179
            if( eRegStatus != MB_ENOERR )
180
            {
181
                eStatus = prveMBError2Exception( eRegStatus );
182
            }
183
        }
184
        else
185
        {
186
            eStatus = MB_EX_ILLEGAL_DATA_VALUE;
187
        }
188
    }
189
    else
190
    {
191
        /* Can't be a valid write coil register request because the length
192
         * is incorrect. */
193
        eStatus = MB_EX_ILLEGAL_DATA_VALUE;
194
    }
195
    return eStatus;
196
}
197

  
198
#endif
199

  
200
#if MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED > 0
201
eMBException
202
eMBFuncWriteMultipleCoils( UCHAR * pucFrame, USHORT * usLen )
203
{
204
    USHORT          usRegAddress;
205
    USHORT          usCoilCnt;
206
    UCHAR           ucByteCount;
207
    UCHAR           ucByteCountVerify;
208

  
209
    eMBException    eStatus = MB_EX_NONE;
210
    eMBErrorCode    eRegStatus;
211

  
212
    if( *usLen > ( MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN ) )
213
    {
214
        usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF] << 8 );
215
        usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF + 1] );
216
        usRegAddress++;
217

  
218
        usCoilCnt = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_COILCNT_OFF] << 8 );
219
        usCoilCnt |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_COILCNT_OFF + 1] );
220

  
221
        ucByteCount = pucFrame[MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF];
222

  
223
        /* Compute the number of expected bytes in the request. */
224
        if( ( usCoilCnt & 0x0007 ) != 0 )
225
        {
226
            ucByteCountVerify = ( UCHAR )( usCoilCnt / 8 + 1 );
227
        }
228
        else
229
        {
230
            ucByteCountVerify = ( UCHAR )( usCoilCnt / 8 );
231
        }
232

  
233
        if( ( usCoilCnt >= 1 ) &&
234
            ( usCoilCnt <= MB_PDU_FUNC_WRITE_MUL_COILCNT_MAX ) &&
235
            ( ucByteCountVerify == ucByteCount ) )
236
        {
237
            eRegStatus =
238
                eMBRegCoilsCB( &pucFrame[MB_PDU_FUNC_WRITE_MUL_VALUES_OFF],
239
                               usRegAddress, usCoilCnt, MB_REG_WRITE );
240

  
241
            /* If an error occured convert it into a Modbus exception. */
242
            if( eRegStatus != MB_ENOERR )
243
            {
244
                eStatus = prveMBError2Exception( eRegStatus );
245
            }
246
            else
247
            {
248
                /* The response contains the function code, the starting address
249
                 * and the quantity of registers. We reuse the old values in the 
250
                 * buffer because they are still valid. */
251
                *usLen = MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF;
252
            }
253
        }
254
        else
255
        {
256
            eStatus = MB_EX_ILLEGAL_DATA_VALUE;
257
        }
258
    }
259
    else
260
    {
261
        /* Can't be a valid write coil register request because the length
262
         * is incorrect. */
263
        eStatus = MB_EX_ILLEGAL_DATA_VALUE;
264
    }
265
    return eStatus;
266
}
267

  
268
#endif
269

  
270
#endif
freemodbus/modbus/functions/mbfuncdiag.c
1
/* 
2
 * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
3
 * Copyright (c) 2006 Christian Walter <wolti@sil.at>
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 * 1. Redistributions of source code must retain the above copyright
10
 *    notice, this list of conditions and the following disclaimer.
11
 * 2. Redistributions in binary form must reproduce the above copyright
12
 *    notice, this list of conditions and the following disclaimer in the
13
 *    documentation and/or other materials provided with the distribution.
14
 * 3. The name of the author may not be used to endorse or promote products
15
 *    derived from this software without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 *
28
 * File: $Id: mbfuncdiag.c,v 1.3 2006/12/07 22:10:34 wolti Exp $
29
 */
freemodbus/modbus/functions/mbfuncdisc.c
1
 /*
2
  * FreeRTOS Modbus Libary: A Modbus serial implementation for FreeRTOS
3
  * Copyright (C) 2006 Christian Walter <wolti@sil.at>
4
  *
5
  * This library is free software; you can redistribute it and/or
6
  * modify it under the terms of the GNU Lesser General Public
7
  * License as published by the Free Software Foundation; either
8
  * version 2.1 of the License, or (at your option) any later version.
9
  *
10
  * This library is distributed in the hope that it will be useful,
11
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
  * Lesser General Public License for more details.
14
  *
15
  * You should have received a copy of the GNU Lesser General Public
16
  * License along with this library; if not, write to the Free Software
17
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
  */
19

  
20

  
21

  
22
/* ----------------------- System includes ----------------------------------*/
23
#include "stdlib.h"
24
#include "string.h"
25

  
26
/* ----------------------- Platform includes --------------------------------*/
27
#include "port.h"
28

  
29
/* ----------------------- Modbus includes ----------------------------------*/
30
#include "mb.h"
31
#include "mbframe.h"
32
#include "mbproto.h"
33
#include "mbconfig.h"
34

  
35
/* ----------------------- Defines ------------------------------------------*/
36
#define MB_PDU_FUNC_READ_ADDR_OFF           ( MB_PDU_DATA_OFF )
37
#define MB_PDU_FUNC_READ_DISCCNT_OFF        ( MB_PDU_DATA_OFF + 2 )
38
#define MB_PDU_FUNC_READ_SIZE               ( 4 )
39
#define MB_PDU_FUNC_READ_DISCCNT_MAX        ( 0x07D0 )
40

  
41
/* ----------------------- Static functions ---------------------------------*/
42
eMBException    prveMBError2Exception( eMBErrorCode eErrorCode );
43

  
44
/* ----------------------- Start implementation -----------------------------*/
45

  
46
#if MB_FUNC_READ_COILS_ENABLED > 0
47

  
48
eMBException
49
eMBFuncReadDiscreteInputs( UCHAR * pucFrame, USHORT * usLen )
50
{
51
    USHORT          usRegAddress;
52
    USHORT          usDiscreteCnt;
53
    UCHAR           ucNBytes;
54
    UCHAR          *pucFrameCur;
55

  
56
    eMBException    eStatus = MB_EX_NONE;
57
    eMBErrorCode    eRegStatus;
58

  
59
    if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) )
60
    {
61
        usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );
62
        usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );
63
        usRegAddress++;
64

  
65
        usDiscreteCnt = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_DISCCNT_OFF] << 8 );
66
        usDiscreteCnt |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_DISCCNT_OFF + 1] );
67

  
68
        /* Check if the number of registers to read is valid. If not
69
         * return Modbus illegal data value exception. 
70
         */
71
        if( ( usDiscreteCnt >= 1 ) &&
72
            ( usDiscreteCnt < MB_PDU_FUNC_READ_DISCCNT_MAX ) )
73
        {
74
            /* Set the current PDU data pointer to the beginning. */
75
            pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];
76
            *usLen = MB_PDU_FUNC_OFF;
77

  
78
            /* First byte contains the function code. */
79
            *pucFrameCur++ = MB_FUNC_READ_DISCRETE_INPUTS;
80
            *usLen += 1;
81

  
82
            /* Test if the quantity of coils is a multiple of 8. If not last
83
             * byte is only partially field with unused coils set to zero. */
84
            if( ( usDiscreteCnt & 0x0007 ) != 0 )
85
            {
86
                ucNBytes = ( UCHAR ) ( usDiscreteCnt / 8 + 1 );
87
            }
88
            else
89
            {
90
                ucNBytes = ( UCHAR ) ( usDiscreteCnt / 8 );
91
            }
92
            *pucFrameCur++ = ucNBytes;
93
            *usLen += 1;
94

  
95
            eRegStatus =
96
                eMBRegDiscreteCB( pucFrameCur, usRegAddress, usDiscreteCnt );
97

  
98
            /* If an error occured convert it into a Modbus exception. */
99
            if( eRegStatus != MB_ENOERR )
100
            {
101
                eStatus = prveMBError2Exception( eRegStatus );
102
            }
103
            else
104
            {
105
                /* The response contains the function code, the starting address
106
                 * and the quantity of registers. We reuse the old values in the 
107
                 * buffer because they are still valid. */
108
                *usLen += ucNBytes;;
109
            }
110
        }
111
        else
112
        {
113
            eStatus = MB_EX_ILLEGAL_DATA_VALUE;
114
        }
115
    }
116
    else
117
    {
118
        /* Can't be a valid read coil register request because the length
119
         * is incorrect. */
120
        eStatus = MB_EX_ILLEGAL_DATA_VALUE;
121
    }
122
    return eStatus;
123
}
124

  
125
#endif
freemodbus/modbus/functions/mbfuncholding.c
1
/* 
2
 * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
3
 * Copyright (c) 2006 Christian Walter <wolti@sil.at>
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 * 1. Redistributions of source code must retain the above copyright
10
 *    notice, this list of conditions and the following disclaimer.
11
 * 2. Redistributions in binary form must reproduce the above copyright
12
 *    notice, this list of conditions and the following disclaimer in the
13
 *    documentation and/or other materials provided with the distribution.
14
 * 3. The name of the author may not be used to endorse or promote products
15
 *    derived from this software without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 *
28
 * File: $Id: mbfuncholding.c,v 1.12 2007/02/18 23:48:22 wolti Exp $
29
 */
30

  
31
/* ----------------------- System includes ----------------------------------*/
32
#include "stdlib.h"
33
#include "string.h"
34

  
35
/* ----------------------- Platform includes --------------------------------*/
36
#include "port.h"
37

  
38
/* ----------------------- Modbus includes ----------------------------------*/
39
#include "mb.h"
40
#include "mbframe.h"
41
#include "mbproto.h"
42
#include "mbconfig.h"
43

  
44
/* ----------------------- Defines ------------------------------------------*/
45
#define MB_PDU_FUNC_READ_ADDR_OFF               ( MB_PDU_DATA_OFF + 0)
46
#define MB_PDU_FUNC_READ_REGCNT_OFF             ( MB_PDU_DATA_OFF + 2 )
47
#define MB_PDU_FUNC_READ_SIZE                   ( 4 )
48
#define MB_PDU_FUNC_READ_REGCNT_MAX             ( 0x007D )
49

  
50
#define MB_PDU_FUNC_WRITE_ADDR_OFF              ( MB_PDU_DATA_OFF + 0)
51
#define MB_PDU_FUNC_WRITE_VALUE_OFF             ( MB_PDU_DATA_OFF + 2 )
52
#define MB_PDU_FUNC_WRITE_SIZE                  ( 4 )
53

  
54
#define MB_PDU_FUNC_WRITE_MUL_ADDR_OFF          ( MB_PDU_DATA_OFF + 0 )
55
#define MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF        ( MB_PDU_DATA_OFF + 2 )
56
#define MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF       ( MB_PDU_DATA_OFF + 4 )
57
#define MB_PDU_FUNC_WRITE_MUL_VALUES_OFF        ( MB_PDU_DATA_OFF + 5 )
58
#define MB_PDU_FUNC_WRITE_MUL_SIZE_MIN          ( 5 )
59
#define MB_PDU_FUNC_WRITE_MUL_REGCNT_MAX        ( 0x0078 )
60

  
61
#define MB_PDU_FUNC_READWRITE_READ_ADDR_OFF     ( MB_PDU_DATA_OFF + 0 )
62
#define MB_PDU_FUNC_READWRITE_READ_REGCNT_OFF   ( MB_PDU_DATA_OFF + 2 )
63
#define MB_PDU_FUNC_READWRITE_WRITE_ADDR_OFF    ( MB_PDU_DATA_OFF + 4 )
64
#define MB_PDU_FUNC_READWRITE_WRITE_REGCNT_OFF  ( MB_PDU_DATA_OFF + 6 )
65
#define MB_PDU_FUNC_READWRITE_BYTECNT_OFF       ( MB_PDU_DATA_OFF + 8 )
66
#define MB_PDU_FUNC_READWRITE_WRITE_VALUES_OFF  ( MB_PDU_DATA_OFF + 9 )
67
#define MB_PDU_FUNC_READWRITE_SIZE_MIN          ( 9 )
68

  
69
/* ----------------------- Static functions ---------------------------------*/
70
eMBException    prveMBError2Exception( eMBErrorCode eErrorCode );
71

  
72
/* ----------------------- Start implementation -----------------------------*/
73

  
74
#if MB_FUNC_WRITE_HOLDING_ENABLED > 0
75

  
76
eMBException
77
eMBFuncWriteHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
78
{
79
    USHORT          usRegAddress;
80
    eMBException    eStatus = MB_EX_NONE;
81
    eMBErrorCode    eRegStatus;
82

  
83
    if( *usLen == ( MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN ) )
84
    {
85
        usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF] << 8 );
86
        usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF + 1] );
87
        usRegAddress++;
88

  
89
        /* Make callback to update the value. */
90
        eRegStatus = eMBRegHoldingCB( &pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF],
91
                                      usRegAddress, 1, MB_REG_WRITE );
92

  
93
        /* If an error occured convert it into a Modbus exception. */
94
        if( eRegStatus != MB_ENOERR )
95
        {
96
            eStatus = prveMBError2Exception( eRegStatus );
97
        }
98
    }
99
    else
100
    {
101
        /* Can't be a valid request because the length is incorrect. */
102
        eStatus = MB_EX_ILLEGAL_DATA_VALUE;
103
    }
104
    return eStatus;
105
}
106
#endif
107

  
108
#if MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED > 0
109
eMBException
110
eMBFuncWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
111
{
112
    USHORT          usRegAddress;
113
    USHORT          usRegCount;
114
    UCHAR           ucRegByteCount;
115

  
116
    eMBException    eStatus = MB_EX_NONE;
117
    eMBErrorCode    eRegStatus;
118

  
119
    if( *usLen >= ( MB_PDU_FUNC_WRITE_MUL_SIZE_MIN + MB_PDU_SIZE_MIN ) )
120
    {
121
        usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF] << 8 );
122
        usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF + 1] );
123
        usRegAddress++;
124

  
125
        usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF] << 8 );
126
        usRegCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_WRITE_MUL_REGCNT_OFF + 1] );
127

  
128
        ucRegByteCount = pucFrame[MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF];
129

  
130
        if( ( usRegCount >= 1 ) &&
131
            ( usRegCount <= MB_PDU_FUNC_WRITE_MUL_REGCNT_MAX ) &&
132
            ( ucRegByteCount == ( UCHAR ) ( 2 * usRegCount ) ) )
133
        {
134
            /* Make callback to update the register values. */
135
            eRegStatus =
136
                eMBRegHoldingCB( &pucFrame[MB_PDU_FUNC_WRITE_MUL_VALUES_OFF],
137
                                 usRegAddress, usRegCount, MB_REG_WRITE );
138

  
139
            /* If an error occured convert it into a Modbus exception. */
140
            if( eRegStatus != MB_ENOERR )
141
            {
142
                eStatus = prveMBError2Exception( eRegStatus );
143
            }
144
            else
145
            {
146
                /* The response contains the function code, the starting
147
                 * address and the quantity of registers. We reuse the
148
                 * old values in the buffer because they are still valid.
149
                 */
150
                *usLen = MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF;
151
            }
152
        }
153
        else
154
        {
155
            eStatus = MB_EX_ILLEGAL_DATA_VALUE;
156
        }
157
    }
158
    else
159
    {
160
        /* Can't be a valid request because the length is incorrect. */
161
        eStatus = MB_EX_ILLEGAL_DATA_VALUE;
162
    }
163
    return eStatus;
164
}
165
#endif
166

  
167
#if MB_FUNC_READ_HOLDING_ENABLED > 0
168

  
169
eMBException
170
eMBFuncReadHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
171
{
172
    USHORT          usRegAddress;
173
    USHORT          usRegCount;
174
    UCHAR          *pucFrameCur;
175

  
176
    eMBException    eStatus = MB_EX_NONE;
177
    eMBErrorCode    eRegStatus;
178

  
179
    if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) )
180
    {
181
        usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );
182
        usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );
183
        usRegAddress++;
184

  
185
        usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] << 8 );
186
        usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] );
187

  
188
        /* Check if the number of registers to read is valid. If not
189
         * return Modbus illegal data value exception. 
190
         */
191
        if( ( usRegCount >= 1 ) && ( usRegCount <= MB_PDU_FUNC_READ_REGCNT_MAX ) )
192
        {
193
            /* Set the current PDU data pointer to the beginning. */
194
            pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];
195
            *usLen = MB_PDU_FUNC_OFF;
196

  
197
            /* First byte contains the function code. */
198
            *pucFrameCur++ = MB_FUNC_READ_HOLDING_REGISTER;
199
            *usLen += 1;
200

  
201
            /* Second byte in the response contain the number of bytes. */
202
            *pucFrameCur++ = ( UCHAR ) ( usRegCount * 2 );
203
            *usLen += 1;
204

  
205
            /* Make callback to fill the buffer. */
206
            eRegStatus = eMBRegHoldingCB( pucFrameCur, usRegAddress, usRegCount, MB_REG_READ );
207
            /* If an error occured convert it into a Modbus exception. */
208
            if( eRegStatus != MB_ENOERR )
209
            {
210
                eStatus = prveMBError2Exception( eRegStatus );
211
            }
212
            else
213
            {
214
                *usLen += usRegCount * 2;
215
            }
216
        }
217
        else
218
        {
219
            eStatus = MB_EX_ILLEGAL_DATA_VALUE;
220
        }
221
    }
222
    else
223
    {
224
        /* Can't be a valid request because the length is incorrect. */
225
        eStatus = MB_EX_ILLEGAL_DATA_VALUE;
226
    }
227
    return eStatus;
228
}
229

  
230
#endif
231

  
232
#if MB_FUNC_READWRITE_HOLDING_ENABLED > 0
233

  
234
eMBException
235
eMBFuncReadWriteMultipleHoldingRegister( UCHAR * pucFrame, USHORT * usLen )
236
{
237
    USHORT          usRegReadAddress;
238
    USHORT          usRegReadCount;
239
    USHORT          usRegWriteAddress;
240
    USHORT          usRegWriteCount;
241
    UCHAR           ucRegWriteByteCount;
242
    UCHAR          *pucFrameCur;
243

  
244
    eMBException    eStatus = MB_EX_NONE;
245
    eMBErrorCode    eRegStatus;
246

  
247
    if( *usLen >= ( MB_PDU_FUNC_READWRITE_SIZE_MIN + MB_PDU_SIZE_MIN ) )
248
    {
249
        usRegReadAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_READ_ADDR_OFF] << 8U );
250
        usRegReadAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_READ_ADDR_OFF + 1] );
251
        usRegReadAddress++;
252

  
253
        usRegReadCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_READ_REGCNT_OFF] << 8U );
254
        usRegReadCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_READ_REGCNT_OFF + 1] );
255

  
256
        usRegWriteAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_ADDR_OFF] << 8U );
257
        usRegWriteAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_ADDR_OFF + 1] );
258
        usRegWriteAddress++;
259

  
260
        usRegWriteCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_REGCNT_OFF] << 8U );
261
        usRegWriteCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READWRITE_WRITE_REGCNT_OFF + 1] );
262

  
263
        ucRegWriteByteCount = pucFrame[MB_PDU_FUNC_READWRITE_BYTECNT_OFF];
264

  
265
        if( ( usRegReadCount >= 1 ) && ( usRegReadCount <= 0x7D ) &&
266
            ( usRegWriteCount >= 1 ) && ( usRegWriteCount <= 0x79 ) &&
267
            ( ( 2 * usRegWriteCount ) == ucRegWriteByteCount ) )
268
        {
269
            /* Make callback to update the register values. */
270
            eRegStatus = eMBRegHoldingCB( &pucFrame[MB_PDU_FUNC_READWRITE_WRITE_VALUES_OFF],
271
                                          usRegWriteAddress, usRegWriteCount, MB_REG_WRITE );
272

  
273
            if( eRegStatus == MB_ENOERR )
274
            {
275
                /* Set the current PDU data pointer to the beginning. */
276
                pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];
277
                *usLen = MB_PDU_FUNC_OFF;
278

  
279
                /* First byte contains the function code. */
280
                *pucFrameCur++ = MB_FUNC_READWRITE_MULTIPLE_REGISTERS;
281
                *usLen += 1;
282

  
283
                /* Second byte in the response contain the number of bytes. */
284
                *pucFrameCur++ = ( UCHAR ) ( usRegReadCount * 2 );
285
                *usLen += 1;
286

  
287
                /* Make the read callback. */
288
                eRegStatus =
289
                    eMBRegHoldingCB( pucFrameCur, usRegReadAddress, usRegReadCount, MB_REG_READ );
290
                if( eRegStatus == MB_ENOERR )
291
                {
292
                    *usLen += 2 * usRegReadCount;
293
                }
294
            }
295
            if( eRegStatus != MB_ENOERR )
296
            {
297
                eStatus = prveMBError2Exception( eRegStatus );
298
            }
299
        }
300
        else
301
        {
302
            eStatus = MB_EX_ILLEGAL_DATA_VALUE;
303
        }
304
    }
305
    return eStatus;
306
}
307

  
308
#endif
freemodbus/modbus/functions/mbfuncinput.c
1
/* 
2
 * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
3
 * Copyright (c) 2006 Christian Walter <wolti@sil.at>
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
7
 * modification, are permitted provided that the following conditions
8
 * are met:
9
 * 1. Redistributions of source code must retain the above copyright
10
 *    notice, this list of conditions and the following disclaimer.
11
 * 2. Redistributions in binary form must reproduce the above copyright
12
 *    notice, this list of conditions and the following disclaimer in the
13
 *    documentation and/or other materials provided with the distribution.
14
 * 3. The name of the author may not be used to endorse or promote products
15
 *    derived from this software without specific prior written permission.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
 *
28
 * File: $Id: mbfuncinput.c,v 1.10 2007/09/12 10:15:56 wolti Exp $
29
 */
30

  
31
/* ----------------------- System includes ----------------------------------*/
32
#include "stdlib.h"
33
#include "string.h"
34

  
35
/* ----------------------- Platform includes --------------------------------*/
36
#include "port.h"
37

  
38
/* ----------------------- Modbus includes ----------------------------------*/
39
#include "mb.h"
40
#include "mbframe.h"
41
#include "mbproto.h"
42
#include "mbconfig.h"
43

  
44
/* ----------------------- Defines ------------------------------------------*/
45
#define MB_PDU_FUNC_READ_ADDR_OFF           ( MB_PDU_DATA_OFF )
46
#define MB_PDU_FUNC_READ_REGCNT_OFF         ( MB_PDU_DATA_OFF + 2 )
47
#define MB_PDU_FUNC_READ_SIZE               ( 4 )
48
#define MB_PDU_FUNC_READ_REGCNT_MAX         ( 0x007D )
49

  
50
#define MB_PDU_FUNC_READ_RSP_BYTECNT_OFF    ( MB_PDU_DATA_OFF )
51

  
52
/* ----------------------- Static functions ---------------------------------*/
53
eMBException    prveMBError2Exception( eMBErrorCode eErrorCode );
54

  
55
/* ----------------------- Start implementation -----------------------------*/
56
#if MB_FUNC_READ_INPUT_ENABLED > 0
57

  
58
eMBException
59
eMBFuncReadInputRegister( UCHAR * pucFrame, USHORT * usLen )
60
{
61
    USHORT          usRegAddress;
62
    USHORT          usRegCount;
63
    UCHAR          *pucFrameCur;
64

  
65
    eMBException    eStatus = MB_EX_NONE;
66
    eMBErrorCode    eRegStatus;
67

  
68
    if( *usLen == ( MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN ) )
69
    {
70
        usRegAddress = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8 );
71
        usRegAddress |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1] );
72
        usRegAddress++;
73

  
74
        usRegCount = ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] << 8 );
75
        usRegCount |= ( USHORT )( pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1] );
76

  
77
        /* Check if the number of registers to read is valid. If not
78
         * return Modbus illegal data value exception. 
79
         */
80
        if( ( usRegCount >= 1 )
81
            && ( usRegCount < MB_PDU_FUNC_READ_REGCNT_MAX ) )
82
        {
83
            /* Set the current PDU data pointer to the beginning. */
84
            pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];
85
            *usLen = MB_PDU_FUNC_OFF;
86

  
87
            /* First byte contains the function code. */
88
            *pucFrameCur++ = MB_FUNC_READ_INPUT_REGISTER;
89
            *usLen += 1;
90

  
91
            /* Second byte in the response contain the number of bytes. */
92
            *pucFrameCur++ = ( UCHAR )( usRegCount * 2 );
93
            *usLen += 1;
94

  
95
            eRegStatus =
96
                eMBRegInputCB( pucFrameCur, usRegAddress, usRegCount );
97

  
98
            /* If an error occured convert it into a Modbus exception. */
99
            if( eRegStatus != MB_ENOERR )
100
            {
101
                eStatus = prveMBError2Exception( eRegStatus );
102
            }
103
            else
104
            {
105
                *usLen += usRegCount * 2;
106
            }
107
        }
108
        else
109
        {
110
            eStatus = MB_EX_ILLEGAL_DATA_VALUE;
111
        }
112
    }
113
    else
114
    {
115
        /* Can't be a valid read input register request because the length
116
         * is incorrect. */
117
        eStatus = MB_EX_ILLEGAL_DATA_VALUE;
118
    }
119
    return eStatus;
120
}
121

  
122
#endif
freemodbus/modbus/functions/mbfuncother.c
1
/* 
2
 * FreeModbus Libary: A portable Modbus implementation for Modbus ASCII/RTU.
3
 * Copyright (c) 2006 Christian Walter <wolti@sil.at>
4
 * All rights reserved.
5
 *
6
 * Redistribution and use in source and binary forms, with or without
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff