// Path: public-java/io/iamcontent-usb/src/main/java/com/iamcontent/io/usb/EasedUsbDevice.java
// public static EasedUsbDevice eased(UsbDevice device) {
// 	if (device instanceof EasyUsbDevice) 
// 		return (EasedUsbDevice) device;
// 	else
// 		return new EasedUsbDevice(device);
// }
// 
// Path: public-java/devices/iamcontent-pololu-servo-controllers/src/main/java/com/iamcontent/device/controller/pololu/maestro/MaestroCardType.java
// public enum MaestroCardType {
// 	
// 	MICRO_MAESTRO_6(6),
// 	MINI_MAESTRO_12(12),
// 	MINI_MAESTRO_18(18),
// 	MINI_MAESTRO_24(24);
// 	
// 	private final int channelCount;
// 
// 	private MaestroCardType(int channelCount) {
// 		this.channelCount = channelCount;
// 	}
// 
// 	public int channelCount() {
// 		return channelCount;
// 	}
// }
// 
// Path: public-java/devices/iamcontent-pololu-servo-controllers/src/main/java/com/iamcontent/device/controller/pololu/maestro/PololuMaestroServoCard.java
// public interface PololuMaestroServoCard {
// 
// 	interface State {
// 		short getPosition(short channel);
// 	}
// 	
// 	void setPosition(short channel, short position);
// 	void setSpeed(short channel, short speed);
// 	void setAcceleration(short channel, short acceleration);
// 
// 	short getPosition(short channel);
// 	State getState();
// 	
// 	MaestroCardType getType();
// 
// }
// 
// Path: public-java/io/iamcontent-usb/src/main/java/com/iamcontent/io/usb/EasyUsbDevice.java
// @SuppressWarnings("rawtypes")
// public interface EasyUsbDevice extends UsbDevice {
// 	String getManufacturerString();
// 
// 	String getSerialNumberString();
// 
// 	String getProductString();
// 
// 	UsbStringDescriptor getUsbStringDescriptor(byte index);
// 
// 	String getString(byte index);
// 
// 	void syncSubmit(UsbControlIrp irp);
// 
// 	void asyncSubmit(UsbControlIrp irp);
// 
// 	void syncSubmit(List list);
// 
// 	void asyncSubmit(List list);
// }


import com.iamcontent.device.controller.pololu.maestro.PololuMaestroServoCard;
import com.iamcontent.io.usb.EasyUsbDevice;
import static com.iamcontent.io.usb.EasedUsbDevice.eased;
import static java.util.stream.Collectors.joining;
import static javax.usb.UsbConst.REQUESTTYPE_DIRECTION_IN;
import static javax.usb.UsbConst.REQUESTTYPE_DIRECTION_OUT;
import static javax.usb.UsbConst.REQUESTTYPE_TYPE_VENDOR;
import java.io.Serializable;
import java.util.stream.IntStream;
import javax.usb.UsbControlIrp;
import javax.usb.UsbDevice;
import com.iamcontent.device.controller.pololu.maestro.MaestroCardType;

/**
  IAmContent Public Libraries.
  Copyright (C) 2015-2021 Greg Elderfield
  @author Greg Elderfield, support@jarchitect.co.uk
 
  This program is free software; you can redistribute it and/or modify it under the terms of the
  GNU General Public License as published by the Free Software Foundation; either version 2 of 
  the License, or (at your option) any later version.

  This program 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 General Public License for more details.

  You should have received a copy of the GNU General Public License along with this program;
  if not, write to the Free Software Foundation, Inc., 
  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
package com.iamcontent.device.controller.pololu.maestro.usb;





/**
 * An abstract {@link PololuMaestroServoCard} that uses Pololu's Native USB protocol.
 * Methods with implementations that vary by card type must be provided by concrete subclasses.
 * 
 * The command values used by this protocol were obtained from Pololu's Native USB SDK,
 * downloaded from www.pololu.com.
 * 
 * @author Greg Elderfield
 */
public abstract class AbstractUsbPololuMaestroServoCard implements PololuMaestroServoCard {
	
	private static final byte REQUEST_SET_TARGET = (byte)0x85;
	private static final byte REQUEST_SET_SERVO_VARIABLE = (byte)0x84;
	
	private static final int BYTES_PER_SERVO_STATUS_BLOCK = 7;

	private final EasyUsbDevice device;
	private final UsbMaestroCardType type;
	private final byte[] dataIn;
	private final byte inRequestCode;
	private final int offsetOfFirstServoStatusBlock;
	
