<commit_before>import _ from 'lodash';
import events from 'events';

import {
    TINYG_MACHINE_STATE_READY,
    TINYG_MACHINE_STATE_ALARM,
    TINYG_MACHINE_STATE_STOP,
    TINYG_MACHINE_STATE_END,

    // G-code Motion Mode
    TINYG_GCODE_MOTION_G0,
    TINYG_GCODE_MOTION_G1,
    TINYG_GCODE_MOTION_G2,
    TINYG_GCODE_MOTION_G3,
    TINYG_GCODE_MOTION_G80,

    // G-code Coordinate System
    TINYG_GCODE_COORDINATE_G53,
    TINYG_GCODE_COORDINATE_G54,
    TINYG_GCODE_COORDINATE_G55,
    TINYG_GCODE_COORDINATE_G56,
    TINYG_GCODE_COORDINATE_G57,
    TINYG_GCODE_COORDINATE_G58,
    TINYG_GCODE_COORDINATE_G59,

    // G-code Plane Selection
    TINYG_GCODE_PLANE_G17,
    TINYG_GCODE_PLANE_G18,
    TINYG_GCODE_PLANE_G19,

    // G-code Units
    TINYG_GCODE_UNITS_G20,
    TINYG_GCODE_UNITS_G21,

    // G-code Distance Mode
    TINYG_GCODE_DISTANCE_G90,
    TINYG_GCODE_DISTANCE_G91,

    // G-code Feedrate Mode
    TINYG_GCODE_FEEDRATE_G93,
    TINYG_GCODE_FEEDRATE_G94,
    TINYG_GCODE_FEEDRATE_G95,

    // G-code Path Control Mode
    TINYG_GCODE_PATH_G61,
    TINYG_GCODE_PATH_G61_1,
    TINYG_GCODE_PATH_G64

} from './constants';

class TinyGParser {
    parse(data) {
        const parsers = [
            TinyGParserResultQueueReports,
            TinyGParserResultStatusReports,
            TinyGParserResultReceiveReports
        ];

        for (let parser of parsers) {
            const result = parser.parse(data);
            if (result) {
                _.set(result, 'payload.raw', data);
                _.set(result, 'payload.f', data.f || []); // footer
                return result;
            }
        }

        return {
            type: null,
            payload: {
                raw: data,
                f: data.f || [] // footer
            }
        };
    }
}

class TinyGParserResultQueueReports {
    static parse(data) {
        const qr = _.get(data, 'r.qr') || _.get(data, 'qr');
        const qi = _.get(data, 'r.qi') || _.get(data, 'qi');
        const qo = _.get(data, 'r.qo') || _.get(data, 'qo');

        if (!qr) {
            return null;
        }

        const payload = {
            qr: qr,
            qi: qi,
            qo: qo
        };

        return {
            type: TinyGParserResultQueueReports,
            payload: payload
        };
    }
}

class TinyGParserResultStatusReports {
    static parse(data) {
        const sr = _.get(data, 'r.sr') || _.get(data, 'sr');
        if (!sr) {
            return null;
        }

        const payload = {
            sr: sr
        };

        return {
            type: TinyGParserResultStatusReports,
            payload: payload
        };
    }
}

class TinyGParserResultReceiveReports {
    static parse(data) {
        const r = _.get(data, 'r.r') || _.get(data, 'r');
        if (!r) {
            return null;
        }

        const payload = {
            r: r
        };

        return {
            type: TinyGParserResultReceiveReports,
            payload: payload
        };
    }
}

