diff --git a/index.js b/index.js index 964254a..ca62207 100644 --- a/index.js +++ b/index.js @@ -2,10 +2,12 @@ Object.defineProperty(exports, "__esModule", { value: true }); const events_1 = require("events"); const fs_1 = require("fs"); +const path = require("path"); /** * Interval of file system polling, in milliseconds. */ const PollingInterval = 100; +const SysfsGPIOPath = "/sys/class/gpio"; const Uint16Max = 65535; function parseUint16(string) { const n = Number.parseInt(string, 10); @@ -78,10 +80,19 @@ class GPIOPort extends events_1.EventEmitter { if (!/^(in|out)$/.test(direction)) { throw new InvalidAccessError(`Must be "in" or "out".`); } + try { + await fs_1.promises.access(path.join(SysfsGPIOPath, `gpio${this.portNumber}`)); + this._exported = true; + } + catch { + this._exported = false; + } try { clearInterval(this._timeout); - await fs_1.promises.writeFile(`/sys/class/gpio/export`, String(this.portNumber)); - await fs_1.promises.writeFile(`/sys/class/gpio/gpio${this.portNumber}/direction`, direction); + if (!this.exported) { + await fs_1.promises.writeFile(path.join(SysfsGPIOPath, "export"), String(this.portNumber)); + } + await fs_1.promises.writeFile(path.join(SysfsGPIOPath, `gpio${this.portNumber}`, "direction"), direction); if (direction === "in") { this._timeout = setInterval(this.read.bind(this), this._pollingInterval); } @@ -95,7 +106,7 @@ class GPIOPort extends events_1.EventEmitter { async unexport() { clearInterval(this._timeout); try { - await fs_1.promises.writeFile(`/sys/class/gpio/unexport`, String(this.portNumber)); + await fs_1.promises.writeFile(path.join(SysfsGPIOPath, "unexport"), String(this.portNumber)); } catch (error) { throw new OperationError(error); @@ -103,8 +114,11 @@ class GPIOPort extends events_1.EventEmitter { this._exported = false; } async read() { + if (!(this.exported && this.direction === "in")) { + throw new InvalidAccessError(`The exported must be true and value of direction must be "in".`); + } try { - const buffer = await fs_1.promises.readFile(`/sys/class/gpio/gpio${this.portNumber}/value`); + const buffer = await fs_1.promises.readFile(path.join(SysfsGPIOPath, `gpio${this.portNumber}`, "value")); const value = parseUint16(buffer.toString()); if (this._value !== value) { this._value = value; @@ -117,8 +131,11 @@ class GPIOPort extends events_1.EventEmitter { } } async write(value) { + if (!(this.exported && this.direction === "out")) { + throw new InvalidAccessError(`The exported must be true and value of direction must be "out".`); + } try { - await fs_1.promises.writeFile(`/sys/class/gpio/gpio${this.portNumber}/value`, parseUint16(value.toString()).toString()); + await fs_1.promises.writeFile(path.join(SysfsGPIOPath, `gpio${this.portNumber}`, "value"), parseUint16(value.toString()).toString()); } catch (error) { throw new OperationError(error); diff --git a/index.ts b/index.ts index 3ddf1dc..24bd161 100644 --- a/index.ts +++ b/index.ts @@ -1,11 +1,14 @@ import { EventEmitter } from "events"; import { promises as fs } from "fs"; +import * as path from "path"; /** * Interval of file system polling, in milliseconds. */ const PollingInterval = 100; +const SysfsGPIOPath = "/sys/class/gpio"; + const Uint16Max = 65535; function parseUint16(string: string) { @@ -127,11 +130,23 @@ export class GPIOPort extends EventEmitter { throw new InvalidAccessError(`Must be "in" or "out".`); } + try { + await fs.access(path.join(SysfsGPIOPath, `gpio${this.portNumber}`)); + this._exported = true; + } catch { + this._exported = false; + } + try { clearInterval(this._timeout as any); - await fs.writeFile(`/sys/class/gpio/export`, String(this.portNumber)); + if (!this.exported) { + await fs.writeFile( + path.join(SysfsGPIOPath, "export"), + String(this.portNumber) + ); + } await fs.writeFile( - `/sys/class/gpio/gpio${this.portNumber}/direction`, + path.join(SysfsGPIOPath, `gpio${this.portNumber}`, "direction"), direction ); if (direction === "in") { @@ -152,7 +167,10 @@ export class GPIOPort extends EventEmitter { clearInterval(this._timeout as any); try { - await fs.writeFile(`/sys/class/gpio/unexport`, String(this.portNumber)); + await fs.writeFile( + path.join(SysfsGPIOPath, "unexport"), + String(this.portNumber) + ); } catch (error) { throw new OperationError(error); } @@ -161,9 +179,15 @@ export class GPIOPort extends EventEmitter { } async read() { + if (!(this.exported && this.direction === "in")) { + throw new InvalidAccessError( + `The exported must be true and value of direction must be "in".` + ); + } + try { const buffer = await fs.readFile( - `/sys/class/gpio/gpio${this.portNumber}/value` + path.join(SysfsGPIOPath, `gpio${this.portNumber}`, "value") ); const value = parseUint16(buffer.toString()) as GPIOValue; @@ -180,9 +204,15 @@ export class GPIOPort extends EventEmitter { } async write(value: GPIOValue) { + if (!(this.exported && this.direction === "out")) { + throw new InvalidAccessError( + `The exported must be true and value of direction must be "out".` + ); + } + try { await fs.writeFile( - `/sys/class/gpio/gpio${this.portNumber}/value`, + path.join(SysfsGPIOPath, `gpio${this.portNumber}`, "value"), parseUint16(value.toString()).toString() ); } catch (error) {