serial osx fix?
This commit is contained in:
+118
-14
@@ -18,7 +18,7 @@ class WallPlotter {
|
||||
// Static constants
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static VERSION = '2.2.2';
|
||||
static VERSION = '2.2.3';
|
||||
static MIN_FEED_MM_MIN = 1;
|
||||
static MAX_FEED_MM_MIN = 10000;
|
||||
/** Offline overlay size when not connected (mm) — 150×150 cm centred on origin */
|
||||
@@ -156,6 +156,9 @@ class WallPlotter {
|
||||
this._updatePlotButtons();
|
||||
userOnStatusChange(status);
|
||||
};
|
||||
|
||||
this._unloadBound = false;
|
||||
this._installUnloadHandler();
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
@@ -394,8 +397,16 @@ class WallPlotter {
|
||||
}
|
||||
if (this.connected) return;
|
||||
|
||||
this.port = await navigator.serial.requestPort();
|
||||
await this.port.open({ baudRate: this.baudRate });
|
||||
let port;
|
||||
try {
|
||||
port = await this._acquirePort();
|
||||
await this._openPort(port);
|
||||
} catch (err) {
|
||||
this.onLog('! ' + err.message);
|
||||
port = await navigator.serial.requestPort();
|
||||
await this._openPort(port);
|
||||
}
|
||||
this.port = port;
|
||||
|
||||
this.writer = this.port.writable.getWriter();
|
||||
this._startReadLoop();
|
||||
@@ -415,37 +426,81 @@ class WallPlotter {
|
||||
}
|
||||
}
|
||||
|
||||
async _acquirePort() {
|
||||
const existing = await navigator.serial.getPorts();
|
||||
if (existing.length === 1) return existing[0];
|
||||
return navigator.serial.requestPort();
|
||||
}
|
||||
|
||||
async _openPort(port) {
|
||||
const opened = port.open({ baudRate: this.baudRate });
|
||||
const timedOut = this._delay(3000).then(() => {
|
||||
const err = new Error(
|
||||
'serial open timeout — port still held after reload. Unplug USB or close other serial tabs.'
|
||||
);
|
||||
err.name = 'TimeoutError';
|
||||
throw err;
|
||||
});
|
||||
try {
|
||||
await Promise.race([opened, timedOut]);
|
||||
} catch (err) {
|
||||
try {
|
||||
await port.close();
|
||||
} catch (_) {
|
||||
/* ignore */
|
||||
}
|
||||
if (typeof port.forget === 'function') {
|
||||
try {
|
||||
await port.forget();
|
||||
} catch (_) {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
/** Close the serial port. */
|
||||
async disconnect() {
|
||||
if (!this.connected) return;
|
||||
if (!this.connected && !this.port) return;
|
||||
|
||||
this.readLoopActive = false;
|
||||
this._cancelPendingOk();
|
||||
this._rxBuf = '';
|
||||
this._machineBusy = false;
|
||||
|
||||
if (this.reader) {
|
||||
const reader = this.reader;
|
||||
const writer = this.writer;
|
||||
const port = this.port;
|
||||
this.reader = null;
|
||||
this.writer = null;
|
||||
this.port = null;
|
||||
|
||||
if (reader) {
|
||||
try {
|
||||
await this.reader.cancel();
|
||||
await reader.cancel();
|
||||
} catch (_) {
|
||||
/* already closed */
|
||||
}
|
||||
this.reader = null;
|
||||
}
|
||||
if (this.writer) {
|
||||
try {
|
||||
this.writer.releaseLock();
|
||||
reader.releaseLock();
|
||||
} catch (_) {
|
||||
/* ignore */
|
||||
}
|
||||
this.writer = null;
|
||||
}
|
||||
if (this.port) {
|
||||
if (writer) {
|
||||
try {
|
||||
await this.port.close();
|
||||
writer.releaseLock();
|
||||
} catch (_) {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
if (port) {
|
||||
try {
|
||||
await port.close();
|
||||
} catch (_) {
|
||||
/* ignore */
|
||||
}
|
||||
this.port = null;
|
||||
}
|
||||
|
||||
this.connected = false;
|
||||
@@ -454,6 +509,55 @@ class WallPlotter {
|
||||
this.onStatusChange('disconnected');
|
||||
}
|
||||
|
||||
/** Best-effort close for page reload (must not await — Mac keeps the USB lock otherwise). */
|
||||
_releaseSerialNow() {
|
||||
if (!this.port && !this.connected) return;
|
||||
this.readLoopActive = false;
|
||||
this._cancelPendingOk();
|
||||
this._rxBuf = '';
|
||||
this._machineBusy = false;
|
||||
const reader = this.reader;
|
||||
const writer = this.writer;
|
||||
const port = this.port;
|
||||
this.reader = null;
|
||||
this.writer = null;
|
||||
this.port = null;
|
||||
this.connected = false;
|
||||
this.homeSet = false;
|
||||
try {
|
||||
reader?.cancel();
|
||||
} catch (_) {
|
||||
/* ignore */
|
||||
}
|
||||
try {
|
||||
reader?.releaseLock();
|
||||
} catch (_) {
|
||||
/* ignore */
|
||||
}
|
||||
try {
|
||||
writer?.releaseLock();
|
||||
} catch (_) {
|
||||
/* ignore */
|
||||
}
|
||||
try {
|
||||
port?.close();
|
||||
} catch (_) {
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
|
||||
_installUnloadHandler() {
|
||||
if (this._unloadBound) return;
|
||||
this._unloadBound = true;
|
||||
const release = () => this._releaseSerialNow();
|
||||
window.addEventListener('pagehide', release);
|
||||
window.addEventListener('beforeunload', release);
|
||||
window.addEventListener('unload', release);
|
||||
window.addEventListener('pageshow', (event) => {
|
||||
if (event.persisted) this._releaseSerialNow();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Write one G-code line; by default wait for Marlin ok.
|
||||
* @param {string} line
|
||||
|
||||
Reference in New Issue
Block a user