Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for the VEC Footpedal #89

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions packages/core/src/products.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1147,4 +1147,23 @@ export const PRODUCTS: { [name: string]: Product } = {
backLight2offset: 0,
//timestamp: none, RailDriver has no time stamp
}),
VECFootpedal: literal<Product>({
name: 'VEC Footpedal',
hidDevices: [[255, 0]],
bBytes: 1,
bBits: 4, // Bit 1=left pedal, bit 2=middle pedal, bit 3=right pedal, bits 4-8=0.
colCount: 3, // 3 pedals in a row
rowCount: 1, // number of physical rows
hasPS: false, //
backLightType: BackLightType.NONE, // no back light LEDs
backLight2offset: 0,
//timestamp: none, VECFootpedal has no time stamp
btnLocation: [
[0, 0],
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I leave this out, the right pedal causes exceptions.

[1, 1],
[1, 2],
[1, 3],
],
disableButtons: [0],
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if this is required or not, if I set it to 1 it does fire left pedal presses.

}),
}
40 changes: 30 additions & 10 deletions packages/core/src/xkeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,23 @@ export class XKeys extends EventEmitter {
for (let i = 0; i < 15; i++) {
data[i] = rdData[i]
}
} else if (deviceInfo.productId === 255) {
// Note: The VEC Footpedal is an older device, which doesn't follow the rest of xkeys data structure.
// To make it easy for us, we'll just remap the data to work for us.

const rdData = new Uint8Array(32)
rdData[0] = 0 // this sets the Unit ID to 0 always
if (!this._firmwareVersionIsSet) {
rdData[1] = 214 // Fake initial message to set _firmwareVersion
} else if (!this._unitIdIsSet) {
rdData[1] = 3 // Fake initial message to set _unitId
Comment on lines +121 to +124
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The first up and down events seem to get swallowed, can we not force extra messages here which I assume would solve this? Presumably this is also the same for the RailDriver?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Am I correct in assuming that this device doesn't really have the concept of a unitId? (That would make sense, since it won't accept the inititial write of _getVersion() and so won't return a unitId.)

If so, I suggest that we solve this by adding

if (this.deviceInfo.productId == 255) {
  this._unitId = 0 // VEC Footpanel doesn't support unitIds
  this._unitIdIsSet = true
}

into the init() method.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given it only ever returns the two bytes, and doesn't accept any writes, I don't think so! Although conversely I've never worked out what the second byte is for (some more generic underlying product/interface)

The device has no serial number via lsusb either (but maybe that's common to all xkeys?).

If so, I suggest that we solve this by adding

Do you think this would solve it missing the first keypress and release too when run as node packages/node/examples/basic-log-all-events.js?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If so, I suggest that we solve this by adding

if (this.deviceInfo.productId == 255) {
  this._unitId = 0 // VEC Footpanel doesn't support unitIds
  this._unitIdIsSet = true
}

into the init() method.

Adding that into the top of the init method (without removing my other changes) certainly doesn't break anything. Although the first press and release are still silently swallowed by the library currently.

} else {
rdData[1] = 0 // no pg switch, byte is always 0
}
rdData[2] = data.readUInt8(0) // remap button bits
rdData[3] = data.readUInt8(1) // remap button bits
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what, if anything, happens with this second byte?


data = Buffer.from(rdData)
}

//------------------------
Expand Down Expand Up @@ -333,18 +350,21 @@ export class XKeys extends EventEmitter {

/** Initialize the device. This ensures that the essential information from the device about its state has been received. */
public async init(): Promise<void> {
const pReceivedVersion = new Promise<void>((resolve) => {
this.receivedVersionResolve = resolve
})
const pReceivedGenerateData = new Promise<void>((resolve) => {
this.receivedGenerateDataResolve = resolve
})
if (this.deviceInfo.productId !== 255) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A question for you:
What happens if we try to write to the device? Does it crash? Or nothing?

I'm thinking that if it crashes we might want to guard against writing to it in some other methods as well.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I ever try and write to it, I get the following (so the device doesn't crash, but node does):

Error in XKeysWatcher TypeError: Cannot write to hid device
    at NodeHIDDevice.write (/home/pi/companion-dev/xkeys-footpedals-fixed/packages/node/dist/node-hid-wrapper.js:19:21)
    at XKeys._write (/home/pi/companion-dev/xkeys-footpedals-fixed/packages/core/dist/xkeys.js:652:25)
    at XKeys._getVersion (/home/pi/companion-dev/xkeys-footpedals-fixed/packages/core/dist/xkeys.js:701:14)
    at XKeys.init (/home/pi/companion-dev/xkeys-footpedals-fixed/packages/core/dist/xkeys.js:319:18)
    at setupXkeysPanel (/home/pi/companion-dev/xkeys-footpedals-fixed/packages/node/dist/methods.js:77:17)
    at XKeysWatcher.handleNewDevice (/home/pi/companion-dev/xkeys-footpedals-fixed/packages/node/dist/watcher.js:196:32)
    at XKeysWatcher.updateConnectedDevices (/home/pi/companion-dev/xkeys-footpedals-fixed/packages/node/dist/watcher.js:181:22)
    at Timeout._onTimeout (/home/pi/companion-dev/xkeys-footpedals-fixed/packages/node/dist/watcher.js:136:22)
    at listOnTimeout (node:internal/timers:569:17)
    at process.processTimers (node:internal/timers:512:7)

So I did the protection in each place that calls write, as it often needed other steps to work around it, but maybe it should be done more centrally?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have been away, but earlier you asked if I could assist. Not sure if I can, the VEC foot pedal is a proprietary device made specifically for VEC and their software. It is not an X-keys so not sure if it belongs here. It is very limited in its capabilities, however, 3 bits is just 3 bits, so it does that. As you are finding there will be a lot of work arounds to make it work.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have been away, but earlier you asked if I could assist. Not sure if I can, the VEC foot pedal is a proprietary device made specifically for VEC and their software.

Fair enough, I'd found lots of other hits on the Internet, and it's just integrated into Linux via the Event stuff, so I didn't realise it was originally designed just for VEC's software.

It is not an X-keys so not sure if it belongs here. It is very limited in its capabilities, however, 3 bits is just 3 bits, so it does that. As you are finding there will be a lot of work arounds to make it work.

That seems quite similar with the RailDriver ( https://xkeys.com/xkeys/rdproducts.html ) stuff too, looking at some of the workarounds for that in the code too.

I would say conversely, they're all P.I. Engineering devices, the VID confirms that, and the fact there's an official XKeys device which looks like later revisions of the VEC Infinity range it would seem a bit of a shame to me if the support wasn't added:
https://xkeys.com/xkeys/switches-pedals/footpedals.html
http://veccorp.com/foot-controls.html

// Note: The VEC Footpedal is an older device, which doesn't accept any writes so we don't do any initialization for it
const pReceivedVersion = new Promise<void>((resolve) => {
this.receivedVersionResolve = resolve
})
const pReceivedGenerateData = new Promise<void>((resolve) => {
this.receivedGenerateDataResolve = resolve
})

this._getVersion()
this._generateData()
this._getVersion()
this._generateData()

await pReceivedVersion
await pReceivedGenerateData
await pReceivedVersion
await pReceivedGenerateData
}

this._initialized = true
}
Expand Down
4 changes: 2 additions & 2 deletions packages/node/src/__tests__/recordings.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ describe('Recorded tests', () => {
.join('\n')}`
)

// This number should be decreased as more recordings are added
expect(Object.values(products).length).toBeLessThanOrEqual(21)
// This number should be increased as more recordings are added
expect(Object.values(products).length).toBeLessThanOrEqual(22)
})
})