/***************************************************************************
 * Copyright (c) 2005, Research Group Embedded Interaction                 *
 * Paul Holleis <paul@hcilab.org>                                          *
 * Matthias Kranz <matthias@hcilab.org>                                    *
 * Albrecht Schmidt <albrecht@hcilab.org>                                  *
 * 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 following disclaimer.      *
 *    * Redistributions in binary form must reproduce the above copyright  *
 *      notice, this list of conditions and the following disclaimer in    *
 *      the documentation and/or other materials provided with the         *
 *      distribution.                                                      *
 *    * Neither the name of the <ORGANIZATION> nor the names of its        *
 *      contributors may be used to endorse or promote products derived    *
 *      from this software without specific prior written permission.      *
 *                                                                         *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS     *
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT       *
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR   *
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT    *
 * OWNER OR CONTRIBUTORS 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.                                                                 *
 **************************************************************************/

#ifndef __ADXL311JE_C__
#define   __ADXL311JE_C__               096

#ifndef ACCL_SENSOR
  #define ACCL_SENSOR
#endif


/**
 * Switches the adxl on
 */
#define AcclSensorOn()   { output_high(PIN_ACCL_ADXL_POWER); }

/**
 * Switches the adxl off
 */
#define AcclSensorOff()   { output_low(PIN_ACCL_ADXL_POWER); }


/**
 * Initializes the adxl
 * Sets power to output and sampling pins to input.
 *
 * @return returns 0 if no error
 */
int AcclSensorInit()
{
   bit_clear(TRIS_ACCL_ADXL_POWER);      // set power pin to output
   bit_set(TRIS_ACCL_ADXL_XOUT);         // set sample pinx to input
   bit_set(TRIS_ACCL_ADXL_YOUT);         // set sample piny to input
   bit_set(TRIS_ACCL_ADXL_ZOUT);         // set sample pinz to input
   bit_set(TRIS_ACCL_ADXL_UOUT);         // set sample pinu to input

   AcclSensorOff();                           // power off for light

   return 0;                        // indicate no error
}

/**
 * Setups the microcontroller for sampling
 * @return returns 0 if no error
 */
int AcclSensorPrepare()
{
   return 0;
}

/**
 * Returns the x acceleration in g scale
 * Unit: for one g (scale=10 means +-1g is +-10 digits)
 * @param g the accl value in g
 * @return returns 0 if no error
 */
int AcclXSensorGetGravity(signed long* ret)
{
   // set channel
   if ( !ADCIsChSet(ADCH_ACCL_ADXL_XOUT) )
   {
      ADCSetCh(ADCH_ACCL_ADXL_XOUT);
   }
   // set conversion clock
   ADCSetClock(0);
   // start ADC
   ADCEnable();

   *ret = ADCRead10();

   // always success
   return 0;
}

/**
 * Returns the y acceleration in g scale
 * Unit: for one g (scale=10 means +-1g is +-10 digits)
 * @param g the accl value in g
 * @return returns 0 if no error
 */
int AcclYSensorGetGravity(signed long* ret)
{
   // set channel
   if ( !ADCIsChSet(ADCH_ACCL_ADXL_YOUT) )
   {
      ADCSetCh(ADCH_ACCL_ADXL_YOUT);
   }
   // set conversion clock
   ADCSetClock(0);
   // start ADC
   ADCEnable();

   *ret = ADCRead10();

   // always success
   return 0;
}

/**
 * Returns the z acceleration in g scale
 * Unit: for one g (scale=10 means +-1g is +-10 digits)
 * @param g the accl value in g
 * @return returns 0 if no error
 */
int AcclZSensorGetGravity(signed long* ret)
{
   // set channel
   if ( !ADCIsChSet(ADCH_ACCL_ADXL_ZOUT) )
   {
      ADCSetCh(ADCH_ACCL_ADXL_ZOUT);
   }
   // set conversion clock
   ADCSetClock(0);
   // start ADC
   ADCEnable();

   *ret = ADCRead10();

   // always success
   return 0;
}

/**
 * Returns the u acceleration in g scale
 * Unit: for one g (scale=10 means +-1g is +-10 digits)
 * @param g the accl value in g
 * @return returns 0 if no error
 */
