feat: 完成前后端旋转编码器的数字孪生

This commit is contained in:
2025-08-17 17:01:42 +08:00
parent cbf85165b7
commit 4a55143b8e
10 changed files with 818 additions and 265 deletions

View File

@@ -1,258 +1,301 @@
<template>
<div class="ec11-container" :style="{
width: width + 'px',
height: height + 'px',
position: 'relative',
}">
<svg xmlns="http://www.w3.org/2000/svg" :width="width" :height="height" viewBox="0 0 100 100"
class="ec11-encoder">
<defs>
<!-- 发光效果滤镜 -->
<filter id="glow" x="-50%" y="-50%" width="200%" height="200%">
<feFlood result="flood" flood-color="#00ff88" flood-opacity="1"></feFlood>
<feComposite in="flood" result="mask" in2="SourceGraphic" operator="in"></feComposite>
<feMorphology in="mask" result="dilated" operator="dilate" radius="1"></feMorphology>
<feGaussianBlur in="dilated" stdDeviation="2" result="blur1" />
<feGaussianBlur in="dilated" stdDeviation="4" result="blur2" />
<feGaussianBlur in="dilated" stdDeviation="8" result="blur3" />
<feMerge>
<feMergeNode in="blur3" />
<feMergeNode in="blur2" />
<feMergeNode in="blur1" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<!-- 编码器主体渐变 -->
<radialGradient id="encoderGradient" cx="50%" cy="30%">
<stop offset="0%" stop-color="#666666" />
<stop offset="70%" stop-color="#333333" />
<stop offset="100%" stop-color="#1a1a1a" />
</radialGradient>
<!-- 旋钮渐变 -->
<radialGradient id="knobGradient" cx="30%" cy="30%">
<stop offset="0%" stop-color="#555555" />
<stop offset="70%" stop-color="#222222" />
<stop offset="100%" stop-color="#111111" />
</radialGradient>
<!-- 按下状态渐变 -->
<radialGradient id="knobPressedGradient" cx="50%" cy="50%">
<stop offset="0%" stop-color="#333333" />
<stop offset="70%" stop-color="#555555" />
<stop offset="100%" stop-color="#888888" />
</radialGradient>
</defs>
<!-- 编码器底座 -->
<rect x="10" y="30" width="80" height="60" rx="8" ry="8"
fill="#2a2a2a" stroke="#444444" stroke-width="1"/>
<!-- 编码器主体外壳 -->
<circle cx="50" cy="60" r="32" fill="url(#encoderGradient)" stroke="#555555" stroke-width="1"/>
<!-- 编码器接线端子 -->
<rect x="5" y="75" width="4" height="8" fill="#c9c9c9" rx="1"/>
<rect x="15" y="85" width="4" height="8" fill="#c9c9c9" rx="1"/>
<rect x="25" y="85" width="4" height="8" fill="#c9c9c9" rx="1"/>
<rect x="81" y="85" width="4" height="8" fill="#c9c9c9" rx="1"/>
<rect x="91" y="75" width="4" height="8" fill="#c9c9c9" rx="1"/>
<!-- 旋钮 -->
<circle cx="50" cy="60" r="22"
:fill="isPressed ? 'url(#knobPressedGradient)' : 'url(#knobGradient)'"
stroke="#666666" stroke-width="1"
:transform="`rotate(${rotation/2} 50 60)`"
class="interactive"
@mousedown="handleMouseDown"
@mouseup="handlePress(false)"
@mouseleave="handlePress(false)"/>
<!-- 旋钮指示器 -->
<line x1="50" y1="42" x2="50" y2="48"
stroke="#ffffff" stroke-width="2" stroke-linecap="round"
:transform="`rotate(${rotation} 50 60)`"/>
<!-- 旋钮上的纹理刻度 -->
<g :transform="`rotate(${rotation} 50 60)`">
<circle cx="50" cy="60" r="18" fill="none" stroke="#777777" stroke-width="0.5"/>
<!-- 刻度线 -->
<g v-for="i in 16" :key="i">
<line :x1="50 + 16 * Math.cos((i-1) * Math.PI / 8)"
:y1="60 + 16 * Math.sin((i-1) * Math.PI / 8)"
:x2="50 + 18 * Math.cos((i-1) * Math.PI / 8)"
:y2="60 + 18 * Math.sin((i-1) * Math.PI / 8)"
stroke="#999999" stroke-width="0.5"/>
</g>
</g>
<!-- 编码器编号标签 -->
<text x="50" y="15" text-anchor="middle" font-family="Arial" font-size="10"
fill="#cccccc" font-weight="bold">
EC11-{{ encoderNumber }}
</text>
<!-- 状态指示器 -->
<circle cx="85" cy="20" r="3" :fill="isPressed ? '#ff4444' : '#444444'"
:filter="isPressed ? 'url(#glow)' : ''"
stroke="#666666" stroke-width="0.5"/>
</svg>
</div>
</template>
<script lang="ts" setup>
import { ref, computed } from 'vue';
interface Props {
size?: number;
encoderNumber?: number;
}
const props = withDefaults(defineProps<Props>(), {
size: 1,
encoderNumber: 1
});
// 组件状态
const isPressed = ref(false);
const rotation = ref(0);
// 拖动状态
const isDragging = ref(false);
const dragStartX = ref(0);
const lastTriggerX = ref(0);
const dragThreshold = 20; // 每20像素触发一次旋转
const hasRotated = ref(false); // 标记是否已经发生了旋转
// 计算宽高
const width = computed(() => 100 * props.size);
const height = computed(() => 100 * props.size);
// 定义发出的事件
const emit = defineEmits(['press', 'release', 'rotate-left', 'rotate-right']);
// 鼠标按下处理
function handleMouseDown(event: MouseEvent) {
isDragging.value = true;
dragStartX.value = event.clientX;
lastTriggerX.value = event.clientX;
hasRotated.value = false; // 重置旋转标记
// 添加全局鼠标事件监听
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp);
}
// 鼠标移动处理
function handleMouseMove(event: MouseEvent) {
if (!isDragging.value) return;
const currentX = event.clientX;
const deltaX = currentX - lastTriggerX.value;
// 检查是否达到触发阈值
if (Math.abs(deltaX) >= dragThreshold) {
hasRotated.value = true; // 标记已经发生旋转
if (deltaX > 0) {
// 右拖动 - 右旋转
rotation.value += 15;
emit('rotate-right', {
encoderNumber: props.encoderNumber
});
} else {
// 左拖动 - 左旋转
rotation.value -= 15;
emit('rotate-left', {
encoderNumber: props.encoderNumber
});
}
// 更新最后触发位置
lastTriggerX.value = currentX;
// 保持角度在0-360度范围内
rotation.value = rotation.value % 720;
if (rotation.value < 0) {
rotation.value += 720;
}
}
}
// 鼠标松开处理
function handleMouseUp() {
isDragging.value = false;
// 只有在没有发生旋转的情况下才识别为按压事件
if (!hasRotated.value) {
// 触发按压和释放事件(模拟快速按压)
handlePress(true);
// 使用setTimeout来模拟按压和释放的时序
setTimeout(() => {
handlePress(false);
}, 100);
}
// 移除全局事件监听
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
}
// 按压处理
function handlePress(pressed: boolean) {
if (pressed !== isPressed.value) {
isPressed.value = pressed;
if (pressed) {
emit('press', { encoderNumber: props.encoderNumber });
} else {
emit('release', { encoderNumber: props.encoderNumber });
}
}
}
// 暴露组件方法
defineExpose({
press: () => handlePress(true),
release: () => handlePress(false),
rotateLeft: () => {
rotation.value -= 15;
emit('rotate-left', {
encoderNumber: props.encoderNumber
});
},
rotateRight: () => {
rotation.value += 15;
emit('rotate-right', {
encoderNumber: props.encoderNumber
});
},
isPressed: () => isPressed.value
});
</script>
<script lang="ts">
// 添加一个静态方法来获取默认props
export function getDefaultProps() {
return {
size: 1,
encoderNumber: 1
};
}
</script>
<style scoped lang="postcss">
.ec11-container {
display: inline-block;
user-select: none;
}
.ec11-encoder {
display: block;
overflow: visible;
}
.interactive {
cursor: pointer;
}
</style>
<template>
<div
class="inline-block select-none"
:style="{
width: width + 'px',
height: height + 'px',
position: 'relative',
}"
>
<svg
xmlns="http://www.w3.org/2000/svg"
:width="width"
:height="height"
viewBox="0 0 100 100"
class="ec11-encoder"
>
<defs>
<!-- 发光效果滤镜 -->
<filter id="glow" x="-50%" y="-50%" width="200%" height="200%">
<feFlood
result="flood"
flood-color="#00ff88"
flood-opacity="1"
></feFlood>
<feComposite
in="flood"
result="mask"
in2="SourceGraphic"
operator="in"
></feComposite>
<feMorphology
in="mask"
result="dilated"
operator="dilate"
radius="1"
></feMorphology>
<feGaussianBlur in="dilated" stdDeviation="2" result="blur1" />
<feGaussianBlur in="dilated" stdDeviation="4" result="blur2" />
<feGaussianBlur in="dilated" stdDeviation="8" result="blur3" />
<feMerge>
<feMergeNode in="blur3" />
<feMergeNode in="blur2" />
<feMergeNode in="blur1" />
<feMergeNode in="SourceGraphic" />
</feMerge>
</filter>
<!-- 编码器主体渐变 -->
<radialGradient id="encoderGradient" cx="50%" cy="30%">
<stop offset="0%" stop-color="#666666" />
<stop offset="70%" stop-color="#333333" />
<stop offset="100%" stop-color="#1a1a1a" />
</radialGradient>
<!-- 旋钮渐变 -->
<radialGradient id="knobGradient" cx="30%" cy="30%">
<stop offset="0%" stop-color="#555555" />
<stop offset="70%" stop-color="#222222" />
<stop offset="100%" stop-color="#111111" />
</radialGradient>
<!-- 按下状态渐变 -->
<radialGradient id="knobPressedGradient" cx="50%" cy="50%">
<stop offset="0%" stop-color="#333333" />
<stop offset="70%" stop-color="#555555" />
<stop offset="100%" stop-color="#888888" />
</radialGradient>
</defs>
<!-- 编码器底座 -->
<rect
x="10"
y="30"
width="80"
height="60"
rx="8"
ry="8"
fill="#2a2a2a"
stroke="#444444"
stroke-width="1"
/>
<!-- 编码器主体外壳 -->
<circle
cx="50"
cy="60"
r="32"
fill="url(#encoderGradient)"
stroke="#555555"
stroke-width="1"
/>
<!-- 编码器接线端子 -->
<rect x="5" y="75" width="4" height="8" fill="#c9c9c9" rx="1" />
<rect x="15" y="85" width="4" height="8" fill="#c9c9c9" rx="1" />
<rect x="25" y="85" width="4" height="8" fill="#c9c9c9" rx="1" />
<rect x="81" y="85" width="4" height="8" fill="#c9c9c9" rx="1" />
<rect x="91" y="75" width="4" height="8" fill="#c9c9c9" rx="1" />
<!-- 旋钮 -->
<circle
cx="50"
cy="60"
r="22"
:fill="isPressed ? 'url(#knobPressedGradient)' : 'url(#knobGradient)'"
stroke="#666666"
stroke-width="1"
:transform="`rotate(${rotationStep * 7.5} 50 60)`"
class="interactive"
@mousedown="handleMouseDown"
@mouseup="handlePress(false)"
@mouseleave="handlePress(false)"
/>
<!-- 旋钮指示器 -->
<line
x1="50"
y1="42"
x2="50"
y2="48"
stroke="#ffffff"
stroke-width="2"
stroke-linecap="round"
:transform="`rotate(${rotationStep * 15} 50 60)`"
/>
<!-- 旋钮上的纹理刻度 -->
<g :transform="`rotate(${rotationStep * 15} 50 60)`">
<circle
cx="50"
cy="60"
r="18"
fill="none"
stroke="#777777"
stroke-width="0.5"
/>
<!-- 刻度线 -->
<g v-for="i in 16" :key="i">
<line
:x1="50 + 16 * Math.cos(((i - 1) * Math.PI) / 8)"
:y1="60 + 16 * Math.sin(((i - 1) * Math.PI) / 8)"
:x2="50 + 18 * Math.cos(((i - 1) * Math.PI) / 8)"
:y2="60 + 18 * Math.sin(((i - 1) * Math.PI) / 8)"
stroke="#999999"
stroke-width="0.5"
/>
</g>
</g>
<!-- 编码器编号标签 -->
<text
x="50"
y="15"
text-anchor="middle"
font-family="Arial"
font-size="10"
fill="#cccccc"
font-weight="bold"
>
EC11-{{ encoderNumber }}
</text>
<!-- 状态指示器 -->
<circle
cx="85"
cy="20"
r="3"
:fill="isPressed ? '#ff4444' : '#444444'"
:filter="isPressed ? 'url(#glow)' : ''"
stroke="#666666"
stroke-width="0.5"
/>
</svg>
</div>
</template>
<script lang="ts" setup>
import { useRotaryEncoder } from "@/stores/Peripherals/RotaryEncoder";
import { RotaryEncoderDirection } from "@/utils/signalR/Peripherals.RotaryEncoderClient";
import { watch } from "vue";
import { watchEffect } from "vue";
import { ref, computed } from "vue";
const rotataryEncoderStore = useRotaryEncoder();
interface Props {
size?: number;
enableDigitalTwin?: boolean;
encoderNumber?: number;
}
const props = withDefaults(defineProps<Props>(), {
size: 1,
enableDigitalTwin: false,
encoderNumber: 1,
});
// 组件状态
const isPressed = ref(false);
const rotationStep = ref(0); // 步进计数1步=15度
// 拖动状态对象,增加 hasRotated 标记
const drag = ref<{
active: boolean;
startX: number;
hasRotated: boolean;
} | null>(null);
const dragThreshold = 20; // 每20像素触发一次旋转
// 计算宽高
const width = computed(() => 100 * props.size);
const height = computed(() => 100 * props.size);
// 鼠标按下处理
function handleMouseDown(event: MouseEvent) {
drag.value = { active: true, startX: event.clientX, hasRotated: false };
window.addEventListener("mousemove", handleMouseMove);
window.addEventListener("mouseup", handleMouseUp);
}
// 鼠标移动处理
function handleMouseMove(event: MouseEvent) {
if (!drag.value?.active) return;
const dx = event.clientX - drag.value.startX;
if (Math.abs(dx) >= dragThreshold) {
rotationStep.value += dx > 0 ? 1 : -1;
drag.value.startX = event.clientX;
drag.value.hasRotated = true;
}
}
// 鼠标松开处理
function handleMouseUp() {
if (drag.value && drag.value.active) {
// 仅在未发生旋转时才触发按压
if (!drag.value.hasRotated) {
isPressed.value = true;
setTimeout(() => {
isPressed.value = false;
}, 100);
}
}
drag.value = null;
window.removeEventListener("mousemove", handleMouseMove);
window.removeEventListener("mouseup", handleMouseUp);
}
// 按压处理用于鼠标离开和mouseup
function handlePress(pressed: boolean) {
isPressed.value = pressed;
}
watchEffect(() => {
rotataryEncoderStore.setEnable(props.enableDigitalTwin);
});
watch(
() => rotationStep.value,
(newStep, oldStep) => {
if (newStep > oldStep) {
rotataryEncoderStore.rotateOnce(
props.encoderNumber,
RotaryEncoderDirection.Clockwise,
);
} else if (newStep < oldStep) {
rotataryEncoderStore.rotateOnce(
props.encoderNumber,
RotaryEncoderDirection.CounterClockwise,
);
}
},
);
</script>
<script lang="ts">
// 添加一个静态方法来获取默认props
export function getDefaultProps() {
return {
size: 1,
enableDigitalTwin: false,
encoderNumber: 1,
};
}
</script>
<style scoped lang="postcss">
.ec11-container {
display: inline-block;
user-select: none;
}
.ec11-encoder {
display: block;
overflow: visible;
}
.interactive {
cursor: pointer;
}
</style>