	/**
	 * Creates an instance with the given UsbDevice.
	 */
	public AbstractUsbPololuMaestroServoCard(UsbDevice device, byte inRequestCode, int offsetOfFirstServoStatusBlock) {

// Path: public-java/io/iamcontent-usb/src/main/java/com/iamcontent/io/usb/EasedUsbDevice.java
// public static EasedUsbDevice eased(UsbDevice device) {
// 	if (device instanceof EasyUsbDevice) 
// 		return (EasedUsbDevice) device;
// 	else
// 		return new EasedUsbDevice(device);
// }
// 
// Path: public-java/devices/iamcontent-pololu-servo-controllers/src/main/java/com/iamcontent/device/controller/pololu/maestro/MaestroCardType.java
// public enum MaestroCardType {
// 	
// 	MICRO_MAESTRO_6(6),
// 	MINI_MAESTRO_12(12),
// 	MINI_MAESTRO_18(18),
// 	MINI_MAESTRO_24(24);
// 	
// 	private final int channelCount;
// 
// 	private MaestroCardType(int channelCount) {
// 		this.channelCount = channelCount;
// 	}
// 
// 	public int channelCount() {
// 		return channelCount;
// 	}
// }
// 
// Path: public-java/devices/iamcontent-pololu-servo-controllers/src/main/java/com/iamcontent/device/controller/pololu/maestro/PololuMaestroServoCard.java
// public interface PololuMaestroServoCard {
// 
// 	interface State {
// 		short getPosition(short channel);
// 	}
// 	
// 	void setPosition(short channel, short position);
// 	void setSpeed(short channel, short speed);
// 	void setAcceleration(short channel, short acceleration);
// 
// 	short getPosition(short channel);
// 	State getState();
// 	
// 	MaestroCardType getType();
// 
// }
// 
// Path: public-java/io/iamcontent-usb/src/main/java/com/iamcontent/io/usb/EasyUsbDevice.java
// @SuppressWarnings("rawtypes")
// public interface EasyUsbDevice extends UsbDevice {
// 	String getManufacturerString();
// 
// 	String getSerialNumberString();
// 
// 	String getProductString();
// 
// 	UsbStringDescriptor getUsbStringDescriptor(byte index);
// 
// 	String getString(byte index);
// 
// 	void syncSubmit(UsbControlIrp irp);
// 
// 	void asyncSubmit(UsbControlIrp irp);
// 
// 	void syncSubmit(List list);
// 
// 	void asyncSubmit(List list);
// }


// Path: public-java/devices/iamcontent-pololu-servo-controllers/src/main/java/com/iamcontent/device/controller/pololu/maestro/usb/AbstractUsbPololuMaestroServoCard.java
import com.iamcontent.device.controller.pololu.maestro.PololuMaestroServoCard;
import com.iamcontent.io.usb.EasyUsbDevice;
import static com.iamcontent.io.usb.EasedUsbDevice.eased;
import static java.util.stream.Collectors.joining;
import static javax.usb.UsbConst.REQUESTTYPE_DIRECTION_IN;
import static javax.usb.UsbConst.REQUESTTYPE_DIRECTION_OUT;
import static javax.usb.UsbConst.REQUESTTYPE_TYPE_VENDOR;
import java.io.Serializable;
import java.util.stream.IntStream;
import javax.usb.UsbControlIrp;
import javax.usb.UsbDevice;
import com.iamcontent.device.controller.pololu.maestro.MaestroCardType;

/**
  IAmContent Public Libraries.
  Copyright (C) 2015-2021 Greg Elderfield
  @author Greg Elderfield, support@jarchitect.co.uk
 
  This program is free software; you can redistribute it and/or modify it under the terms of the
  GNU General Public License as published by the Free Software Foundation; either version 2 of 
  the License, or (at your option) any later version.

  This program 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 General Public License for more details.

  You should have received a copy of the GNU General Public License along with this program;
  if not, write to the Free Software Foundation, Inc., 
  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */
package com.iamcontent.device.controller.pololu.maestro.usb;





/**
 * An abstract {@link PololuMaestroServoCard} that uses Pololu's Native USB protocol.
 * Methods with implementations that vary by card type must be provided by concrete subclasses.
 * 
 * The command values used by this protocol were obtained from Pololu's Native USB SDK,
 * downloaded from www.pololu.com.
 * 
 * @author Greg Elderfield
 */
public abstract class AbstractUsbPololuMaestroServoCard implements PololuMaestroServoCard {
	
	private static final byte REQUEST_SET_TARGET = (byte)0x85;
	private static final byte REQUEST_SET_SERVO_VARIABLE = (byte)0x84;
	
	private static final int BYTES_PER_SERVO_STATUS_BLOCK = 7;

	private final EasyUsbDevice device;
	private final UsbMaestroCardType type;
	private final byte[] dataIn;
	private final byte inRequestCode;
	private final int offsetOfFirstServoStatusBlock;
	
	/**
	 * Creates an instance with the given UsbDevice.
	 */
	public AbstractUsbPololuMaestroServoCard(UsbDevice device, byte inRequestCode, int offsetOfFirstServoStatusBlock) {

		this.device = eased(device);
