492 lines
10 KiB
TypeScript
492 lines
10 KiB
TypeScript
/*!
|
|
* Buttplug JS Source Code File - Visit https://buttplug.io for more info about
|
|
* the project. Licensed under the BSD 3-Clause license. See LICENSE file in the
|
|
* project root for full license information.
|
|
*
|
|
* @copyright Copyright (c) Nonpolynomial Labs LLC. All rights reserved.
|
|
*/
|
|
|
|
// tslint:disable:max-classes-per-file
|
|
"use strict";
|
|
|
|
import { instanceToPlain, Type } from "class-transformer";
|
|
import "reflect-metadata";
|
|
|
|
export const SYSTEM_MESSAGE_ID = 0;
|
|
export const DEFAULT_MESSAGE_ID = 1;
|
|
export const MAX_ID = 4294967295;
|
|
export const MESSAGE_SPEC_VERSION = 3;
|
|
|
|
export class MessageAttributes {
|
|
public ScalarCmd?: Array<GenericDeviceMessageAttributes>;
|
|
public RotateCmd?: Array<GenericDeviceMessageAttributes>;
|
|
public LinearCmd?: Array<GenericDeviceMessageAttributes>;
|
|
public RawReadCmd?: RawDeviceMessageAttributes;
|
|
public RawWriteCmd?: RawDeviceMessageAttributes;
|
|
public RawSubscribeCmd?: RawDeviceMessageAttributes;
|
|
public SensorReadCmd?: Array<SensorDeviceMessageAttributes>;
|
|
public SensorSubscribeCmd?: Array<SensorDeviceMessageAttributes>;
|
|
public StopDeviceCmd: {};
|
|
|
|
constructor(data: Partial<MessageAttributes>) {
|
|
Object.assign(this, data);
|
|
}
|
|
|
|
public update() {
|
|
this.ScalarCmd?.forEach((x, i) => (x.Index = i));
|
|
this.RotateCmd?.forEach((x, i) => (x.Index = i));
|
|
this.LinearCmd?.forEach((x, i) => (x.Index = i));
|
|
this.SensorReadCmd?.forEach((x, i) => (x.Index = i));
|
|
this.SensorSubscribeCmd?.forEach((x, i) => (x.Index = i));
|
|
}
|
|
}
|
|
|
|
export enum ActuatorType {
|
|
Unknown = "Unknown",
|
|
Vibrate = "Vibrate",
|
|
Rotate = "Rotate",
|
|
Oscillate = "Oscillate",
|
|
Constrict = "Constrict",
|
|
Inflate = "Inflate",
|
|
Position = "Position",
|
|
}
|
|
|
|
export enum SensorType {
|
|
Unknown = "Unknown",
|
|
Battery = "Battery",
|
|
RSSI = "RSSI",
|
|
Button = "Button",
|
|
Pressure = "Pressure",
|
|
// Temperature,
|
|
// Accelerometer,
|
|
// Gyro,
|
|
}
|
|
|
|
export class GenericDeviceMessageAttributes {
|
|
public FeatureDescriptor: string;
|
|
public ActuatorType: ActuatorType;
|
|
public StepCount: number;
|
|
public Index = 0;
|
|
constructor(data: Partial<GenericDeviceMessageAttributes>) {
|
|
Object.assign(this, data);
|
|
}
|
|
}
|
|
|
|
export class RawDeviceMessageAttributes {
|
|
constructor(public Endpoints: Array<string>) {}
|
|
}
|
|
|
|
export class SensorDeviceMessageAttributes {
|
|
public FeatureDescriptor: string;
|
|
public SensorType: SensorType;
|
|
public StepRange: Array<number>;
|
|
public Index = 0;
|
|
constructor(data: Partial<GenericDeviceMessageAttributes>) {
|
|
Object.assign(this, data);
|
|
}
|
|
}
|
|
|
|
export abstract class ButtplugMessage {
|
|
constructor(public Id: number) {}
|
|
|
|
// tslint:disable-next-line:ban-types
|
|
public get Type(): Function {
|
|
return this.constructor;
|
|
}
|
|
|
|
public toJSON(): string {
|
|
return JSON.stringify(this.toProtocolFormat());
|
|
}
|
|
|
|
public toProtocolFormat(): object {
|
|
const jsonObj = {};
|
|
jsonObj[(this.constructor as unknown as { Name: string }).Name] =
|
|
instanceToPlain(this);
|
|
return jsonObj;
|
|
}
|
|
|
|
public update() {}
|
|
}
|
|
|
|
export abstract class ButtplugDeviceMessage extends ButtplugMessage {
|
|
constructor(
|
|
public DeviceIndex: number,
|
|
public Id: number,
|
|
) {
|
|
super(Id);
|
|
}
|
|
}
|
|
|
|
export abstract class ButtplugSystemMessage extends ButtplugMessage {
|
|
constructor(public Id: number = SYSTEM_MESSAGE_ID) {
|
|
super(Id);
|
|
}
|
|
}
|
|
|
|
export class Ok extends ButtplugSystemMessage {
|
|
static Name = "Ok";
|
|
|
|
constructor(public Id: number = DEFAULT_MESSAGE_ID) {
|
|
super(Id);
|
|
}
|
|
}
|
|
|
|
export class Ping extends ButtplugMessage {
|
|
static Name = "Ping";
|
|
|
|
constructor(public Id: number = DEFAULT_MESSAGE_ID) {
|
|
super(Id);
|
|
}
|
|
}
|
|
|
|
export enum ErrorClass {
|
|
ERROR_UNKNOWN,
|
|
ERROR_INIT,
|
|
ERROR_PING,
|
|
ERROR_MSG,
|
|
ERROR_DEVICE,
|
|
}
|
|
|
|
export class Error extends ButtplugMessage {
|
|
static Name = "Error";
|
|
|
|
constructor(
|
|
public ErrorMessage: string,
|
|
public ErrorCode: ErrorClass = ErrorClass.ERROR_UNKNOWN,
|
|
public Id: number = DEFAULT_MESSAGE_ID,
|
|
) {
|
|
super(Id);
|
|
}
|
|
|
|
get Schemversion() {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
export class DeviceInfo {
|
|
public DeviceIndex: number;
|
|
public DeviceName: string;
|
|
@Type(() => MessageAttributes)
|
|
public DeviceMessages: MessageAttributes;
|
|
public DeviceDisplayName?: string;
|
|
public DeviceMessageTimingGap?: number;
|
|
|
|
constructor(data: Partial<DeviceInfo>) {
|
|
Object.assign(this, data);
|
|
}
|
|
}
|
|
|
|
export class DeviceList extends ButtplugMessage {
|
|
static Name = "DeviceList";
|
|
|
|
@Type(() => DeviceInfo)
|
|
public Devices: DeviceInfo[];
|
|
public Id: number;
|
|
|
|
constructor(devices: DeviceInfo[], id: number = DEFAULT_MESSAGE_ID) {
|
|
super(id);
|
|
this.Devices = devices;
|
|
this.Id = id;
|
|
}
|
|
|
|
public update() {
|
|
for (const device of this.Devices) {
|
|
device.DeviceMessages.update();
|
|
}
|
|
}
|
|
}
|
|
|
|
export class DeviceAdded extends ButtplugSystemMessage {
|
|
static Name = "DeviceAdded";
|
|
|
|
public DeviceIndex: number;
|
|
public DeviceName: string;
|
|
@Type(() => MessageAttributes)
|
|
public DeviceMessages: MessageAttributes;
|
|
public DeviceDisplayName?: string;
|
|
public DeviceMessageTimingGap?: number;
|
|
|
|
constructor(data: Partial<DeviceAdded>) {
|
|
super();
|
|
Object.assign(this, data);
|
|
}
|
|
|
|
public update() {
|
|
this.DeviceMessages.update();
|
|
}
|
|
}
|
|
|
|
export class DeviceRemoved extends ButtplugSystemMessage {
|
|
static Name = "DeviceRemoved";
|
|
|
|
constructor(public DeviceIndex: number) {
|
|
super();
|
|
}
|
|
}
|
|
|
|
export class RequestDeviceList extends ButtplugMessage {
|
|
static Name = "RequestDeviceList";
|
|
|
|
constructor(public Id: number = DEFAULT_MESSAGE_ID) {
|
|
super(Id);
|
|
}
|
|
}
|
|
|
|
export class StartScanning extends ButtplugMessage {
|
|
static Name = "StartScanning";
|
|
|
|
constructor(public Id: number = DEFAULT_MESSAGE_ID) {
|
|
super(Id);
|
|
}
|
|
}
|
|
|
|
export class StopScanning extends ButtplugMessage {
|
|
static Name = "StopScanning";
|
|
|
|
constructor(public Id: number = DEFAULT_MESSAGE_ID) {
|
|
super(Id);
|
|
}
|
|
}
|
|
|
|
export class ScanningFinished extends ButtplugSystemMessage {
|
|
static Name = "ScanningFinished";
|
|
|
|
constructor() {
|
|
super();
|
|
}
|
|
}
|
|
|
|
export class RequestServerInfo extends ButtplugMessage {
|
|
static Name = "RequestServerInfo";
|
|
|
|
constructor(
|
|
public ClientName: string,
|
|
public MessageVersion: number = 0,
|
|
public Id: number = DEFAULT_MESSAGE_ID,
|
|
) {
|
|
super(Id);
|
|
}
|
|
}
|
|
|
|
export class ServerInfo extends ButtplugSystemMessage {
|
|
static Name = "ServerInfo";
|
|
|
|
constructor(
|
|
public MessageVersion: number,
|
|
public MaxPingTime: number,
|
|
public ServerName: string,
|
|
public Id: number = DEFAULT_MESSAGE_ID,
|
|
) {
|
|
super();
|
|
}
|
|
}
|
|
|
|
export class StopDeviceCmd extends ButtplugDeviceMessage {
|
|
static Name = "StopDeviceCmd";
|
|
|
|
constructor(
|
|
public DeviceIndex: number = -1,
|
|
public Id: number = DEFAULT_MESSAGE_ID,
|
|
) {
|
|
super(DeviceIndex, Id);
|
|
}
|
|
}
|
|
|
|
export class StopAllDevices extends ButtplugMessage {
|
|
static Name = "StopAllDevices";
|
|
|
|
constructor(public Id: number = DEFAULT_MESSAGE_ID) {
|
|
super(Id);
|
|
}
|
|
}
|
|
|
|
export class GenericMessageSubcommand {
|
|
protected constructor(public Index: number) {}
|
|
}
|
|
|
|
export class ScalarSubcommand extends GenericMessageSubcommand {
|
|
constructor(
|
|
Index: number,
|
|
public Scalar: number,
|
|
public ActuatorType: ActuatorType,
|
|
) {
|
|
super(Index);
|
|
}
|
|
}
|
|
|
|
export class ScalarCmd extends ButtplugDeviceMessage {
|
|
static Name = "ScalarCmd";
|
|
|
|
constructor(
|
|
public Scalars: ScalarSubcommand[],
|
|
public DeviceIndex: number = -1,
|
|
public Id: number = DEFAULT_MESSAGE_ID,
|
|
) {
|
|
super(DeviceIndex, Id);
|
|
}
|
|
}
|
|
|
|
export class RotateSubcommand extends GenericMessageSubcommand {
|
|
constructor(
|
|
Index: number,
|
|
public Speed: number,
|
|
public Clockwise: boolean,
|
|
) {
|
|
super(Index);
|
|
}
|
|
}
|
|
|
|
export class RotateCmd extends ButtplugDeviceMessage {
|
|
static Name = "RotateCmd";
|
|
|
|
public static Create(
|
|
deviceIndex: number,
|
|
commands: [number, boolean][],
|
|
): RotateCmd {
|
|
const cmdList: RotateSubcommand[] = new Array<RotateSubcommand>();
|
|
|
|
let i = 0;
|
|
for (const [speed, clockwise] of commands) {
|
|
cmdList.push(new RotateSubcommand(i, speed, clockwise));
|
|
++i;
|
|
}
|
|
|
|
return new RotateCmd(cmdList, deviceIndex);
|
|
}
|
|
constructor(
|
|
public Rotations: RotateSubcommand[],
|
|
public DeviceIndex: number = -1,
|
|
public Id: number = DEFAULT_MESSAGE_ID,
|
|
) {
|
|
super(DeviceIndex, Id);
|
|
}
|
|
}
|
|
|
|
export class VectorSubcommand extends GenericMessageSubcommand {
|
|
constructor(
|
|
Index: number,
|
|
public Position: number,
|
|
public Duration: number,
|
|
) {
|
|
super(Index);
|
|
}
|
|
}
|
|
|
|
export class LinearCmd extends ButtplugDeviceMessage {
|
|
static Name = "LinearCmd";
|
|
|
|
public static Create(
|
|
deviceIndex: number,
|
|
commands: [number, number][],
|
|
): LinearCmd {
|
|
const cmdList: VectorSubcommand[] = new Array<VectorSubcommand>();
|
|
|
|
let i = 0;
|
|
for (const cmd of commands) {
|
|
cmdList.push(new VectorSubcommand(i, cmd[0], cmd[1]));
|
|
++i;
|
|
}
|
|
|
|
return new LinearCmd(cmdList, deviceIndex);
|
|
}
|
|
constructor(
|
|
public Vectors: VectorSubcommand[],
|
|
public DeviceIndex: number = -1,
|
|
public Id: number = DEFAULT_MESSAGE_ID,
|
|
) {
|
|
super(DeviceIndex, Id);
|
|
}
|
|
}
|
|
|
|
export class SensorReadCmd extends ButtplugDeviceMessage {
|
|
static Name = "SensorReadCmd";
|
|
|
|
constructor(
|
|
public DeviceIndex: number,
|
|
public SensorIndex: number,
|
|
public SensorType: SensorType,
|
|
public Id: number = DEFAULT_MESSAGE_ID,
|
|
) {
|
|
super(DeviceIndex, Id);
|
|
}
|
|
}
|
|
|
|
export class SensorReading extends ButtplugDeviceMessage {
|
|
static Name = "SensorReading";
|
|
|
|
constructor(
|
|
public DeviceIndex: number,
|
|
public SensorIndex: number,
|
|
public SensorType: SensorType,
|
|
public Data: number[],
|
|
public Id: number = DEFAULT_MESSAGE_ID,
|
|
) {
|
|
super(DeviceIndex, Id);
|
|
}
|
|
}
|
|
|
|
export class RawReadCmd extends ButtplugDeviceMessage {
|
|
static Name = "RawReadCmd";
|
|
|
|
constructor(
|
|
public DeviceIndex: number,
|
|
public Endpoint: string,
|
|
public ExpectedLength: number,
|
|
public Timeout: number,
|
|
public Id: number = DEFAULT_MESSAGE_ID,
|
|
) {
|
|
super(DeviceIndex, Id);
|
|
}
|
|
}
|
|
|
|
export class RawWriteCmd extends ButtplugDeviceMessage {
|
|
static Name = "RawWriteCmd";
|
|
|
|
constructor(
|
|
public DeviceIndex: number,
|
|
public Endpoint: string,
|
|
public Data: Uint8Array,
|
|
public WriteWithResponse: boolean,
|
|
public Id: number = DEFAULT_MESSAGE_ID,
|
|
) {
|
|
super(DeviceIndex, Id);
|
|
}
|
|
}
|
|
|
|
export class RawSubscribeCmd extends ButtplugDeviceMessage {
|
|
static Name = "RawSubscribeCmd";
|
|
|
|
constructor(
|
|
public DeviceIndex: number,
|
|
public Endpoint: string,
|
|
public Id: number = DEFAULT_MESSAGE_ID,
|
|
) {
|
|
super(DeviceIndex, Id);
|
|
}
|
|
}
|
|
|
|
export class RawUnsubscribeCmd extends ButtplugDeviceMessage {
|
|
static Name = "RawUnsubscribeCmd";
|
|
|
|
constructor(
|
|
public DeviceIndex: number,
|
|
public Endpoint: string,
|
|
public Id: number = DEFAULT_MESSAGE_ID,
|
|
) {
|
|
super(DeviceIndex, Id);
|
|
}
|
|
}
|
|
|
|
export class RawReading extends ButtplugDeviceMessage {
|
|
static Name = "RawReading";
|
|
|
|
constructor(
|
|
public DeviceIndex: number,
|
|
public Endpoint: string,
|
|
public Data: number[],
|
|
public Id: number = DEFAULT_MESSAGE_ID,
|
|
) {
|
|
super(DeviceIndex, Id);
|
|
}
|
|
}
|