class TinyG extends events.EventEmitter {
    state = {
        // Queue Reports
        qr: 0,
        qi: 0,
        qo: 0,
        // Status Reports
        sr: {
            machineState: '',
            mpos: {
                x: '0.000',
                y: '0.000',
                z: '0.000'
            },
            wpos: {
                x: '0.000',
                y: '0.000',
                z: '0.000'
            },
            modal: {
                motion: '', // G0, G1, G2, G3, G38.2, G38.3, G38.4, G38.5, G80
                coordinate: '', // G54, G55, G56, G57, G58, G59
                plane: '', // G17: xy-plane, G18: xz-plane, G19: yz-plane
                units: '', // G20: Inches, G21: Millimeters
                distance: '', // G90: Absolute, G91: Relative
                feedrate: '' // G93: Inverse Time Mode, G94: Units Per Minutes
            }
        }
    };
    // Identification Parameters
    // https://github.com/synthetos/g2/wiki/Configuring-0.99-System-Groups#identification-parameters
    ident = {
        fv: 0, // Firmware Version
        fb: 0, // Firmware Build
        fbs: '', // Firmware Build String
        fbc: '', // Firmware Build Config
        hp: 0, // Hardware Platform: 1=Xmega, 2=Due, 3=v9(ARM)
        hv: 0, // Hardware Version
        id: '' // board ID
    };
    footer = {
        revision: 0,
        statusCode: 0, // https://github.com/synthetos/g2/wiki/Status-Codes
        rxBufferInfo: 0
    };
    parser = new TinyGParser();

