Skip to content

Commit

Permalink
feat: additional studio firmware versions (usb)
Browse files Browse the repository at this point in the history
  • Loading branch information
Julusian committed Nov 14, 2024
1 parent 46c49d7 commit 4e2e5df
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 39 deletions.
9 changes: 8 additions & 1 deletion packages/core/src/models/studio.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { DeviceModelId, MODEL_NAMES } from '../id.js'
import { freezeDefinitions, generateButtonsGrid } from '../controlsGenerator.js'
import type { StreamDeckControlDefinition } from '../controlDefinition.js'
import type { PropertiesService } from '../services/properties/interface.js'
import { StudioPropertiesService } from '../services/properties/studio.js'

const studioControls: StreamDeckControlDefinition[] = [
{
Expand Down Expand Up @@ -52,6 +53,12 @@ export function StreamDeckStudioFactory(
options: Required<OpenStreamDeckOptions>,
propertiesService?: PropertiesService,
): StreamDeckBase {
const services = createBaseGen2Properties(device, options, studioProperties, propertiesService ?? null, true)
const services = createBaseGen2Properties(
device,
options,
studioProperties,
propertiesService ?? new StudioPropertiesService(device),
true,
)
return new StreamDeckBase(device, options, services)
}
36 changes: 36 additions & 0 deletions packages/core/src/services/properties/all-firmware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { uint8ArrayToDataView } from '../../util'

Check failure on line 1 in packages/core/src/services/properties/all-firmware.ts

View workflow job for this annotation

GitHub Actions / lint

Can't resolve '../../util' in '/home/runner/work/node-elgato-stream-deck/node-elgato-stream-deck/packages/core/src/services/properties'

export async function parseAllFirmwareVersionsHelper(reportData: {
// Future: LD, AP1?
ap2: Uint8Array | null
encoderAp2: Uint8Array | null
encoderLd: Uint8Array | null
}): Promise<Record<string, string>> {
const decoder = new TextDecoder('ascii')

const versions: Record<string, string> = {}

if (reportData.ap2) {
const ap2DataDataView = uint8ArrayToDataView(reportData.ap2)
versions.AP2 = decoder.decode(reportData.ap2.subarray(6, 6 + 8))
versions.AP2_CHECKSUM = ap2DataDataView.getUint32(2, false).toString(16)
}

if (reportData.encoderLd && (reportData.encoderLd[0] === 0x18 || reportData.encoderLd[1] === 0x18)) {
const encoderLdDataView = uint8ArrayToDataView(reportData.encoderLd)
versions.ENCODER_LD_1 = decoder.decode(reportData.encoderLd.subarray(2, 2 + 8))
versions.ENCODER_LD_1_CHECKSUM = encoderLdDataView.getUint32(10, false).toString(16)
versions.ENCODER_LD_2 = decoder.decode(reportData.encoderLd.subarray(14, 14 + 8))
versions.ENCODER_LD_2_CHECKSUM = encoderLdDataView.getUint32(22, false).toString(16)
}

if (reportData.encoderAp2 && (reportData.encoderAp2[0] === 0x18 || reportData.encoderAp2[1] === 0x18)) {
const encoderAp2DataView = uint8ArrayToDataView(reportData.encoderAp2)
versions.ENCODER_AP2_1 = decoder.decode(reportData.encoderAp2.subarray(2, 2 + 8))
versions.ENCODER_AP2_1_CHECKSUM = encoderAp2DataView.getUint32(10, false).toString(16)
versions.ENCODER_AP2_2 = decoder.decode(reportData.encoderAp2.subarray(14, 14 + 8))
versions.ENCODER_AP2_2_CHECKSUM = encoderAp2DataView.getUint32(22, false).toString(16)
}

return versions
}
12 changes: 6 additions & 6 deletions packages/core/src/services/properties/gen2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ import type { HIDDevice } from '../../hid-device.js'
import type { PropertiesService } from './interface.js'

export class Gen2PropertiesService implements PropertiesService {
readonly #device: HIDDevice
protected readonly device: HIDDevice

constructor(device: HIDDevice) {
this.#device = device
this.device = device
}

public async setBrightness(percentage: number): Promise<void> {
Expand All @@ -21,7 +21,7 @@ export class Gen2PropertiesService implements PropertiesService {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
]);
await this.#device.sendFeatureReport(brightnessCommandBuffer)
await this.device.sendFeatureReport(brightnessCommandBuffer)
}

public async resetToLogo(): Promise<void> {
Expand All @@ -33,11 +33,11 @@ export class Gen2PropertiesService implements PropertiesService {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
]);
await this.#device.sendFeatureReport(resetCommandBuffer)
await this.device.sendFeatureReport(resetCommandBuffer)
}

public async getFirmwareVersion(): Promise<string> {
const val = await this.#device.getFeatureReport(5, 32)
const val = await this.device.getFeatureReport(5, 32)
const end = val[1] + 2
return new TextDecoder('ascii').decode(val.subarray(6, end))
}
Expand All @@ -50,7 +50,7 @@ export class Gen2PropertiesService implements PropertiesService {
}

public async getSerialNumber(): Promise<string> {
const val = await this.#device.getFeatureReport(6, 32)
const val = await this.device.getFeatureReport(6, 32)
const end = val[1] + 2
return new TextDecoder('ascii').decode(val.subarray(2, end))
}
Expand Down
14 changes: 12 additions & 2 deletions packages/core/src/services/properties/studio.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
import { parseAllFirmwareVersionsHelper } from './all-firmware'
import { Gen2PropertiesService } from './gen2'

export class StudioPropertiesService extends Gen2PropertiesService {
public async getAllFirmwareVersions(): Promise<Record<string, string>> {
// Not supported for most models
return {}
const [ap2Data, encoderAp2Data, encoderLdData] = await Promise.all([
this.device.getFeatureReport(0x05, 32),
this.device.getFeatureReport(0x11, 32),
this.device.getFeatureReport(0x13, 32),
])

return parseAllFirmwareVersionsHelper({
ap2: ap2Data,
encoderAp2: encoderAp2Data,
encoderLd: encoderLdData,
})
}
}
1 change: 1 addition & 0 deletions packages/node/examples/streamdeck-studio.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ function generateEncoderColor(value, max) {

console.log('firmware', await streamDeck.getFirmwareVersion())
console.log('serial number', await streamDeck.getSerialNumber())
console.log('all-firmware', await streamDeck.getAllFirmwareVersions())

/** @type {import('@elgato-stream-deck/core').StreamDeckEncoderControlDefinition[]} */
const encoders = streamDeck.CONTROLS.filter((control) => control.type === 'encoder')
Expand Down
37 changes: 7 additions & 30 deletions packages/tcp/src/connectionManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ import { DEFAULT_TCP_PORT } from './constants.js'
import { SocketWrapper } from './socketWrapper.js'
import { type JPEGEncodeOptions, encodeJPEG } from '@elgato-stream-deck/node-lib'
import type { HIDDevice, OpenStreamDeckOptions, ChildHIDDeviceInfo, PropertiesService } from '@elgato-stream-deck/core'
import { DEVICE_MODELS, uint8ArrayToDataView } from '@elgato-stream-deck/core'
import { DEVICE_MODELS } from '@elgato-stream-deck/core'
import { StreamDeckTcpWrapper } from './tcpWrapper.js'
import { TcpHidDevice } from './hid-device.js'
import { parseAllFirmwareVersionsHelper } from '@elgato-stream-deck/core/dist/services/properties/all-firmware.js'

export interface StreamDeckTcpConnectionManagerEvents {
connected: [streamdeck: StreamDeckTcp]
Expand Down Expand Up @@ -284,41 +285,17 @@ class TcpPropertiesService implements PropertiesService {
}

public async getAllFirmwareVersions(): Promise<Record<string, string>> {
// Future: LD, AP1?
const [ap2Data, encoderAp2Data, encoderLdData] = await Promise.all([
this.#device.getFeatureReport(0x83, -1),
this.#device.getFeatureReport(0x86, -1),
this.#device.getFeatureReport(0x8a, -1),
])

const decoder = new TextDecoder('ascii')

const ap2DataDataView = uint8ArrayToDataView(ap2Data)

const versions: Record<string, string> = {
AP2: decoder.decode(ap2Data.subarray(8, 16)),
AP2_CHECKSUM: ap2DataDataView.getUint32(4, false).toString(16),
}

const encoderLdDataLen = encoderLdData[2]
if (encoderLdDataLen === 0x18) {
const encoderLdDataView = uint8ArrayToDataView(encoderLdData)
versions.ENCODER_LD_1 = decoder.decode(encoderLdData.subarray(4, 4 + 8))
versions.ENCODER_LD_1_CHECKSUM = encoderLdDataView.getUint32(12, false).toString(16)
versions.ENCODER_LD_2 = decoder.decode(encoderLdData.subarray(16, 16 + 8))
versions.ENCODER_LD_2_CHECKSUM = encoderLdDataView.getUint32(24, false).toString(16)
}

const encoderAp2DataLen = encoderAp2Data[2]
if (encoderAp2DataLen === 0x18) {
const encoderAp2DataView = uint8ArrayToDataView(encoderAp2Data)
versions.ENCODER_AP2_1 = decoder.decode(encoderAp2Data.subarray(4, 4 + 8))
versions.ENCODER_AP2_1_CHECKSUM = encoderAp2DataView.getUint32(12, false).toString(16)
versions.ENCODER_AP2_2 = decoder.decode(encoderAp2Data.subarray(16, 16 + 8))
versions.ENCODER_AP2_2_CHECKSUM = encoderAp2DataView.getUint32(24, false).toString(16)
}

return versions
return parseAllFirmwareVersionsHelper({
ap2: ap2Data.slice(2),
encoderAp2: encoderAp2Data.slice(2),
encoderLd: encoderLdData.slice(2),
})
}

public async getSerialNumber(): Promise<string> {
Expand Down

0 comments on commit 4e2e5df

Please sign in to comment.