View File

@@ -0,0 +1,92 @@
import { AuthManager } from "@/utils/AuthManager";
import type { RotaryEncoderDirection } from "@/utils/signalR/Peripherals.RotaryEncoderClient";
import {
getHubProxyFactory,
getReceiverRegister,
} from "@/utils/signalR/TypedSignalR.Client";
import type {
IRotaryEncoderHub,
IRotaryEncoderReceiver,
} from "@/utils/signalR/TypedSignalR.Client/server.Hubs";
import { HubConnectionState, type HubConnection } from "@microsoft/signalr";
import { isUndefined } from "mathjs";
import { defineStore } from "pinia";
import { onMounted, onUnmounted, ref, shallowRef } from "vue";
export const useRotaryEncoder = defineStore("RotaryEncoder", () => {
const rotaryEncoderHub = shallowRef<{
connection: HubConnection;
proxy: IRotaryEncoderHub;
} | null>(null);
const rotaryEncoderReceiver: IRotaryEncoderReceiver = {
onReceiveRotate: async (data) => {},
};
onMounted(() => {
initHub();
});
onUnmounted(() => {
clearHub();
});
function initHub() {
if (rotaryEncoderHub.value) return;
const connection = AuthManager.createHubConnection("RotaryEncoderHub");
const proxy =
getHubProxyFactory("IRotaryEncoderHub").createHubProxy(connection);
getReceiverRegister("IRotaryEncoderReceiver").register(
connection,
rotaryEncoderReceiver,
);
connection.start();
rotaryEncoderHub.value = { connection, proxy };
}
function clearHub() {
if (!rotaryEncoderHub.value) return;
rotaryEncoderHub.value.connection.stop();
rotaryEncoderHub.value = null;
}
function reinitializeHub() {
clearHub();
initHub();
}
function getHubProxy() {
if (!rotaryEncoderHub.value) throw new Error("Hub not initialized");
return rotaryEncoderHub.value.proxy;
}
async function setEnable(enabled: boolean) {
const proxy = getHubProxy();
return await proxy.setEnable(enabled);
}
async function rotateOnce(num: number, direction: RotaryEncoderDirection) {
const proxy = getHubProxy();
return await proxy.rotateEncoderOnce(num, direction);
}
async function enableCycleRotate(
num: number,
direction: RotaryEncoderDirection,
freq: number,
) {
const proxy = getHubProxy();
return await proxy.enableCycleRotateEncoder(num, direction, freq);
}
async function disableCycleRotate() {
const proxy = getHubProxy();
return await proxy.disableCycleRotateEncoder();
}
return {
setEnable,
rotateOnce,
enableCycleRotate,
disableCycleRotate,
};
});

