<commit_before>/*
 * Copyright (c) 2016, OpenAV Productions,
 * <NAME> <<EMAIL>>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the copyright holder nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>

#include "ni_maschine_mikro_mk2.h"
#include "../device_impl.h"

#define NI_VENDOR             (0x17cc)
#define NI_MASCHINE_MIKRO_MK2 (0x1200)
#define USB_INTERFACE_ID      (0x00)
#define USB_ENDPOINT_READ     (0x81)
#define USB_ENDPOINT_WRITE    (0x01)

/* This struct is a generic struct to identify hw controls */
struct ni_maschine_mikro_mk2_ctlr_t {
	int event_id;
	int buf_byte_offset;
	uint32_t mask;
};

static const char *ni_maschine_mikro_mk2_control_names[] = {
	/* Buttons */
	"Restart",
	"Arrow (Left)",
	"Arrow (Right)",
	"Grid",
	"Play",
	"Record",
	"Erase",
	"Shift",
	"Group",
	"Browse",
	"Sampling",
	"Note Repeat",
	"Encoder Press",
	"F1",
	"F2",
	"F3",
	"Control",
	"Nav",
	"Nav Arrow (Left)",
	"Nav Arrow (Right)",
	"Main",
	"Scene",
	"Pattern",
	"Pad Mode",
	"View",
	"Duplicate",
	"Select",
	"Solo",
	"Mute",
	/* Encoder */
	"Encoder Rotate",
};
#define CONTROL_NAMES_SIZE (sizeof(ni_maschine_mikro_mk2_control_names) /\
			    sizeof(ni_maschine_mikro_mk2_control_names[0]))

static const struct ni_maschine_mikro_mk2_ctlr_t buttons[] = {
	{NI_MASCHINE_MIKRO_MK2_BTN_RESTART    , 1, 0x80},
	{NI_MASCHINE_MIKRO_MK2_BTN_LEFT_ARROW , 1, 0x40},
	{NI_MASCHINE_MIKRO_MK2_BTN_RIGHT_ARROW, 1, 0x20},
	{NI_MASCHINE_MIKRO_MK2_BTN_GRID       , 1, 0x10},
	{NI_MASCHINE_MIKRO_MK2_BTN_PLAY  , 1, 0x08},
	{NI_MASCHINE_MIKRO_MK2_BTN_RECORD, 1, 0x04},
	{NI_MASCHINE_MIKRO_MK2_BTN_ERASE , 1, 0x02},
	{NI_MASCHINE_MIKRO_MK2_BTN_SHIFT , 1, 0x01},

	{NI_MASCHINE_MIKRO_MK2_BTN_GROUP      , 2, 0x80},
	{NI_MASCHINE_MIKRO_MK2_BTN_BROWSE     , 2, 0x40},
	{NI_MASCHINE_MIKRO_MK2_BTN_SAMPLING   , 2, 0x20},
	{NI_MASCHINE_MIKRO_MK2_BTN_NOTE_REPEAT, 2, 0x10},

	{NI_MASCHINE_MIKRO_MK2_BTN_ENCODER_PRESS, 2, 0x08},
	/* unused
	{NI_MASCHINE_MIKRO_MK2_BTN_ , 2, 0x0},
	{NI_MASCHINE_MIKRO_MK2_BTN_ , 2, 0x0},
	{NI_MASCHINE_MIKRO_MK2_BTN_ , 2, 0x0},
	*/

	{NI_MASCHINE_MIKRO_MK2_BTN_F1       , 3, 0x80},
	{NI_MASCHINE_MIKRO_MK2_BTN_F2       , 3, 0x40},
	{NI_MASCHINE_MIKRO_MK2_BTN_F3       , 3, 0x20},
	{NI_MASCHINE_MIKRO_MK2_BTN_CONTROL  , 3, 0x10},
	{NI_MASCHINE_MIKRO_MK2_BTN_NAV      , 3, 0x08},
	{NI_MASCHINE_MIKRO_MK2_BTN_NAV_LEFT , 3, 0x04},
	{NI_MASCHINE_MIKRO_MK2_BTN_NAV_RIGHT, 3, 0x02},
	{NI_MASCHINE_MIKRO_MK2_BTN_MAIN     , 3, 0x01},

	{NI_MASCHINE_MIKRO_MK2_BTN_SCENE    , 4, 0x80},
	{NI_MASCHINE_MIKRO_MK2_BTN_PATTERN  , 4, 0x40},
	{NI_MASCHINE_MIKRO_MK2_BTN_PAD_MODE , 4, 0x20},
	{NI_MASCHINE_MIKRO_MK2_BTN_VIEW     , 4, 0x10},
	{NI_MASCHINE_MIKRO_MK2_BTN_DUPLICATE, 4, 0x08},
	{NI_MASCHINE_MIKRO_MK2_BTN_SELECT   , 4, 0x04},
	{NI_MASCHINE_MIKRO_MK2_BTN_SOLO     , 4, 0x02},
	{NI_MASCHINE_MIKRO_MK2_BTN_MUTE     , 4, 0x01},
};
#define BUTTONS_SIZE (sizeof(buttons) / sizeof(buttons[0]))

