Subversion Repositories HomeAutomation

Rev

Rev 486 | Rev 514 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

/**
 * CAN Relay.
 *
 *
 * @date    2006-12-17
 * @author  Erik Larsson
 *
 *   ADC=Vin*1024/Vref
 *   Vout=( 10 mV/C )( Temperature C ) + 500 mV
 *
 *  Transmitts: DATA: <temperature low byte> <temperature high byte> <relay status> <failsafe mode>
 *
 *
 */

#define TWO_BUTTON_MODE 0 /* If using two (or just one but nothing more) auxiliary buttons */

/*-----------------------------------------------------------------------------
 * Includes
 *---------------------------------------------------------------------------*/
/* system files */
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
/* lib files */
#include <config.h>
#include <bios.h>
#include <drivers/timer/timebase.h>
//#include <funcdefs.h>

/* defines */
#define RELAY_OFF           0x01
#define RELAY_ON            0x02
#define FAILSAFE_MODE       0x0F
#define FAILSAFE_TRESHOLD   0xFF  /* Degrees when nodeRelay goes into failsafe mode */

#define RELAY_CMD_ON        0x01
#define RELAY_CMD_OFF       0x02
#define RELAY_CMD_TOGGLE    0x03
#define RELAY_CMD_STATUS    0x04
#define RELAY_CMD_RESET     0x05
#define STATUS_SEND_PERIOD  10000UL /* milliseconds */
#define FAILSAFE_SEND_PERIOD    10000UL /* milliseconds */
#define BOUNCE_TIME         10 /* milliseconds */
#define BUTTON1             1
#define BUTTON2             2

#define THISRELAYID         NODE_ID     /* application software should not depend on the id of the physical node
                                            but for now lets do it like this */

#define APP_TYPE    CAN_APPTYPES_RELAY
#define APP_VERSION 0x0001

/*-------------------------------------------------------------------------
 * Global variables
 * -----------------------------------------------------------------------*/
uint8_t relayStatus, failsafe_flag = 0;
uint32_t boardTemperature = 0;

volatile Can_Message_t rxMsg; // Message storage
volatile uint8_t rxMsgFull;   // Synchronization flag


/*----------------------------------------------------------------------------
 * Functions
 * -------------------------------------------------------------------------*/
uint8_t relayOff();
uint8_t relayOn();
void relayFailsafe();
void sendStatus();

void can_receive(Can_Message_t *msg)
{ // CAN callback function
    if (!rxMsgFull) {
        memcpy((void*)&rxMsg, msg, sizeof(rxMsg));
        rxMsgFull = 1;
    }
}

/*----------------------------------------------------------------------------
 * Interrupt routines // FIXME ordna och testa tryckknappar/rotary encoder
 * -------------------------------------------------------------------------*/
#if TWO_BUTTON_MODE
ISR( PCINT2_vect )
{

}
#endif

/*-----------------------------------------------------------------------------
 * Main Program
 *---------------------------------------------------------------------------*/
int main(void) {

    uint32_t timeStamp = Timebase_CurrentTime(), temp = timeStamp;

    adcTemperatureInit();

    // Set up callback for CAN messages
    BIOS_CanCallback = &can_receive;

    sei();
    
    Timebase_Init();

    Can_Message_t txMsg;
    txMsg.Id = (CAN_NMT_APP_START << CAN_SHIFT_NMT_TYPE) | (NODE_ID << CAN_SHIFT_NMT_SID);
    txMsg.DataLength = 4;
    txMsg.RemoteFlag = 0;
    txMsg.ExtendedFlag = 1;
    txMsg.Data.words[0] = APP_TYPE;
    txMsg.Data.words[1] = APP_VERSION;
    BIOS_CanSend(&txMsg);

    // Turn relay off
    relayStatus = relayOff();

    // Main loop
    while (1) {

        temp = Timebase_CurrentTime();
        if( temp - timeStamp >= STATUS_SEND_PERIOD ){
            timeStamp = temp;
            // Send relay status to CAN
            sendStatus();
        }

        if (rxMsgFull) {
            uint8_t acttype;
            uint16_t relayid;
        
            if ( ((rxMsg.Id & CAN_MASK_CLASS)>>CAN_SHIFT_CLASS) == CAN_ACT){
                // Actuator package
                acttype =(uint8_t)((rxMsg.Id & CAN_MASK_ACT_TYPE) >> CAN_SHIFT_ACT_TYPE);
                relayid = (uint16_t)((rxMsg.Id & CAN_MASK_ACT_ID) >> CAN_SHIFT_ACT_ID);
                
                if ((acttype == ACT_TYPE_RELAY) && (relayid == THISRELAYID)) {
                    // This is a message for this relay
                    if (rxMsg.Data.bytes[0] == RELAY_CMD_RESET) {
                        // Return to normal operation
                        failsafe_flag = 0;
                    }
                    
                    if (!failsafe_flag) {
                        if (rxMsg.Data.bytes[0] == RELAY_CMD_ON ){
                            // Turn relay on
                            relayStatus = relayOn();
            
                        } else if (rxMsg.Data.bytes[0] == RELAY_CMD_OFF ){
                            // Turn relay off
                            relayStatus = relayOff();
            
                        } else if (rxMsg.Data.bytes[0] == RELAY_CMD_TOGGLE ){
                                // Toggle relay
                                if(relayStatus == RELAY_OFF){
                                    relayStatus = relayOn();
                                }else{
                                    relayStatus = relayOff();
                                }
            
                        }else if(rxMsg.Data.bytes[0] == RELAY_CMD_STATUS ){
                            // Send relay status to CAN
                            sendStatus();
                        }
                    }
                }
            }
            rxMsgFull = 0; //  

        }
        
    }
    return 0;
}

uint8_t relayOff()
{
    // Turn off relay
    PORTC &= ~(1<<PC1);
    DDRC |= (1<<DDC1);

    return RELAY_OFF;
}

uint8_t relayOn()
{
    // Turn on relay
    DDRC &= ~(1<<DDC1);
    PORTC |= (1<<PC1);

    return RELAY_ON;
}

void relayFailsafe()
{
    uint32_t failsafe_timeStamp, temp;
    relayStatus = relayOff();
    failsafe_flag = 1;

    while(1){

        if( !failsafe_flag ){
            // Return from failsafe mode
            return;
        }
// TODO skicka med period
        sendStatus( );
    }
}

void sendStatus()
{
    uint32_t temperature;
    Can_Message_t statusMsg;
    statusMsg.RemoteFlag = 0;
    statusMsg.ExtendedFlag = 1;
    statusMsg.DataLength = 4;
    statusMsg.Id = ( CAN_SNS<<CAN_SHIFT_CLASS )|( SNS_TYPE_RELAY_STATUS<<CAN_SHIFT_ACT_TYPE )|( NODE_ID<<CAN_SHIFT_SNS_SID );
    
    temperature = getTC1047temperature();
    if( (int32_t)temperature >= FAILSAFE_TRESHOLD && !failsafe_flag ){
        // Goto failsafe mode
        relayFailsafe();
    }else{
        // Transmitt node status
        statusMsg.Data.bytes[0] = temperature & 0x00FF;
        statusMsg.Data.bytes[1] = (temperature & 0xFF00)>>8;
        statusMsg.Data.bytes[2] = relayStatus;
        statusMsg.Data.bytes[3] = failsafe_flag;

        BIOS_CanSend( &statusMsg );
    }
}