View File

@@ -45,7 +45,7 @@ export class AuthManager {
// SignalR连接 - 简单明了
static createHubConnection(
hubPath: "ProgressHub" | "JtagHub" | "DigitalTubesHub",
hubPath: "ProgressHub" | "JtagHub" | "DigitalTubesHub" | "RotaryEncoderHub",
) {
return new HubConnectionBuilder()
.withUrl(`http://127.0.0.1:5000/hubs/${hubPath}`, {

View File

@@ -0,0 +1,10 @@
/* THIS (.ts) FILE IS GENERATED BY Tapper */
/* eslint-disable */
/* tslint:disable */
/** Transpiled from Peripherals.RotaryEncoderClient.RotaryEncoderDirection */
export enum RotaryEncoderDirection {
CounterClockwise = 0,
Clockwise = 1,
}

View File

@@ -3,8 +3,9 @@
/* tslint:disable */
// @ts-nocheck
import type { HubConnection, IStreamResult, Subject } from '@microsoft/signalr';
import type { IDigitalTubesHub, IJtagHub, IProgressHub, IDigitalTubesReceiver, IJtagReceiver, IProgressReceiver } from './server.Hubs';
import type { IDigitalTubesHub, IJtagHub, IProgressHub, IRotaryEncoderHub, IDigitalTubesReceiver, IJtagReceiver, IProgressReceiver, IRotaryEncoderReceiver } from './server.Hubs';
import type { DigitalTubeTaskStatus, ProgressInfo } from '../server.Hubs';
import type { RotaryEncoderDirection } from '../Peripherals.RotaryEncoderClient';
// components
@@ -46,6 +47,7 @@ export type HubProxyFactoryProvider = {
(hubType: "IDigitalTubesHub"): HubProxyFactory<IDigitalTubesHub>;
(hubType: "IJtagHub"): HubProxyFactory<IJtagHub>;
(hubType: "IProgressHub"): HubProxyFactory<IProgressHub>;
(hubType: "IRotaryEncoderHub"): HubProxyFactory<IRotaryEncoderHub>;
}
export const getHubProxyFactory = ((hubType: string) => {
@@ -58,12 +60,16 @@ export const getHubProxyFactory = ((hubType: string) => {
if(hubType === "IProgressHub") {
return IProgressHub_HubProxyFactory.Instance;
}
if(hubType === "IRotaryEncoderHub") {
return IRotaryEncoderHub_HubProxyFactory.Instance;
}
}) as HubProxyFactoryProvider;
export type ReceiverRegisterProvider = {
(receiverType: "IDigitalTubesReceiver"): ReceiverRegister<IDigitalTubesReceiver>;
(receiverType: "IJtagReceiver"): ReceiverRegister<IJtagReceiver>;
(receiverType: "IProgressReceiver"): ReceiverRegister<IProgressReceiver>;
(receiverType: "IRotaryEncoderReceiver"): ReceiverRegister<IRotaryEncoderReceiver>;
}
export const getReceiverRegister = ((receiverType: string) => {
@@ -76,6 +82,9 @@ export const getReceiverRegister = ((receiverType: string) => {
if(receiverType === "IProgressReceiver") {
return IProgressReceiver_Binder.Instance;
}
if(receiverType === "IRotaryEncoderReceiver") {
return IRotaryEncoderReceiver_Binder.Instance;
}
}) as ReceiverRegisterProvider;
// HubProxy
@@ -171,6 +180,39 @@ class IProgressHub_HubProxy implements IProgressHub {
}
}
class IRotaryEncoderHub_HubProxyFactory implements HubProxyFactory<IRotaryEncoderHub> {
public static Instance = new IRotaryEncoderHub_HubProxyFactory();
private constructor() {
}
public readonly createHubProxy = (connection: HubConnection): IRotaryEncoderHub => {
return new IRotaryEncoderHub_HubProxy(connection);
}
}
class IRotaryEncoderHub_HubProxy implements IRotaryEncoderHub {
public constructor(private connection: HubConnection) {
}
public readonly setEnable = async (enable: boolean): Promise<boolean> => {
return await this.connection.invoke("SetEnable", enable);
}
public readonly rotateEncoderOnce = async (num: number, direction: RotaryEncoderDirection): Promise<boolean> => {
return await this.connection.invoke("RotateEncoderOnce", num, direction);
}
public readonly enableCycleRotateEncoder = async (num: number, direction: RotaryEncoderDirection, freq: number): Promise<boolean> => {
return await this.connection.invoke("EnableCycleRotateEncoder", num, direction, freq);
}
public readonly disableCycleRotateEncoder = async (): Promise<boolean> => {
return await this.connection.invoke("DisableCycleRotateEncoder");
}
}
// Receiver
@@ -237,3 +279,24 @@ class IProgressReceiver_Binder implements ReceiverRegister<IProgressReceiver> {
}
}
class IRotaryEncoderReceiver_Binder implements ReceiverRegister<IRotaryEncoderReceiver> {
public static Instance = new IRotaryEncoderReceiver_Binder();
private constructor() {
}
public readonly register = (connection: HubConnection, receiver: IRotaryEncoderReceiver): Disposable => {
const __onReceiveRotate = (...args: [number, RotaryEncoderDirection]) => receiver.onReceiveRotate(...args);
connection.on("OnReceiveRotate", __onReceiveRotate);
const methodList: ReceiverMethod[] = [
{ methodName: "OnReceiveRotate", method: __onReceiveRotate }
]
return new ReceiverMethodSubscription(connection, methodList);
}
}

View File

@@ -4,6 +4,7 @@
// @ts-nocheck
import type { IStreamResult, Subject } from '@microsoft/signalr';
import type { DigitalTubeTaskStatus, ProgressInfo } from '../server.Hubs';
import type { RotaryEncoderDirection } from '../Peripherals.RotaryEncoderClient';
export type IDigitalTubesHub = {
/**
@@ -60,6 +61,31 @@ export type IProgressHub = {
getProgress(taskId: string): Promise<ProgressInfo>;
}
export type IRotaryEncoderHub = {
/**
* @param enable Transpiled from bool
* @returns Transpiled from System.Threading.Tasks.Task<bool>
*/
setEnable(enable: boolean): Promise<boolean>;
/**
* @param num Transpiled from int
* @param direction Transpiled from Peripherals.RotaryEncoderClient.RotaryEncoderDirection
* @returns Transpiled from System.Threading.Tasks.Task<bool>
*/
rotateEncoderOnce(num: number, direction: RotaryEncoderDirection): Promise<boolean>;
/**
* @param num Transpiled from int
* @param direction Transpiled from Peripherals.RotaryEncoderClient.RotaryEncoderDirection
* @param freq Transpiled from int
* @returns Transpiled from System.Threading.Tasks.Task<bool>
*/
enableCycleRotateEncoder(num: number, direction: RotaryEncoderDirection, freq: number): Promise<boolean>;
/**
* @returns Transpiled from System.Threading.Tasks.Task<bool>
*/
disableCycleRotateEncoder(): Promise<boolean>;
}
export type IDigitalTubesReceiver = {
/**
* @param data Transpiled from byte[]
@@ -84,3 +110,12 @@ export type IProgressReceiver = {
onReceiveProgress(message: ProgressInfo): Promise<void>;
}
export type IRotaryEncoderReceiver = {
/**
* @param num Transpiled from int
* @param direction Transpiled from Peripherals.RotaryEncoderClient.RotaryEncoderDirection
* @returns Transpiled from System.Threading.Tasks.Task
*/
onReceiveRotate(num: number, direction: RotaryEncoderDirection): Promise<void>;
}