Completed
Push — master ( a1dfae...853db6 )
by Roberto
06:19 queued 03:11
created

DefaultPrinter::lineFeed()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2

Importance

Changes 4
Bugs 0 Features 0
Metric Value
c 4
b 0
f 0
dl 0
loc 9
ccs 7
cts 7
cp 1
rs 9.6666
cc 2
eloc 6
nc 2
nop 1
crap 2
1
<?php
2
3
namespace Posprint\Printers;
4
5
/*
6
 * Default class for POS thermal printers.
7
 * 
8
 * From this class all other are extended.
9
 * In the child classes should be included all the commands that are different
10
 * from those in this class, especially those specific to particular brand and 
11
 * model of printer
12
 * 
13
 * NOTE: It was built around the commands of the Epson TM-T20,
14
 * so in theory the Epson class will be almost empty just extending this class.
15
 * 
16
 * CodePage default WINDOWS-1250
17
 * CountyPage default LATIN
18
 * 
19
 * @category   NFePHP
20
 * @package    Posprint
21
 * @copyright  Copyright (c) 2016
22
 * @license    http://www.gnu.org/licenses/lesser.html LGPL v3
23
 * @author     Roberto L. Machado <linux.rlm at gmail dot com>
24
 * @link       http://github.com/nfephp-org/posprint for the canonical source repository
25
 */
