#include "led_operation.h"
#include "dy_utils/dy_common.h"

#define ADDR_AUTOINCREMENT  0x40
#define ADDR_STATIONARY     0x44

unsigned char led_status_regs[LED_GROUPS_NUM] = {
	0b00000000,		// led group 1
	0b00000000,		// led group 2
	0b00000000,		// led group 3
	0b00000000,		// led group 4
	0b00000000,		// led group 5
	0b00000000,		// led group 6
	0b00000000,		// led group 7
	0b00000000,		// led group 8
	0b00000000,		// led group 9
	0b00000000,		// led group 10
	0b00000000,		// led group 11
	0b00000000,		// led group 12
	0b00000000		// led group 13
};

struct num_to_ss {  // SS: seven segments
    int num;
    unsigned char seg;
};


/* Bit values map to digit segments (and decimal dot)
 * according to the following drawing:
 *
 *       0
 *     ====
 *  5||    ||1
 *   ||  6 ||
 *     ====
 *  4||    ||2
 *   ||  3 ||
 *     ====  (o)7
*/

const struct num_to_ss num_to_ss[] = {
    { 0, 0b0111111 },
    { 1, 0b0000110 },
    { 2, 0b1011011 },
    { 3, 0b1001111 },
    { 4, 0b1100110 },
    { 5, 0b1101101 },
    { 6, 0b1111101 },
    { 7, 0b0000111 },
    { 8, 0b1111111 },
    { 9, 0b1101111 }
};

static int convert_num_to_seg(int group_id, int num, unsigned char *seg)
{
    const struct num_to_ss *p = num_to_ss;  // ss: seven segments
    int len = sizeof(num_to_ss) / sizeof(struct num_to_ss);
    int i = 0;

    if (num > 9 || num < 0) {
        dy_syslog(LOG_ERR, "Invalid num: %d, It should be (9 >= num >= 0)\n", num);
        return -1;
    }

    for (i=0; i<len; i++) {
        if (num == p->num) {
            *seg = p->seg | led_status_regs[group_id];
            return 0;
        }
        p++;
    }

    return -1;
}

void turn_led_on(tm1640_gpio *gpio_handler, unsigned char group_id, unsigned char code)
{
    led_status_regs[group_id] |= code;
    tm1640_gpio_command(gpio_handler, ADDR_STATIONARY);
    tm1640_gpio_byte(gpio_handler, group_id, led_status_regs[group_id]);
}

void turn_led_off(tm1640_gpio *gpio_handler, unsigned char group_id, unsigned char code)
{
    led_status_regs[group_id] &= code;
    tm1640_gpio_command(gpio_handler, ADDR_STATIONARY);
    tm1640_gpio_byte(gpio_handler, group_id, led_status_regs[group_id]);
}

void set_digital_tube(tm1640_gpio *gpio_handler, int group_id, int val)
{
    unsigned char seg = 0;
    if(0 != convert_num_to_seg(group_id, val, &seg)) {
        return;
    }
    tm1640_gpio_command(gpio_handler, ADDR_STATIONARY);
    tm1640_gpio_byte(gpio_handler, group_id, seg);
}

void clean_digital_tube(tm1640_gpio *gpio_handler, int group_id)
{
    turn_led_off(gpio_handler, group_id, DIGITAL_TUBE_OFF);
}
