#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <errno.h>

#include "i2c-dev.h"

#include "msp430lib.h"

/* Enables or disables debug output */
#ifdef __DEBUG
#define __D(fmt, args...) fprintf(stderr, "MSP430lib Debug: " fmt, ## args)
#else
#define __D(fmt, args...)
#endif

#ifdef __DEBUG
#define __E(fmt, args...) fprintf(stderr, "MSP430lib Error: " fmt, ## args)
#else
#define __E(fmt, args...)
#endif

#define I2C_DEVICE "/dev/i2c/0"
#define I2C_DEV_ADDR 0x23

static int msp430lib_fd = -1;
static int oldval;

static int get_ir_val(int *val)
{
    __u8 buf[4];

    buf[0] = 2;
    buf[1] = 3;

    if (write(msp430lib_fd, buf, 2) != 2) {
        __E("Failed to write get IR value command to device [%s]\n",
                                                            strerror(errno));
        return MSP430LIB_FAILURE;
    }

    usleep(100);

    if (read(msp430lib_fd, buf, 4) != 4) {
        __E("Failed to read RTC data\n");
        return MSP430LIB_FAILURE;
    }

#if 0
    if (buf[0] != 4 || buf[1] != 3) {
        __E("Failed to read IR ACK from device [%d %d]\n", buf[0], buf[1]);
        return MSP430LIB_FAILURE;
    }
#endif

    *val = buf[2] | (buf[3] << 8);

    return MSP430LIB_SUCCESS;
}

int msp430lib_init(void)
{
    if (msp430lib_fd != -1) {
        __E("Library already initialized\n");
        return MSP430LIB_FAILURE;
    }

    msp430lib_fd = open(I2C_DEVICE, O_RDWR);

    if (msp430lib_fd < 0) {
        __E("Error while opening i2c device %s\n", I2C_DEVICE);
        return MSP430LIB_FAILURE;
    }

    if (ioctl(msp430lib_fd, I2C_SLAVE, I2C_DEV_ADDR) == -1) {
        __E("Failed to set I2C_SLAVE to %#x\n", I2C_DEV_ADDR);
        return MSP430LIB_FAILURE;
    }

    if (get_ir_val(&oldval) == MSP430LIB_FAILURE) {
        return MSP430LIB_FAILURE;
    }

    return MSP430LIB_SUCCESS;
}

int msp430lib_get_rtc(int *year, int *month, int *day, int *hour,
                      int *minute, int *second)
{
    __u8 buf[9];

    if (msp430lib_fd == -1) {
        __E("Library not initialized\n");
        return MSP430LIB_FAILURE;
    }

    buf[0] = 0x2;
    buf[1] = 0x1;

    if (write(msp430lib_fd, buf, 2) != 2) {
        __E("Failed to write get RTC command to device [%s]\n",
                                                            strerror(errno));
        return MSP430LIB_FAILURE;
    }

    usleep(100);

    if (read(msp430lib_fd, buf, 9) != 9) {
        __E("Failed to read RTC data [%s]\n", strerror(errno));
        return MSP430LIB_FAILURE;
    }

    if (buf[0] != 9 || buf[1] != 1) {
        __E("get_rtc - Failed to read RTC ACK from device [got %#x%#x]\n",
                                                            buf[0], buf[1]);
        return MSP430LIB_FAILURE;
    }

    *year =  buf[2] | (buf[3] << 8);
    *month = buf[4];
    *day = buf[5];
    *hour = buf[6];
    *minute = buf[7];
    *second = buf[8];

    usleep(100);

    return MSP430LIB_SUCCESS;
}

int msp430lib_set_rtc(int year, int month, int day, int hour,
                      int minute, int second)
{
    __u8 buf[9];

    if (msp430lib_fd == -1) {
        __E("Library not initialized\n");
        return MSP430LIB_FAILURE;
    }

    buf[0] = 0x9;
    buf[1] = 0;
    buf[2] = year & 0xff;
    buf[3] = year >> 8;
    buf[4] = month;
    buf[5] = day;
    buf[6] = hour;
    buf[7] = minute;
    buf[8] = second;

    if (write(msp430lib_fd, buf, 9) != 9) {
        __E("Failed to write set RTC command to device [%s]\n",
                                                            strerror(errno));
        return MSP430LIB_FAILURE;
    }

    usleep(100);

    return MSP430LIB_SUCCESS;
}

int msp430lib_get_ir_key(enum msp430lib_keycode *key)
{
    int val;

    if (msp430lib_fd == -1) {
        __E("Library not initialized\n");
        return MSP430LIB_FAILURE;
    }

    if (get_ir_val(&val) == MSP430LIB_FAILURE) {
        return MSP430LIB_FAILURE;
    }

    if (val != oldval) {
        *key = val & ~(1<<11);
        oldval = val;
    }
    else {
        *key = 0;
    }

    usleep(100);

    return MSP430LIB_SUCCESS;
}

int msp430lib_exit(void)
{
    if (msp430lib_fd == -1) {
        __E("Library not initialized\n");
        return MSP430LIB_FAILURE;
    }

    if (close(msp430lib_fd) == -1) {
        __E("Failed to close i2c device %s\n", I2C_DEVICE);
        return MSP430LIB_FAILURE;
    }

    msp430lib_fd = -1; 

    return MSP430LIB_SUCCESS;
}

