#include <stdio.h>  /*标准输入输出定义*/
#include <stdlib.h> /*标准函数库定义*/
#include <unistd.h> /*Unix 标准函数定义*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>   /*文件控制定义*/
#include <termios.h> /*PPSIX 终端控制定义*/
#include <errno.h>   /*错误号定义*/
#include <string.h>
#include <pthread.h>

#define MAX_PORT 4
#define USE_DEVICES_LIST "/sys/kernel/debug/usb/devices"

typedef struct usb_device
{
    int slot;
    int vendorId;
    int productId;
    char driver[50];
    int insert;
} usb_device_t;

typedef struct
{
    usb_device_t device[MAX_PORT];
} mpcie_var_t;

static int GetInt(char *string, char *pattern, int base)
{
    char *pointer;

    pointer = strstr(string, pattern);
    if (pointer == NULL)
        return (0);

    pointer += strlen(pattern);
    return ((int)(strtol(pointer, NULL, base)));
}

static void GetString(char *dest, char *source, char *pattern, int maxSize)
{
    char *pointer;

    pointer = strstr(source, pattern);
    if (pointer == NULL)
        return;

    pointer += strlen(pattern);
    strncpy(dest, pointer, maxSize);
    return;
}

static int usb_parse_line(mpcie_var_t *var, char *line)
{
    static int this_port = -1;

    switch (line[0])
    {
    case 'T':
#define TOPOLOGY_BUS_STRING "Bus="
#define TOPOLOGY_LEVEL_STRING "Lev="
#define TOPOLOGY_PARENT_STRING "Prnt="
#define TOPOLOGY_PORT_STRING "Port="
    {
        int busNumber = GetInt(line, TOPOLOGY_BUS_STRING, 10);
        int level = GetInt(line, TOPOLOGY_LEVEL_STRING, 10);
        int parentNumber = GetInt(line, TOPOLOGY_PARENT_STRING, 10);
        int portNumber = GetInt(line, TOPOLOGY_PORT_STRING, 10);

        if (busNumber == 1 && level == 2 && parentNumber == 2)
        {
            if (portNumber >= MAX_PORT)
            {
                fprintf(stderr, "wrong port number");
                return 0;
            }

            var->device[portNumber].slot = portNumber + 1;
            this_port = portNumber;
            var->device[portNumber].insert = 1;
        }
        else
        {
            this_port = -1;
        }
    }

    break;
    case 'P':
#define DEVICE_VENDOR_STRING "Vendor="
#define DEVICE_PRODUCTID_STRING "ProdID="
        if (this_port >= 0 && this_port < MAX_PORT)
        {
            int vendorId = GetInt(line, DEVICE_VENDOR_STRING, 16);
            int productId = GetInt(line, DEVICE_PRODUCTID_STRING, 16);

            var->device[this_port].vendorId = vendorId;
            var->device[this_port].productId = productId;
        }

    case 'I':
#define INTERFACE_DRIVERNAME_STRING "Driver="
        if (this_port >= 0 && this_port < MAX_PORT)
        {
            GetString(var->device[this_port].driver, line, INTERFACE_DRIVERNAME_STRING, sizeof(var->device[this_port].driver));
            if (var->device[this_port].driver[strlen(var->device[this_port].driver) - 1] == '\n')
            {
                var->device[this_port].driver[strlen(var->device[this_port].driver) - 1] = 0;
            }
        }

    default:
        break;
    }
}

static int turn_led(mpcie_var_t *var, int idx, int on)
{
    char cmd[] = "cd /sys/devices/platform/leds/leds/led-pcie%d && echo %d > brightness";

    sprintf(cmd, "cd /sys/devices/platform/leds/leds/led-pcie%d && echo %d > brightness", idx, on);
    system(cmd);
}

static int rtk_btusb(mpcie_var_t *var, int slot)
{
    char cmd[128];

    sprintf(cmd, "sh /lib/dyiot/bin/rtl_bt.sh add --slot %d", slot);
    system(cmd);
}

static int cp210x_detect(mpcie_var_t *var, int slot)
{
    char cmd[128];

    sprintf(cmd, "sh /lib/dyiot/bin/cp210x.sh add --slot %d", slot);
    system(cmd);
}

static int usb_detect(mpcie_var_t *var)
{
    char dataLine[1024];
    FILE *usbFile;
    int i = 0;

    for (i = 0; i < MAX_PORT; i++)
    {
        usb_device_t *dev = &var->device[i];
        dev->slot = i + 1;
        printf("slot:%d insert:%d vid:%04X pid:%04X driver:%s\n", dev->slot, dev->insert, dev->vendorId, dev->productId, dev->driver);
        sprintf(dataLine, "/etc/init.d/ra06_%d disable; /etc/init.d/ra06_%d stop", i + 1, i + 1);
        system(dataLine);
        sprintf(dataLine, "/etc/init.d/fastzigbee_%d disable; /etc/init.d/fastzigbee_%d stop", i + 1, i + 1);
        system(dataLine);
        sprintf(dataLine, "/etc/init.d/ble_%d disable; /etc/init.d/ble_%d stop", i + 1, i + 1);
        system(dataLine);
    }

    usbFile = fopen(USE_DEVICES_LIST, "r");
    if (usbFile == NULL)
    {
        fprintf(stderr, "open use file failed");
        return -1;
    }

    while (!feof(usbFile) && fgets(dataLine, 1023, usbFile) != NULL && dataLine[strlen(dataLine) - 1] == '\n')
    {
        usb_parse_line(var, dataLine);
    }

    fclose(usbFile);

    for (i = 0; i < MAX_PORT; i++)
    {
        usb_device_t *dev = &var->device[i];
        turn_led(var, dev->slot, dev->insert);
        printf("slot:%d insert:%d vid:%04X pid:%04X driver:%s\n", dev->slot, dev->insert, dev->vendorId, dev->productId, dev->driver);
        if (dev->insert == 1)
        {
            if (strcmp(dev->driver, "cp210x") == 0)
            {
                cp210x_detect(var, dev->slot);
            }
            else if (strcmp(dev->driver, "rtk_btusb") == 0 || strcmp(dev->driver, "btusb") == 0)
            {
                rtk_btusb(var, dev->slot);
            }
        }
    }
}

int main(int argc, char *argv[])
{
    mpcie_var_t var = {0};

    memset(&var, 0, sizeof(var));
    usb_detect(&var);

    return 0;
}
