Skip to content

Commit

Permalink
Add CNC controlling feature (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
baku89 committed Apr 11, 2024
1 parent a7b4c35 commit c1afa1b
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 0 deletions.
13 changes: 13 additions & 0 deletions src/components/TitleBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {computed, onUnmounted, ref} from 'vue'
import {useAuxStore} from '@/stores/aux'
import {useCameraStore} from '@/stores/camera'
import {useCncStore} from '@/stores/cnc'
import {useOpfsStore} from '@/stores/opfs'
import {useProjectStore} from '@/stores/project'
import {useTimerStore} from '@/stores/timer'
Expand All @@ -19,6 +20,7 @@ const project = useProjectStore()
const camera = useCameraStore()
const timer = useTimerStore()
const aux = useAuxStore()
const cnc = useCncStore()
const gamepads = ref<string[]>([])
Expand Down Expand Up @@ -140,6 +142,17 @@ const destinationInfo = computed(() => {
icon="tabler:gizmo"
:active="aux.tracker.enabled"
/>
<vTooltip>
<Tq.IconIndicator
icon="game-icons:mechanical-arm"
:active="cnc.connected"
/>
<template #popper>
<p>{{ cnc.connected ? 'CNC Connected' : 'No CNC Available' }}</p>
<pre>{{ cnc.log }}</pre>
<Tq.InputButton label="Status" />
</template>
</vTooltip>
</template>
</Tq.TitleBar>
</template>
140 changes: 140 additions & 0 deletions src/stores/cnc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/* eslint-disable no-constant-condition */
import {isEqual} from 'lodash'
import {defineStore} from 'pinia'
import {useActionsStore, useAppConfigStore} from 'tweeq'
import {computed, ref, watch} from 'vue'

export const useCncStore = defineStore('cnc', () => {
const appConfig = useAppConfigStore()

const port = ref<SerialPort | null>(null)

const connected = computed(() => port.value !== null)

const savedInfo = appConfig.ref<SerialPortInfo | null>('cnc.info', null)

const init = async () => {
const ports = await navigator.serial.getPorts()

for (const p of ports) {
const info = p.getInfo()
if (isEqual(info, savedInfo.value)) {
port.value = p
return
}
}
}

init()

const connect = async () => {
try {
port.value = await navigator.serial.requestPort()
} catch (e) {
port.value = null
}
}

watch(
port,
async (port, oldPort) => {
if (oldPort) {
oldPort.close()
}

if (port) {
savedInfo.value = port.getInfo()
receive()
} else {
savedInfo.value = null
}
},
{immediate: true}
)

const decoder = new TextDecoder()
const encoder = new TextEncoder()

const log = ref('')

async function receive() {
const p = port.value

if (!p) return

console.log('connected to CNC', p.getInfo())

await p.open({baudRate: 115200})

const reader = p.readable?.getReader()
if (!reader) {
console.info('cannot read from CNC', port.value?.getInfo())
port.value = null
return
}

try {
while (p.readable) {
const {value, done} = await reader.read()
if (done) break

log.value += decoder.decode(value)
}
} finally {
reader.releaseLock()
}
}

async function send(gcode: string) {
const writer = port.value?.writable?.getWriter()
if (!writer) {
return
}

try {
await writer.write(encoder.encode(gcode))
log.value += `> ${gcode}\n`
} finally {
writer.releaseLock()
}
}

// Actions

const actions = useActionsStore()

actions.register([
{
id: 'motion-control',
label: 'Motion Control',
icon: 'game-icons:mechanical-arm',
children: [
{
id: 'connect-cnc',
label: 'Connect to CNC',
perform: connect,
},
{
id: 'get-status',
label: 'Get CNC status',
perform: () => send('$$\n'),
},
{
id: 'send-gcode',
label: 'Send G-Code',
perform: () => {
const gcode = prompt('G-code', '')
if (gcode) send(gcode + '\n')
},
},
],
},
])

return {
connect,
connected,
send,
log,
}
})

0 comments on commit c1afa1b

Please sign in to comment.