Compare commits

..

2 Commits

13 changed files with 227 additions and 95 deletions

View File

@ -1,5 +1,5 @@
{ {
"version": "1.7.22", "version": "1.7.24",
"ext_port": 1111, "ext_port": 1111,
"profiles": { "profiles": {
"mcopy": { "mcopy": {

View File

@ -54,10 +54,13 @@ class Arduino {
async init() { async init() {
const Log = require('log'); const Log = require('log');
this.log = await Log({ label: 'arduino' }); this.log = await Log({ label: 'arduino' });
this.keys = Object.keys(cfg.arduino.cmd);
this.values = this.keys.map(key => cfg.arduino.cmd[key]);
} }
/** /**
* Enumerate all connected devices that might be Arduinos * Enumerate all connected devices that might be Arduinos
* *
* @async
* @returns {Promise} Resolves after enumerating * @returns {Promise} Resolves after enumerating
**/ **/
async enumerate() { async enumerate() {
@ -98,9 +101,10 @@ class Arduino {
/** /**
* Send a command to an Arduino using async/await * Send a command to an Arduino using async/await
* *
* @param {string} device Arduino identifier * @param {string} device The Arduino device identifier
* @param {string} cmd Single character command to send * @param {string} cmd Single character command to send
* *
* @async
* @returns {Promise} Resolves after sending * @returns {Promise} Resolves after sending
**/ **/
async sendAsync(device, cmd) { async sendAsync(device, cmd) {
@ -119,7 +123,15 @@ class Arduino {
}); });
} }
/** /**
* Sends a command to the specified Arduino and waits for a response.
* Handles the communication lock to prevent sending multiple commands simultaneously.
* Emits an 'arduino_send' event after successfully sending the command.
* *
* @async
* @param {string} device - The Arduino device identifier.
* @param {string} cmd - The command to be sent to the Arduino.
* @returns {Promise<boolean|string>} Returns 'false' if the communication is locked, otherwise returns the response from the device.
* @throws {Error} Throws an error if the sendAsync method encounters an error.
**/ **/
async send(device, cmd) { async send(device, cmd) {
const serial = this.alias[device]; const serial = this.alias[device];
@ -143,7 +155,15 @@ class Arduino {
return ms; return ms;
} }
/** /**
* Sends a string to the specified Arduino.
* Handles different types of devices, including fake devices for testing purposes.
* Waits for a specified delay before sending the string.
* *
* @async
* @param {string} device - The Arduino device identifier.
* @param {string} str - The string to be sent to the Arduino.
* @returns {Promise<boolean|string>} Returns 'true' if the string is sent successfully, otherwise returns an error message.
* @throws {Error} Throws an error if the writeAsync method encounters an error.
**/ **/
async sendString(device, str) { async sendString(device, str) {
let writeSuccess; let writeSuccess;
@ -240,7 +260,13 @@ class Arduino {
}); });
} }
/** /**
* Handles the end of communication with the Arduino.
* Calculates the time taken for the communication, executes the callback,
* and emits an 'arduino_end' event. Handles errors and stray data received.
* *
* @param {string} serial - The serial address of the Arduino device.
* @param {string} data - The data received from the Arduino.
* @returns {any} The time taken for the communication in milliseconds.
**/ **/
end(serial, data) { end(serial, data) {
const end = new Date().getTime(); const end = new Date().getTime();
@ -264,19 +290,42 @@ class Arduino {
else if (data[0] === cfg.arduino.cmd.error) { else if (data[0] === cfg.arduino.cmd.error) {
this.log.error(`Received error from device ${serial}`); this.log.error(`Received error from device ${serial}`);
this.unlock(serial); this.unlock(serial);
this.error(serial, data);
//error state //error state
//stop sequence //stop sequence
//throw error in ui //throw error in ui
} }
else { else {
//this.log.info('Received stray "' + data + '"') //silent to user this.log.info('Received stray "' + data + '"'); //silent to user
} }
return ms; return ms;
} }
error(serial, data) {
this.log.error("ERROR", data);
}
/**
* Associates an alias with an Arduinos serial address.
* Used to map multi-purpose devices onto the same serial connection.
*
* @param {string} device - The serial number of the target Arduino.
* @param {string} serial - The alias to be associated with the target device.
**/
aliasSerial(device, serial) { aliasSerial(device, serial) {
//this.log.info(`Making "${serial}" an alias of ${device}`) //this.log.info(`Making "${serial}" an alias of ${device}`)
this.alias[device] = serial; this.alias[device] = serial;
} }
/**
* Connects to an Arduino using its serial number.
* Sets up the SerialPort instance and path for the device, and handles data communication.
* Handles opening the connection and emitting 'arduino_end' or 'confirmEnd' events upon receiving data.
*
* @async
* @param {string} device - The device identifier (common name).
* @param {string} serial - The serial address of the target Arduino (e.g., COM port on Windows).
* @param {function} confirm - A callback function to be executed upon receiving confirmation data.
* @returns {Promise<string>} Resolves with the device path if the connection is successful.
* @throws {Error} Rejects with an error message if the connection fails.
**/
async connect(device, serial, confirm) { async connect(device, serial, confirm) {
//this.log.info(`connect device ${device}`) //this.log.info(`connect device ${device}`)
//this.log.info(`connect serial ${serial}`) //this.log.info(`connect serial ${serial}`)
@ -295,7 +344,7 @@ class Arduino {
connectSuccess = await this.openArduino(device); connectSuccess = await this.openArduino(device);
} }
catch (e) { catch (e) {
this.log.error('failed to open: ' + e); this.log.error(`Failed to open ${device} @ ${serial}: ` + e);
return reject(e); return reject(e);
} }
this.log.info(`Opened connection with ${this.path[device]} as ${device}`); this.log.info(`Opened connection with ${this.path[device]} as ${device}`);
@ -316,30 +365,14 @@ class Arduino {
return resolve(this.path[serial]); return resolve(this.path[serial]);
}); });
} }
/**
* Handles the confirmation data received from an Arduino.
* Executes the confirmation callback function if the received data is present in the list of expected values.
*
* @param {string} data - The data received from the Arduino.
**/
confirmEnd(data) { confirmEnd(data) {
if (data === cfg.arduino.cmd.connect if (this.values.indexOf(data) !== -1) {
|| data === cfg.arduino.cmd.projector_identifier
|| data === cfg.arduino.cmd.camera_identifier
|| data === cfg.arduino.cmd.light_identifier
|| data === cfg.arduino.cmd.projector_light_identifier
|| data === cfg.arduino.cmd.projector_camera_light_identifier
|| data === cfg.arduino.cmd.projector_camera_identifier
|| data === cfg.arduino.cmd.projector_second_identifier
|| data === cfg.arduino.cmd.projectors_identifier
|| data === cfg.arduino.cmd.projector_second_forward
|| data === cfg.arduino.cmd.projector_second_backward
|| data === cfg.arduino.cmd.projector_second
|| data === cfg.arduino.cmd.projectors
|| data === cfg.arduino.cmd.camera_second_identifier
|| data === cfg.arduino.cmd.cameras_identifier
|| data === cfg.arduino.cmd.camera_second_forward
|| data === cfg.arduino.cmd.camera_second_backward
|| data === cfg.arduino.cmd.camera_second
|| data === cfg.arduino.cmd.cameras
|| data === cfg.arduino.cmd.capper_identifier
|| data === cfg.arduino.cmd.camera_capper_identifier
|| data === cfg.arduino.cmd.camera_capper_projector_identifier
|| data === cfg.arduino.cmd.camera_capper_projectors_identifier) {
this.confirmExec(null, data); this.confirmExec(null, data);
this.confirmExec = {}; this.confirmExec = {};
this.unlock(this.alias['connect']); this.unlock(this.alias['connect']);
@ -350,6 +383,14 @@ class Arduino {
this.unlock(this.alias['connect']); this.unlock(this.alias['connect']);
} }
} }
/**
* Verifies the connection to an Arduino by sending a connect command.
* The confirmation callback checks if the received data matches the expected connect command.
*
* @async
* @returns {Promise<boolean>} Resolves with 'true' if the connection is verified successfully.
* @throws {Error} Rejects with an error message if the connection verification fails.
**/
async verify() { async verify() {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
const device = 'connect'; const device = 'connect';
@ -372,6 +413,14 @@ class Arduino {
return resolve(writeSuccess); return resolve(writeSuccess);
}); });
} }
/**
* Distinguishes the type of Arduino connected.
* Sends a command to the device to identify its type and resolves the promise with the received type.
*
* @async
* @returns {Promise<string>} Resolves with the type of the connected Arduino-based device.
* @throws {Error} Rejects with an error message if the distinguish operation fails.
**/
async distinguish() { async distinguish() {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
const device = 'connect'; const device = 'connect';
@ -441,6 +490,13 @@ class Arduino {
} }
}); });
} }
/**
* Closes the connection to an Arduino.
*
* @async
* @returns {Promise<boolean>} Resolves with 'true' if the connection is closed successfully.
* @throws {Error} Throws an error if the closeArduino method encounters an error.
**/
async close() { async close() {
const device = 'connect'; const device = 'connect';
let closeSuccess; let closeSuccess;
@ -452,6 +508,14 @@ class Arduino {
} }
return closeSuccess; return closeSuccess;
} }
/**
* Establishes a fake connection to an Arduino for testing purposes.
* Creates a fake SerialPort instance with custom write and string methods.
*
* @async
* @param {string} serial - The device identifier of the fake Arduino.
* @returns {Promise<boolean>} Resolves with 'true' if the fake connection is established successfully.
**/
async fakeConnect(device) { async fakeConnect(device) {
const serial = '/dev/fake'; const serial = '/dev/fake';
this.aliasSerial(device, serial); this.aliasSerial(device, serial);

File diff suppressed because one or more lines are too long

View File

@ -7,6 +7,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
const path_1 = require("path"); const path_1 = require("path");
const url_1 = require("url"); const url_1 = require("url");
const delay_1 = require("delay"); const delay_1 = require("delay");
const Log = require("log");
const { BrowserWindow } = require('electron'); const { BrowserWindow } = require('electron');
class WebView { class WebView {
constructor(platform, display) { constructor(platform, display) {
@ -31,6 +32,7 @@ class WebView {
pathname: pagePath, pathname: pagePath,
protocol: 'file:' protocol: 'file:'
}); });
this.init();
if (!display.primary) { if (!display.primary) {
prefs.x = display.x + 50; prefs.x = display.x + 50;
prefs.y = display.y + 50; prefs.y = display.y + 50;
@ -51,6 +53,9 @@ class WebView {
this.ipc = require('electron').ipcMain; this.ipc = require('electron').ipcMain;
this.ipc.on('display_load', this.onLoad.bind(this)); this.ipc.on('display_load', this.onLoad.bind(this));
} }
async init() {
this.log = await Log({ label: 'devices' });
}
async open() { async open() {
this.digitalWindow.show(); this.digitalWindow.show();
this.showing = true; this.showing = true;
@ -64,14 +69,14 @@ class WebView {
async show(src) { async show(src) {
const normalSrc = path_1.normalize(path_1.join(src)); const normalSrc = path_1.normalize(path_1.join(src));
if (!this.digitalWindow) { if (!this.digitalWindow) {
console.warn(`Cannot show "${src}" because window does not exist`); this.log.warn(`Cannot show "${src}" because window does not exist`);
return false; return false;
} }
try { try {
this.digitalWindow.webContents.send('display', { src: normalSrc }); this.digitalWindow.webContents.send('display', { src: normalSrc });
} }
catch (err) { catch (err) {
console.error(err); this.log.error(err);
} }
this.showing = true; this.showing = true;
return new Promise(function (resolve) { return new Promise(function (resolve) {
@ -86,7 +91,7 @@ class WebView {
} }
async focus() { async focus() {
if (!this.digitalWindow) { if (!this.digitalWindow) {
console.warn(`Cannot show focus screen because window does not exist`); this.log.warn(`Cannot show focus screen because window does not exist`);
return false; return false;
} }
await delay_1.delay(500); await delay_1.delay(500);
@ -94,12 +99,12 @@ class WebView {
this.digitalWindow.webContents.send('focus', { focus: true }); this.digitalWindow.webContents.send('focus', { focus: true });
} }
catch (err) { catch (err) {
console.error(err); this.log.error(err);
} }
} }
async field(ratio) { async field(ratio) {
if (!this.digitalWindow) { if (!this.digitalWindow) {
console.warn(`Cannot show field guide because window does not exist`); this.log.warn(`Cannot show field guide because window does not exist`);
return false; return false;
} }
await delay_1.delay(500); await delay_1.delay(500);
@ -107,12 +112,12 @@ class WebView {
this.digitalWindow.webContents.send('field', { field: true, ratio }); this.digitalWindow.webContents.send('field', { field: true, ratio });
} }
catch (err) { catch (err) {
console.error(err); this.log.error(err);
} }
} }
async meter() { async meter() {
if (!this.digitalWindow) { if (!this.digitalWindow) {
console.warn(`Cannot show meter screen because window does not exist`); this.log.warn(`Cannot show meter screen because window does not exist`);
return false; return false;
} }
await delay_1.delay(500); await delay_1.delay(500);
@ -120,7 +125,7 @@ class WebView {
this.digitalWindow.webContents.send('meter', { meter: true }); this.digitalWindow.webContents.send('meter', { meter: true });
} }
catch (err) { catch (err) {
console.error(err); this.log.error(err);
} }
} }
hide() { hide() {

File diff suppressed because one or more lines are too long

2
app/package-lock.json generated
View File

@ -1,6 +1,6 @@
{ {
"name": "mcopy-app", "name": "mcopy-app",
"version": "1.7.22", "version": "1.7.24",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {

View File

@ -1,6 +1,6 @@
{ {
"name": "mcopy-app", "name": "mcopy-app",
"version": "1.7.22", "version": "1.7.24",
"description": "GUI for the mcopy small gauge film optical printer platform", "description": "GUI for the mcopy small gauge film optical printer platform",
"main": "main.js", "main": "main.js",
"scripts": { "scripts": {

View File

@ -1,5 +1,5 @@
{ {
"version": "1.7.22", "version": "1.7.24",
"ext_port": 1111, "ext_port": 1111,
"profiles": { "profiles": {
"mcopy": { "mcopy": {

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{ {
"name": "mcopy", "name": "mcopy",
"version": "1.7.22", "version": "1.7.24",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "mcopy", "name": "mcopy",
"version": "1.7.22", "version": "1.7.24",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"arduino": "file:app/lib/arduino", "arduino": "file:app/lib/arduino",

View File

@ -1,6 +1,6 @@
{ {
"name": "mcopy", "name": "mcopy",
"version": "1.7.22", "version": "1.7.24",
"description": "Small gauge film optical printer platform", "description": "Small gauge film optical printer platform",
"main": "build.js", "main": "build.js",
"directories": { "directories": {

View File

@ -1,5 +1,5 @@
{ {
"version": "1.7.22", "version": "1.7.24",
"ext_port": 1111, "ext_port": 1111,
"profiles": { "profiles": {
"mcopy": { "mcopy": {

View File

@ -57,6 +57,8 @@ class Arduino {
private locks : any = {}; private locks : any = {};
private confirmExec : any; private confirmExec : any;
private errorState : Function; private errorState : Function;
private keys : string[];
private values : string[];
public stateStr : any = {}; public stateStr : any = {};
@ -68,11 +70,14 @@ class Arduino {
async init () { async init () {
const Log = require('log'); const Log = require('log');
this.log = await Log({ label : 'arduino' }); this.log = await Log({ label : 'arduino' });
this.keys = Object.keys(cfg.arduino.cmd);
this.values = this.keys.map(key => cfg.arduino.cmd[key]);
} }
/** /**
* Enumerate all connected devices that might be Arduinos * Enumerate all connected devices that might be Arduinos
* *
* @async
* @returns {Promise} Resolves after enumerating * @returns {Promise} Resolves after enumerating
**/ **/
public async enumerate () : Promise<string[]>{ public async enumerate () : Promise<string[]>{
@ -108,9 +113,10 @@ class Arduino {
/** /**
* Send a command to an Arduino using async/await * Send a command to an Arduino using async/await
* *
* @param {string} device Arduino identifier * @param {string} device The Arduino device identifier
* @param {string} cmd Single character command to send * @param {string} cmd Single character command to send
* *
* @async
* @returns {Promise} Resolves after sending * @returns {Promise} Resolves after sending
**/ **/
private async sendAsync (device : string, cmd : string) : Promise<number> { private async sendAsync (device : string, cmd : string) : Promise<number> {
@ -130,7 +136,15 @@ class Arduino {
} }
/** /**
* Sends a command to the specified Arduino and waits for a response.
* Handles the communication lock to prevent sending multiple commands simultaneously.
* Emits an 'arduino_send' event after successfully sending the command.
* *
* @async
* @param {string} device - The Arduino device identifier.
* @param {string} cmd - The command to be sent to the Arduino.
* @returns {Promise<boolean|string>} Returns 'false' if the communication is locked, otherwise returns the response from the device.
* @throws {Error} Throws an error if the sendAsync method encounters an error.
**/ **/
public async send (device : string, cmd : string) : Promise<any> { public async send (device : string, cmd : string) : Promise<any> {
const serial : any = this.alias[device] const serial : any = this.alias[device]
@ -155,7 +169,15 @@ class Arduino {
} }
/** /**
* Sends a string to the specified Arduino.
* Handles different types of devices, including fake devices for testing purposes.
* Waits for a specified delay before sending the string.
* *
* @async
* @param {string} device - The Arduino device identifier.
* @param {string} str - The string to be sent to the Arduino.
* @returns {Promise<boolean|string>} Returns 'true' if the string is sent successfully, otherwise returns an error message.
* @throws {Error} Throws an error if the writeAsync method encounters an error.
**/ **/
public async sendString (device : string, str : string) : Promise<any> { public async sendString (device : string, str : string) : Promise<any> {
let writeSuccess : any let writeSuccess : any
@ -257,7 +279,13 @@ class Arduino {
} }
/** /**
* Handles the end of communication with the Arduino.
* Calculates the time taken for the communication, executes the callback,
* and emits an 'arduino_end' event. Handles errors and stray data received.
* *
* @param {string} serial - The serial address of the Arduino device.
* @param {string} data - The data received from the Arduino.
* @returns {any} The time taken for the communication in milliseconds.
**/ **/
private end (serial : string, data : string) : any { private end (serial : string, data : string) : any {
const end : number = new Date().getTime() const end : number = new Date().getTime()
@ -279,20 +307,42 @@ class Arduino {
} else if (data[0] === cfg.arduino.cmd.error) { } else if (data[0] === cfg.arduino.cmd.error) {
this.log.error(`Received error from device ${serial}`) this.log.error(`Received error from device ${serial}`)
this.unlock(serial) this.unlock(serial)
this.error(serial, data)
//error state //error state
//stop sequence //stop sequence
//throw error in ui //throw error in ui
} else { } else {
//this.log.info('Received stray "' + data + '"') //silent to user this.log.info('Received stray "' + data + '"') //silent to user
} }
return ms return ms
} }
private error(serial : string, data : string) {
this.log.error("ERROR", data)
}
/**
* Associates an alias with an Arduinos serial address.
* Used to map multi-purpose devices onto the same serial connection.
*
* @param {string} device - The serial number of the target Arduino.
* @param {string} serial - The alias to be associated with the target device.
**/
public aliasSerial (device : string, serial : string) { public aliasSerial (device : string, serial : string) {
//this.log.info(`Making "${serial}" an alias of ${device}`) //this.log.info(`Making "${serial}" an alias of ${device}`)
this.alias[device] = serial; this.alias[device] = serial;
} }
/**
* Connects to an Arduino using its serial number.
* Sets up the SerialPort instance and path for the device, and handles data communication.
* Handles opening the connection and emitting 'arduino_end' or 'confirmEnd' events upon receiving data.
*
* @async
* @param {string} device - The device identifier (common name).
* @param {string} serial - The serial address of the target Arduino (e.g., COM port on Windows).
* @param {function} confirm - A callback function to be executed upon receiving confirmation data.
* @returns {Promise<string>} Resolves with the device path if the connection is successful.
* @throws {Error} Rejects with an error message if the connection fails.
**/
public async connect (device : string, serial : string, confirm : any) : Promise<any> { public async connect (device : string, serial : string, confirm : any) : Promise<any> {
//this.log.info(`connect device ${device}`) //this.log.info(`connect device ${device}`)
//this.log.info(`connect serial ${serial}`) //this.log.info(`connect serial ${serial}`)
@ -310,7 +360,7 @@ class Arduino {
try { try {
connectSuccess = await this.openArduino(device) connectSuccess = await this.openArduino(device)
} catch (e) { } catch (e) {
this.log.error('failed to open: ' + e) this.log.error(`Failed to open ${device} @ ${serial}: ` + e)
return reject(e) return reject(e)
} }
this.log.info(`Opened connection with ${this.path[device]} as ${device}`) this.log.info(`Opened connection with ${this.path[device]} as ${device}`)
@ -331,35 +381,14 @@ class Arduino {
return resolve(this.path[serial]) return resolve(this.path[serial])
}) })
} }
/**
* Handles the confirmation data received from an Arduino.
* Executes the confirmation callback function if the received data is present in the list of expected values.
*
* @param {string} data - The data received from the Arduino.
**/
private confirmEnd (data : string) { private confirmEnd (data : string) {
if ( data === cfg.arduino.cmd.connect if (this.values.indexOf(data) !== -1) {
|| data === cfg.arduino.cmd.projector_identifier
|| data === cfg.arduino.cmd.camera_identifier
|| data === cfg.arduino.cmd.light_identifier
|| data === cfg.arduino.cmd.projector_light_identifier
|| data === cfg.arduino.cmd.projector_camera_light_identifier
|| data === cfg.arduino.cmd.projector_camera_identifier
|| data === cfg.arduino.cmd.projector_second_identifier
|| data === cfg.arduino.cmd.projectors_identifier
|| data === cfg.arduino.cmd.projector_second_forward
|| data === cfg.arduino.cmd.projector_second_backward
|| data === cfg.arduino.cmd.projector_second
|| data === cfg.arduino.cmd.projectors
|| data === cfg.arduino.cmd.camera_second_identifier
|| data === cfg.arduino.cmd.cameras_identifier
|| data === cfg.arduino.cmd.camera_second_forward
|| data === cfg.arduino.cmd.camera_second_backward
|| data === cfg.arduino.cmd.camera_second
|| data === cfg.arduino.cmd.cameras
|| data === cfg.arduino.cmd.capper_identifier
|| data === cfg.arduino.cmd.camera_capper_identifier
|| data === cfg.arduino.cmd.camera_capper_projector_identifier
|| data === cfg.arduino.cmd.camera_capper_projectors_identifier) {
this.confirmExec(null, data) this.confirmExec(null, data)
this.confirmExec = {} this.confirmExec = {}
this.unlock(this.alias['connect']) this.unlock(this.alias['connect'])
@ -369,7 +398,14 @@ class Arduino {
this.unlock(this.alias['connect']) this.unlock(this.alias['connect'])
} }
} }
/**
* Verifies the connection to an Arduino by sending a connect command.
* The confirmation callback checks if the received data matches the expected connect command.
*
* @async
* @returns {Promise<boolean>} Resolves with 'true' if the connection is verified successfully.
* @throws {Error} Rejects with an error message if the connection verification fails.
**/
public async verify () { public async verify () {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
const device : string = 'connect' const device : string = 'connect'
@ -392,8 +428,15 @@ class Arduino {
return resolve(writeSuccess) return resolve(writeSuccess)
}) })
} }
/**
public async distinguish () { * Distinguishes the type of Arduino connected.
* Sends a command to the device to identify its type and resolves the promise with the received type.
*
* @async
* @returns {Promise<string>} Resolves with the type of the connected Arduino-based device.
* @throws {Error} Rejects with an error message if the distinguish operation fails.
**/
public async distinguish () : Promise<string> {
return new Promise(async (resolve, reject) => { return new Promise(async (resolve, reject) => {
const device : string = 'connect' const device : string = 'connect'
let writeSuccess : any let writeSuccess : any
@ -447,8 +490,14 @@ class Arduino {
} }
}) })
} }
/**
public async close () { * Closes the connection to an Arduino.
*
* @async
* @returns {Promise<boolean>} Resolves with 'true' if the connection is closed successfully.
* @throws {Error} Throws an error if the closeArduino method encounters an error.
**/
public async close () : Promise<boolean> {
const device : string = 'connect' const device : string = 'connect'
let closeSuccess : boolean let closeSuccess : boolean
try { try {
@ -458,7 +507,14 @@ class Arduino {
} }
return closeSuccess return closeSuccess
} }
/**
* Establishes a fake connection to an Arduino for testing purposes.
* Creates a fake SerialPort instance with custom write and string methods.
*
* @async
* @param {string} serial - The device identifier of the fake Arduino.
* @returns {Promise<boolean>} Resolves with 'true' if the fake connection is established successfully.
**/
public async fakeConnect (device : string) { public async fakeConnect (device : string) {
const serial : string = '/dev/fake' const serial : string = '/dev/fake'
this.aliasSerial(device, serial) this.aliasSerial(device, serial)

View File

@ -8,6 +8,7 @@
import { join as pathJoin, normalize as pathNormalize } from 'path'; import { join as pathJoin, normalize as pathNormalize } from 'path';
import { format as urlFormat } from 'url'; import { format as urlFormat } from 'url';
import { delay } from 'delay'; import { delay } from 'delay';
import Log = require('log');
const { BrowserWindow } = require('electron'); const { BrowserWindow } = require('electron');
@ -19,6 +20,7 @@ class WebView {
public display : any; public display : any;
private loadWait : any = {}; private loadWait : any = {};
private ipc : any; private ipc : any;
private log : any;
constructor (platform : string, display : any) { constructor (platform : string, display : any) {
const prefs : any = { const prefs : any = {
@ -39,6 +41,8 @@ class WebView {
pathname : pagePath, pathname : pagePath,
protocol : 'file:' protocol : 'file:'
}); });
this.init();
if (!display.primary) { if (!display.primary) {
prefs.x = display.x + 50; prefs.x = display.x + 50;
prefs.y = display.y + 50; prefs.y = display.y + 50;
@ -61,6 +65,9 @@ class WebView {
this.ipc.on('display_load', this.onLoad.bind(this)); this.ipc.on('display_load', this.onLoad.bind(this));
} }
async init () {
this.log = await Log({ label : 'devices' })
}
async open () { async open () {
this.digitalWindow.show(); this.digitalWindow.show();
this.showing = true; this.showing = true;
@ -74,13 +81,13 @@ class WebView {
async show (src : string) { async show (src : string) {
const normalSrc : string = pathNormalize(pathJoin(src)); const normalSrc : string = pathNormalize(pathJoin(src));
if (!this.digitalWindow) { if (!this.digitalWindow) {
console.warn(`Cannot show "${src}" because window does not exist`); this.log.warn(`Cannot show "${src}" because window does not exist`)
return false; return false;
} }
try { try {
this.digitalWindow.webContents.send('display', { src : normalSrc }); this.digitalWindow.webContents.send('display', { src : normalSrc });
} catch (err) { } catch (err) {
console.error(err); this.log.error(err);
} }
this.showing = true; this.showing = true;
@ -97,38 +104,38 @@ class WebView {
} }
async focus () { async focus () {
if (!this.digitalWindow) { if (!this.digitalWindow) {
console.warn(`Cannot show focus screen because window does not exist`); this.log.warn(`Cannot show focus screen because window does not exist`);
return false; return false;
} }
await delay(500); await delay(500);
try { try {
this.digitalWindow.webContents.send('focus', { focus : true }); this.digitalWindow.webContents.send('focus', { focus : true });
} catch (err) { } catch (err) {
console.error(err); this.log.error(err);
} }
} }
async field (ratio : number) { async field (ratio : number) {
if (!this.digitalWindow) { if (!this.digitalWindow) {
console.warn(`Cannot show field guide because window does not exist`); this.log.warn(`Cannot show field guide because window does not exist`);
return false; return false;
} }
await delay(500); await delay(500);
try { try {
this.digitalWindow.webContents.send('field', { field : true, ratio }); this.digitalWindow.webContents.send('field', { field : true, ratio });
} catch (err) { } catch (err) {
console.error(err); this.log.error(err);
} }
} }
async meter () { async meter () {
if (!this.digitalWindow) { if (!this.digitalWindow) {
console.warn(`Cannot show meter screen because window does not exist`); this.log.warn(`Cannot show meter screen because window does not exist`);
return false; return false;
} }
await delay(500); await delay(500);
try { try {
this.digitalWindow.webContents.send('meter', { meter : true }); this.digitalWindow.webContents.send('meter', { meter : true });
} catch (err) { } catch (err) {
console.error(err); this.log.error(err);
} }
} }
hide () { hide () {