"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.GetHardwareService = exports.GpioBoard = exports.HwOutput = exports.HwInput = void 0;
const child_process_1 = require("child_process");
const os = require("os");
const onoff_1 = require("onoff");
const events_1 = require("events");
class HwInput extends events_1.EventEmitter {
    constructor(pin) {
        super();
        this.pin = pin;
        this.gpio = new onoff_1.Gpio(pin, 'in', 'both');
        this.gpio.watch((err, value) => {
            if (!err) {
                this.set(value);
            }
        });
        //setInterval(() => this.gpio.read((_err, value) => this.set(value)), 100)
        this.gpio.read((_err, value) => this.set(value));
    }
    set(value) {
        const b = value === 1;
        if (this.value !== b) {
            this.value = b;
            this.emit('change', this.value);
        }
    }
    getValue() {
        return this.value || false;
    }
    getPin() {
        return this.pin;
    }
}
exports.HwInput = HwInput;
class HwOutput extends events_1.EventEmitter {
    constructor(pin) {
        super();
        this.test = false;
        this.pin = pin;
        this.gpio = new onoff_1.Gpio(pin, 'out', 'both');
        this.gpio.watch((err, value) => {
            if (!err) {
                this.set(value);
            }
        });
        //setInterval(() => this.gpio.read((_err, value) => this.set(value)), 100)
        this.gpio.read((_err, value) => this.set(value));
    }
    set(value) {
        const b = value === 1;
        if (this.value !== b) {
            this.value = b;
            this.emit('change', this.getValue());
        }
    }
    setValue(value) {
        return this.gpio.write(value ? 1 : 0).then(() => {
            this.set(value ? 1 : 0);
        }, err => console.log(err));
    }
    setTest(value) {
        if (this.test === value)
            return Promise.resolve();
        this.test = value;
        return this.gpio.write(this.getValue() ? 1 : 0).then(() => {
            this.emit('change', this.getValue());
        }, err => console.log(err));
    }
    getValue() {
        return this.test || this.value || false;
    }
    getPin() {
        return this.pin;
    }
}
exports.HwOutput = HwOutput;
class GpioBoard extends events_1.EventEmitter {
    constructor(id, base, count) {
        super();
        this.inputs = [];
        this.outputs = [];
        this.id = id;
        const inputCount = count / 2;
        for (let i = 0; i < inputCount; i++) {
            const item = new HwInput(base + i);
            item.on('change', v => {
                this.emit('change', 'in.' + i, v);
            });
            this.inputs.push(item);
        }
        const outputCount = count - inputCount;
        for (let i = 0; i < outputCount; i++) {
            const item = new HwOutput(base + inputCount + i);
            item.on('change', v => {
                this.emit('change', 'out.' + i, v);
            });
            this.outputs.push(item);
        }
    }
}
exports.GpioBoard = GpioBoard;
let hwServiceSingleton = null;
function GetHardwareService() {
    if (hwServiceSingleton === null) {
        hwServiceSingleton = (os.platform() === 'linux') ? new RpiHardwareService() : new EmulatorHardwareService();
    }
    return hwServiceSingleton;
}
exports.GetHardwareService = GetHardwareService;
const GPIO_RUN_LED = 7;
class RpiHardwareService {
    constructor() {
        this.boardList = [];
        const runLedGpioNo = parseInt((0, child_process_1.execSync)('cat /sys/kernel/debug/gpio | grep GPIO' + GPIO_RUN_LED + ' | sed \'s/gpio-//\' | awk \'{print $1 }\'', { encoding: 'utf8' }));
        this.runLed = new HwOutput(runLedGpioNo);
    }
    GetGpioBoards() {
        if (this.boardList.length === 0) {
            // cache boards (boards don't change during run)
            const reGpioChips = /gpiochip\d+/;
            const reAddress = /i2c-\d\/\d-00(2[0-7])$/m;
            const boardIds = (0, child_process_1.execSync)('ls -1 /sys/class/gpio', { encoding: 'utf8' }).split('\n').filter(v => reGpioChips.test(v));
            for (const id of boardIds) {
                const label = (0, child_process_1.execSync)(`cat /sys/class/gpio/${id}/label`, { encoding: 'utf8' }).trim();
                if (label === 'mcp23017') {
                    const device = (0, child_process_1.execSync)(`readlink -f /sys/class/gpio/${id}/device`, { encoding: 'utf8' }).trim();
                    const addressMatch = reAddress.exec(device);
                    if (addressMatch) {
                        const address = parseInt(addressMatch[1], 16);
                        const index = address - 0x20;
                        const base = parseInt((0, child_process_1.execSync)(`cat /sys/class/gpio/${id}/base`, { encoding: 'utf8' }), 10);
                        const count = parseInt((0, child_process_1.execSync)(`cat /sys/class/gpio/${id}/ngpio`, { encoding: 'utf8' }), 10);
                        this.boardList.push(new GpioBoard(index, base, count));
                    }
                }
            }
        }
        this.boardList = this.boardList.sort((a, b) => a.id === b.id ? 0 : (a.id > b.id ? 1 : -1));
        return this.boardList;
    }
    SetRunLed(v) {
        this.runLed.setValue(v);
    }
    GetTemperature() {
        const value = parseFloat((0, child_process_1.execSync)('vcgencmd measure_temp', { encoding: 'utf8' }));
        return value;
    }
}
class EmulatorHardwareService {
    constructor() {
        this.boardList = [];
    }
    GetGpioBoards() {
        return this.boardList;
    }
    SetRunLed(v) {
        console.log(`Setting run LED to ${v ? '1' : '0'}`);
    }
    GetTemperature() {
        return 40.2;
    }
}
//# sourceMappingURL=HardwareService.js.map