/* ----------------------------------------------------------------------------
 *         ATMEL Microcontroller Software Support
 * ----------------------------------------------------------------------------
 * Copyright (c) 2012, Atmel Corporation
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the disclaimer below.
 *
 * Atmel's name may not be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * ----------------------------------------------------------------------------
 */

/*----------------------------------------------------------------------------
 *        Headers
 *----------------------------------------------------------------------------*/
#include <stdbool.h>

#include "board.h"
#include "motion_detector.h"

/*----------------------------------------------------------------------------
 *        Local variables
 *----------------------------------------------------------------------------*/
static volatile E_CMP_RES eCmpRes = CMP_EQUAL;

/** determine wich kind of trigger the PIR device use to detect a motion. See
Figure 6.6 of Application note**/
#define RISING_EDGE 0 //trigger on rising edge of the motion signal
#define FALLING_EDGE 1 //trigger on falling edge of the motion signal
#define FALLING_AND_RISING_EDGE 2 //trigger on both rising and falling edge of the motion signal

#define MOTION_DETECT_TRIGGER FALLING_AND_RISING_EDGE

/** indicate if there's any comparison event triggered*/
static volatile   bool bCmpEventFlag = false;

/*----------------------------------------------------------------------------
 *        Exported functions
 *----------------------------------------------------------------------------*/

/**
 * Interrupt handler for the ACC.
 */
void ACC_IrqHandler( void )
{
    uint32_t status;

    status = ACC_GetStatus(ACC);
    /*Compare Output Interrupt*/
    if ((status & ACC_IER_CE) == ACC_IER_CE) {

        bCmpEventFlag = true;

        if (ACC_GetComparisonResult(ACC, status)) {

            eCmpRes = CMP_GREATER;

        } else {

            eCmpRes = CMP_LESS;

        }
    }
   NVIC_DisableIRQ(ACC_IRQn);
   ACC_DisableIt(ACC,ACC_IDR_CE);
}


/* initalize PIR ACC for motion detect*/
void MD_Init(void)
{
    /* Configure AD4 AD5 as analog inputs*/
    ADC_EnableChannel(ADC, 0);
    ADC_EnableChannel(ADC, 4);
    ADC_EnableChannel(ADC, 5);

    /* Initialize ACC*/
    ACC_Configure( ACC,
                  ID_ACC,
                  ACC_MR_SELPLUS_AD4,
                  ACC_MR_SELMINUS_AD0,
                  ACC_MR_ACEN_EN,
                  ACC_MR_EDGETYP_ANY,
                  ACC_MR_INV_DIS);
    /* select comparison pair*/
    ACC_SetComparisonPair(ACC,ACC_MR_SELPLUS_AD4,ACC_MR_SELMINUS_AD0);

    /*clear status*/
    ACC_GetStatus(ACC);

    /* reset event flags*/
    eCmpRes = CMP_EQUAL;
    bCmpEventFlag = false;
}

void MD_Enabled(void)
{
   /*Enable compasion interrupt*/
   ACC_EnableIt(ACC,ACC_IER_CE);
   /*Enable ACC interrupt*/
   NVIC_EnableIRQ(ACC_IRQn);

}
void MD_Disabled(void)
{
    /* disable Comparison Event*/
   ACC->ACC_MR &= (uint32_t)~ACC_MR_ACEN_EN;
   /* stop peripheral clock*/
   PMC->PMC_PCER1 = 1 << (ID_ACC - 32);

   /* disable interrupt*/
   NVIC_DisableIRQ(ACC_IRQn);
   ACC_DisableIt(ACC,ACC_IDR_CE);
}

/** return comparison result*/
E_CMP_RES ACC_GetComparRes(void)
{
    return eCmpRes;
}

/** return the status of motion detection*/
bool MD_IsDetected(void)
{

/*Motion detect on rising edge*/
#if (MOTION_DETECT_TRIGGER == RISING_EDGE)
    return ( bCmpEventFlag && (eCmpRes == CMP_GREATER));

/*Motion detect on falling edge*/
#elif (MOTION_DETECT_TRIGGER == FALLING_EDGE)
    return ( bCmpEventFlag && (eCmpRes == CMP_LESS));

/*by default motion detect on falling and rising edge edge*/
#else
    return (bCmpEventFlag);
#endif
}

/** Reset the variables*/
void MD_Reset(void)
{
    bCmpEventFlag = false;
    eCmpRes = CMP_EQUAL;
}
