diff --git a/.gitignore b/.gitignore index 2c79e77..2b132a4 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ /.idea/ /vendor/ -/programs/*/* +/config/part_programs/* +/config/sub_programs/* +/config/tools.yaml !.gitignore diff --git a/README.md b/README.md index 4da6362..d3dd5b3 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,122 @@ -### Philips CNC6600 NC System Interpreter -This is an interpreter for programs written for the MAHO MH-C 700. -It basically creates a state-machine that represents the Philips NC system. - -Written in PHP, because why not? +# Philips CNC6600 NC System Interpreter -#### Usage -Put parts programs (plain text) in `/programs/part`, put subpart programs (plain text) in `/programs/sub`. - -To see what's working so far; run +## Description + +This is an interpreter for programs written for the MAHO MH-C 700. +It basically creates a state-machine that represents the Philips CNC6600 NC system. + +## Requirements + +- `PHP7.4` +- `composer` ([get it here](https://getcomposer.org/download/)) + +## Usage + +### Installation ```bash -php bin/app.php +## install dependencies and autoloader +$ composer install + +## copy tool configuration data and edit it +$ cp config/tools.yaml.dist config/tools.yaml +$ nano config/tools.yaml ``` + +### Tool data + +Tools are loaded from `config/tools.yaml`. +A tool configuration example would be: + +```yaml +# config/tools.yaml + +T1: + X: 5500 # radius in 0.001mm + Z: 2500 # length in 0.001mm + +T2: + X: 3000 + Z: 61379 +``` + +### Programs + +The application loads programs from `config/part_programs` and `config/sub_programs`. +The programs are stored in the memory of the machine. + +- A file containing a program _may_ have any name (a program is identified by its program number) +- A program _must_ have a program number as the first block +- A program is terminated either by a comment containing 'EOF' (case sensitive) or by a physical EOF +- A comment is denoted by `;`, anything after this character on the same line is ignored + +An example of a program would be: + +```text +; config/part_programs/some_name + +;; Some program that drills two holes +N9045 + +; and yes, comments are fully supported, +; or rather, detected and ignored by the parser +N10 G18 T2 M6 +N20 G1 F1500 S1250 +N30 M4 + +; prepare and execute drill cycle +N40 G81 Y2000 Z-7000 B48000 + +; the parser also understands this +N50G79X-20000Y0Z-15000 + +; hell, you may even put multiple blocks on one line: +; N50G0X2N60G1Y20 +; though it's good practice to align your program: +N60 G79 X20000 Y0 Z15000 + +N70 G0 Y150000 ; safely retract +N80 M2 ; turn off spindle, no return + +;; EOF +``` + +Executing program `9045` from the example: +```bash +## execute the example program +$ bin/run_program 9045 + +## or +$ php bin/run_program 9045 +``` + +- calling a subprogram (`G22 X9...`) is supported +- line repetitions (`E0302`) are _not_ supported yet +- parameter programming is _not_ supported yet + +### Machine State + +The machine state can be saved to a file to continue later on by using `State\Persister`. + +```php +use Machine\CNC6600; +use State\Persister; + +$CNC6600 = new CNC6600(); + +// Do some things with the machine... + +// Saving the machine state +$persister = new Persister(); +$persister->persist('some_state_identifier', $CNC6600); + +// Retrieving the saved state +$CNC6600 = $persister->load('some_state_identifier'); +``` + +## Future + +- Tool path simulation +- Manual Data Input (_MDI_) mode +- Proper tool compensation +- Line repetitions +- Parameter programming diff --git a/bin/app.php b/bin/app.php deleted file mode 100644 index 26fb8dd..0000000 --- a/bin/app.php +++ /dev/null @@ -1,15 +0,0 @@ -TM->write(new ToolData(1, 5500, 2)); -$nc->TM->write(new ToolData(2, 3000, 61379)); -(new ProgramLoader)->loadPrograms($nc); - -$nc->loadProgram(9002); -$nc->run(); - diff --git a/bin/bootstrap.php b/bin/bootstrap.php new file mode 100644 index 0000000..b8bd924 --- /dev/null +++ b/bin/bootstrap.php @@ -0,0 +1,18 @@ +load($CNC6600->PPM, __DIR__ . '/../config/part_programs/*'); +$programLoader->load($CNC6600->SPM, __DIR__ . '/../config/sub_programs/*'); + +$toolLoader = new ToolLoader(); +$toolLoader->load($CNC6600->TM, __DIR__ . '/../config/tools.yaml'); + +return $CNC6600; diff --git a/bin/run_program b/bin/run_program new file mode 100755 index 0000000..e6f7c20 --- /dev/null +++ b/bin/run_program @@ -0,0 +1,13 @@ +#!/usr/bin/env php7.4 +\n"); + exit(1); +} + +$CNC6600 = require_once __DIR__ . '/bootstrap.php'; +$CNC6600->loadProgram($argv[1]); +$CNC6600->execute(); diff --git a/composer.json b/composer.json index 6be7abd..3bbccfc 100644 --- a/composer.json +++ b/composer.json @@ -15,7 +15,9 @@ "ext-ctype": "*", "ext-json": "*", "ext-readline": "*", + "ext-zlib": "*", "symfony/var-dumper": "^5.0", - "illuminate/support": "^7.10" + "illuminate/support": "^7.10", + "symfony/yaml": "^5.0" } } diff --git a/composer.lock b/composer.lock index 107dd47..2d0a0a5 100644 --- a/composer.lock +++ b/composer.lock @@ -4,37 +4,41 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "1e9e0fcf3c3cc215c6ab1cd71d6bb903", + "content-hash": "add2ead9d9a8adb0a79475f10b111470", "packages": [ { "name": "doctrine/inflector", - "version": "1.3.1", + "version": "2.0.1", "source": { "type": "git", "url": "https://github.com/doctrine/inflector.git", - "reference": "ec3a55242203ffa6a4b27c58176da97ff0a7aec1" + "reference": "18b995743e7ec8b15fd6efc594f0fa3de4bfe6d7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/inflector/zipball/ec3a55242203ffa6a4b27c58176da97ff0a7aec1", - "reference": "ec3a55242203ffa6a4b27c58176da97ff0a7aec1", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/18b995743e7ec8b15fd6efc594f0fa3de4bfe6d7", + "reference": "18b995743e7ec8b15fd6efc594f0fa3de4bfe6d7", "shasum": "" }, "require": { - "php": "^7.1" + "php": "^7.2" }, "require-dev": { - "phpunit/phpunit": "^6.2" + "doctrine/coding-standard": "^7.0", + "phpstan/phpstan": "^0.11", + "phpstan/phpstan-phpunit": "^0.11", + "phpstan/phpstan-strict-rules": "^0.11", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "1.3.x-dev" + "dev-master": "2.0.x-dev" } }, "autoload": { "psr-4": { - "Doctrine\\Common\\Inflector\\": "lib/Doctrine/Common/Inflector" + "Doctrine\\Inflector\\": "lib/Doctrine/Inflector" } }, "notification-url": "https://packagist.org/downloads/", @@ -63,19 +67,39 @@ "email": "schmittjoh@gmail.com" } ], - "description": "Common String Manipulations with regard to casing and singular/plural rules.", - "homepage": "http://www.doctrine-project.org", + "description": "PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.", + "homepage": "https://www.doctrine-project.org/projects/inflector.html", "keywords": [ "inflection", - "pluralize", - "singularize", - "string" + "inflector", + "lowercase", + "manipulation", + "php", + "plural", + "singular", + "strings", + "uppercase", + "words" ], - "time": "2019-10-30T19:59:35+00:00" + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finflector", + "type": "tidelift" + } + ], + "time": "2020-05-11T11:25:59+00:00" }, { "name": "illuminate/contracts", - "version": "v7.10.3", + "version": "v7.11.0", "source": { "type": "git", "url": "https://github.com/illuminate/contracts.git", @@ -119,20 +143,20 @@ }, { "name": "illuminate/support", - "version": "v7.10.3", + "version": "v7.11.0", "source": { "type": "git", "url": "https://github.com/illuminate/support.git", - "reference": "cd11fa914c52a2249c48cde08d03a871597e8781" + "reference": "5458d0d0048f185b3d4a911e5d21d2bb2fb336ca" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/illuminate/support/zipball/cd11fa914c52a2249c48cde08d03a871597e8781", - "reference": "cd11fa914c52a2249c48cde08d03a871597e8781", + "url": "https://api.github.com/repos/illuminate/support/zipball/5458d0d0048f185b3d4a911e5d21d2bb2fb336ca", + "reference": "5458d0d0048f185b3d4a911e5d21d2bb2fb336ca", "shasum": "" }, "require": { - "doctrine/inflector": "^1.1", + "doctrine/inflector": "^1.4|^2.0", "ext-json": "*", "ext-mbstring": "*", "illuminate/contracts": "^7.0", @@ -177,7 +201,7 @@ ], "description": "The Illuminate Support package.", "homepage": "https://laravel.com", - "time": "2020-05-05T16:21:56+00:00" + "time": "2020-05-12T14:31:35+00:00" }, { "name": "nesbot/carbon", @@ -359,17 +383,89 @@ "time": "2017-10-23T01:57:42+00:00" }, { - "name": "symfony/polyfill-mbstring", - "version": "v1.15.0", + "name": "symfony/polyfill-ctype", + "version": "v1.17.0", "source": { "type": "git", - "url": "https://github.com/symfony/polyfill-mbstring.git", - "reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac" + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "e94c8b1bbe2bc77507a1056cdb06451c75b427f9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/81ffd3a9c6d707be22e3012b827de1c9775fc5ac", - "reference": "81ffd3a9c6d707be22e3012b827de1c9775fc5ac", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/e94c8b1bbe2bc77507a1056cdb06451c75b427f9", + "reference": "e94c8b1bbe2bc77507a1056cdb06451c75b427f9", + "shasum": "" + }, + "require": { + "php": ">=5.3.3" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.17-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + }, + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-05-12T16:14:59+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.17.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "fa79b11539418b02fc5e1897267673ba2c19419c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/fa79b11539418b02fc5e1897267673ba2c19419c", + "reference": "fa79b11539418b02fc5e1897267673ba2c19419c", "shasum": "" }, "require": { @@ -381,7 +477,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "1.15-dev" + "dev-master": "1.17-dev" } }, "autoload": { @@ -429,7 +525,7 @@ "type": "tidelift" } ], - "time": "2020-03-09T19:04:49+00:00" + "time": "2020-05-12T16:47:27+00:00" }, { "name": "symfony/translation", @@ -668,6 +764,79 @@ ], "time": "2020-04-12T16:45:47+00:00" }, + { + "name": "symfony/yaml", + "version": "v5.0.8", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "482fb4e710e5af3e0e78015f19aa716ad953392f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/482fb4e710e5af3e0e78015f19aa716ad953392f", + "reference": "482fb4e710e5af3e0e78015f19aa716ad953392f", + "shasum": "" + }, + "require": { + "php": "^7.2.5", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/console": "<4.4" + }, + "require-dev": { + "symfony/console": "^4.4|^5.0" + }, + "suggest": { + "symfony/console": "For validating YAML files using the lint command" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Yaml Component", + "homepage": "https://symfony.com", + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2020-04-28T17:58:55+00:00" + }, { "name": "voku/portable-ascii", "version": "1.4.10", diff --git a/programs/part/.gitignore b/config/part_programs/.gitignore similarity index 100% rename from programs/part/.gitignore rename to config/part_programs/.gitignore diff --git a/programs/sub/.gitignore b/config/sub_programs/.gitignore similarity index 100% rename from programs/sub/.gitignore rename to config/sub_programs/.gitignore diff --git a/config/tools.yaml.dist b/config/tools.yaml.dist new file mode 100644 index 0000000..781ad1e --- /dev/null +++ b/config/tools.yaml.dist @@ -0,0 +1,9 @@ +# config/tools.yaml + +#T: +# X: +# Z: + +#T: +# X: +# Z: diff --git a/src/Loader/ProgramLoader.php b/src/Loader/ProgramLoader.php new file mode 100644 index 0000000..ab78165 --- /dev/null +++ b/src/Loader/ProgramLoader.php @@ -0,0 +1,30 @@ +parser = new WordParser(); + $this->builder = new ProgramBuilder(); + } + + + public function load(ProgramMemory $memory, string $globPattern): void + { + foreach (glob($globPattern) as $file) { + $words = $this->parser->parseFile($file); + $program = $this->builder->build($words); + $memory->write($program); + } + } +} diff --git a/src/Loader/ToolLoader.php b/src/Loader/ToolLoader.php new file mode 100644 index 0000000..1e094df --- /dev/null +++ b/src/Loader/ToolLoader.php @@ -0,0 +1,26 @@ +parser = new ToolParser(); + } + + + public function load(ToolMemory $toolMemory, string $yamlFile): void + { + $tools = $this->parser->parseFile($yamlFile); + foreach ($tools as $toolData) { + $toolMemory->write($toolData); + } + } +} diff --git a/src/Automata/NC.php b/src/Machine/CNC6600.php similarity index 66% rename from src/Automata/NC.php rename to src/Machine/CNC6600.php index 7758a63..1c946a6 100644 --- a/src/Automata/NC.php +++ b/src/Machine/CNC6600.php @@ -1,12 +1,13 @@ PPM = new ProgramMemory(); $this->SPMC = new MemoryController($this->SPM); $this->PPMC = new MemoryController($this->PPM); - $this->AMC = $this->PPMC; + $this->_AMC = $this->PPMC; } public function loadProgram(int $N): void { $this->PPMC->loadProgram($N); - $this->AMC = $this->PPMC; + $this->_AMC = $this->PPMC; } public function step(): void { - if ($this->AMC === $this->SPMC && count($this->AMC) === 0) { - $this->AMC = $this->PPMC; + if ($this->_AMC === $this->SPMC && count($this->_AMC) === 0) { + $this->_AMC = $this->PPMC; } - $block = $this->AMC->next(); + $block = $this->_AMC->next(); $this->IS->apply($block); } - public function run(): void + public function execute(): void { while ($this->PPMC->ready()) { $this->step(); diff --git a/src/Automata/Definitions.php b/src/Machine/Definitions.php similarity index 67% rename from src/Automata/Definitions.php rename to src/Machine/Definitions.php index df29ba2..e9c7cc4 100644 --- a/src/Automata/Definitions.php +++ b/src/Machine/Definitions.php @@ -1,20 +1,18 @@ 'Rapid traverse', // Default - 1 => 'Linear interpolation', - 2 => 'Circular interpolation (CW)', - 3 => 'Circular interpolation (CCW)', + 0 => 'Rapid traverse', // Default + 1 => 'Linear interpolation', + 2 => 'Circular interpolation (CW)', + 3 => 'Circular interpolation (CCW)', // quest-ce-que c'est? - 4 => 'Dwell', + 4 => 'Dwell', // plane selection mode 17 => 'Plane selection (XY-plane)', // Default @@ -57,17 +55,18 @@ class Definitions // reference to zero 98 => 'Automatic positioning to reference datum point', ]; - private array $M = [ - 0 => 'Programmed stop (Sets M5 and M9)', - 2 => 'End of program (Sets M5 and M9)', - 3 => 'Spindle start CW (CCW in G18)', - 4 => 'Spindle start CCW (CW in G18)', - 5 => 'Spindle stop', - 6 => 'Tool change (Sets M5 and M9)', + + public const M = [ + 0 => 'Programmed stop (Sets M5 and M9)', + 2 => 'End of program (Sets M5 and M9)', + 3 => 'Spindle start CW (CCW in G18)', + 4 => 'Spindle start CCW (CW in G18)', + 5 => 'Spindle stop', + 6 => 'Tool change (Sets M5 and M9)', // coolant control - 8 => 'Coolant on', - 9 => 'Coolant off', + 8 => 'Coolant on', + 9 => 'Coolant off', // table clamping (unsupported) 10 => 'Table clamping - close', @@ -76,19 +75,4 @@ class Definitions 30 => 'End of program with skip back to start (Sets M5 and M9)', 67 => 'Enter new tool information without machine stop', ]; - private array $S = [ - 0, 40, 50, 63, 80, 100, 125, 160, 200, 250, - 315, 400, 500, 630, 800, 1000, 1250, 1600, 2000, - ]; - - public function hasPredefinedValue(Word $word): bool - { - return in_array($word->register, ['G', 'M']); - } - - - public function translatePredefinedValue(Word $word): ?string - { - return @$this->{$word->register}[$word->value]; - } } diff --git a/src/Automata/InstructionSet.php b/src/Machine/InstructionSet.php similarity index 58% rename from src/Automata/InstructionSet.php rename to src/Machine/InstructionSet.php index 2d3495c..71fa012 100644 --- a/src/Automata/InstructionSet.php +++ b/src/Machine/InstructionSet.php @@ -1,6 +1,6 @@ machine = $machine; + $this->CNC6600 = $CNC6600; } @@ -36,13 +36,13 @@ class InstructionSet } foreach ($block->words as $word) { // The word value may be put into the machine registers directly - if (property_exists($this->machine->DR, $word->register)) { - $this->machine->DR->{$word->register} = $block->pop($word->register); + if (property_exists($this->CNC6600->DR, $word->register)) { + $this->CNC6600->DR->{$word->register} = $block->pop($word->register); } else { print("WARNING: No method or register for word '{$word}'\n"); } } - dump($this->machine->DR); + dump($this->CNC6600->DR); readline(); } @@ -57,8 +57,8 @@ class InstructionSet { // Triggers an exception if not found, good enough for now. // Might implement compensations and more explicit tool registers later on - $this->machine->TM->read($value); - $this->machine->DR->T = $value; + $this->CNC6600->TM->read($value); + $this->CNC6600->DR->T = $value; } @@ -70,31 +70,31 @@ class InstructionSet implode(', ', self::SPEEDS) )); } - $this->machine->DR->S = $value; + $this->CNC6600->DR->S = $value; } protected function G0(Block $block): void { - $this->machine->DR->G_TRAVERSE = $block->read('G'); + $this->CNC6600->DR->G_TRAVERSE = $block->read('G'); } protected function G1(Block $block): void { - $this->machine->DR->G_TRAVERSE = $block->read('G'); + $this->CNC6600->DR->G_TRAVERSE = $block->read('G'); } protected function G2(Block $block): void { - $this->machine->DR->G_TRAVERSE = $block->read('G'); + $this->CNC6600->DR->G_TRAVERSE = $block->read('G'); } protected function G3(Block $block): void { - $this->machine->DR->G_TRAVERSE = $block->read('G'); + $this->CNC6600->DR->G_TRAVERSE = $block->read('G'); } @@ -106,115 +106,115 @@ class InstructionSet protected function G17(Block $block): void { - $this->machine->DR->G_PLANE_SELECTION = $block->read('G'); + $this->CNC6600->DR->G_PLANE_SELECTION = $block->read('G'); } protected function G18(Block $block): void { - $this->machine->DR->G_PLANE_SELECTION = $block->read('G'); + $this->CNC6600->DR->G_PLANE_SELECTION = $block->read('G'); } protected function G19(Block $block): void { - $this->machine->DR->G_PLANE_SELECTION = $block->read('G'); + $this->CNC6600->DR->G_PLANE_SELECTION = $block->read('G'); } protected function G22(Block $block): void { $N = $block->pop('X'); - $this->machine->SPMC->loadProgram($N); - $this->machine->AMC = $this->machine->SPMC; + $this->CNC6600->SPMC->loadProgram($N); + $this->CNC6600->_AMC = $this->CNC6600->SPMC; } protected function G40(Block $block): void { - $this->machine->DR->G_RADIUS_COMPENSATION = $block->read('G'); + $this->CNC6600->DR->G_RADIUS_COMPENSATION = $block->read('G'); } protected function G41(Block $block): void { - $this->machine->DR->G_RADIUS_COMPENSATION = $block->read('G'); + $this->CNC6600->DR->G_RADIUS_COMPENSATION = $block->read('G'); } protected function G42(Block $block): void { - $this->machine->DR->G_RADIUS_COMPENSATION = $block->read('G'); + $this->CNC6600->DR->G_RADIUS_COMPENSATION = $block->read('G'); } protected function G43(Block $block): void { - $this->machine->DR->G_RADIUS_COMPENSATION = $block->read('G'); + $this->CNC6600->DR->G_RADIUS_COMPENSATION = $block->read('G'); } protected function G44(Block $block): void { - $this->machine->DR->G_RADIUS_COMPENSATION = $block->read('G'); + $this->CNC6600->DR->G_RADIUS_COMPENSATION = $block->read('G'); } protected function G79(Block $block): void { - // Ignore... ?? The action will be executed on set location - if ($this->machine->DR->B_WORKCYCLE === 0) { + if ($this->CNC6600->DR->B_WORKCYCLE === 0) { throw new RuntimeException('No workcycle prepared!'); } + // TODO verify active workcycle, execute it? } protected function G81(Block $block): void { - $this->machine->DR->G_WORKCYCLE = $block->read('G'); + $this->CNC6600->DR->G_WORKCYCLE = $block->read('G'); $this->getWorkcycleParameters($block); } protected function G84(Block $block): void { - $this->machine->DR->G_WORKCYCLE = $block->read('G'); + $this->CNC6600->DR->G_WORKCYCLE = $block->read('G'); $this->getWorkcycleParameters($block); } protected function G85(Block $block): void { - $this->machine->DR->G_WORKCYCLE = $block->read('G'); + $this->CNC6600->DR->G_WORKCYCLE = $block->read('G'); $this->getWorkcycleParameters($block); } protected function G86(Block $block): void { - $this->machine->DR->G_WORKCYCLE = $block->read('G'); + $this->CNC6600->DR->G_WORKCYCLE = $block->read('G'); $this->getWorkcycleParameters($block); } private function getWorkcycleParameters(Block $block): void { - $this->machine->DR->X_WORKCYCLE = $block->has('X') ? $block->pop('X') : 0; - $this->machine->DR->Y_WORKCYCLE = $block->has('Y') ? $block->pop('Y') : 0; - $this->machine->DR->Z_WORKCYCLE = $block->has('Z') ? $block->pop('Z') : 0; - $this->machine->DR->B_WORKCYCLE = $block->has('B') ? $block->pop('B') : 0; + $this->CNC6600->DR->X_WORKCYCLE = $block->has('X') ? $block->pop('X') : 0; + $this->CNC6600->DR->Y_WORKCYCLE = $block->has('Y') ? $block->pop('Y') : 0; + $this->CNC6600->DR->Z_WORKCYCLE = $block->has('Z') ? $block->pop('Z') : 0; + $this->CNC6600->DR->B_WORKCYCLE = $block->has('B') ? $block->pop('B') : 0; } protected function G90(Block $block): void { - $this->machine->DR->G_DIMENSION_PROGRAMMING = $block->read('G'); + $this->CNC6600->DR->G_DIMENSION_PROGRAMMING = $block->read('G'); } protected function G91(Block $block): void { - $this->machine->DR->G_DIMENSION_PROGRAMMING = $block->read('G'); + $this->CNC6600->DR->G_DIMENSION_PROGRAMMING = $block->read('G'); } @@ -223,7 +223,7 @@ class InstructionSet // Incremental foreach (['X', 'Y', 'Z'] as $R) { if ($block->has($R)) { - $this->machine->DR->{$R} = -$block->pop($R); + $this->CNC6600->DR->{$R} = -$block->pop($R); } } } @@ -234,7 +234,7 @@ class InstructionSet // Absolute zero datum shift foreach (['X', 'Y', 'Z'] as $R) { if ($block->has($R)) { - $this->machine->DR->{$R} -= $block->pop($R); + $this->CNC6600->DR->{$R} -= $block->pop($R); } } } @@ -249,78 +249,78 @@ class InstructionSet protected function M0(Block $block): void { - $this->machine->DR->M_PROGRAM = 0; - $this->machine->DR->M_SPINDLE = 5; - $this->machine->DR->M_COOLANT = 9; + $this->CNC6600->DR->M_PROGRAM = $block->read('M'); + $this->CNC6600->DR->M_SPINDLE = 5; + $this->CNC6600->DR->M_COOLANT = 9; } protected function M2(Block $block): void { - $this->machine->DR->M_PROGRAM = 2; - $this->machine->DR->M_SPINDLE = 5; - $this->machine->DR->M_COOLANT = 9; + $this->CNC6600->DR->M_PROGRAM = $block->read('M'); + $this->CNC6600->DR->M_SPINDLE = 5; + $this->CNC6600->DR->M_COOLANT = 9; } protected function M3(Block $block): void { - $this->machine->DR->M_SPINDLE = 3; + $this->CNC6600->DR->M_SPINDLE = $block->read('M'); } protected function M4(Block $block): void { - $this->machine->DR->M_SPINDLE = 4; + $this->CNC6600->DR->M_SPINDLE = $block->read('M'); } protected function M5(Block $block): void { - $this->machine->DR->M_SPINDLE = 5; + $this->CNC6600->DR->M_SPINDLE = $block->read('M'); } protected function M6(Block $block): void { - $this->machine->DR->M_SPINDLE = 5; - $this->machine->DR->M_COOLANT = 9; + $this->CNC6600->DR->M_SPINDLE = 5; + $this->CNC6600->DR->M_COOLANT = 9; } protected function M8(Block $block): void { - $this->machine->DR->M_COOLANT = 8; + $this->CNC6600->DR->M_COOLANT = $block->read('M'); } protected function M9(Block $block): void { - $this->machine->DR->M_COOLANT = 9; + $this->CNC6600->DR->M_COOLANT = $block->read('M'); } protected function M10(Block $block): void { - $this->machine->DR->M_TABLE_CLAMPING = 10; + $this->CNC6600->DR->M_TABLE_CLAMPING = $block->read('M'); } protected function M11(Block $block): void { - $this->machine->DR->M_TABLE_CLAMPING = 11; + $this->CNC6600->DR->M_TABLE_CLAMPING = $block->read('M'); } protected function M30(Block $block): void { - $this->machine->DR->M_SPINDLE = 5; - $this->machine->DR->M_COOLANT = 9; - $N = $this->machine->PPMC->N; - $this->machine->PPMC->reset(); - $this->machine->SPMC->reset(); - $this->machine->PPMC->loadProgram($N); - $this->machine->AMC = $this->machine->PPMC; + $this->CNC6600->DR->M_SPINDLE = 5; + $this->CNC6600->DR->M_COOLANT = 9; + $N = $this->CNC6600->PPMC->N; + $this->CNC6600->PPMC->reset(); + $this->CNC6600->SPMC->reset(); + $this->CNC6600->PPMC->loadProgram($N); + $this->CNC6600->_AMC = $this->CNC6600->PPMC; } diff --git a/src/Automata/DataRegisters.php b/src/Machine/Memory/DataRegisters.php similarity index 96% rename from src/Automata/DataRegisters.php rename to src/Machine/Memory/DataRegisters.php index 0851a5c..836711b 100644 --- a/src/Automata/DataRegisters.php +++ b/src/Machine/Memory/DataRegisters.php @@ -1,6 +1,6 @@ guardInvalidToolNumber($tool->T); $this->memory[$tool->T] = $tool; } - public function read(int $T): ?ToolData + public function read(int $T): ?Tool { return @$this->memory[$T]; } diff --git a/src/Program/Builder/ProgramBuilder.php b/src/Program/Builder/ProgramBuilder.php new file mode 100644 index 0000000..d425901 --- /dev/null +++ b/src/Program/Builder/ProgramBuilder.php @@ -0,0 +1,42 @@ +value); + + $blockBuffer = null; + while ($word = array_shift($words)) { + if ($word->register === 'N') { + if (!is_null($blockBuffer)) { + $program->addBlock($blockBuffer); + } + $blockBuffer = new Block($word->value); + continue; + } + $blockBuffer->addWord($word); + } + if (!is_null($blockBuffer)) { + $program->addBlock($blockBuffer); + } + + return $program; + } +} diff --git a/src/Program/ProgramParser.php b/src/Program/Parser/WordParser.php similarity index 50% rename from src/Program/ProgramParser.php rename to src/Program/Parser/WordParser.php index 7d83f82..523e252 100644 --- a/src/Program/ProgramParser.php +++ b/src/Program/Parser/WordParser.php @@ -1,12 +1,16 @@ value); - $lineBuffer = null; - while ($word = array_shift($words)) { - if ($word->register === 'N') { - if (!is_null($lineBuffer)) { - $program->addBlock($lineBuffer); - } - $lineBuffer = new Block($word->value); - continue; - } - $lineBuffer->addWord($word); - } - if (!is_null($lineBuffer)) { - $program->addBlock($lineBuffer); - } - - return $program; + return $words; } } diff --git a/src/ProgramLoader.php b/src/ProgramLoader.php deleted file mode 100644 index 73aaa64..0000000 --- a/src/ProgramLoader.php +++ /dev/null @@ -1,22 +0,0 @@ -parseFile($partProgramFile); - $machine->PPM->write($partProgram); - } - - foreach (glob(__DIR__ . '/../programs/sub/*') as $subProgramFile) { - $subProgram = $parser->parseFile($subProgramFile); - $machine->SPM->write($subProgram); - } - } -} diff --git a/src/State/Persister.php b/src/State/Persister.php new file mode 100644 index 0000000..95e7b77 --- /dev/null +++ b/src/State/Persister.php @@ -0,0 +1,49 @@ +getFilename($identifier); + $state = serialize($CNC6600); + $state = gzcompress($state, 6); + @file_put_contents($filename, $state); + } + + + public function load(string $identifier): CNC6600 + { + $filename = $this->getFilename($identifier); + $this->guardStateFileDoesNotExist($filename); + $state = file_get_contents($filename); + $state = gzuncompress($state); + + return unserialize($state); + } + + + public function getFilename(string $identifier): string + { + $identifier = md5("machine_state_$identifier"); + + return self::WORKING_DIR . "/$identifier"; + } + + + private function guardStateFileDoesNotExist(string $filename): void + { + if (!file_exists($filename)) { + throw new RuntimeException('State not found'); + } + } +} + + diff --git a/src/Tool/Parser/ToolParser.php b/src/Tool/Parser/ToolParser.php new file mode 100644 index 0000000..b4264af --- /dev/null +++ b/src/Tool/Parser/ToolParser.php @@ -0,0 +1,39 @@ +parse($data); + } + + + /** + * @param array $data + * @return Tool[] + */ + public function parse(array $data): array + { + $tools = []; + foreach ($data as $T => $tool) { + $T = (int)filter_var($T, FILTER_SANITIZE_NUMBER_INT); + $tools[] = new Tool($T, $tool['X'], $tool['Z']); + } + + return $tools; + } +} diff --git a/src/Automata/ToolData.php b/src/Tool/Tool.php similarity index 87% rename from src/Automata/ToolData.php rename to src/Tool/Tool.php index be6cfe0..b3b6836 100644 --- a/src/Automata/ToolData.php +++ b/src/Tool/Tool.php @@ -1,8 +1,8 @@