Add Memory Controllers for SP and PP, add Instruction Set
This commit is contained in:
parent
ee896160b3
commit
fda22052b8
10
bin/app.php
10
bin/app.php
@ -1,14 +1,16 @@
|
||||
<?php
|
||||
|
||||
use Automata\Machine;
|
||||
use Automata\Tool;
|
||||
use Automata\ToolData;
|
||||
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
$machine = new Machine();
|
||||
$machine->toolMemory->save(new Tool(1, 5500, 2));
|
||||
$machine->toolMemory->save(new Tool(2, 3000, 61379));
|
||||
$machine->TM->write(new ToolData(1, 5500, 2));
|
||||
$machine->TM->write(new ToolData(2, 3000, 61379));
|
||||
(new ProgramLoader)->loadPrograms($machine);
|
||||
|
||||
$machine->loadProgram(9002);
|
||||
$machine->start();
|
||||
while ($machine->PPMC->ready()) {
|
||||
$machine->step();
|
||||
}
|
||||
|
BIN
ref/block_structure.jpeg
Normal file
BIN
ref/block_structure.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 151 KiB |
BIN
ref/program_code_1.jpeg
Normal file
BIN
ref/program_code_1.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 171 KiB |
BIN
ref/program_code_2.jpeg
Normal file
BIN
ref/program_code_2.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 160 KiB |
BIN
ref/program_code_3.jpeg
Normal file
BIN
ref/program_code_3.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 129 KiB |
BIN
ref/programmable_words.jpeg
Normal file
BIN
ref/programmable_words.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 160 KiB |
BIN
ref/spindle_speeds.jpeg
Normal file
BIN
ref/spindle_speeds.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 97 KiB |
@ -2,7 +2,7 @@
|
||||
|
||||
namespace Automata;
|
||||
|
||||
class Registers
|
||||
class DataRegisters
|
||||
{
|
||||
public int $B = 0; // Traverse information
|
||||
public int $X = 0; // Dimension along X-axis
|
||||
@ -17,5 +17,14 @@ class Registers
|
||||
public int $T = 0; // Tool number
|
||||
public int $H = 0; // Additional functions (unused)
|
||||
public int $M = 0; // Auxiliary functions
|
||||
public int $E = 0; // Number of repetitions / multiple meanins
|
||||
public int $E = 0; // Number of repetitions / multiple meanings
|
||||
// Modals
|
||||
public int $TM = 0; // Traverse (0, 1, 2, 3)
|
||||
public int $PS = 18; // Plane Selection (18, 19, 20)
|
||||
public int $RC = 40; // Radius Compensation
|
||||
public int $DM = 90; // Dimension (90, 91)
|
||||
public int $WC = 0; // Work Cycle (null, 81, 84, 85, 86)
|
||||
public int $CM = 8; // Coolant (8, 9)
|
||||
public int $SM = 5; // Spindle (3, 4, 5)
|
||||
public int $TC = 10; // Table Clamping (10, 11)
|
||||
}
|
41
src/Automata/InstructionSet.php
Normal file
41
src/Automata/InstructionSet.php
Normal file
@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Automata;
|
||||
|
||||
use Program\Block;
|
||||
|
||||
class InstructionSet
|
||||
{
|
||||
private Machine $machine;
|
||||
/** @var callable<Machine>[] */
|
||||
private array $map;
|
||||
|
||||
|
||||
public function __construct(Machine $machine)
|
||||
{
|
||||
$this->machine = $machine;
|
||||
$this->map = [];
|
||||
}
|
||||
|
||||
|
||||
public function apply(Block $block): void
|
||||
{
|
||||
$words = $block->words;
|
||||
while ($word = array_shift($words)) {
|
||||
$method = "{$word}";
|
||||
if (!method_exists($this, $method)) {
|
||||
continue;
|
||||
}
|
||||
$this->{$method}($block);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function G22(Block $block): void
|
||||
{
|
||||
$number = $block->valueOf('X');
|
||||
$this->machine->SPMC->loadProgram($number);
|
||||
$this->machine->AMC = $this->machine->SPMC;
|
||||
}
|
||||
}
|
@ -2,79 +2,57 @@
|
||||
|
||||
namespace Automata;
|
||||
|
||||
use Automata\Storage\ProgramMemory;
|
||||
use Automata\Storage\ToolMemory;
|
||||
use Program\Block;
|
||||
use Program\Program;
|
||||
use Program\Word;
|
||||
use RuntimeException;
|
||||
use SplStack;
|
||||
use Automata\Memory\MemoryController;
|
||||
use Automata\Memory\ProgramMemory;
|
||||
use Automata\Memory\ToolMemory;
|
||||
|
||||
/*
|
||||
* executing a program:
|
||||
* - load parts program
|
||||
* - execute line by line
|
||||
* - load sub program
|
||||
* - execute lines from subprogram
|
||||
* - back to parts program
|
||||
*/
|
||||
class Machine
|
||||
{
|
||||
public State $state;
|
||||
public ToolMemory $toolMemory;
|
||||
public ProgramMemory $subProgramMemory;
|
||||
public ProgramMemory $partProgramMemory;
|
||||
/** @var SplStack|Program[] */
|
||||
private SplStack $programStack;
|
||||
private ?Program $activeProgram = null;
|
||||
private Definitions $definitions;
|
||||
public DataRegisters $DR;
|
||||
public InstructionSet $IS;
|
||||
public ToolMemory $TM;
|
||||
public ProgramMemory $SPM;
|
||||
public ProgramMemory $PPM;
|
||||
public MemoryController $SPMC;
|
||||
public MemoryController $PPMC;
|
||||
public ?MemoryController $AMC;
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->state = new State();
|
||||
$this->definitions = new Definitions();
|
||||
$this->toolMemory = new ToolMemory();
|
||||
$this->subProgramMemory = new ProgramMemory();
|
||||
$this->partProgramMemory = new ProgramMemory();
|
||||
$this->programStack = new SplStack();
|
||||
$this->DR = new DataRegisters();
|
||||
$this->IS = new InstructionSet($this);
|
||||
$this->TM = new ToolMemory();
|
||||
$this->SPM = new ProgramMemory();
|
||||
$this->PPM = new ProgramMemory();
|
||||
$this->SPMC = new MemoryController($this->SPM);
|
||||
$this->PPMC = new MemoryController($this->PPM);
|
||||
$this->AMC = $this->PPMC;
|
||||
}
|
||||
|
||||
|
||||
public function loadProgram(int $N): void
|
||||
{
|
||||
$this->programStack = new SplStack();
|
||||
$program = $this->partProgramMemory->read($N);
|
||||
$this->programStack->push($program);
|
||||
$this->PPMC->loadProgram($N);
|
||||
$this->AMC = $this->PPMC;
|
||||
}
|
||||
|
||||
|
||||
public function start(): void
|
||||
public function step(): void
|
||||
{
|
||||
$this->activeProgram = $this->programStack->pop();
|
||||
if (is_null($this->activeProgram)) {
|
||||
throw new RuntimeException('No program loaded');
|
||||
}
|
||||
foreach ($this->activeProgram as $block) {
|
||||
$this->executeBlock($block);
|
||||
}
|
||||
}
|
||||
|
||||
private function executeBlock(Block $block): void
|
||||
{
|
||||
/** @var Word[] $words */
|
||||
$words = $block->words;
|
||||
while ($word = array_shift($words)) {
|
||||
$this->state->apply($word);
|
||||
system('clear');
|
||||
dump($this->state);
|
||||
readline();
|
||||
$block = $this->AMC->next();
|
||||
if (is_null($block) && $this->AMC === $this->SPMC) {
|
||||
// SP ended, back to PP
|
||||
$this->AMC = $this->PPMC;
|
||||
$block = $this->AMC->next();
|
||||
}
|
||||
$this->IS->apply($block);
|
||||
}
|
||||
|
||||
|
||||
public function reset(): void
|
||||
{
|
||||
$this->activeProgram = null;
|
||||
$this->PPMC->reset();
|
||||
$this->SPMC->reset();
|
||||
}
|
||||
}
|
||||
|
66
src/Automata/Memory/MemoryController.php
Normal file
66
src/Automata/Memory/MemoryController.php
Normal file
@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
namespace Automata\Memory;
|
||||
|
||||
use Countable;
|
||||
use InvalidArgumentException;
|
||||
use Program\Block;
|
||||
use RuntimeException;
|
||||
|
||||
class MemoryController implements Countable
|
||||
{
|
||||
private ProgramMemory $memory;
|
||||
/** @var Block[]|null */
|
||||
private ?array $blocks;
|
||||
|
||||
|
||||
public function __construct(ProgramMemory $memory)
|
||||
{
|
||||
$this->memory = $memory;
|
||||
$this->blocks = null;
|
||||
}
|
||||
|
||||
|
||||
public function loadProgram(int $N): void
|
||||
{
|
||||
$program = $this->memory->read($N);
|
||||
if (!$program) {
|
||||
throw new InvalidArgumentException("Program N{$N} not found");
|
||||
}
|
||||
$this->blocks = $program->getIterator()->getArrayCopy();
|
||||
}
|
||||
|
||||
|
||||
public function reset(): void
|
||||
{
|
||||
$this->blocks = null;
|
||||
}
|
||||
|
||||
|
||||
public function count()
|
||||
{
|
||||
return count($this->blocks);
|
||||
}
|
||||
|
||||
|
||||
public function next(): ?Block
|
||||
{
|
||||
$this->guardNoProgramLoaded();
|
||||
|
||||
return array_shift($this->blocks);
|
||||
}
|
||||
|
||||
|
||||
public function ready(): bool
|
||||
{
|
||||
return !empty($this->blocks);
|
||||
}
|
||||
|
||||
|
||||
private function guardNoProgramLoaded(): void
|
||||
{
|
||||
if (is_null($this->blocks)) {
|
||||
throw new RuntimeException('No program loaded in memory');
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace Automata\Storage;
|
||||
namespace Automata\Memory;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Program\Program;
|
||||
@ -11,7 +11,7 @@ class ProgramMemory
|
||||
private array $memory = [];
|
||||
|
||||
|
||||
public function save(Program $program): void
|
||||
public function write(Program $program): void
|
||||
{
|
||||
$this->guardInvalidProgramNumber($program->N);
|
||||
$this->memory[$program->N] = $program;
|
||||
@ -30,5 +30,4 @@ class ProgramMemory
|
||||
throw new InvalidArgumentException('Program number must be in range 9001 - 9998');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,24 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Automata\Storage;
|
||||
namespace Automata\Memory;
|
||||
|
||||
use Automata\Tool;
|
||||
use Automata\ToolData;
|
||||
use InvalidArgumentException;
|
||||
|
||||
class ToolMemory
|
||||
{
|
||||
/** @var Tool[] */
|
||||
/** @var ToolData[] */
|
||||
private array $memory = [];
|
||||
|
||||
|
||||
public function save(Tool $tool): void
|
||||
public function write(ToolData $tool): void
|
||||
{
|
||||
$this->guardInvalidToolNumber($tool->T);
|
||||
$this->memory[$tool->T] = $tool;
|
||||
}
|
||||
|
||||
|
||||
public function read(int $T): ?Tool
|
||||
public function read(int $T): ?ToolData
|
||||
{
|
||||
return @$this->memory[$T];
|
||||
}
|
||||
@ -30,5 +30,4 @@ class ToolMemory
|
||||
throw new InvalidArgumentException('Tool number must be in range 1 - 64');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Automata;
|
||||
|
||||
use Automata\Modes\G\DimensionMode;
|
||||
use Automata\Modes\G\PlaneSelection;
|
||||
use Automata\Modes\G\RadiusCompensation;
|
||||
use Automata\Modes\G\TraverseMode;
|
||||
use Automata\Modes\G\WorkCycle;
|
||||
use Automata\Modes\M\CoolantMode;
|
||||
use Automata\Modes\M\SpindleMode;
|
||||
use Automata\Modes\M\TableClampingMode;
|
||||
use Program\Word;
|
||||
|
||||
class State
|
||||
{
|
||||
public Registers $registers;
|
||||
// G
|
||||
public TraverseMode $traverseMode;
|
||||
public PlaneSelection $planeSelection;
|
||||
public RadiusCompensation $radiusCompensation;
|
||||
public DimensionMode $dimensionMode;
|
||||
public WorkCycle $workCycleSelection;
|
||||
// M
|
||||
public CoolantMode $coolantMode;
|
||||
public SpindleMode $spindleMode;
|
||||
public TableClampingMode $tableClamping;
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->registers = new Registers();
|
||||
$this->traverseMode = new TraverseMode(0);
|
||||
$this->planeSelection = new PlaneSelection(17);
|
||||
$this->radiusCompensation = new RadiusCompensation(40);
|
||||
$this->dimensionMode = new DimensionMode(90);
|
||||
$this->workCycleSelection = new WorkCycle(0);
|
||||
|
||||
$this->coolantMode = new CoolantMode(9);
|
||||
$this->spindleMode = new SpindleMode(5);
|
||||
$this->tableClamping = new TableClampingMode(10);
|
||||
}
|
||||
|
||||
|
||||
public function apply(Word $word): void
|
||||
{
|
||||
if ($word->register === 'G') {
|
||||
$this->traverseMode->apply($word->value);
|
||||
$this->planeSelection->apply($word->value);
|
||||
$this->radiusCompensation->apply($word->value);
|
||||
$this->dimensionMode->apply($word->value);
|
||||
$this->workCycleSelection->apply($word->value);
|
||||
|
||||
// TODO Handle other G commands
|
||||
|
||||
return;
|
||||
}
|
||||
if ($word->register === 'M') {
|
||||
$this->coolantMode->apply($word->value);
|
||||
$this->spindleMode->apply($word->value);
|
||||
$this->tableClamping->apply($word->value);
|
||||
|
||||
// TODO Handle other M commands
|
||||
return;
|
||||
}
|
||||
|
||||
if (property_exists($this->registers, $word->register)) {
|
||||
$this->registers->{$word->register} = $word->value;
|
||||
}
|
||||
}
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace Automata;
|
||||
|
||||
class Tool
|
||||
class ToolData
|
||||
{
|
||||
public int $T; // Tool number
|
||||
public int $X; // Radius in 0.001 mm
|
@ -2,6 +2,8 @@
|
||||
|
||||
namespace Program;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class Block
|
||||
{
|
||||
public string $N;
|
||||
@ -20,4 +22,27 @@ class Block
|
||||
{
|
||||
$this->words[] = $word;
|
||||
}
|
||||
|
||||
|
||||
public function valueOf(string $register): int
|
||||
{
|
||||
foreach ($this->words as $word) {
|
||||
if ($word->register === $register) {
|
||||
return $word->value;
|
||||
}
|
||||
}
|
||||
|
||||
throw new RuntimeException("No word in block for register '$register'");
|
||||
}
|
||||
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
$buffer = "$this->N\t";
|
||||
foreach ($this->words as $word) {
|
||||
$buffer .= "$word\t";
|
||||
}
|
||||
|
||||
return $buffer;
|
||||
}
|
||||
}
|
||||
|
@ -11,12 +11,12 @@ class ProgramLoader
|
||||
|
||||
foreach (glob(__DIR__ . '/../programs/part/*') as $partProgramFile) {
|
||||
$partProgram = $parser->parseFile($partProgramFile);
|
||||
$machine->partProgramMemory->save($partProgram);
|
||||
$machine->PPM->write($partProgram);
|
||||
}
|
||||
|
||||
foreach (glob(__DIR__ . '/../programs/sub/*') as $subProgramFile) {
|
||||
$subProgram = $parser->parseFile($subProgramFile);
|
||||
$machine->subProgramMemory->save($subProgram);
|
||||
$machine->SPM->write($subProgram);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user