26
27
use Posprint\Connectors\ConnectorInterface;
28
use Posprint\Connectors\Buffer;
29
use Posprint\Graphics\Graphics;
30
use RuntimeException;
31
use InvalidArgumentException;
32
33
abstract class DefaultPrinter implements PrinterInterface
34
{
35
    //set standards
36
    const NUL = "\x0"; //Nulo
37
    const EOT = "\x4"; //EOT fim da transmissão
38
    const ENQ = "\x5"; //ENQ colocar na fila Pedido de status 1
39
    const HT = "\x9"; //tabulação horizontal
40
    const VT = "\xb"; //tabulação vertical
41
    const LF = "\x0a"; //Inicia a impressão e avança uma linha
42
    const FF = "\x0c"; //avança pagina
43
    const CR = "\x0d"; //retorno de carro
44
    const DLE = "\x10"; //Data Link Escape
45
    const CAN = "\x18"; //CAN Cancela linha enviada
46
    const BEL = "\x07"; //BEL sinal sonoro
47
    const ESC = "\x1b"; //escape
48
    const FS = "\x1c"; //FS
49
    const GS = "\x1d"; //GS
50
    const SO = "\x0e"; //SO Inicia modo expandido
51
    const DC1 = "\x11"; //DC1 Inicia modo enfatizado
52
    const DC2 = "\x12"; //DC2 Cancela modo condensado
53
    const DC3 = "\x13"; //DC3 Cancela modo enfatizado
54
    const DC4 = "\x14"; //DC4 Controle de dispositivo 4 Inicia modo normal
55
    const SI = "\x0f"; //Seleciona modo condensado
56
    const EM = "\x19"; //Avança 4 linhas
57
    const DEL = "\x7f"; //Cancela último caracter
58
    const SYN = "\x16"; //Sincronismo
59
    const NOTRANS = false; //not translate characters codepage
60
    const TRANS = true; //perform a character convertion to codepage
61
62
    // Cut types 
63
    const CUT_FULL = 65;
64
    const CUT_PARTIAL = 66;
65
66
    //1D barcode types
67
    const UPC_A = 'A';
68
    const UPC_E = 'B';
69
    const EAN13 = 'C';
70
    const EAN8 = 'D';
71
    const CODE39 = 'E';
72
    const ITF = 'F';
73
    const CODABAR = 'G';
74
    const CODE93 = 'H';
75
    const CODE128 = 'I';
76
    const GS1_128 = 'J';
77
    const GS1_DataBar_Omnidirectional = 'K';
78
    const GS1_DataBar_Truncated = 'L';
79
    const GS1_DataBar_Limited = 'M';
80
    const GS1_DataBar_Expanded = 'N';
81
82
    /**
83
     * List all available region pages.
84
     *
85
     * @var array
86
     */
87
    protected $aRegion = array(
88
        'USA',
89
        'FRANCE',
90
        'GERMANY',
91
        'UK',
92
        'DENMARK',
93
        'SWEDEN',
94
        'ITALY',
95
        'SPAIN',
96
        'JAPAN',
97
        'NORWAY',
98
        'DENMARK2',
99
        'SPAIN2',
100
        'LATIN',
101
        'KOREA',
102
        'SLOVENIA',
103
        'CHINA',
104
        'VIETNAM',
105
        'ARABIA',
106
    );
107
108
    /**
109
     * List all available code pages.
110
     *
111
     * @var array
112
     */
113
    protected $aCodePage = array(
114
        'CP437' => array('conv' => '437', 'table' => '0', 'desc' => 'PC437: USA, Standard Europe'),
115
        'CP850' => array('conv' => '850', 'table' => '2', 'desc' => 'PC850: Multilingual'),
116
        'CP860' => array('conv' => '860', 'table' => '3', 'desc' => 'PC860: Portuguese'),
117
        'CP863' => array('conv' => '863', 'table' => '4', 'desc' => 'PC863: Canadian-French'),
118
        'CP865' => array('conv' => '865', 'table' => '5', 'desc' => 'PC865: Nordic'),
119
        'CP851' => array('conv' => '851', 'table' => '11', 'desc' => 'PC851: Greek'),
120
        'CP853' => array('conv' => '853', 'table' => '12', 'desc' => 'PC853: Turkish'),
121
        'CP857' => array('conv' => '857', 'table' => '13', 'desc' => 'PC857: Turkish'),
122
        'CP737' => array('conv' => '737', 'table' => '14', 'desc' => 'PC737: Greek'),
123
        'ISO8859-7' => array('conv' => 'ISO8859-7', 'table' => '15', 'desc' => 'ISO8859-7: Greek'),
124
        'CP866' => array('conv' => '866', 'table' => '17', 'desc' => 'PC866: Cyrillic #2'),
125
        'CP852' => array('conv' => '852', 'table' => '18', 'desc' => 'PC852: Latin2'),
126
        'CP858' => array('conv' => '858', 'table' => '19', 'desc' => 'PC858: Euro'),
127
        'CP720' => array('conv' => '720', 'table' => '32', 'desc' => 'PC720: Arabic'),
128
        'CP855' => array('conv' => '855', 'table' => '34', 'desc' => 'PC855: Cyrillic'),
129
        'CP861' => array('conv' => '861', 'table' => '35', 'desc' => 'PC861: Icelandic'),
130
        'CP862' => array('conv' => '862', 'table' => '36', 'desc' => 'PC862: Hebrew'),
131
        'CP864' => array('conv' => '864', 'table' => '37', 'desc' => 'PC864: Arabic'),
132
        'CP869' => array('conv' => '869', 'table' => '38', 'desc' => 'PC869: Greek'),
133
        'ISO8859-2' => array('conv' => 'ISO8859-2', 'table' => '39', 'desc' => 'ISO8859-2: Latin2'),
134
        'ISO8859-15' => array('conv' => 'ISO8859-15', 'table' => '40', 'desc' => 'ISO8859-15: Latin9'),
135
        'WINDOWS-1250' => array('conv' => 'WINDOWS-1250', 'table' => '45', 'desc' => 'WPC1250: Latin2'),
136
        'WINDOWS-1251' => array('conv' => 'WINDOWS-1251', 'table' => '46', 'desc' => 'WPC1251: Cyrillic'),
137
        'WINDOWS-1252' => array('conv' => 'WINDOWS-1252', 'table' => '47', 'desc' => 'WPC1253: Greek'),
138
        'WINDOWS-1254' => array('conv' => 'WINDOWS-1254', 'table' => '48', 'desc' => 'WPC1254: Turkish'),
139
        'WINDOWS-1255' => array('conv' => 'WINDOWS-1255', 'table' => '49', 'desc' => 'WPC1255: Hebrew'),
140
        'WINDOWS-1256' => array('conv' => 'WINDOWS-1256', 'table' => '50', 'desc' => 'WPC1256: Arabic'),
141
        'WINDOWS-1257' => array('conv' => 'WINDOWS-1257', 'table' => '51', 'desc' => 'WPC1257: Baltic Rim'),
142
        'WINDOWS-1258' => array('conv' => 'WINDOWS-1258', 'table' => '52', 'desc' => 'WPC1258: Vietnamese'),
143
    );
144
    /**
145
     * Seleted code page
146
     * Defined in printer class.
147
     *
148
     * @var string
149
     */
150
    protected $codepage = 'CP437';
151
    /**
152
     * Number of codpage in printer memory.
153
     *
154
     * @var int
155
     */
156
    protected $charsetTableNum = 0;
157
    /**
158
     * Selected Region character page
159
     * Defined in printer class.
160
     *
161
     * @var string
162
     */
163
    protected $region = 'LATIN';
164
    /**
165
     * List all avaiable fonts
166
     * @var array
167
     */
168
    protected $aFont = array(0 => 'A', 1 => 'B', 2 => 'C', 3 => 'D', 4 => 'E', 97 => 'SA', 98 => 'SB');
169
    /**
170
     * Selected internal font.
171
     *
172
     * @var string
173
     */
174
    protected $font = 'A';           
175
    /**
176
     * Resolution in dpi.
177
     *
178
     * @var int
179
     */
180
    public $dpi = 203; //dots per inch
181
    /**
182
     * Resolution in dpmm.
183
     *
184
     * @var int
185
     */
186
    public $dpmm = 8; //dots per mm
187
    /**
188
     * Maximum width paper.
189
     *
190
     * @var int
191
     */
192
    public $widthMaxmm = 80;//mm
193
    /**
194
     * Selected Width paper.
195
     *
196
     * @var int
197
     */
198
    public $widthPaper = 80;//mm
199
    /**
200
     * Maximum width for printed area.
201
     *
202
     * @var int
203
     */
204
    public $widthPrint = 72;//mm
205
    /**
206
     * Maximum width for printed area in dots.
207
     *
208
     * @var int
209
     */
210
    public $widthMaxdots = 576;//dots
211
    /**
212
     * Maximum number of characters per line.
213
     *
214
     * @var int
215
     */
216
    public $maxchars = 48;//max characters per line
217
218
    //protected property standards
219
    /**
220
     * Connector to printer.
221
     *
222
     * @var ConnectosInterface
223
     */
224
    protected $connector = null;
225
    /**
226
     * Seleted printer mode.
227
     *
228
     * @var string
229
     */
230
    protected $printerMode = 'normal';
231
    /**
232
     * Selected bold mode.
233
     *
234
     * @var bool
235
     */
236
    protected $boldMode = false;
237
    /**
238
     * Selected reverse colors mode.
239
     *
240
     * @var bool
241
     */
242
    protected $reverseColors = false;
243
    /**
244
     * Selected under lined mode.
245
     * 
246
     * @var bool
247
     */
248
    protected $underlineMode = false;
249
    /**
250
     * Selected rotate 90 degrees mode
251
     * @var bool
252
     */
253
    protected $rotateMode = false;
254
    /**
255
     * Buffer class.
256
     *
257
     * @var Connectors\Buffer
258
     */
259
    protected $buffer = null;
260
261
    /**
262
     * Class constructor
263
     * Instantiates the data buffer.
264
     *
265
     * @param ConnectorInterface $conn
266
     */
267 24
    public function __construct(ConnectorInterface $conn = null)
268
    {
269 24
        if (!is_null($conn)) {
270
            $this->connector = $conn;
0 ignored issues
show
Documentation Bug introduced by
It seems like $conn of type object<Posprint\Connectors\ConnectorInterface> is incompatible with the declared type object<Posprint\Printers\ConnectosInterface> of property $connector.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
271
        }
272 24
        $this->buffer = new Buffer();
0 ignored issues
show
Documentation Bug introduced by
It seems like new \Posprint\Connectors\Buffer() of type object<Posprint\Connectors\Buffer> is incompatible with the declared type object<Posprint\Printers\Connectors\Buffer> of property $buffer.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
273 24
    }
274
275
    /**
276
     * Returns a default region for codepage
277
     * if param $region is null will return actual default region from class
278
     * if param $region is 'all' will return a array with all avaiable regions
279
     * if param $region is a string will set the region parameter of class and returns it.
280
     * NOTE: This command do not set the printer, only class parameters
281
     * 
282
     * @param string $region
283
     * @return string|array
284
     */
285 2
    public function defaultRegionPage($region = null)
286
    {
287 2
        if (!is_null($region)) {
288 2
            $region = strtoupper(trim($region));
289 2
            if ($region == 'ALL') {
290 1
                return $this->aRegion;
291
            }
292 2
            $reg = array_search($region, $this->aRegion, true);
293 2
            if ($reg !== false) {
294 2
                $this->region = $region;
295 2
            }
296 2
        }
297 2
        return $this->region;
298
    }
299
300
    /**
301
     * Returns a default codepage
302
     * if param $codepage is null will return actual default codepage from class
303
     * if param $codepage is 'all' will return a array with all avaiable codepages
304
     * if param $codepage is a string will set the codepage parameter of class and returns it.
305
     * NOTE: This command do not set the printer, only class parameters
306
     * 
307
     * @param string $codepage
308
     * @return string|array
309
     */
310 21
    public function defaultCodePage($codepage = null)
311
    {
312 21
        if (!is_null($codepage)) {
313 21
            $codepage = strtoupper(trim($codepage));
314 21
            if ($codepage == 'ALL') {
315 1
                return array_keys($this->aCodePage);
316
            }
317 21
            if (array_key_exists($codepage, $this->aCodePage)) {
318 3
                $this->codepage = $codepage;
319 3
                $table = $this->aCodePage[$codepage];
320 3
                $this->charsetTableNum = $table['table'];
321 3
            }
322 21
        }
323 21
        return $this->codepage;
324
    }
325
326
    /**
327
     * Set a codepage table in printer.
328
     *
329
     * @param string $codepage
330
     */
331 2
    public function setCodePage($codepage = null)
332
    {
333 2
        $codepage = $this->defaultCodePage($codepage);
0 ignored issues
show
Unused Code introduced by
$codepage is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
334 2
        $this->buffer->write(self::ESC.'t'.chr($this->charsetTableNum));
335 2
    }
336
337
    /**
338
     * Set a region page.
339
     * The numeric key of array $this->aRegion is the command parameter.
340
     *
341
     * @param string $region
342
     */
343 1
    public function setRegionPage($region = null)
344
    {
345 1
        $region = $this->defaultRegionPage($region);
346 1
        $mode = array_keys($this->aRegion, $region, true);
347 1
        $this->buffer->write(self::ESC.'R'.chr($mode[0]));
348 1
    }
349
    
350
    /**
351
     * Returns the default printer font 
352
     * A - Font A (12 x 24)
353
     * B - Font B (9 x 17)
354
     * C - Font C
355
     * D - Font D
356
     * E - Font E
357
     * Special A
358
     * Special B
359
     * Default Font A.
360
     * if param $font is null will return actual default font from class
361
     * if param $font is 'all' will return a array with all avaiable printer fonts
362
     * if param $font is a string will set the font parameter of class and returns it.
363
     * NOTE: This command do not set the printer, only class parameters
364
     * 
365
     * @param string $font
366
     * @return array|string
367
     */
368 2
    public function defaultFont($font = null)
369
    {
370 2
        if (!is_null($font)) {
371 2
            $font = strtoupper(trim($font));
372 2
            if ($font == 'ALL') {
373
                //return array
374
                return $this->aFont;
375
            }
376
            //set $this->font
377 2
            $fonts = array_flip($this->aFont);
378 2
            $keys = array_keys($fonts);
379 2
            $reg = array_search($font, $keys, true);
380 2
            if ($reg !== false) {
381 2
                $this->font = $font;
382 2
            }
383 2
        }
384 2
        return $this->font;
385
    }
386
    
387
    /**
388
     * Set a printer font 
389
     * If send a valid font name will set the printer otherelse a default font is selected
390
     * @param string $font
391
     */
392 1
    public function setFont($font = null)
393
    {
394 1
        $font = $this->defaultFont($font);
395 1
        $mode = array_keys($this->aFont, $font, true);
396 1
        $this->buffer->write(self::ESC.'M'.chr($mode[0]));
397 1
    }
398
399
    /**
400
     * Set emphasys mode on or off.
401
     */
402 1
    public function setBold()
403
    {
404 1
        if ($this->boldMode) {
405 1
            $this->boldMode = false;
406 1
            $mode = 0;
407 1
        } else {
408 1
            $this->boldMode = true;
409 1
            $mode = 1;
410
        }
411 1
        $this->buffer->write(self::ESC . 'E' . chr($mode));
412 1
    }
413
414
    /**
415
     * Set underline mode on or off.
416
     */
417 1
    public function setUnderlined()
418
    {
419 1
        if ($this->underlineMode) {
420 1
            $this->underlineMode = false;
421 1
            $mode = 0;
422 1
        } else {
423 1
            $this->underlineMode = true;
424 1
            $mode = 1;
425
        }
426 1
        $this->buffer->write(self::ESC . '-' . chr($mode));
427 1
    }
428
429
    /**
430
     * Aligns all data in one line to the selected layout in standard mode.
431
     * L - left  C - center  R - rigth
432
     * 
433
     * @param string $align 
434
     */
435 1
    public function setAlign($align = null)
436
    {
437 1
        if (is_null($align)) {
438
            $align = 'L';
439
        }
440 1
        $value = strtoupper($align);
441
        switch ($value) {
442 1
            case 'C':
443 1
               $mode = 1;
444 1
               break;
445 1
            case 'R':
446
               $mode = 2;
447
               break;
448 1
            default:
449 1
                $mode = 0;
450 1
        }
451 1
        $this->buffer->write(self::ESC . 'a' . chr($mode));
452 1
    }
453
    
454
    /**
455
     * Turns white/black reverse print On or Off for characters.
456
     * n = odd: On, n = even: Off.
457
     */
458 1
    public function setReverseColors()
459
    {
460 1
        if ($this->reverseColors) {
461 1
            $this->reverseColors = false;
462 1
            $mode = 0;
463 1
        } else {
464 1
            $this->reverseColors = true;
465 1
            $mode = 1;
466
        }
467 1
        $this->buffer->write(self::GS.'B'.chr($mode));
468 1
    }
469
    
470
    /**
471
     * Set expanded mode.
472
     * @param int $size multiplies normal size 1 - 8 
473
     */
474 1
    public function setExpanded($size = null)
475
    {
476 1
        $size = self::validateInteger($size, 1, 8, 1);
477
        $aSize = [
478 1
            [0, 0],
479 1
            [16, 1],
480 1
            [32, 2],
481 1
            [48, 3],
482 1
            [64, 4],
483 1
            [80, 5],
484 1
            [96, 6],
485 1
            [112, 7]
486 1
        ];
487 1
        $mode = $aSize[$size-1][0] + $aSize[$size-1][1];
488 1
        $this->buffer->write(self::ESC.'!'.chr($mode));
489 1
    }
490
491
    /**
492
     * Set condensed mode.
493
     */
494
    public function setCondensed()
495
    {
496
        $this->setExpanded(1);
497
        $this->setFont('B');
498
    }
499
    
500
501
    /**
502
     * Set the printer mode.
503
     */
504
    abstract public function setPrintMode($mode = null);
505
506
    /**
507
     * Set rotate 90 degrees.
508
     */
509 1
    public function setRotate90()
510
    {
511 1
        if ($this->rotateMode) {
512 1
            $this->rotateMode = false;
513 1
            $mode = 0;
514 1
        } else {
515 1
            $this->rotateMode = true;
516 1
            $mode = 1;
517
        }
518 1
        $this->buffer->write(self::ESC.'V'.chr($mode));
519 1
    }
520
    
521
    /**
522
     * initialize printer
523
     * Clears the data in the print buffer and resets the printer modes to 
524
     * the modes that were in effect when the power was turned on.
525
     */
526 20
    public function initialize()
527
    {
528 20
        $this->buffer->write(self::ESC.'@');
529 20
        $this->rotateMode = false;
530 20
        $this->defaultCodePage('CP470');
531 20
        $this->underlineMode = false;
532 20
        $this->boldMode = false;
533 20
        $this->printerMode = 'normal';
534 20
        $this->font = 'A';
535 20
    }
536
    
537
    /**
538
     * Send message or command to buffer
539
     * when sending commands is not required to convert characters,
540
     * so the variable may translate by false.
541
     * 
542
     * @param string $text
543
     */
544 1
    public function text($text = '')
545
    {
546 1
        $text = $this->translate($text);
547 1
        $this->buffer->write($text);
548 1
    }
549
550
    /**
551
     * Set horizontal and vertical motion units
552
     * $horizontal => character spacing 1/x"
553
     * $vertical => line spacing 1/y".
554
     *
555
     * @param int $horizontal
556
     * @param int $vertical
557
     */
558 1
    public function setSpacing($horizontal = 30, $vertical = 30)
559
    {
560 1
        $horizontal = self::validateInteger($horizontal, 0, 255, 30);
561 1
        $vertical = self::validateInteger($vertical, 0, 255, 30);
562 1
        $this->buffer->write(self::GS.'P'.chr($horizontal).chr($vertical));
563 1
    }
564
565
    /**
566
     * Set right-side character spacing
567
     * 0 ≤ n ≤ 255 => 1/x".
568
     * 
569
     * @param int $value
570
     */
571 1
    public function setCharSpacing($value = 3)
572
    {
573 1
        $value = self::validateInteger($value, 0, 255, 0);
574 1
        $this->buffer->write(self::ESC.' '.chr($value));
575 1
    }
576
577
    /**
578
     * Line spacing
579
     * The default is set to zero and 30/180 "
580
     * any different number of zero will generate multiples of.
581
     * n  1/180-inch vertical motion
582
     * normal paragraph 30/180" => 4.23 mm
583
     * 
584
     * @param int $paragraph
0 ignored issues
show
Bug introduced by
There is no parameter named $paragraph. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
585
     */
586 1
    public function setParagraph($value = 0)
587
    {  
588 1
        $value = self::validateInteger($value, 0, 255, 0);
589 1
        $paragraph = ceil($value);
590 1
        if ($paragraph == 0) {
591 1
            $this->buffer->write(self::ESC.'2');
592 1
            return;
593
        }
594 1
        if ($paragraph < 25) {
595
            $paragraph = 25;
596 1
        } elseif ($paragraph > 255) {
597
            $paragraph = 255;
598
        }
599 1
        $this->buffer->write(self::ESC.'3'.chr($paragraph));
600 1
    }
601
602
    /**
603
     * Prints data and feeds paper n lines
604
     * ESC d n Prints data and feeds paper n lines.
605
     *
606
     * @param type $lines
607
     */
608 1
    public function lineFeed($lines = 1)
609
    {
610 1
        $lines = self::validateInteger($lines, 0, 255, 1);
611 1
        if ($lines == 1) {
612 1
            $this->buffer->write(self::LF);
613 1
            return;
614
        }
615 1
        $this->buffer->write(self::ESC.'d'.chr($lines));
616 1
    }
617
618
    /**
619
     * Prints data and feeds paper n dots
620
     * ESC J n Prints data and feeds paper n dots.
621
     *
622
     * @param int $dots
623
     */
624 1
    public function dotFeed($dots = 1)
625
    {
626 1
        $dots = self::validateInteger($dots, 0, 80, 0);
627 1
        $this->buffer->write(self::ESC.'J'.chr($dots));
628 1
    }
629
630
    /**
631
     * Generate a pulse, for opening a cash drawer if one is connected.
632
     * The default settings should open an Epson drawer.
633
     *
634
     * @param int $pin    0 or 1, for pin 2 or pin 5 kick-out connector respectively.
635
     * @param int $on_ms  pulse ON time, in milliseconds.
636
     * @param int $off_ms pulse OFF time, in milliseconds.
637
     */
638 1
    public function pulse($pin = 0, $on_ms = 120, $off_ms = 240)
639
    {
640 1
        $pin = self::validateInteger($pin, 0, 1, 0);
641 1
        $on_ms = self::validateInteger($on_ms, 1, 511, 120);
642 1
        $off_ms = self::validateInteger($off_ms, 1, 511, 240);
643 1
        $this->buffer->write(self::ESC.'p'.chr($pin + 48).chr($on_ms / 2).chr($off_ms / 2));
644 1
    }
645
646
    /**
647
     * Cut the paper.
648
     *
649
     * @param int $mode  FULL or PARTIAL. If not specified, FULL will be used. 
650
     * @param int $lines Number of lines to feed after cut
651
     */
652 1
    public function cut($mode = 'PARTIAL', $lines = 3)
653
    {
654 1
        $lines = self::validateInteger($lines, 1, 10, 3);
655 1
        if ($mode == 'FULL') {
656 1
            $mode = self::CUT_FULL;
657 1
        } else {
658 1
            $mode = self::CUT_PARTIAL;
659
        }
660 1
        $this->buffer->write(self::GS.'V'.chr($mode).chr($lines));
661 1
    }
662
663
    /**
664
     * Implements barcodes 1D
665
     * GS k m n d1...dn
666
     * Prints bar code. n specifies the data length.
667
     *   m    bar code system             number of d (=k)
668
     *  "A"     UPC-A                       11 or 12
669
     *  "B"     UPC-E                       6, 7, 8, 11 or 12
670
     *  "C"     JAN13 / EAN13               12 or 13
671
     *  "D"     JAN8 / EAN8                 7 or 8
672
     *  "E"     CODE39                      1 or more
673
     *  "F"     ITF                         even
674
     *  "G"     CODABAR (NW-7)              2 or more
675
     *  "H"     CODE93                      1–255
676
     *  "I"     CODE128                     2–255    
677
     *  "J"     GS1-128                     2–255    
678
     *  "K"     GS1 DataBar Omnidirectional 13
679
     *  "L"     GS1 DataBar Truncated       13
680
     *  "M"     GS1 DataBar Limited         13
681
     *  "N"     GS1 DataBar Expanded        2–255.
682
     * 
683
     *  GS h n Sets bar code height to n dots.
684
     *  GS w n Sets bar width of bar code. n = 2–6 (thin–thick)
685
     *  GS H n Selects print position of HRI characters.
686
     *           n = 0, "0": Not printed
687
     *           n = 1, "1": Above the bar code
688
     *           n = 2, "2": Below the bar code
689
     *           n = 3, "3": Both above and below the bar code
690
     *  GS f n Selects font for the HRI characters.
691
     *           n = 0, "0": Font A,
692
     *           n = 1, "1": Font B
693
     *
694
     * @param int    $type        Default CODE128
695
     * @param int    $height
696
     * @param int    $lineWidth
697
     * @param string $txtPosition
698
     * @param string $txtFont
699
     * @param string $data
700
     */
701 1
    public function barcode(
702
        $type = self::CODE128,
703
        $height = 162,
704
        $lineWidth = 2,
705
        $txtPosition = 'none',
706
        $txtFont = '',
707
        $data = '123456'
708
    ) {
709
        switch ($txtPosition) {
710 1
            case 'Above':
711
                $tPos = 1;
712
                break;
713 1
            case 'Below':
714
                $tPos = 2;
715
                break;
716 1
            case 'Both':
717
                $tPos = 3;
718
                break;
719 1
            default:
720
                //none
721 1
                $tPos = 0;
722 1
        }
723 1
        $font = 0;
724 1
        if ($txtFont === 'B') {
725
            $font = 1;
726
        }
727 1
        $id = 0;
728 1
        if (self::validateBarcodeData($type, $id, $data) === false) {
729
            return false;
730
        }
731 1
        $height = self::validateInteger($height, 1, 255, 4);
732 1
        $lineWidth = self::validateInteger($lineWidth, 1, 6, 2);
733 1
        $nlen = strlen($data);
734
        //set barcode height
735 1
        $this->buffer->write(self::GS.'h'.chr($height));
736
        //set barcode bar width
737 1
        $this->buffer->write(self::GS.'w'.chr($lineWidth));
738
        //Selects print position of HRI characters.
739 1
        $this->buffer->write(self::GS.'H'.chr($tPos));
740
        //Selects font for the HRI characters.
741 1
        $this->buffer->write(self::GS.'f'.chr($font));
742
        //Print barcode
743 1
        $this->buffer->write(self::GS.'k'.chr($id).chr($nlen).$data);
744 1
    }
745
    
746
    /**
747
     * Imprime o QR Code
748
     * @param string $data Dados a serem inseridos no QRCode
749
     * @param string $level Nivel de correção L,M,Q ou H
750
     * @param int $modelo modelo de QRCode 1, 2 ou 0 Micro
751
     * @param int $wmod largura da barra 3 ~ 16
752
     */
753 1
    public function barcodeQRCode($data = '', $level = 'L', $modelo = 2, $wmod = 4)
754
    {
755
        //set model of QRCode
756 1
        $n1 = 50;
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $n1. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
757 1
        if ($modelo == 1) {
758
            $n1 = 49;
759
        }
760 1
        $this->buffer->write(self::GS."(k".chr(4).chr(0).chr(49).chr(65).chr($n1).chr(0));
761
        //set module bar width
762 1
        $this->buffer->write(self::GS."(k".chr(3).chr(0).chr(49).chr(67).chr($wmod));
763
        //set error correction level
764 1
        $level = strtoupper($level);
765
        switch ($level) {
766 1
            case 'L':
767
                $n = 48;
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $n. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
768
                break;
769 1
            case 'M':
770 1
                $n = 49;
771 1
                break;
772
            case 'Q':
773
                $n = 50;
774
                break;
775
            case 'H':
776
                $n = 51;
777
                break;
778
            default:
779
                $n = 49;
780
        }
781 1
        $this->buffer->write(self::GS."(k".chr(3).chr(0).chr(49).chr(69).chr($n));
782
        //set data for QR Code assuming print only alphanumeric data
783 1
        $len = strlen($data) + 3;
784 1
        $pH = ($len / 256);
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $pH. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
785 1
        $pL = $len % 256;
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $pL. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
786 1
        $this->buffer->write(self::GS."(k".chr($pL).chr($pH).chr(49).chr(80).chr(48).$data);
787
        //Print QR Code
788 1
        $this->buffer->write(self::GS."(k".chr(3).chr(0).chr(49).chr(81).chr(48));
789 1
    }
790
791
    /**
792
     * Close and clean buffer
793
     * All data will be lost.
794
     */
795
    public function close()
796
    {
797
        $this->buffer->close();
798
    }
799
800
    /**
801
     * Return all data buffer.
802
     *
803
     * @param string $type specifies the return format
804
     */
805 20
    public function getBuffer($type = '')
806
    {
807
        switch ($type) {
808 20
            case 'binA':
809
                //returns a binary array of buffer
810
                $resp = $this->buffer->getDataBinary(true);
811
                break;
812 20
            case 'binS':
813
                //returns a binary string of buffer
814 19
                $resp = $this->buffer->getDataBinary(false);
815 19
                break;
816 1
            case 'b64A':
817
                //returns a base64 encoded array of buffer
818
                $resp = $this->buffer->getDataBase64(true);
819
                break;
820 1
            case 'b64S':
821
                //returns a base64 encoded string of buffer
822
                $resp = $this->buffer->getDataBase64(false);
823
                break;
824 1
            case 'json':
825
                //returns a json encoded of array buffer
826
                $resp = $this->buffer->getDataJson();
827
                break;
828 1
            case 'readA':
829
                //returns a human readable format of array buffer
830
                //only for debug reasons
831
                $resp = $this->buffer->getDataReadable(true);
832
                break;
833 1
            default :
0 ignored issues
show
Coding Style introduced by
There must be no space before the colon in a DEFAULT statement

As per the PSR-2 coding standard, there must not be a space in front of the colon in the default statement.

switch ($expr) {
    default : //wrong
        doSomething();
        break;
}

switch ($expr) {
    default: //right
        doSomething();
        break;
}

To learn more about the PSR-2 coding standard, please refer to the PHP-Fig.

Loading history...
834
                //returns a human readable format of string buffer
835
                //only for debug reasons
836 1
                $resp = $this->buffer->getDataReadable(false);
837 1
        }
838 20
        return $resp;
839
    }
840
841
    /**
842
     * Send commands from buffer to connector printer.
843
     */
844
    public function send(ConnectorInterface $conn = null)
845
    {
846
        if (!is_null($conn)) {
847
            $this->connector = $conn;
0 ignored issues
show
Documentation Bug introduced by
It seems like $conn of type object<Posprint\Connectors\ConnectorInterface> is incompatible with the declared type object<Posprint\Printers\ConnectosInterface> of property $connector.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
848
        }
849
        if (is_null($this->connector)) {
850
            return $this->getBuffer();
851
        }
852
        $aCmds = $this->getBuffer('binA');
853
        foreach ($aCmds as $cmd) {
854
            $this->connector->write($cmd);
855
        }
856
    }
857
858
    /**
859
     * Checks whether the barcode data is compatible with the chosen model
860
     * 
861
     * @param string $type
862
     * @param int    $id
863
     * @param string $data
864
     * @return string 
865
     */
866 1
    protected static function validateBarcodeData($type, &$id, &$data)
0 ignored issues
show
Unused Code introduced by
The parameter $data is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
867
    {
868
        $aTypes = [
869 1
            'A' => ['id' => 65, 'desc' => 'UPC-A', 'len' => '11;12', 'type' => 'N'],
870 1
            'B' => ['id' => 66, 'desc' => 'UPC-E', 'len' => '6;7;8;11;12', 'type' => 'N'],
871 1
            'C' => ['id' => 67, 'desc' => 'EAN13', 'len' => '12;13', 'type' => 'N'],
872 1
            'D' => ['id' => 68, 'desc' => 'EAN8', 'len' => '7;8', 'type' => 'N'],
873 1
            'E' => ['id' => 69, 'desc' => 'CODE39', 'len' => '1-', 'type' => 'C'],
874 1
            'F' => ['id' => 70, 'desc' => 'ITF (i25)', 'len' => '1-even ', 'type' => 'N'],
875 1
            'G' => ['id' => 71, 'desc' => 'CODABAR', 'len' => '2-more', 'type' => 'C'],
876 1
            'H' => ['id' => 72, 'desc' => 'CODE93', 'len' => '1-255', 'type' => 'C'],
877 1
            'I' => ['id' => 73, 'desc' => 'CODE128', 'len' => '2-255', 'type' => 'C'],
878 1
            'J' => ['id' => 74, 'desc' => 'GS1-128', 'len' => '2-255', 'type' => 'C'],
879 1
            'K' => ['id' => 75, 'desc' => 'GS1 DataBar Omnidirectional', 'len' => '13', 'type' => 'N'],
880 1
            'L' => ['id' => 76, 'desc' => 'GS1 DataBar Truncated', 'len' => '13', 'type' => 'N'],
881 1
            'M' => ['id' => 77, 'desc' => 'GS1 DataBar Limited', 'len' => '13', 'type' => 'N'],
882 1
            'N' => ['id' => 78, 'desc' => 'GS1 DataBar Expanded', 'len' => '2-255', 'type' => 'C'],
883 1
        ];
884 1
        if (!array_key_exists($type, $aTypes)) {
885
            return false;
886
        }
887 1
        $bar = $aTypes[$type];
888 1
        $id = $bar['id'];
889 1
        $len = $bar['len'];
0 ignored issues
show
Unused Code introduced by
$len is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
890 1
        $dtype = $bar['type'];
0 ignored issues
show
Unused Code introduced by
$dtype is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
891
        //check data type if N only numeric is acceptable and all others chars must be removed
892
        //and if then field stay is empty, this is must be completed to an acceptable standard value
893
        
894
        //check for length of data, if the field length is different from the 
895
        //acceptable values, it must be adjusted by removing or adding characters
896 1
        return true;
897
    }
898
899
    /**
900
     * Insert a image.
901
     *
902
     * @param string $filename Path to image file
903
     * @param float  $width
904
     * @param float  $height
905
     * @throws RuntimeException
906
     */
907
    public function putImage($filename = '', $width = null, $height = null)
908
    {
909
        try {
910
            $img = new Graphics($filename, $width, $height);
911
        } catch (RuntimeException $e) {
912
            throw new RuntimeException($e->getMessage());
913
        } catch (InvalidArgumentException $e) {
914
            throw new RuntimeException($e->getMessage());
915
        }
916
        $imgHeader = self::dataHeader(array($img->getWidth(), $img->getHeight()), true);
917
        $tone = '0';
918
        $colors = '1';
919
        $xm = (($size & self::IMG_DOUBLE_WIDTH) == self::IMG_DOUBLE_WIDTH) ? chr(2) : chr(1);
0 ignored issues
show
Bug introduced by
The variable $size does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Comprehensibility introduced by
Avoid variables with short names like $xm. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
920
        $ym = (($size & self::IMG_DOUBLE_HEIGHT) == self::IMG_DOUBLE_HEIGHT) ? chr(2) : chr(1);
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $ym. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
921
        $header = $tone.$xm.$ym.$colors.$imgHeader;
922
        $this->sendGraphicsData('0', 'p', $header.$img->getRasterImage());
923
        $this->sendGraphicsData('0', '2');
924
    }
925
    
926
    /**
927
     * Calculate the size of the word.
928
     *
929
     * @param string $data
930
     */
931
    protected function getWordLength($data = '')
0 ignored issues
show
Unused Code introduced by
The parameter $data is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
932
    {
933
        //k = (pL + pH × 256) – 3
934
        $len = strlen($texto);
0 ignored issues
show
Bug introduced by
The variable $texto does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Unused Code introduced by
$len is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
935
    }
936
937
    /**
938
     * Generate two characters for a number: 
939
     * In lower and higher parts, or more parts as needed.
940
     *
941
     * @param int $int    Input number
0 ignored issues
show
Bug introduced by
There is no parameter named $int. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
942
     * @param int $length The number of bytes to output (1 - 4).
943
     */
944
    protected static function intLowHigh($input, $length)
945
    {
946
        $maxInput = (256 << ($length * 8) - 1);
0 ignored issues
show
Unused Code introduced by
$maxInput is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
947
        $outp = '';
948
        for ($i = 0; $i < $length; ++$i) {
949
            $outp .= chr($input % 256);
950
            $input = (int) ($input / 256);
951
        }
952
        return $outp;
953
    }
954
955
    /**
956
     * Convert widths and heights to characters.
957
     * Used before sending graphics to set the size.
958
     *
959
     * @param array $inputs
960
     * @param bool  $long   True to use 4 bytes, false to use 2
961
     * @return string
962
     */
963
    protected static function dataHeader(array $inputs, $long = true)
964
    {
965
        $outp = array();
966
        foreach ($inputs as $input) {
967
            if ($long) {
968
                $outp[] = self::intLowHigh($input, 2);
969
            } else {
970
                self::validateInteger($input, 0, 255, __FUNCTION__);
971
                $outp[] = chr($input);
972
            }
973
        }
974
        return implode('', $outp);
975
    }
976
977
    /**
978
     * Verify if the argument given is not a boolean.
979
     * 
980
     * @param bool   $test   the input to test
981
     * @param bool    $default the default value
982
     * @return bool 
983
     */
984
    protected static function validateBoolean($test, $default)
985
    {
986
        if (!($test === true || $test === false)) {
987
            return $default;
988
        }
989
        return $test;
990
    }
991
992
    /**
993
     * Verify if the argument given is not an integer within the specified range.
994
     * will return default instead
995
     * 
996
     * @param int    $test    the input to test
997
     * @param int    $min     the minimum allowable value (inclusive)
998
     * @param int    $max     the maximum allowable value (inclusive)
999
     * @param int    $default the default value
1000
     * @return int
1001
     */
1002 9
    protected static function validateInteger($test, $min, $max, $default)
1003
    {
1004 9
        if (!is_integer($test) || $test < $min || $test > $max) {
1005 1
            return $default;
1006
        }
1007 9
        return $test;
1008
    }
1009
1010
    /**
1011
     * Verify if the argument given can't be cast to a string.
1012
     *
1013
     * @param string $test    the input to test
1014
     * @param string $default the default value
1015
     * @return string
1016
     */
1017
    protected static function validateString($test, $default)
1018
    {
1019
        if (is_object($test) && !method_exists($test, '__toString')) {
1020
            return $default;
1021
        }
1022
        return $test;
1023
    }
1024
    
1025
    /**
1026
     * Translate the text from UTF-8 for the specified codepage
1027
     * this translation uses "iconv" and admits texts ONLY in UTF-8.
1028
     *
1029
     * @param string $text
1030
     * @return string
1031
     */
1032 1
    protected function translate($text = '')
1033
    {
1034 1
        $indCode = $this->defaultCodePage();
1035 1
        if (!empty($indCode)) {
1036 1
            $codep = $this->aCodePage[$indCode];
1037 1
            if (!empty($codep)) {
1038 1
                $text = iconv('UTF-8', $codep['conv'], $text);
1039 1
            }
1040 1
        }
1041 1
        return $text;
1042
    }
1043
    
1044
    /**
1045
     * Wrapper for GS ( L, to calculate and send correct data length.
1046
     *
1047
     * @param string $m    Modifier/variant for function. Usually '0'.
1048
     * @param string $fn   Function number to use, as character.
1049
     * @param string $data Data to send.
1050
     *
1051
     * @throws InvalidArgumentException Where the input lengths are bad.
1052
     */
1053
    private function sendGraphicsData($m, $fn, $data = '')
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $m. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
Comprehensibility introduced by
Avoid variables with short names like $fn. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
1054
    {
1055
        if (strlen($m) != 1 || strlen($fn) != 1) {
1056
            throw new InvalidArgumentException('wrapperSendGraphicsData: m and fn must be one character each.');
1057
        }
1058
        $header = $this->intLowHigh(strlen($data) + 2, 2);
1059
        $this->buffer->write(self::GS.'(L'.$header.$m.$fn.$data);
1060
    }
1061
}
1062