diff --git a/examples/index.html b/examples/index.html index 7955aac..67a72f7 100644 --- a/examples/index.html +++ b/examples/index.html @@ -53,6 +53,12 @@ GET_DEF: 0x87, } + const FIELD_TYPE = { + BOOLEAN: 'BOOLEAN', + BITMAP: 'BITMAP', + NUMBER: 'NUMBER', + } + const video = document.querySelector('video') const camSelector = document.querySelector('select') const camControls = document.querySelector('.cam-controls') @@ -93,65 +99,100 @@ console.log(controlDescriptions) const camControlsHTML = await Promise.all(controlDescriptions.map(async ctrl => { - // TODO support controls with multiple fields let currentVal = await fetch(`/get/${ctrl.name}`).then(res => res.json()) console.log('currentVal', ctrl.name, currentVal) - currentVal = Object.values(currentVal)[0] - // console.log(ctrl.fields[0].type) + const fieldControlsHTML = await Promise.all(ctrl.fields.map(async (field, i) => { + // console.log(field) + const fieldVal = currentVal[field.name] + const id = `${ctrl.name}-${field.name}` + + if (ctrl.requests.indexOf(REQUEST.GET_MIN) !== -1) { + try { + const minMax = await fetch(`/range/${ctrl.name}`).then(res => res.json()) + return `
` + } catch (e) { + return '' + } + } else if (field.options) { - if (ctrl.requests.indexOf(REQUEST.GET_MIN) !== -1) { - // range - // console.log('range', ctrl.name) - try { - const minMax = await fetch(`/range/${ctrl.name}`).then(res => res.json()) - return `
` - } catch (e) { + let options = Object.entries(field.options).map(([key, val]) => { + const selected = fieldVal === val ? 'selected' : '' + return `` + }) + return `
` + + } else if (field.type === FIELD_TYPE.BOOLEAN) { + return `
` + } else { return '' } - } else if (ctrl.fields[0].options) { - let options = Object.entries(ctrl.fields[0].options).map(([key, val]) => - ``) - // TODO set selected index - return `
` + })) + return `

${ctrl.name}

${fieldControlsHTML.join('')}
` - } else if (ctrl.fields[0].type === 'Boolean') { - return `
` - } else { - return '' - } })) camControls.innerHTML += camControlsHTML.join('') - document.querySelectorAll('.range.ctrl input').forEach(ctrlEl => { + const listenForFieldControlChanges = (ctrlEl) => { ctrlEl.addEventListener('change', (e) => { console.log(ctrlEl.id, ctrlEl.value) - fetch(`/set/${ctrlEl.id}/${ctrlEl.value}`, { + const [controlId] = ctrlEl.id.split('-') + const values = getSiblingFieldValues(controlId).join() + fetch(`/set/${controlId}/${values}`, { method: 'POST' }) }) - }) + } + document.querySelectorAll('.range.ctrl input').forEach(listenForFieldControlChanges) + document.querySelectorAll('.select.ctrl select').forEach(listenForFieldControlChanges) + document.querySelectorAll('.bool.ctrl input').forEach(listenForFieldControlChanges) + + // document.querySelectorAll('.range.ctrl input').forEach(ctrlEl => { + // ctrlEl.addEventListener('change', (e) => { + // console.log(ctrlEl.id, ctrlEl.value) + // const [controlId] = ctrlEl.id.split('-') + // const values = getSiblingFieldValues(controlId).join() + // fetch(`/set/${controlId}/${values}`, { + // method: 'POST' + // }) + // }) + // }) + + // document.querySelectorAll('.select.ctrl select').forEach(ctrlEl => { + // ctrlEl.addEventListener('change', (e) => { + // console.log(ctrlEl.id, ctrlEl.value) + // const [controlId] = ctrlEl.id.split('-') + // const values = getSiblingFieldValues(controlId).join() + // fetch(`/set/${controlId}/${values}`, { + // method: 'POST' + // }) + // }) + // }) + + // document.querySelectorAll('.bool.ctrl input').forEach(ctrlEl => { + // ctrlEl.addEventListener('change', (e) => { + // console.log(ctrlEl.checked) + // const [controlId] = ctrlEl.id.split('-') + // const values = getSiblingFieldValues(controlId).join() + // fetch(`/set/${controlId}/${values}`, { + // method: 'POST' + // }) + // }) + // }) - document.querySelectorAll('.select.ctrl select').forEach(ctrlEl => { - ctrlEl.addEventListener('change', (e) => { - console.log(ctrlEl.id, ctrlEl.value) - fetch(`/set/${ctrlEl.id}/${ctrlEl.value}`, { - method: 'POST' - }) - }) - }) + } - document.querySelectorAll('.bool.ctrl input').forEach(ctrlEl => { - ctrlEl.addEventListener('change', (e) => { - console.log(ctrlEl.checked) - fetch(`/set/${ctrlEl.id}/${ctrlEl.checked ? 1 : 0}`, { - method: 'POST' - }) - }) + function getSiblingFieldValues(controlId) { + const controlDiv = document.querySelector(`#${controlId}`) + const values = [] + controlDiv.querySelectorAll('.ctrl').forEach(ctrl => { + const input = ctrl.querySelector('input, select') + if (input.type === 'checkbox') values.push(input.checked ? 1 : 0) + else values.push(input.value) }) - + return values } setup() diff --git a/examples/server.js b/examples/server.js index 34a93e8..fb829d7 100644 --- a/examples/server.js +++ b/examples/server.js @@ -39,11 +39,6 @@ app.get('/range/:control', (req, res) => { app.post('/set/:control/:values', (req, res) => { let values = req.params.values.split(',') - // values = values.map(val => { - // if (val === 'true') return 1 - // else if (val === 'false') return 0 - // else return val - // }) console.log('setting', req.params.control, values) cam.set(req.params.control, ...values).then(vals => { res.send('ok') diff --git a/index.js b/index.js index 0a6f6d2..b84f541 100644 --- a/index.js +++ b/index.js @@ -7,6 +7,7 @@ const { // VS, // VS_DESCRIPTOR_SUBTYPE, BM_REQUEST_TYPE, + FIELD_TYPE, REQUEST, KEY, } = require('./lib/constants') @@ -181,7 +182,7 @@ class UVCControl extends EventEmitter { // NOTE min fixes out of bounds error, but this approach doesn't account for multiple fields... let int = buffer.readIntLE(field.offset, Math.min(buffer.byteLength, field.size)) let result = int - if (field.type === 'Boolean') { + if (field.type === FIELD_TYPE.BOOLEAN) { result = Boolean(int) } const results = { diff --git a/lib/constants.js b/lib/constants.js index 963c43a..a39bc9a 100644 --- a/lib/constants.js +++ b/lib/constants.js @@ -42,6 +42,12 @@ const KEY = { PAL_525_60: 'PAL_525_60', } +const FIELD_TYPE = { + BOOLEAN: 'BOOLEAN', + BITMAP: 'BITMAP', + NUMBER: 'NUMBER', +} + const BM_REQUEST_TYPE = { GET: 0b10100001, SET: 0b00100001, @@ -183,4 +189,5 @@ module.exports = { REQUEST, BM_REQUEST_TYPE, VS_DESCRIPTOR_SUBTYPE, + FIELD_TYPE, } diff --git a/lib/controls.js b/lib/controls.js index 7f49df4..dfc0f5b 100644 --- a/lib/controls.js +++ b/lib/controls.js @@ -2,6 +2,7 @@ // http://www.usb.org/developers/docs/devclass_docs/ const { + FIELD_TYPE, REQUEST, PU, CT, @@ -27,7 +28,7 @@ const CONTROLS = { // description: 'The setting for the Still Image Trigger Control', // offset: 0, // size: 1, - // type: 'Number', + // type: FIELD_TYPE.NUMBER, // options: { // NORMAL: 0, // TRANSMIT: 1, @@ -57,7 +58,7 @@ const CONTROLS = { description: 'The setting for the attribute of the addressed Auto-Exposure Mode Control', offset: 0, size: 1, - type: 'Bitmap', + type: FIELD_TYPE.BITMAP, options: { MANUAL: 0b00000001, AUTO: 0b00000010, @@ -80,7 +81,7 @@ const CONTROLS = { fields: [{ name: 'bAutoExposurePriority', description: 'The setting for the attribute of the addressed AutoExposure Priority control.', - type: 'Number', + type: FIELD_TYPE.NUMBER, offset: 0, size: 1, }] @@ -102,7 +103,7 @@ const CONTROLS = { fields: [{ name: 'dwExposureTimeAbsolute', description: 'The setting for the attribute of the addressed Exposure Time (Absolute) Control. 0: Reserved, 1: 0.0001 sec, 100000: 10 sec', - type: 'Number', + type: FIELD_TYPE.NUMBER, offset: 0, size: 4, }] @@ -123,7 +124,7 @@ const CONTROLS = { fields: [{ name: 'wFocusAbsolute', description: 'The setting for the attribute of the addressed Focus (Absolute) Control.', - type: 'Number', + type: FIELD_TYPE.NUMBER, offset: 0, size: 2, }], @@ -147,7 +148,7 @@ const CONTROLS = { fields: [{ name: 'wObjectiveFocalLength', description: 'The value of Zcur(see section 2.4.2.5.1 "Optical Zoom".)', - type: 'Number', + type: FIELD_TYPE.NUMBER, offset: 0, size: 2, }], @@ -171,13 +172,13 @@ const CONTROLS = { fields: [{ name: 'dwPanAbsolute', description: 'The setting for the attribute of the addressed Pan (Absolute) Control.', - type: 'Number', // Signed Number + type: FIELD_TYPE.NUMBER, // Signed Number offset: 0, size: 4, }, { name: 'dwTiltAbsolute', description: 'The setting for the attribute of the addressed Tilt (Absolute) Control.', - type: 'Number', // Signed Number + type: FIELD_TYPE.NUMBER, // Signed Number offset: 4, size: 4, }], @@ -196,7 +197,7 @@ const CONTROLS = { fields: [{ name: 'bFocusAuto', description: 'The setting for the attribute of the addressed Focus Auto control.', - type: 'Boolean', + type: FIELD_TYPE.BOOLEAN, offset: 0, size: 1, }], @@ -215,7 +216,7 @@ const CONTROLS = { fields: [{ name: 'bScanningMode', description: 'The setting for the attribute of the addressed Scanning Mode Control', - type: 'Boolean', + type: FIELD_TYPE.BOOLEAN, offset: 0, size: 1, options: { @@ -237,7 +238,7 @@ const CONTROLS = { fields: [{ name: 'bExposureTimeRelative', description: 'The setting for the attribute of the addressed Exposure Time (Relative) Control', - type: 'Number', // Signed Number + type: FIELD_TYPE.NUMBER, // Signed Number offset: 0, size: 1, options: { @@ -264,7 +265,7 @@ const CONTROLS = { fields: [{ name: 'bFocusRelative', description: 'The setting for the attribute of the addressed Focus (Relative) Control', - type: 'Number', // Signed Number + type: FIELD_TYPE.NUMBER, // Signed Number offset: 0, size: 1, options: { @@ -275,7 +276,7 @@ const CONTROLS = { }, { name: 'bSpeed', description: 'Speed for the control change', - type: 'Number', + type: FIELD_TYPE.NUMBER, offset: 1, size: 1, }], @@ -301,7 +302,7 @@ const CONTROLS = { description: 'The setting for the attribute of the addressed Iris (Absolute) Control.', offset: 0, size: 2, - type: 'Number', + type: FIELD_TYPE.NUMBER, }], }, [KEY.relative_iris]: { @@ -317,7 +318,7 @@ const CONTROLS = { fields: [{ name: 'bIrisRelative', description: 'The setting for the attribute of the addressed Iris (Relative) Control', - type: 'Number', + type: FIELD_TYPE.NUMBER, offset: 0, size: 1, options: { @@ -344,7 +345,7 @@ const CONTROLS = { fields: [{ name: 'bZoom', description: 'The setting for the attribute of the addressed Zoom Control', - type: 'Number', // Signed number + type: FIELD_TYPE.NUMBER, // Signed number offset: 0, size: 1, options: { @@ -357,7 +358,7 @@ const CONTROLS = { name: 'bDigitalZoom', offset: 1, size: 1, - type: 'Boolean', + type: FIELD_TYPE.BOOLEAN, options: { OFF: 0, ON: 1, @@ -365,7 +366,7 @@ const CONTROLS = { }, { name: 'bSpeed', description: 'Speed for the control change', - type: 'Number', + type: FIELD_TYPE.NUMBER, offset: 2, size: 1, } @@ -388,7 +389,7 @@ const CONTROLS = { fields: [{ name: 'bPanRelative', description: 'The setting for the attribute of the addressed Pan(Relative) Control', - type: 'Number', // Signed Number + type: FIELD_TYPE.NUMBER, // Signed Number offset: 0, size: 1, options: { @@ -399,7 +400,7 @@ const CONTROLS = { }, { name: 'bPanSpeed', description: 'Speed of the Pan movement', - type: 'Number', + type: FIELD_TYPE.NUMBER, offset: 1, size: 1, }, { @@ -407,7 +408,7 @@ const CONTROLS = { description: 'The setting for the attribute of the addressed Tilt(Relative) Control', offset: 2, size: 1, - type: 'Number', // Signed Number + type: FIELD_TYPE.NUMBER, // Signed Number options: { STOP: 0, UP: 1, @@ -416,7 +417,7 @@ const CONTROLS = { }, { name: 'bTiltSpeed', description: 'Speed for the Tilt movement', - type: 'Number', + type: FIELD_TYPE.NUMBER, offset: 3, size: 1, }], @@ -440,7 +441,7 @@ const CONTROLS = { fields: [{ name: 'wRollAbsolute', description: 'The setting for the attribute of the addressed Roll (Absolute) Control.', - type: 'Number', // Signed Number + type: FIELD_TYPE.NUMBER, // Signed Number offset: 0, size: 2, }], @@ -462,7 +463,7 @@ const CONTROLS = { fields: [{ name: 'bRollRelative', description: 'The setting for the attribute of the addressed Roll (Relative) Control', - type: 'Number', // Signed Number + type: FIELD_TYPE.NUMBER, // Signed Number offset: 0, size: 1, options: { @@ -475,7 +476,7 @@ const CONTROLS = { description: 'Speed for the Roll movement', offset: 1, size: 1, - type: 'Number', + type: FIELD_TYPE.NUMBER, }], }, [KEY.privacy]: { @@ -493,7 +494,7 @@ const CONTROLS = { fields: [{ name: 'bPrivacy', description: 'The setting for the attribute of the addressed Privacy Control', - type: 'Boolean', + type: FIELD_TYPE.BOOLEAN, offset: 0, size: 1, options: { @@ -520,7 +521,7 @@ const CONTROLS = { fields: [{ name: 'bPowerLineFrequency', description: 'The setting for the attribute of the addressed Power Line Frequency control.', - type: 'Number', + type: FIELD_TYPE.NUMBER, offset: 0, size: 1, options: { @@ -549,7 +550,7 @@ const CONTROLS = { fields: [{ name: 'wHue', description: 'The setting for the attribute of the addressed Hue control.', - type: 'Number', // Signed Number + type: FIELD_TYPE.NUMBER, // Signed Number offset: 0, size: 2, }], @@ -573,13 +574,13 @@ const CONTROLS = { fields: [{ name: 'wWhiteBalanceBlue', description: 'The setting for the blue component of the addressed White Balance Component control.', - type: 'Number', + type: FIELD_TYPE.NUMBER, offset: 0, size: 2, }, { name: 'wWhiteBalanceRed', description: 'The setting for the red component of the addressed White Balance Component control.', - type: 'Number', + type: FIELD_TYPE.NUMBER, offset: 1, size: 2, }], @@ -598,7 +599,7 @@ const CONTROLS = { fields: [{ name: 'bWhiteBalanceComponentAuto', description: 'The setting for the attribute of the addressed White Balance Component, Auto control.', - type: 'Number', + type: FIELD_TYPE.NUMBER, offset: 0, size: 1, }], @@ -620,7 +621,7 @@ const CONTROLS = { fields: [{ name: 'wMultiplierStep', description: 'The value Z′cur (see section 2.4.2.5.2 "Digital Zoom".)', - type: 'Number', + type: FIELD_TYPE.NUMBER, offset: 0, size: 2, }], @@ -642,7 +643,7 @@ const CONTROLS = { fields: [{ name: 'wMultiplierLimit', description: 'A value specifying the upper bound for Z′cur (see section 2.4.2.5.2 "Digital Zoom".)', - type: 'Number', + type: FIELD_TYPE.NUMBER, offset: 0, size: 2, }], @@ -661,7 +662,7 @@ const CONTROLS = { fields: [{ name: 'bHueAuto', description: 'The setting for the attribute of the addressed Hue, Auto control.', - type: 'Number', + type: FIELD_TYPE.NUMBER, offset: 0, size: 1, }], @@ -678,7 +679,7 @@ const CONTROLS = { fields: [{ name: 'bVideoStandard', description: 'The Analog Video Standard of the input video signal.', - type: 'Number', + type: FIELD_TYPE.NUMBER, offset: 0, size: 1, options: { @@ -703,7 +704,7 @@ const CONTROLS = { fields: [{ name: 'bStatus', description: 'Lock status', - type: 'Number', + type: FIELD_TYPE.NUMBER, offset: 0, size: 1, options: { @@ -729,7 +730,7 @@ const CONTROLS = { fields: [{ name: 'wBrightness', description: 'The setting for the attribute of the addressed Brightness control.', - type: 'Number', // Signed Number + type: FIELD_TYPE.NUMBER, // Signed Number offset: 0, size: 2, }], @@ -751,7 +752,7 @@ const CONTROLS = { fields: [{ name: 'wContrast', description: 'The setting for the attribute of the addressed Contrast control.', - type: 'Number', + type: FIELD_TYPE.NUMBER, offset: 0, size: 2, }], @@ -773,7 +774,7 @@ const CONTROLS = { fields: [{ name: 'wGain', description: 'The setting for the attribute of the addressed Gain control.', - type: 'Number', + type: FIELD_TYPE.NUMBER, offset: 0, size: 2, }], @@ -795,7 +796,7 @@ const CONTROLS = { fields: [{ name: 'wSaturation', description: 'The setting for the attribute of the addressed Saturation control.', - type: 'Number', + type: FIELD_TYPE.NUMBER, offset: 0, size: 2, }], @@ -817,7 +818,7 @@ const CONTROLS = { fields: [{ name: 'wSharpness', description: 'The setting for the attribute of the addressed Sharpness control.', - type: 'Number', + type: FIELD_TYPE.NUMBER, offset: 0, size: 2, }], @@ -841,7 +842,7 @@ const CONTROLS = { fields: [{ name: 'wWhiteBalanceTemperature', description: 'The setting for the attribute of the addressed White Balance Temperature control.', - type: 'Number', + type: FIELD_TYPE.NUMBER, offset: 0, size: 2, }], @@ -863,7 +864,7 @@ const CONTROLS = { fields: [{ name: 'wBacklightCompensation', description: 'The setting for the attribute of the addressed Backlight Compensation control.', - type: 'Number', + type: FIELD_TYPE.NUMBER, offset: 0, size: 2, }], @@ -885,7 +886,7 @@ const CONTROLS = { fields: [{ name: 'wGain', description: 'The setting for the attribute of the addressed Gain control.', - type: 'Number', + type: FIELD_TYPE.NUMBER, offset: 0, size: 2, }], @@ -904,7 +905,7 @@ const CONTROLS = { fields: [{ name: 'bWhiteBalanceTemperatureAuto', description: 'The setting for the attribute of the addressed White Balance Temperature, Auto control.', - type: 'Number', + type: FIELD_TYPE.BOOLEAN, offset: 0, size: 1, }], @@ -926,7 +927,7 @@ const CONTROLS = { fields: [{ name: 'wGamma', description: 'The setting for the attribute of the addressed Gamma control.', - type: 'Number', + type: FIELD_TYPE.NUMBER, offset: 0, size: 2, }],