AVR/demo.c

/* 
 * MODBUS Slave Library: AVR demo application
 * Copyright (c) 2007 Christian Walter <wolti@sil.at>
 * All rights reserved.
 *
 * $Id: demo.c,v 1.7 2010/08/19 20:05:45 embedded-so.embedded-solutions.1 Exp $
 */

/* ----------------------- System includes ----------------------------------*/
#if defined(  __CODEVISIONAVR__ )
#else
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#endif

/* ----------------------- Platform includes --------------------------------*/
#include "mbport.h"

/* ----------------------- Modbus includes ----------------------------------*/
#include "mbs.h"
#include "common/mbtypes.h"
#include "common/mbutils.h"
#include "common/mbportlayer.h"

/* ----------------------- Defines ------------------------------------------*/
#define DEBUG_LED_PORT              ( PORTA )
#define DEBUG_LED_PIN               ( PINA4 )
#define DEBUG_LED_DDR               ( DDRA )

#define DEBUG_LED_0                 ( 0 )

#define MBS_SERIAL_PORT             ( 0 )
#define MBS_SERIAL_BAUDRATE         ( 19200 )
#define MBS_PARITY                  ( MB_PAR_NONE )
#define MBS_SLAVE_ADDRESS           ( 1 )

#define REG_INPUT_SECONDS_OFF       ( 0 )
#define REG_INPUT_MINUTES_OFF       ( 1 )
#define REG_INPUT_HOURS_OFF         ( 2 )
#define REG_INPUT_POWER_OUT         ( 3 )

#define REG_HOLDING_POWER_OUT       ( 0 )
#define REG_HOLDING_VALVE_1         ( 1 )
#define REG_HOLDING_VALVE_2         ( 2 )

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

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

STATIC USHORT   usRegInputValue[16];
STATIC USHORT   usRegHoldingValue[3];

/* ----------------------- Static functions ---------------------------------*/
STATIC void     vIOSetLED( UBYTE ubIdx, BOOL bTurnOn );
STATIC eMBException eMyRegInputCB( UBYTE * pubRegBuffer, USHORT usAddress, USHORT usNRegs );
STATIC eMBException eMyRegHoldingCB( UBYTE * pubRegBuffer, USHORT usAddress,
                                     USHORT usNRegs, eMBSRegisterMode eRegMode );
STATIC eMBException eMyDiscInputCB( UBYTE * pubRegBuffer, USHORT usAddress, USHORT usNRegs );
STATIC void     vSetupRTC( void );

/* ----------------------- Start implementation -----------------------------*/
#if defined(  __CODEVISIONAVR__ )
void
main( void )
#else
int
main( void )
#endif
{
    eMBErrorCode    eStatus;

    xMBSHandle      xMBSHdl;

    sei(  );
    do
    {
        vSetupRTC(  );
        if( MB_ENOERR !=
            ( eStatus =
              eMBSSerialInit( &xMBSHdl, MB_RTU, MBS_SLAVE_ADDRESS,
                              MBS_SERIAL_PORT, MBS_SERIAL_BAUDRATE, MBS_PARITY ) ) )
        {
        }
        else if( MB_ENOERR != ( eStatus = eMBSRegisterInputCB( xMBSHdl, eMyRegInputCB ) ) )
        {
            ( void )eMBSClose( xMBSHdl );
        }
        else if( MB_ENOERR != ( eStatus = eMBSRegisterHoldingCB( xMBSHdl, eMyRegHoldingCB ) ) )
        {
            ( void )eMBSClose( xMBSHdl );
        }
        else if( MB_ENOERR != ( eStatus = eMBSRegisterDiscreteCB( xMBSHdl, eMyDiscInputCB ) ) )
        {
            ( void )eMBSClose( xMBSHdl );
        }
        else
        {
            do
            {
                /* Poll the communication stack. */
                eMBSPoll( xMBSHdl );


                /* Update register values. */
                vIOSetLED( DEBUG_LED_0, usRegHoldingValue[REG_HOLDING_VALVE_1] > 0 ? 1 : 0 );
            }
            while( MB_ENOERR == eStatus );
            ( void )eMBSClose( xMBSHdl );
        }
    }
    while( TRUE );
}

eMBException
eMyRegInputCB( UBYTE * pubRegBuffer, USHORT usAddress, USHORT usNRegs )
{
    eMBException    eException = MB_PDU_EX_ILLEGAL_DATA_ADDRESS;
    STATIC const ULONG usRegsMappedAt = 0x0100;
    ULONG           usRegStart = usAddress;
    ULONG           usRegEnd = usAddress + usNRegs - 1;
    USHORT          usIndex;
    USHORT          usIndexEnd;

    if( ( usNRegs > 0 ) &&
        ( usRegStart >= usRegsMappedAt ) && ( usRegEnd <= ( usRegsMappedAt + MB_UTILS_NARRSIZE( usRegInputValue ) ) ) )
    {
        usIndex = ( USHORT ) ( usRegStart - usRegsMappedAt );
        usIndexEnd = ( USHORT ) ( usRegEnd - usRegsMappedAt );
        for( ; usIndex <= usIndexEnd; usIndex++ )
        {
            *pubRegBuffer++ = ( UBYTE ) ( usRegInputValue[usIndex] >> 8 );
            *pubRegBuffer++ = ( UBYTE ) ( usRegInputValue[usIndex] & 0xFF );
        }
        eException = MB_PDU_EX_NONE;
    }
    return eException;
}

