Files
dualshock-tools.github.io/js/controllers/base-controller.js
2025-09-20 17:01:11 +02:00

142 lines
3.6 KiB
JavaScript

'use strict';
/**
* Base Controller class that provides common functionality for all controller types
*/
class BaseController {
constructor(device, uiDependencies = {}) {
this.device = device;
this.model = "undefined"; // to be set by subclasses
this.finetuneMaxValue; // to be set by subclasses
// UI dependencies injected from core
this.l = uiDependencies.l;
}
getModel() {
return this.model;
}
/**
* Get the underlying HID device
* @returns {HIDDevice} The HID device
*/
getDevice() {
return this.device;
}
getInputConfig() {
throw new Error('getInputConfig() must be implemented by subclass');
}
/**
* Get the maximum value for finetune data
* @returns {number} Maximum value for finetune adjustments
*/
getFinetuneMaxValue() {
if(!this.finetuneMaxValue) throw new Error('getFinetuneMaxValue() must be implemented by subclass');
return this.finetuneMaxValue;
}
/**
* Set input report handler
* @param {Function} handler Input report handler function
*/
setInputReportHandler(handler) {
this.device.oninputreport = handler;
}
/**
* Allocate request buffer with proper size based on device feature reports
* @param {number} id Report ID
* @param {Array} data Data array to include in the request
* @returns {Uint8Array} Allocated request buffer
*/
alloc_req(id, data = []) {
const fr = this.device.collections[0].featureReports;
const report = fr.find(e => e.reportId === id);
const maxLen = report?.reportCount || data.length;
const out = new Uint8Array(data.length);
out.set(data.slice(0, maxLen));
return out;
}
/**
* Send feature report to device
* @param {number} reportId Report ID
* @param {ArrayBuffer|Array} data Data to send (if Array, will be processed through allocReq)
*/
async sendFeatureReport(reportId, data) {
// If data is an array, use allocReq to create proper buffer
if (Array.isArray(data)) {
data = this.alloc_req(reportId, data);
}
return await this.device.sendFeatureReport(reportId, data);
}
/**
* Receive feature report from device
* @param {number} reportId Report ID
*/
async receiveFeatureReport(reportId) {
return await this.device.receiveFeatureReport(reportId);
}
/**
* Close the HID device connection
*/
async close() {
if (this.device && this.device.opened) {
await this.device.close();
}
}
// Abstract methods that must be implemented by subclasses
async getInfo() {
throw new Error('getInfo() must be implemented by subclass');
}
async flash(progressCallback = null) {
throw new Error('flash() must be implemented by subclass');
}
async reset() {
throw new Error('reset() must be implemented by subclass');
}
async nvsLock() {
throw new Error('nvsLock() must be implemented by subclass');
}
async nvsUnlock() {
throw new Error('nvsUnlock() must be implemented by subclass');
}
async calibrateSticksBegin() {
throw new Error('calibrateSticksBegin() must be implemented by subclass');
}
async calibrateSticksEnd() {
throw new Error('calibrateSticksEnd() must be implemented by subclass');
}
async calibrateSticksSample() {
throw new Error('calibrateSticksSample() must be implemented by subclass');
}
async calibrateRangeBegin() {
throw new Error('calibrateRangeBegin() must be implemented by subclass');
}
async calibrateRangeEnd() {
throw new Error('calibrateRangeEnd() must be implemented by subclass');
}
parseBatteryStatus(data) {
throw new Error('parseBatteryStatus() must be implemented by subclass');
}
}
export default BaseController;