int AcclUSensorGetGravity(signed long* ret)
{
   // set channel
   if ( !ADCIsChSet(ADCH_ACCL_ADXL_UOUT) )
   {
      ADCSetCh(ADCH_ACCL_ADXL_UOUT);
   }
   // set conversion clock
   ADCSetClock(0);
   // start ADC
   ADCEnable();

   *ret = ADCRead10();

   // always success
   return 0;
}

/**
 * Gets the values of the accelerometer sensors for x, y, z and u axis.
 * The values are averaged over AVGNUM samples.
 * Call it via AcclGetAvg(AVGNUM, &accel_x, &accel_y, &accel_z, &accel_u);
 */
void AcclGetAvg(unsigned int AVGNUM, signed long *accel_x, signed long *accel_y,
                signed long *accel_z, signed long *accel_u)
{
  signed long tmp_accel_x = 0;
  signed long tmp_accel_y = 0;
  signed long tmp_accel_z = 0;
  signed long tmp_accel_u = 0;
  int i;

  *accel_x = *accel_y = *accel_z = *accel_u = 0;

  for (i = 0; i < AVGNUM; i++)
    {
      // Prepare the acceleration sensor for data aquisition.
      AcclSensorPrepare();
      // get the two values for 2D gravity
      AcclXSensorGetGravity(&tmp_accel_x);
      AcclYSensorGetGravity(&tmp_accel_y);
      AcclZSensorGetGravity(&tmp_accel_z);
      AcclUSensorGetGravity(&tmp_accel_u);

      *accel_x += tmp_accel_x;
      *accel_y += tmp_accel_y;
      *accel_z += tmp_accel_z;
      *accel_u += tmp_accel_u;
    }
    *accel_x /= AVGNUM;
    *accel_y /= AVGNUM;
    *accel_u /= AVGNUM;
    *accel_z /= AVGNUM;
}

/**
 * Packs the given value directly in the sendbuffer
 * as an ACL packet which is ready to be sent.
 * @return error code, 0 if no error
 *
 * Note: The format is described in acltypes.h
 */
int PackInACL(signed long value, int highval, int lowval)
{

  if ( ACLGetRemainingPayloadSpace() > 5 )
  {
    ACLAddNewType(highval, lowval); // SGX
    ACLAddData((byte)(value>>8));         // value
    ACLAddData((byte)(value&0x00FF));       // value
    ACLAddData(0);                  // index = 0
  }
  else
  {
    return 1;   // not enough space left
  }

  return 0; // no error
}


/**
 * Packs the accl sensor value for the x axis directly in the sendbuffer
 * as an ACL packet which is ready to be sent.
 * @param value accel x sensor value
 * @return error code, 0 if no error
 *
 * Note: The format is described in acltypes.h
 */
int AcclXSensorPackInACL(signed long value)
{
  return PackInACL(value, ACL_TYPE_SGX_HI, ACL_TYPE_SGX_LO);
}


/**
* Packs the accl sensor value for the y axis directly in the sendbuffer
* as an ACL packet which is ready to be sent.
 * @param value accel y sensor value
* @return error code, 0 if no error
*
* Note: The format is described in acltypes.h
*/
int AcclYSensorPackInACL(signed long value)
{
  return PackInACL(value, ACL_TYPE_SGY_HI, ACL_TYPE_SGY_LO);
}

/**
 * Packs the accl sensor value for the z axis directly in the sendbuffer
 * as an ACL packet which is ready to be sent.
 * @param value accel z sensor value
 * @return error code, 0 if no error
 *
 * Note: The format is described in acltypes.h
 */
int AcclZSensorPackInACL(signed long value)
{
  return PackInACL(value, ACL_TYPE_SGZ_HI, ACL_TYPE_SGZ_LO);
}


/**
* Packs the accl sensor value for the u axis directly in the sendbuffer
* as an ACL packet which is ready to be sent.
* @param value accel u sensor value
* @return error code, 0 if no error
*
* Note: The format is described in acltypes.h
*/
int AcclUSensorPackInACL(signed long value)
{
  return PackInACL(value, ACL_TYPE_SGU_HI, ACL_TYPE_SGU_LO);
}

#endif
