/*
 * Common controller functions and structures
 *
 * Copyright 2018 Aric Stewart
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

/* Blocks of data for building HID device descriptions */

static const BYTE REPORT_HEADER[] = {
    0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
    0x09, 0x00, /* USAGE (??) */
    0xa1, 0x01, /* COLLECTION (Application) */
    0x09, 0x01, /*   USAGE () */
    0xa1, 0x00, /*   COLLECTION (Physical) */
};
#define IDX_HEADER_PAGE 1
#define IDX_HEADER_USAGE 3

static const BYTE REPORT_BUTTONS[] = {
    0x05, 0x09, /* USAGE_PAGE (Button) */
    0x19, 0x01, /* USAGE_MINIMUM (Button 1) */
    0x29, 0x03, /* USAGE_MAXIMUM (Button 3) */
    0x15, 0x00, /* LOGICAL_MINIMUM (0) */
    0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
    0x35, 0x00, /* LOGICAL_MINIMUM (0) */
    0x45, 0x01, /* LOGICAL_MAXIMUM (1) */
    0x95, 0x03, /* REPORT_COUNT (3) */
    0x75, 0x01, /* REPORT_SIZE (1) */
    0x81, 0x02, /* INPUT (Data,Var,Abs) */
};
#define IDX_BUTTON_MIN_USAGE 3
#define IDX_BUTTON_MAX_USAGE 5
#define IDX_BUTTON_COUNT 11

static const BYTE REPORT_PADDING[] = {
    0x95, 0x03, /* REPORT_COUNT (3) */
    0x75, 0x01, /* REPORT_SIZE (1) */
    0x81, 0x03, /* INPUT (Cnst,Var,Abs) */
};
#define IDX_PADDING_BIT_COUNT 1

static const BYTE REPORT_AXIS_HEADER[] = {
    0x05, 0x01,  /* USAGE_PAGE (Generic Desktop) */
};
#define IDX_AXIS_PAGE 1

static const BYTE REPORT_AXIS_USAGE[] = {
    0x09, 0x30,  /* USAGE (X) */
};
#define IDX_AXIS_USAGE 1

static const BYTE REPORT_REL_AXIS_TAIL[] = {
    0x15, 0x81,    /* LOGICAL_MINIMUM (0) */
    0x25, 0x7f,    /* LOGICAL_MAXIMUM (0xffff) */
    0x75, 0x08,    /* REPORT_SIZE (16) */
    0x95, 0x02,    /* REPORT_COUNT (2) */
    0x81, 0x06,    /* INPUT (Data,Var,Rel) */
};
#define IDX_REL_AXIS_COUNT 7

static const BYTE REPORT_HATSWITCH[] = {
    0x05, 0x01,  /* USAGE_PAGE (Generic Desktop) */
    0x09, 0x39,  /* USAGE (Hatswitch) */
    0x15, 0x00,  /* LOGICAL_MINIMUM (0) */
    0x25, 0x08,  /* LOGICAL_MAXIMUM (0x08) */
    0x35, 0x00,  /* PHYSICAL_MINIMUM (0) */
    0x45, 0x08,  /* PHYSICAL_MAXIMUM (8) */
    0x75, 0x08,  /* REPORT_SIZE (8) */
    0x95, 0x01,  /* REPORT_COUNT (1) */
    0x81, 0x02,  /* INPUT (Data,Var,Abs) */
};
#define IDX_HATSWITCH_COUNT 15

static const BYTE REPORT_TAIL[] = {
    0xc0, /*   END_COLLECTION */
    0xc0  /* END_COLLECTION */
};

static inline BYTE *add_button_block(BYTE* report_ptr, BYTE usage_min, BYTE usage_max)
{
    memcpy(report_ptr, REPORT_BUTTONS, sizeof(REPORT_BUTTONS));
    report_ptr[IDX_BUTTON_MIN_USAGE] = usage_min;
    report_ptr[IDX_BUTTON_MAX_USAGE] = usage_max;
    report_ptr[IDX_BUTTON_COUNT] = (usage_max - usage_min) + 1;
    return report_ptr + sizeof(REPORT_BUTTONS);
}


static inline BYTE *add_padding_block(BYTE *report_ptr, BYTE bitcount)
{
    memcpy(report_ptr, REPORT_PADDING, sizeof(REPORT_PADDING));
    report_ptr[IDX_PADDING_BIT_COUNT] = bitcount;
    return report_ptr + sizeof(REPORT_PADDING);
}

static inline BYTE *add_hatswitch(BYTE *report_ptr, INT count)
{
    memcpy(report_ptr, REPORT_HATSWITCH, sizeof(REPORT_HATSWITCH));
    report_ptr[IDX_HATSWITCH_COUNT] = count;
    return report_ptr + sizeof(REPORT_HATSWITCH);
}

static inline void set_button_value(int index, int value, BYTE* buffer)
{
    int bindex = index / 8;
    int b = index % 8;
    BYTE mask;

    mask = 1<<b;
    if (value)
        buffer[bindex] = buffer[bindex] | mask;
    else
    {
        mask = ~mask;
        buffer[bindex] = buffer[bindex] & mask;
    }
}
