Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Marlin): add support for parsing temperature data for heated chamber, cooler, and other temperature states #832

Merged
merged 1 commit into from
Jul 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
116 changes: 105 additions & 11 deletions src/server/controllers/Marlin/MarlinLineParserResultTemperature.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,21 @@
import { ensureString } from 'ensure-type';

class MarlinLineParserResultTemperature {
// https://github.com/MarlinFirmware/Marlin/blob/2.1.x/Marlin/src/module/temperature.cpp
//
// Print a single heater state in the form:
// Bed: " B:nnn.nn /nnn.nn"
// Chamber: " C:nnn.nn /nnn.nn"
// Cooler: " L:nnn.nn /nnn.nn"
// Probe: " P:nnn.nn"
// Board: " M:nnn.nn"
// SoC: " S:nnn.nn"
// Redundant: " R:nnn.nn /nnn.nn"
// Extruder: " T0:nnn.nn /nnn.nn"
// With ADC: " T0:nnn.nn /nnn.nn (nnn.nn)"
//
// Example #1
// ```
// ok T:0
// ok T:293.0 /0.0 B:25.9 /0.0 @:0 B@:0
// ok T:293.0 /0.0 B:25.9 /0.0 T0:293.0 /0.0 T1:100.0 /0.0 @:0 B@:0 @0:0 @1:0
Expand All @@ -12,36 +27,66 @@ class MarlinLineParserResultTemperature {
// T:293.0 /0.0 B:25.9 /0.0 T0:293.0 /0.0 T1:100.0 /0.0 @:0 B@:0 @0:0 @1:0
// T:293.0 /0.0 (0.0) B:25.9 /0.0 T0:293.0 /0.0 (0.0) T1:100.0 /0.0 (0.0) @:0 B@:0 @0:0 @1:0
// T0:27.37 /0.00 B:28.27 /0.00 T0:27.58 /0.00 T1:27.37 /0.00 @:0 B@:0 @0:0 @1:0
// ```
//
// Example: When the active hot end is set to T0
// Example #2: T0 is the active hotend
// ```
// T:293.0 /0.0 B:25.9 /0.0 T0:293.0 /0.0 T1:100.0 /0.0 @:0 B@:0 @0:0 @1:0
// T0:293.0 /0.0 B:25.9 /0.0 T0:293.0 /0.0 T1:100.0 /0.0 @:0 B@:0 @0:0 @1:0
// ```
//
// Example: When the active hot end is set to T1
// Example #3: T1 is the active hotend
// ```
// T:100.0 /0.0 B:25.9 /0.0 T0:293.0 /0.0 T1:100.0 /0.0 @:0 B@:0 @0:0 @1:0
// T0:100.0 /0.0 B:25.9 /0.0 T0:293.0 /0.0 T1:100.0 /0.0 @:0 B@:0 @0:0 @1:0
// ```
static parse(line) {
let r = line.match(/^(ok)?\s+(T|T\d+):[0-9\.\-]+/i);
let r = line.match(/^(ok)?\s+(T\d+|T|B|C|L|P|M|S|R):[0-9\.\-]+/i);
if (!r) {
return null;
}

const payload = {
ok: line.startsWith('ok'),
extruder: {}, // active hotend
heatedBed: {},

// T0:nnn.nn /nnn.nn
// T1:nnn.nn /nnn.nn
hotend: {},

// T:nnn.nn /nnn.nn
extruder: {},

// B:nnn.nn /nnn.nn
heatedBed: {},

// C:nnn.nn /nnn.nn
heatedChamber: {},

// L:nnn.nn /nnn.nn
cooler: {},

// P:nnn.nn
probe: {},

// M:nnn.nn
board: {},

// S:nnn.nn
soc: {},

// R:nnn.nn /nnn.nn
redundant: {},
};

const re = /(?:(?:(T|B|T\d+):([0-9\.\-]+)\s+\/([0-9\.\-]+)(?:\s+\((?:[0-9\.\-]+)\))?)|(?:(@|B@|@\d+):([0-9\.\-]+))|(?:(W):(\?|[0-9]+)))/ig;
const re = /(?:(?:(T\d+|T|B|C|L|P|M|S|R):([0-9\.\-]+)\s+\/([0-9\.\-]+)(?:\s+\((?:[0-9\.\-]+)\))?)|(?:(@|B@|C@|@\d+):([0-9\.\-]+))|(?:(W):(\?|[0-9]+)))/ig;

while ((r = re.exec(line))) {
// r[1] = T, B, T0, T1
// r[4] = @, B@, @0, @1
// r[1] = T0, T1, T, B, C, L, P, M, S, R
// r[4] = @, B@, C@, @0, @1
// r[6] = W
const key = r[1] || r[4] || r[6];

{ // Hotend temperature (T0:293.0 /0.0)
{ // Multi-Hotend (T0:293.0 /0.0)
const found = ensureString(key).match(/^T(\d+)$/);
if (found) {
const hotendIndex = parseInt(found[1], 10);
Expand All @@ -61,18 +106,51 @@ class MarlinLineParserResultTemperature {
}
}

if (key === 'T') { // T:293.0 /0.0
if (key === 'T') { // Hotend (T:293.0 /0.0)
payload.extruder.deg = payload.extruder.deg ?? r[2];
payload.extruder.degTarget = payload.extruder.degTarget ?? r[3];
continue;
}

if (key === 'B') { // B:60.0 /0.0
if (key === 'B') { // Heated bed (B:60.0 /0.0)
payload.heatedBed.deg = r[2];
payload.heatedBed.degTarget = r[3];
continue;
}

if (key === 'C') { // Heated chamber
payload.heatedChamber.deg = r[2];
payload.heatedChamber.degTarget = r[3];
continue;
}

if (key === 'L') { // Cooler
payload.cooler.deg = r[2];
payload.cooler.degTarget = r[3];
continue;
}

if (key === 'P') { // Probe
payload.probe.deg = r[2];
continue;
}

if (key === 'M') { // Board
payload.board.deg = r[2];
continue;
}

if (key === 'S') { // SoC
payload.soc.deg = r[2];
continue;
}

if (key === 'R') { // Redundant
payload.redundant.deg = r[2];
payload.redundant.degTarget = r[3];
continue;
}

if (key === '@') { // @:127
payload.extruder.power = r[5];
continue;
Expand All @@ -83,6 +161,22 @@ class MarlinLineParserResultTemperature {
continue;
}

if (key === 'C@') { // C@:127
// The first @C:nnn represents the soft PWM amount of the heated chamber
if (payload.heatedChamber.deg !== undefined && payload.heatedChamber.power === undefined) {
// Set power for heated chamber if not set
payload.heatedChamber.power = r[5];
continue;
}

// The second @C:nnn represents the soft PWM amount of the cooler
if (payload.cooler.deg !== undefined && payload.cooler.power === undefined) {
// Set power for cooler if not set
payload.cooler.power = r[5];
continue;
}
}

{ // Hotend power (@0:0)
const found = ensureString(key).match(/^@(\d+)$/);
if (found) {
Expand Down
45 changes: 45 additions & 0 deletions test/marlin.js
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,51 @@ test('MarlinLineParserResultTemperature', (t) => {
runner.parse(line);
});

t.test('ok L:21.84 /0.00 @:0 C@:0', (t) => {
const runner = new MarlinRunner();
runner.on('temperature', ({ raw, ok, extruder, cooler }) => {
t.equal(raw, 'ok L:21.84 /0.00 @:0 C@:0');
t.equal(ok, true);
t.same(extruder, {
power: 0,
});
t.same(cooler, {
deg: '21.84',
degTarget: '0.00',
power: 0,
});
t.end();
});

const line = 'ok L:21.84 /0.00 @:0 C@:0';
runner.parse(line);
});

t.test('ok C:25.9 /0.00 L:21.84 /0.00 @:0 C@:127 C@:0', (t) => {
const runner = new MarlinRunner();
runner.on('temperature', ({ raw, ok, extruder, heatedChamber, cooler }) => {
t.equal(raw, 'ok C:25.9 /0.00 L:21.84 /0.00 @:0 C@:127 C@:0');
t.equal(ok, true);
t.same(extruder, {
power: 0,
});
t.same(heatedChamber, {
deg: '25.9',
degTarget: '0.00',
power: 127,
});
t.same(cooler, {
deg: '21.84',
degTarget: '0.00',
power: 0,
});
t.end();
});

const line = 'ok C:25.9 /0.00 L:21.84 /0.00 @:0 C@:127 C@:0';
runner.parse(line);
});

t.test(' T:293.0 /0.0 B:25.9 /0.0 @:0 B@:0', (t) => {
const runner = new MarlinRunner();
runner.on('temperature', ({ raw, ok, extruder, heatedBed, hotend, wait }) => {
Expand Down