/*
 * Copyright (C) 2014 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_NDEBUG 0

#include <fcntl.h>
#include <errno.h>
#include <math.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/select.h>
#include <cutils/log.h>
#include <linux/input.h>
#include <string.h>

#include "PressureSensor.IIO.secondary.h"
#include "sensors.h"
#include "MPLSupport.h"
#include "sensor_params.h"
#include "ml_sysfs_helper.h"

#pragma message("HAL:build pressure sensor on Invensense MPU secondary bus")
/* dynamically get this when driver supports it */
#define CHIP_ID "BMP280"

//#define TIMER (1)
#define DEFAULT_POLL_TIME 300
#define PRESSURE_MAX_SYSFS_ATTRB sizeof(pressureSysFs) / sizeof(char*)

static int s_poll_time = -1;
static int min_poll_time = 50;
static struct timespec t_pre;

/*****************************************************************************/

PressureSensor::PressureSensor(const char *sysfs_path) 
                  : SensorBase(NULL, NULL),
                    pressure_fd(-1)
{
    VFUNC_LOG;

    mSysfsPath = sysfs_path;
    LOGV_IF(ENG_VERBOSE, "pressuresensor path: %s", mSysfsPath);
    if(inv_init_sysfs_attributes()) {
        LOGE("Error Instantiating Pressure Sensor\n");
        return;
    } else {
        LOGI_IF(PROCESS_VERBOSE, "HAL:Secondary Chip Id: %s", CHIP_ID);
    }
}

PressureSensor::~PressureSensor()
{
    VFUNC_LOG;

    if( pressure_fd > 0)
        close(pressure_fd);
}

int PressureSensor::getFd() const
{
    VHANDLER_LOG;
    return pressure_fd;
}

/**
 *  @brief        This function will enable/disable sensor.
 *  @param[in]    handle
 *                  which sensor to enable/disable.
 *  @param[in]    en
 *                  en=1, enable; 
 *                  en=0, disable
 *  @return       if the operation is successful.
 */
int PressureSensor::enable(int32_t handle, int en) 
{
    VFUNC_LOG;

    int res = 0;

    LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %d > %s (%lld)",
            en, pressureSysFs.pressure_enable, getTimestamp());
    res = write_sysfs_int(pressureSysFs.pressure_enable, en);

    return res;
}

int PressureSensor::setDelay(int32_t handle, int64_t ns) 
{
    VFUNC_LOG;
    
    int res = 0;

    mDelay = int(1000000000.f / ns);
    LOGV_IF(SYSFS_VERBOSE, "HAL:sysfs:echo %lld > %s (%lld)",
            mDelay, pressureSysFs.pressure_rate, getTimestamp());
    res = write_sysfs_int(pressureSysFs.pressure_rate, mDelay);
     
#ifdef TIMER
    int t_poll_time = (int)(ns / 1000000LL);
    if (t_poll_time > min_poll_time) {
        s_poll_time = t_poll_time;
    } else {
        s_poll_time = min_poll_time;
    }
    LOGV_IF(PROCESS_VERBOSE,
            "HAL:setDelay : %llu ns, (%.2f Hz)", ns, 1000000000.f/ns);
#endif
    return res;
}


/**
    @brief      This function will return the state of the sensor.
    @return     1=enabled; 0=disabled
**/
int PressureSensor::getEnable(int32_t handle)
{
    VFUNC_LOG;
    return mEnable;
}

/**
 *  @brief  This function will return the current delay for this sensor.
 *  @return delay in nanoseconds. 
 */
int64_t PressureSensor::getDelay(int32_t handle)
{
    VFUNC_LOG;

#ifdef TIMER
    if (mEnable) {
        return s_poll_time;
    } else {
        return -1;
    }
#endif
    return mDelay;
}

void PressureSensor::fillList(struct sensor_t *list)
{
    VFUNC_LOG;

    const char *pressure = "BMP280";

    if (pressure) {
        if(!strcmp(pressure, "BMP280")) {
            list->maxRange = PRESSURE_BMP280_RANGE;
            list->resolution = PRESSURE_BMP280_RESOLUTION;
            list->power = PRESSURE_BMP280_POWER;
            list->minDelay = PRESSURE_BMP280_MINDELAY;
            mMinDelay = list->minDelay;
            return;
        }      
    }
    LOGE("HAL:unknown pressure id %s -- "
         "params default to bmp280 and might be wrong.",
         pressure);
    list->maxRange = PRESSURE_BMP280_RANGE;
    list->resolution = PRESSURE_BMP280_RESOLUTION;
    list->power = PRESSURE_BMP280_POWER;
    list->minDelay = PRESSURE_BMP280_MINDELAY;
    mMinDelay = list->minDelay;
    return;
}

int PressureSensor::inv_init_sysfs_attributes(void)
{
    VFUNC_LOG;

    pathP = (char*)calloc(PRESSURE_MAX_SYSFS_ATTRB,
                          sizeof(char[MAX_SYSFS_NAME_LEN]));
    if (pathP == NULL)
        return -1;

    char *sptr = pathP;
    char **dptr = reinterpret_cast<char **>(&pressureSysFs);
    for (size_t i = 0; i < PRESSURE_MAX_SYSFS_ATTRB; i++) {
      *dptr++ = sptr;
      sptr += sizeof(char[MAX_SYSFS_NAME_LEN]);
    }

    sprintf(pressureSysFs.pressure_enable, "%s%s", mSysfsPath, "/pressure_enable");
    sprintf(pressureSysFs.pressure_rate, "%s%s", mSysfsPath, "/pressure_rate");

    // Supported by driver ?
    FILE  *sysfsfp;
    sysfsfp = fopen(pressureSysFs.pressure_rate, "r");
    if (sysfsfp == NULL) {
        LOGE("HAL: HAL configured to support Pressure sensor but not by driver");
    } else {
        fclose(sysfsfp);
    }
    return 0;
}