static const struct ni_maschine_mikro_mk2_ctlr_t encoders[] = {
	{NI_MASCHINE_MIKRO_MK2_BTN_ENCODER_ROTATE, 5, 0x0F},
};
#define ENCODERS_SIZE (sizeof(encoders) / sizeof(encoders[0]))

#define CONTROLS_SIZE (BUTTONS_SIZE + ENCODERS_SIZE)

/* Represents the the hardware device */
struct ni_maschine_mikro_mk2_t {
	/* base handles usb i/o etc */
	struct ctlr_dev_t base;
	/* current value of each controller is stored here */
	float hw_values[CONTROLS_SIZE];
	/* current state of the lights, only flush on dirty */
	uint8_t lights_dirty;
#warning FIXME: lights array size
	uint8_t lights[200];
};

static const char *
ni_maschine_mikro_mk2_control_get_name(struct ctlr_dev_t *base,
			       uint32_t control_id)
{
	struct ni_maschine_mikro_mk2_t *dev = (struct ni_maschine_mikro_mk2_t *)base;
	if(control_id < CONTROL_NAMES_SIZE)
		return ni_maschine_mikro_mk2_control_names[control_id];
	return 0;
}

static uint32_t ni_maschine_mikro_mk2_poll(struct ctlr_dev_t *base)
{
	struct ni_maschine_mikro_mk2_t *dev = (struct ni_maschine_mikro_mk2_t *)base;
	uint8_t buf[1024];
	int32_t nbytes;

	do {
		int handle_idx = 0;
		nbytes = ctlr_dev_impl_usb_xfer(base, handle_idx,
							 USB_ENDPOINT_READ,
							 buf, 1024);
		if(nbytes == 0)
			return 0;

		switch(nbytes) {
		case 6: {
			for(uint32_t i = 0; i < ENCODERS_SIZE; i++) {
#if 0
				int id     = sliders[i].event_id;
				int offset = sliders[i].buf_byte_offset;
				int mask   = sliders[i].mask;

				uint16_t v = *((uint16_t *)&buf[offset]) & mask;
				if(dev->hw_values[i] != v) {
					dev->hw_values[i] = v;
					struct ctlr_event_t event = {
						.id = CTLR_EVENT_SLIDER,
						.slider  = {
							.id = id,
							.value = v / 4096.f},
					};
					struct ctlr_event_t *e = {&event};
					dev->base.event_func(&dev->base, 1, &e,<commit_msg>maschine mikro mk2: pad pressures read<commit_after>/*
 * Copyright (c) 2016, OpenAV Productions,
 * <NAME> <<EMAIL>>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the copyright holder nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>

#include "ni_maschine_mikro_mk2.h"
#include "../device_impl.h"

#define NI_VENDOR             (0x17cc)
#define NI_MASCHINE_MIKRO_MK2 (0x1200)
#define USB_INTERFACE_ID      (0x00)
#define USB_ENDPOINT_READ     (0x81)
#define USB_ENDPOINT_WRITE    (0x01)

/* This struct is a generic struct to identify hw controls */
struct ni_maschine_mikro_mk2_ctlr_t {
	int event_id;
	int buf_byte_offset;
	uint32_t mask;
};

static const char *ni_maschine_mikro_mk2_control_names[] = {
	/* Buttons */
	"Restart",
	"Arrow (Left)",
	"Arrow (Right)",
	"Grid",
	"Play",
	"Record",
	"Erase",
	"Shift",
	"Group",
	"Browse",
	"Sampling",
	"Note Repeat",
	"Encoder Press",
	"F1",
	"F2",
	"F3",
	"Control",
	"Nav",
	"Nav Arrow (Left)",
	"Nav Arrow (Right)",
	"Main",
	"Scene",
	"Pattern",
	"Pad Mode",
	"View",
	"Duplicate",
	"Select",
	"Solo",
	"Mute",
	/* Encoder */
	"Encoder Rotate",
};
#define CONTROL_NAMES_SIZE (sizeof(ni_maschine_mikro_mk2_control_names) /\
			    sizeof(ni_maschine_mikro_mk2_control_names[0]))

static const struct ni_maschine_mikro_mk2_ctlr_t buttons[] = {
	{NI_MASCHINE_MIKRO_MK2_BTN_RESTART    , 1, 0x80},
	{NI_MASCHINE_MIKRO_MK2_BTN_LEFT_ARROW , 1, 0x40},
	{NI_MASCHINE_MIKRO_MK2_BTN_RIGHT_ARROW, 1, 0x20},
	{NI_MASCHINE_MIKRO_MK2_BTN_GRID       , 1, 0x10},
	{NI_MASCHINE_MIKRO_MK2_BTN_PLAY  , 1, 0x08},
	{NI_MASCHINE_MIKRO_MK2_BTN_RECORD, 1, 0x04},
	{NI_MASCHINE_MIKRO_MK2_BTN_ERASE , 1, 0x02},
	{NI_MASCHINE_MIKRO_MK2_BTN_SHIFT , 1, 0x01},

	{NI_MASCHINE_MIKRO_MK2_BTN_GROUP      , 2, 0x80},
	{NI_MASCHINE_MIKRO_MK2_BTN_BROWSE     , 2, 0x40},
	{NI_MASCHINE_MIKRO_MK2_BTN_SAMPLING   , 2, 0x20},
	{NI_MASCHINE_MIKRO_MK2_BTN_NOTE_REPEAT, 2, 0x10},

	{NI_MASCHINE_MIKRO_MK2_BTN_ENCODER_PRESS, 2, 0x08},
	/* unused
	{NI_MASCHINE_MIKRO_MK2_BTN_ , 2, 0x0},
	{NI_MASCHINE_MIKRO_MK2_BTN_ , 2, 0x0},
	{NI_MASCHINE_MIKRO_MK2_BTN_ , 2, 0x0},
	*/

	{NI_MASCHINE_MIKRO_MK2_BTN_F1       , 3, 0x80},
	{NI_MASCHINE_MIKRO_MK2_BTN_F2       , 3, 0x40},
	{NI_MASCHINE_MIKRO_MK2_BTN_F3       , 3, 0x20},
	{NI_MASCHINE_MIKRO_MK2_BTN_CONTROL  , 3, 0x10},
	{NI_MASCHINE_MIKRO_MK2_BTN_NAV      , 3, 0x08},
	{NI_MASCHINE_MIKRO_MK2_BTN_NAV_LEFT , 3, 0x04},
	{NI_MASCHINE_MIKRO_MK2_BTN_NAV_RIGHT, 3, 0x02},
	{NI_MASCHINE_MIKRO_MK2_BTN_MAIN     , 3, 0x01},

	{NI_MASCHINE_MIKRO_MK2_BTN_SCENE    , 4, 0x80},
	{NI_MASCHINE_MIKRO_MK2_BTN_PATTERN  , 4, 0x40},
	{NI_MASCHINE_MIKRO_MK2_BTN_PAD_MODE , 4, 0x20},
	{NI_MASCHINE_MIKRO_MK2_BTN_VIEW     , 4, 0x10},
	{NI_MASCHINE_MIKRO_MK2_BTN_DUPLICATE, 4, 0x08},
	{NI_MASCHINE_MIKRO_MK2_BTN_SELECT   , 4, 0x04},
	{NI_MASCHINE_MIKRO_MK2_BTN_SOLO     , 4, 0x02},
	{NI_MASCHINE_MIKRO_MK2_BTN_MUTE     , 4, 0x01},
};
#define BUTTONS_SIZE (sizeof(buttons) / sizeof(buttons[0]))

static const struct ni_maschine_mikro_mk2_ctlr_t encoders[] = {
	{NI_MASCHINE_MIKRO_MK2_BTN_ENCODER_ROTATE, 5, 0x0F},
};
#define ENCODERS_SIZE (sizeof(encoders) / sizeof(encoders[0]))

#define CONTROLS_SIZE (BUTTONS_SIZE + ENCODERS_SIZE)

/* Represents the the hardware device */
struct ni_maschine_mikro_mk2_t {
	/* base handles usb i/o etc */
	struct ctlr_dev_t base;
	/* current value of each controller is stored here */
	float hw_values[CONTROLS_SIZE];
	/* current state of the lights, only flush on dirty */
	uint8_t lights_dirty;
#warning FIXME: lights array size
	uint8_t lights[200];
};

static const char *
ni_maschine_mikro_mk2_control_get_name(struct ctlr_dev_t *base,
			       uint32_t control_id)
{
	struct ni_maschine_mikro_mk2_t *dev = (struct ni_maschine_mikro_mk2_t *)base;
	if(control_id < CONTROL_NAMES_SIZE)
		return ni_maschine_mikro_mk2_control_names[control_id];
	return 0;
}

static uint32_t ni_maschine_mikro_mk2_poll(struct ctlr_dev_t *base)
{
	struct ni_maschine_mikro_mk2_t *dev = (struct ni_maschine_mikro_mk2_t *)base;
	uint8_t buf[1024];
	int32_t nbytes;

	do {
		int handle_idx = 0;
		nbytes = ctlr_dev_impl_usb_xfer(base, handle_idx,
							 USB_ENDPOINT_READ,
							 buf, 1024);
		if(nbytes == 0)
			return 0;

		switch(nbytes) {
		case 65: {
				for(int i = 0; i < 16; i++) {
					uint16_t v = *((uint16_t *)&buf[i+1]);
					printf("%s", v > 50 ? "." : " " );
				}
				printf("\n");
			}
			break;
		case 6: {
			for(uint32_t i = 0; i < ENCODERS_SIZE; i++) {
#if 0
				int id     = sliders[i].event_id;
				int offset = sliders[i].buf_byte_offset;
				int mask   = sliders[i].mask;

				uint16_t v = *((uint16_t *)&buf[offset]) & mask;
				if(dev->hw_values[i] != v) {
					dev->hw_values[i] = v;
					struct ctlr_event_t event = {
						.id = CTLR_EVENT_SLIDER,
						.slider  = {
							.id = id,
							.value = v / 4096.f},
					};
					struct ctlr_event_t *e = {&event};
					dev->base.event_func(&dev->base, 1, &e,
{'fraction_non_alphanumeric': 0.10531331903740768, 'fraction_numerical': 0.0407433881343817, 'mean_word_length': 4.429926692539888, 'pattern_counts': {'":': 0, '<': 22, '<?xml version=': 0, '>': 26, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1992293', 'n_tokens_mistral': 5967, 'n_tokens_neox': 5290, 'n_words': 1187}