eMBException
eMyRegHoldingCB( UBYTE * pubRegBuffer, USHORT usAddress, USHORT usNRegs, eMBSRegisterMode eRegMode )
{
    eMBException    eException = MB_PDU_EX_ILLEGAL_DATA_ADDRESS;
    STATIC const ULONG usRegsMappedAt = 0x0200;
    ULONG           usRegStart = usAddress;
    ULONG           usRegEnd = usAddress + usNRegs - 1;
    USHORT          usIndex;
    USHORT          usIndexEnd;

    if( ( usNRegs > 0 ) &&
        ( usRegStart >= usRegsMappedAt )
        && ( usRegEnd <= ( usRegsMappedAt + MB_UTILS_NARRSIZE( usRegHoldingValue ) ) ) )
    {
        usIndex = ( USHORT ) ( usRegStart - usRegsMappedAt );
        usIndexEnd = ( USHORT ) ( usRegEnd - usRegsMappedAt );
        switch ( eRegMode )
        {
        case MBS_REGISTER_WRITE:
            for( ; usIndex <= usIndexEnd; usIndex++ )
            {
                usRegHoldingValue[usIndex] = ( USHORT ) * pubRegBuffer++ << 8;
                usRegHoldingValue[usIndex] |= ( USHORT ) * pubRegBuffer++;
            }
            break;

        default:
        case MBS_REGISTER_READ:

            for( ; usIndex <= usIndexEnd; usIndex++ )
            {
                *pubRegBuffer++ = ( UBYTE ) ( usRegHoldingValue[usIndex] >> 8 );
                *pubRegBuffer++ = ( UBYTE ) ( usRegHoldingValue[usIndex] & 0xFF );
            }
            break;
        }
        eException = MB_PDU_EX_NONE;
    }
    return eException;
}

eMBException
eMyDiscInputCB( UBYTE * pubRegBuffer, USHORT usAddress, USHORT usNRegs )
{
    eMBException    eException = MB_PDU_EX_ILLEGAL_DATA_ADDRESS;
    STATIC const ULONG usRegsMappedAt = 0x0100;
    ULONG           usRegStart = usAddress;
    ULONG           usRegEnd = usAddress + usNRegs - 1;
    USHORT          usIndex;
    USHORT          usIndexEnd;

    if( ( usNRegs > 0 ) &&
        ( usRegStart >= usRegsMappedAt ) && ( usRegEnd <= ( usRegsMappedAt + MB_UTILS_NARRSIZE( usRegInputValue ) ) ) )
    {
        usIndex = ( USHORT ) ( usRegStart - usRegsMappedAt );
        usIndexEnd = ( USHORT ) ( usRegEnd - usRegsMappedAt );
        for( ; usIndex <= usIndexEnd; usIndex++ )
        {
            *pubRegBuffer++ = ( UBYTE ) ( usRegInputValue[usIndex] >> 8 );
            *pubRegBuffer++ = ( UBYTE ) ( usRegInputValue[usIndex] & 0xFF );
        }
        eException = MB_PDU_EX_NONE;
    }
    return eException;
}

void
vSetupRTC( void )
{
    MBP_ENTER_CRITICAL_SECTION(  );
#if defined( __AVR_ATmega168__ )
    TCCR0A = _BV( WGM01 );
    TCCR0B = _BV( CS02 ) | _BV( CS00 );
    OCR0A = ( ( F_CPU ) / ( ( ULONG ) 1024UL * 100UL ) );       /* 10ms timer */
    TIMSK0 = _BV( OCIE0A );
#endif
    MBP_EXIT_CRITICAL_SECTION(  );
}

void
vIOSetLED( UBYTE ubIdx, BOOL bTurnOn )
{
    STATIC BOOL     bIsInitalized = FALSE;

    if( !bIsInitalized )
    {
        DEBUG_LED_DDR |= _BV( DEBUG_LED_PIN );
        DEBUG_LED_PORT |= _BV( DEBUG_LED_PIN );
        bIsInitalized = TRUE;
    }
    switch ( ubIdx )
    {
    case DEBUG_LED_0:
        if( bTurnOn )
        {
            DEBUG_LED_PORT &= ~_BV( DEBUG_LED_PIN );
        }
        else
        {
            DEBUG_LED_PORT |= _BV( DEBUG_LED_PIN );
        }
        break;

    default:
        break;
    }
}

#if defined( __AVR_ATmega168__ )
SIGNAL( SIG_OUTPUT_COMPARE0A )
{
    STATIC UBYTE    us100MSSecCounter = 0;
    STATIC UBYTE    us10MSSecCounter = 0;

    us10MSSecCounter++;
    us100MSSecCounter++;
    if( us10MSSecCounter >= 100 )
    {
        us10MSSecCounter = 0;
        usRegInputValue[REG_INPUT_SECONDS_OFF]++;
        if( usRegInputValue[REG_INPUT_SECONDS_OFF] >= 60 )
        {
            usRegInputValue[REG_INPUT_SECONDS_OFF] = 0;
            usRegInputValue[REG_INPUT_MINUTES_OFF]++;
            if( usRegInputValue[REG_INPUT_MINUTES_OFF] >= 60 )
            {
                usRegInputValue[REG_INPUT_MINUTES_OFF] = 0;
                usRegInputValue[REG_INPUT_HOURS_OFF]++;
            }
        }

    }
    if( us100MSSecCounter >= 10 )
    {
        us100MSSecCounter = 0;
        if( usRegHoldingValue[REG_HOLDING_POWER_OUT] != usRegInputValue[REG_INPUT_POWER_OUT] )
        {
            if( usRegInputValue[REG_INPUT_POWER_OUT] < usRegHoldingValue[REG_HOLDING_POWER_OUT] )
            {
                usRegInputValue[REG_INPUT_POWER_OUT]++;
            }
            else
            {
                usRegInputValue[REG_INPUT_POWER_OUT]--;
            }
        }
    }
}
#endif

(C) 2007 Embedded Solutions. Last updated on 13 Mar 2013.