    parse(data) {
        data = ('' + data).replace(/\s+$/, '');
        if (!data) {
            return;
        }

        this.emit('raw', { raw: data });

        if (data.match(/^{/)) {
            try {
                data = JSON.parse(data);
            } catch (err) {
                data = {};
            }

            const result = this.parser.parse(data) || {};
            const { type, payload } = result;

            if (type === TinyGParserResultQueueReports) {
                const { qr, qi, qo } = payload;
                if (this.state.qr !== qr ||
                    this.state.qi !== qi ||
                    this.state.qo !== qo) {
                    this.state = { // enforce state change
                        ...this.state,<commit_msg>Check the planner buffer pool size every time the planner buffer changes<commit_after>import _ from 'lodash';
import events from 'events';

import {
    TINYG_MACHINE_STATE_READY,
    TINYG_MACHINE_STATE_ALARM,
    TINYG_MACHINE_STATE_STOP,
    TINYG_MACHINE_STATE_END,

    // G-code Motion Mode
    TINYG_GCODE_MOTION_G0,
    TINYG_GCODE_MOTION_G1,
    TINYG_GCODE_MOTION_G2,
    TINYG_GCODE_MOTION_G3,
    TINYG_GCODE_MOTION_G80,

    // G-code Coordinate System
    TINYG_GCODE_COORDINATE_G53,
    TINYG_GCODE_COORDINATE_G54,
    TINYG_GCODE_COORDINATE_G55,
    TINYG_GCODE_COORDINATE_G56,
    TINYG_GCODE_COORDINATE_G57,
    TINYG_GCODE_COORDINATE_G58,
    TINYG_GCODE_COORDINATE_G59,

    // G-code Plane Selection
    TINYG_GCODE_PLANE_G17,
    TINYG_GCODE_PLANE_G18,
    TINYG_GCODE_PLANE_G19,

    // G-code Units
    TINYG_GCODE_UNITS_G20,
    TINYG_GCODE_UNITS_G21,

    // G-code Distance Mode
    TINYG_GCODE_DISTANCE_G90,
    TINYG_GCODE_DISTANCE_G91,

    // G-code Feedrate Mode
    TINYG_GCODE_FEEDRATE_G93,
    TINYG_GCODE_FEEDRATE_G94,
    TINYG_GCODE_FEEDRATE_G95,

    // G-code Path Control Mode
    TINYG_GCODE_PATH_G61,
    TINYG_GCODE_PATH_G61_1,
    TINYG_GCODE_PATH_G64

} from './constants';

class TinyGParser {
    parse(data) {
        const parsers = [
            TinyGParserResultQueueReports,
            TinyGParserResultStatusReports,
            TinyGParserResultReceiveReports
        ];

        for (let parser of parsers) {
            const result = parser.parse(data);
            if (result) {
                _.set(result, 'payload.raw', data);
                _.set(result, 'payload.f', data.f || []); // footer
                return result;
            }
        }

        return {
            type: null,
            payload: {
                raw: data,
                f: data.f || [] // footer
            }
        };
    }
}

class TinyGParserResultQueueReports {
    static parse(data) {
        const qr = _.get(data, 'r.qr') || _.get(data, 'qr');
        const qi = _.get(data, 'r.qi') || _.get(data, 'qi');
        const qo = _.get(data, 'r.qo') || _.get(data, 'qo');

        if (!qr) {
            return null;
        }

        const payload = {
            qr: Number(qr) || 0,
            qi: Number(qi) || 0,
            qo: Number(qo) || 0
        };

        return {
            type: TinyGParserResultQueueReports,
            payload: payload
        };
    }
}

class TinyGParserResultStatusReports {
    static parse(data) {
        const sr = _.get(data, 'r.sr') || _.get(data, 'sr');
        if (!sr) {
            return null;
        }

        const payload = {
            sr: sr
        };

        return {
            type: TinyGParserResultStatusReports,
            payload: payload
        };
    }
}

class TinyGParserResultReceiveReports {
    static parse(data) {
        const r = _.get(data, 'r.r') || _.get(data, 'r');
        if (!r) {
            return null;
        }

        const payload = {
            r: r
        };

        return {
            type: TinyGParserResultReceiveReports,
            payload: payload
        };
    }
}

class TinyG extends events.EventEmitter {
    state = {
        // Queue Reports
        qr: 0,
        qi: 0,
        qo: 0,
        // Status Reports
        sr: {
            machineState: '',
            mpos: {
                x: '0.000',
                y: '0.000',
                z: '0.000'
            },
            wpos: {
                x: '0.000',
                y: '0.000',
                z: '0.000'
            },
            modal: {
                motion: '', // G0, G1, G2, G3, G38.2, G38.3, G38.4, G38.5, G80
                coordinate: '', // G54, G55, G56, G57, G58, G59
                plane: '', // G17: xy-plane, G18: xz-plane, G19: yz-plane
                units: '', // G20: Inches, G21: Millimeters
                distance: '', // G90: Absolute, G91: Relative
                feedrate: '' // G93: Inverse Time Mode, G94: Units Per Minutes
            }
        }
    };
    // Identification Parameters
    // https://github.com/synthetos/g2/wiki/Configuring-0.99-System-Groups#identification-parameters
    ident = {
        fv: 0, // Firmware Version
        fb: 0, // Firmware Build
        fbs: '', // Firmware Build String
        fbc: '', // Firmware Build Config
        hp: 0, // Hardware Platform: 1=Xmega, 2=Due, 3=v9(ARM)
        hv: 0, // Hardware Version
        id: '' // board ID
    };
    footer = {
        revision: 0,
        statusCode: 0, // https://github.com/synthetos/g2/wiki/Status-Codes
        rxBufferInfo: 0
    };
    plannerBufferPoolSize = 0; // Suggest 12 min. Limit is 255

    parser = new TinyGParser();

    parse(data) {
        data = ('' + data).replace(/\s+$/, '');
        if (!data) {
            return;
        }

        this.emit('raw', { raw: data });

        if (data.match(/^{/)) {
            try {
                data = JSON.parse(data);
            } catch (err) {
                data = {};
            }

            const result = this.parser.parse(data) || {};
            const { type, payload } = result;

            if (type === TinyGParserResultQueueReports) {
                const { qr, qi, qo } = payload;

                // The planner buffer pool size will be checked every time the planner buffer changes
                if (qr > this.plannerBufferPoolSize) {
                    this.plannerBufferPoolSize = qr;
                }

                if (this.state.qr !== qr ||
                    this.state.qi !== qi ||
                    this.state.qo !== qo) {
                    this.state = { // enforce state change
                        ...this.state,
{'fraction_non_alphanumeric': 0.11714493280058118, 'fraction_numerical': 0.025880857246640028, 'mean_word_length': 1.4703903095558546, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 4, 'https://': 4, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7039572', 'n_tokens_mistral': 4072, 'n_tokens_neox': 3707, 'n_words': 730}