Skip to content

Commit

Permalink
[Sigma] Update
Browse files Browse the repository at this point in the history
  • Loading branch information
baku89 committed Oct 9, 2023
1 parent 0bbdfa5 commit e8afda1
Show file tree
Hide file tree
Showing 2 changed files with 147 additions and 100 deletions.
173 changes: 112 additions & 61 deletions src/PTPDevice.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import EventEmitter from 'eventemitter3'
import promiseTimeout from 'p-timeout'
import PromiseQueue from 'promise-queue'
import sleep from 'sleep-promise'

import {ResCode} from './PTPDatacode'
import {PTPDataView} from './PTPDataView'
Expand All @@ -15,6 +16,8 @@ enum PTPType {

const PTPCommandMaxByteLength = 12 + 4 * 3
const PTPDefaultTimeoutMs = 10000
const PTPTryCount = 30
const PTPTryAgainIntervalMs = 500

interface PTPSendCommandOption {
label?: string
Expand Down Expand Up @@ -209,29 +212,45 @@ export class PTPDevice extends EventEmitter<EventTypes> {
expectedResCodes: [ResCode.OK],
...option,
}
const id = this.generateTransactionId()

await this.transferOutCommand(opcode, id, parameters)
for (let i = 0; i < PTPTryCount; i++) {
const id = this.generateTransactionId()

const res = await this.waitBulkIn(id, PTPCommandMaxByteLength)
await this.transferOutCommand(opcode, id, parameters)

// Error checking
if (res.type !== PTPType.Response) {
throw new Error(
`Expected response type: ${PTPType.Response}, got: ${res.type}`
)
}
const res = await this.waitBulkIn(id, PTPCommandMaxByteLength)

if (!expectedResCodes.includes(res.code)) {
const expected = expectedResCodes.map(toHexString)
const got = toHexString(res.code)
throw new Error(`Expected rescode=[${expected}], got= ${got}`)
}
// Error checking
if (res.type !== PTPType.Response) {
throw new Error(
`Expected response type: ${PTPType.Response}, got: ${res.type}`
)
}

return {
resCode: res.code,
parameters: [...new Uint32Array(res.payload)],
// When the device is busy, try again
const tryAgain =
!expectedResCodes.includes(ResCode.DeviceBusy) &&
res.code === ResCode.DeviceBusy

if (tryAgain) {
sleep(PTPTryAgainIntervalMs)
continue
}

// Check rescode
if (!expectedResCodes.includes(res.code)) {
const expected = expectedResCodes.map(toHexString)
const got = toHexString(res.code)
throw new Error(`Expected rescode=[${expected}], got= ${got}`)
}

return {
resCode: res.code,
parameters: [...new Uint32Array(res.payload)],
}
}

throw new Error('Cannot send command')
}

private sendDataNow = async (
Expand All @@ -242,30 +261,46 @@ export class PTPDevice extends EventEmitter<EventTypes> {
expectedResCodes: [ResCode.OK],
...option,
}
const id = this.generateTransactionId()

await this.transferOutCommand(opcode, id, parameters)
await this.transferOutData(opcode, id, data)
for (let i = 0; i < PTPTryCount; i++) {
const id = this.generateTransactionId()

const res = await this.waitBulkIn(id, PTPCommandMaxByteLength)
await this.transferOutCommand(opcode, id, parameters)
await this.transferOutData(opcode, id, data)

// Error checking
if (res.type !== PTPType.Response) {
throw new Error(
`Expected response type: ${PTPType.Response}, got: ${res.type}`
)
}
const res = await this.waitBulkIn(id, PTPCommandMaxByteLength)

if (!expectedResCodes.includes(res.code)) {
const expected = expectedResCodes.map(toHexString)
const got = toHexString(res.code)
throw new Error(`Expected rescode=[${expected}], got=${got}`)
}
// Error checking
if (res.type !== PTPType.Response) {
throw new Error(
`Expected response type: ${PTPType.Response}, got: ${res.type}`
)
}

return {
resCode: res.code,
parameters: [...new Uint32Array(res.payload)],
// When the device is busy, try again
const tryAgain =
!expectedResCodes.includes(ResCode.DeviceBusy) &&
res.code === ResCode.DeviceBusy

if (tryAgain) {
sleep(PTPTryAgainIntervalMs)
continue
}

// Check rescode
if (!expectedResCodes.includes(res.code)) {
const expected = expectedResCodes.map(toHexString)
const got = toHexString(res.code)
throw new Error(`Expected rescode=[${expected}], got=${got}`)
}

return {
resCode: res.code,
parameters: [...new Uint32Array(res.payload)],
}
}

throw new Error('Cannot send data')
}

private receiveDataNow = async (
Expand All @@ -277,39 +312,55 @@ export class PTPDevice extends EventEmitter<EventTypes> {
maxByteLength: 10_000, // = 10KB. Looks enough for non-media data transfer
...option,
}
const id = this.generateTransactionId()

await this.transferOutCommand(opcode, id, parameters)
const res1 = await this.waitBulkIn(id, maxByteLength)

if (res1.type === PTPType.Response) {
if (expectedResCodes.includes(res1.code)) {
this.#console.groupEnd()
return {
resCode: res1.code,
parameters: [],
data: new ArrayBuffer(0),

for (let i = 0; i < PTPTryCount; i++) {
const id = this.generateTransactionId()

await this.transferOutCommand(opcode, id, parameters)
const res1 = await this.waitBulkIn(id, maxByteLength)

if (res1.type === PTPType.Response) {
if (expectedResCodes.includes(res1.code)) {
this.#console.groupEnd()
return {
resCode: res1.code,
parameters: [],
data: new ArrayBuffer(0),
}
}
}
}

if (res1.type !== PTPType.Data) {
throw new Error(`Cannot receive data code=${toHexString(res1.code)}`)
}
if (res1.type !== PTPType.Data) {
throw new Error(`Cannot receive data code=${toHexString(res1.code)}`)
}

const res2 = await this.waitBulkIn(id, PTPCommandMaxByteLength)
const res2 = await this.waitBulkIn(id, PTPCommandMaxByteLength)

if (res2.type !== PTPType.Response) {
throw new Error(
`Expected response type: ${PTPType.Response}, but got: ${res2.type}`
)
}
if (res2.type !== PTPType.Response) {
throw new Error(
`Expected response type: ${PTPType.Response}, but got: ${res2.type}`
)
}
// When the device is busy, try again
const tryAgain =
!expectedResCodes.includes(ResCode.DeviceBusy) &&
res2.code === ResCode.DeviceBusy

if (tryAgain) {
sleep(PTPTryAgainIntervalMs)
continue
}

return {
resCode: res2.code,
parameters: [...new Uint32Array(res2.payload)],
data: res1.payload,
// Check rescode

return {
resCode: res2.code,
parameters: [...new Uint32Array(res2.payload)],
data: res1.payload,
}
}

throw new Error('Cannot receive data')
}

waitEvent = async (code: number): Promise<PTPEvent> => {
Expand Down
74 changes: 35 additions & 39 deletions src/TethrPTPUSB/TethrSigma.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,23 +244,36 @@ export class TethrSigma extends TethrPTPUSB {

const [lvTop, lvBottom, lvLeft, lvRight] = focusValidArea

// Assume the margins are symmetrical
return [lvLeft + lvRight, lvTop + lvBottom] as Vec2
}

async getAutoFocusFrameCenterDesc(): Promise<ConfigDesc<Vec2>> {
if (!(await this.get('canRunAutoFocus'))) {
return {writable: false, value: null}
}
async #enableSpotAutoFocus() {
await this.device.sendData({
label: 'SigmaFP SetCamDataGroupFocus',
opcode: OpCodeSigma.SetCamDataGroupFocus,
data: encodeIFD({
// 2 === 1-spot selection
focusArea: {tag: 10, type: IFDType.Byte, value: [2]},
}),
})

// First, enable the spot focus area
await this.device.sendData({
label: 'SigmaFP SetCamDataGroupFocus',
opcode: OpCodeSigma.SetCamDataGroupFocus,
data: encodeIFD({
focusArea: {tag: 10, type: IFDType.Short, value: [2]},
onePointSelectionMethod: {tag: 11, type: IFDType.Short, value: [49]},
// 49 === 49-point selection mode
onePointSelectionMethod: {tag: 11, type: IFDType.Byte, value: [49]},
}),
})
}

async getAutoFocusFrameCenterDesc(): Promise<ConfigDesc<Vec2>> {
if (!(await this.get('canRunAutoFocus'))) {
return {writable: false, value: null}
}

await this.#enableSpotAutoFocus()

// Then, get the current position
const {distanceMeasurementFramePosition} = await this.getCamStatus()
Expand Down Expand Up @@ -300,46 +313,29 @@ export class TethrSigma extends TethrPTPUSB {
return {status: 'invalid parameter'}
}

// First, enable the spot focus area
await this.device.sendData({
label: 'SigmaFP SetCamDataGroupFocus',
opcode: OpCodeSigma.SetCamDataGroupFocus,
data: encodeIFD({
focusArea: {tag: 10, type: IFDType.Short, value: [2]},
onePointSelectionMethod: {tag: 11, type: IFDType.Short, value: [49]},
}),
})
await this.#enableSpotAutoFocus()

const lvSize = await this.#getLVCoordinateSize()

// Assume the margins are symmetrical
const [x, y] = vec2.round(vec2.mul(center, lvSize))

const data = encodeIFD({
distanceMeasurementFramePosition: {
tag: 13,
type: IFDType.Short,
value: [y, x],
},
const {resCode} = await this.device.sendData({
label: 'SigmaFP SetCamDataGroupFocus',
opcode: OpCodeSigma.SetCamDataGroupFocus,
data: encodeIFD({
distanceMeasurementFramePosition: {
tag: 13,
type: IFDType.Short,
value: [y, x],
},
}),
})

// Try to set the focus position many times because it often fails
for (let i = 0; i < 20; i++) {
const {resCode} = await this.device.sendData({
label: 'SigmaFP SetCamDataGroupFocus',
opcode: OpCodeSigma.SetCamDataGroupFocus,
expectedResCodes: [ResCode.OK, ResCode.DeviceBusy],
data,
})

if (resCode === ResCode.OK) {
return {status: 'ok'}
}

await sleep(50)
if (resCode === ResCode.OK) {
return {status: 'ok'}
} else {
return {status: 'invalid parameter'}
}

return {status: 'invalid parameter'}
}

async getAutoFocusFrameSizeDesc(): Promise<ConfigDesc<string>> {
Expand Down

0 comments on commit e8afda1

Please sign in to comment.