Merge branch 'development' into development
This commit is contained in:
commit
b6e5279419
@ -2,6 +2,32 @@
|
|||||||
Changelog
|
Changelog
|
||||||
*********
|
*********
|
||||||
|
|
||||||
|
2017-07-27 - Version 3.0a2 - "It's My Party And I'll Sing If I Want To"
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
This release is the third alpha release of the new version 3.0. Please
|
||||||
|
be aware that the API will still change until v3.0 is released.
|
||||||
|
|
||||||
|
changes
|
||||||
|
^^^^^^^
|
||||||
|
- refactor of the set-method
|
||||||
|
- preliminary support of POS "line display" printing
|
||||||
|
- improvement of tests
|
||||||
|
- added ImageWidthError
|
||||||
|
- list authors in repository
|
||||||
|
- add support for software-based barcode-rendering
|
||||||
|
- fix SerialException when trying to close device on __del__
|
||||||
|
- added the DLE EOT querying command for USB
|
||||||
|
- ensure QR codes have a large enough border
|
||||||
|
- make feed for cut optional
|
||||||
|
- fix the behavior of horizontal tabs
|
||||||
|
|
||||||
|
contributors
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
- csoft2k
|
||||||
|
- Patrick Kanzler
|
||||||
|
- Romain Porte
|
||||||
|
- Ahmed Tahri
|
||||||
|
|
||||||
2017-03-29 - Version 3.0a1 - "Headcrash"
|
2017-03-29 - Version 3.0a1 - "Headcrash"
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
This release is the second alpha release of the new version 3.0. Please
|
This release is the second alpha release of the new version 3.0. Please
|
||||||
|
11
examples/barcodes.py
Normal file
11
examples/barcodes.py
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
from escpos.printer import Usb
|
||||||
|
|
||||||
|
|
||||||
|
# Adapt to your needs
|
||||||
|
p = Usb(0x0416, 0x5011, profile="POS-5890")
|
||||||
|
|
||||||
|
# Print software and then hardware barcode with the same content
|
||||||
|
p.soft_barcode('code39', '123456')
|
||||||
|
p.text('\n')
|
||||||
|
p.text('\n')
|
||||||
|
p.barcode('123456', 'CODE39')
|
@ -251,5 +251,10 @@ S_RASTER_2H = _PRINT_RASTER_IMG(b'\x02') # Set raster image double height
|
|||||||
S_RASTER_Q = _PRINT_RASTER_IMG(b'\x03') # Set raster image quadruple
|
S_RASTER_Q = _PRINT_RASTER_IMG(b'\x03') # Set raster image quadruple
|
||||||
|
|
||||||
# Status Command
|
# Status Command
|
||||||
RT_STATUS_ONLINE = DLE + EOT + b'\x01';
|
RT_STATUS = DLE + EOT
|
||||||
RT_MASK_ONLINE = 8;
|
RT_STATUS_ONLINE = RT_STATUS + b'\x01'
|
||||||
|
RT_STATUS_PAPER = RT_STATUS + b'\x04'
|
||||||
|
RT_MASK_ONLINE = 8
|
||||||
|
RT_MASK_PAPER = 18
|
||||||
|
RT_MASK_LOWPAPER = 30
|
||||||
|
RT_MASK_NOPAPER = 114
|
@ -33,9 +33,10 @@ from .constants import LINESPACING_FUNCS, LINESPACING_RESET
|
|||||||
from .constants import LINE_DISPLAY_OPEN, LINE_DISPLAY_CLEAR, LINE_DISPLAY_CLOSE
|
from .constants import LINE_DISPLAY_OPEN, LINE_DISPLAY_CLEAR, LINE_DISPLAY_CLOSE
|
||||||
from .constants import CD_KICK_DEC_SEQUENCE, CD_KICK_5, CD_KICK_2, PAPER_FULL_CUT, PAPER_PART_CUT
|
from .constants import CD_KICK_DEC_SEQUENCE, CD_KICK_5, CD_KICK_2, PAPER_FULL_CUT, PAPER_PART_CUT
|
||||||
from .constants import HW_RESET, HW_SELECT, HW_INIT
|
from .constants import HW_RESET, HW_SELECT, HW_INIT
|
||||||
from .constants import CTL_VT, CTL_HT, CTL_CR, CTL_FF, CTL_LF, CTL_SET_HT, PANEL_BUTTON_OFF, PANEL_BUTTON_ON
|
from .constants import CTL_VT, CTL_CR, CTL_FF, CTL_LF, CTL_SET_HT, PANEL_BUTTON_OFF, PANEL_BUTTON_ON
|
||||||
from .constants import TXT_STYLE
|
from .constants import TXT_STYLE
|
||||||
from .constants import RT_STATUS_ONLINE, RT_MASK_ONLINE
|
from .constants import RT_STATUS_ONLINE, RT_MASK_ONLINE
|
||||||
|
from .constants import RT_STATUS_PAPER, RT_MASK_PAPER, RT_MASK_LOWPAPER, RT_MASK_NOPAPER
|
||||||
|
|
||||||
from .exceptions import BarcodeTypeError, BarcodeSizeError, TabPosError
|
from .exceptions import BarcodeTypeError, BarcodeSizeError, TabPosError
|
||||||
from .exceptions import CashDrawerError, SetVariableError, BarcodeCodeError
|
from .exceptions import CashDrawerError, SetVariableError, BarcodeCodeError
|
||||||
@ -250,9 +251,9 @@ class Escpos(object):
|
|||||||
"""
|
"""
|
||||||
max_input = (256 << (out_bytes * 8) - 1)
|
max_input = (256 << (out_bytes * 8) - 1)
|
||||||
if not 1 <= out_bytes <= 4:
|
if not 1 <= out_bytes <= 4:
|
||||||
raise ValueError("Can only output 1-4 byes")
|
raise ValueError("Can only output 1-4 bytes")
|
||||||
if not 0 <= inp_number <= max_input:
|
if not 0 <= inp_number <= max_input:
|
||||||
raise ValueError("Number too large. Can only output up to {0} in {1} byes".format(max_input, out_bytes))
|
raise ValueError("Number too large. Can only output up to {0} in {1} bytes".format(max_input, out_bytes))
|
||||||
outp = b''
|
outp = b''
|
||||||
for _ in range(0, out_bytes):
|
for _ in range(0, out_bytes):
|
||||||
outp += six.int2byte(inp_number % 256)
|
outp += six.int2byte(inp_number % 256)
|
||||||
@ -574,7 +575,7 @@ class Escpos(object):
|
|||||||
|
|
||||||
self._raw(LINESPACING_FUNCS[divisor] + six.int2byte(spacing))
|
self._raw(LINESPACING_FUNCS[divisor] + six.int2byte(spacing))
|
||||||
|
|
||||||
def cut(self, mode='FULL'):
|
def cut(self, mode='FULL', feed=True):
|
||||||
""" Cut paper.
|
""" Cut paper.
|
||||||
|
|
||||||
Without any arguments the paper will be cut completely. With 'mode=PART' a partial cut will
|
Without any arguments the paper will be cut completely. With 'mode=PART' a partial cut will
|
||||||
@ -584,8 +585,14 @@ class Escpos(object):
|
|||||||
.. todo:: Check this function on TM-T88II.
|
.. todo:: Check this function on TM-T88II.
|
||||||
|
|
||||||
:param mode: set to 'PART' for a partial cut. default: 'FULL'
|
:param mode: set to 'PART' for a partial cut. default: 'FULL'
|
||||||
|
:param feed: print and feed before cutting. default: true
|
||||||
:raises ValueError: if mode not in ('FULL', 'PART')
|
:raises ValueError: if mode not in ('FULL', 'PART')
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if not feed:
|
||||||
|
self._raw(GS + b'V' + six.int2byte(66) + b'\x00')
|
||||||
|
return
|
||||||
|
|
||||||
self.print_and_feed(6)
|
self.print_and_feed(6)
|
||||||
|
|
||||||
mode = mode.upper()
|
mode = mode.upper()
|
||||||
@ -689,7 +696,7 @@ class Escpos(object):
|
|||||||
else:
|
else:
|
||||||
raise ValueError("n must be betwen 0 and 255")
|
raise ValueError("n must be betwen 0 and 255")
|
||||||
|
|
||||||
def control(self, ctl, pos=4):
|
def control(self, ctl, count=5, tab_size=8):
|
||||||
""" Feed control sequences
|
""" Feed control sequences
|
||||||
|
|
||||||
:param ctl: string for the following control sequences:
|
:param ctl: string for the following control sequences:
|
||||||
@ -700,7 +707,8 @@ class Escpos(object):
|
|||||||
* HT *for Horizontal Tab*
|
* HT *for Horizontal Tab*
|
||||||
* VT *for Vertical Tab*
|
* VT *for Vertical Tab*
|
||||||
|
|
||||||
:param pos: integer between 1 and 16, controls the horizontal tab position
|
:param count: integer between 1 and 32, controls the horizontal tab count. Defaults to 5.
|
||||||
|
:param tab_size: integer between 1 and 255, controls the horizontal tab size in characters. Defaults to 8
|
||||||
:raises: :py:exc:`~escpos.exceptions.TabPosError`
|
:raises: :py:exc:`~escpos.exceptions.TabPosError`
|
||||||
"""
|
"""
|
||||||
# Set position
|
# Set position
|
||||||
@ -711,13 +719,16 @@ class Escpos(object):
|
|||||||
elif ctl.upper() == "CR":
|
elif ctl.upper() == "CR":
|
||||||
self._raw(CTL_CR)
|
self._raw(CTL_CR)
|
||||||
elif ctl.upper() == "HT":
|
elif ctl.upper() == "HT":
|
||||||
if not (1 <= pos <= 16):
|
if not (0 <= count <= 32 and
|
||||||
|
1 <= tab_size <= 255 and
|
||||||
|
count * tab_size < 256):
|
||||||
raise TabPosError()
|
raise TabPosError()
|
||||||
else:
|
else:
|
||||||
# Set tab positions
|
# Set tab positions
|
||||||
self._raw(CTL_SET_HT + six.int2byte(pos))
|
self._raw(CTL_SET_HT)
|
||||||
|
for iterator in range(1, count):
|
||||||
self._raw(CTL_HT)
|
self._raw(six.int2byte(iterator * tab_size))
|
||||||
|
self._raw(NUL)
|
||||||
elif ctl.upper() == "VT":
|
elif ctl.upper() == "VT":
|
||||||
self._raw(CTL_VT)
|
self._raw(CTL_VT)
|
||||||
|
|
||||||
@ -744,19 +755,40 @@ class Escpos(object):
|
|||||||
else:
|
else:
|
||||||
self._raw(PANEL_BUTTON_OFF)
|
self._raw(PANEL_BUTTON_OFF)
|
||||||
|
|
||||||
def query_status(self):
|
def query_status(self, mode):
|
||||||
""" Queries the printer for its status, and returns an array of integers containing it.
|
""" Queries the printer for its status, and returns an array of integers containing it.
|
||||||
|
:param mode: Integer that sets the status mode queried to the printer.
|
||||||
|
RT_STATUS_ONLINE: Printer status.
|
||||||
|
RT_STATUS_PAPER: Paper sensor.
|
||||||
:rtype: array(integer)"""
|
:rtype: array(integer)"""
|
||||||
self._raw(RT_STATUS_ONLINE)
|
self._raw(mode)
|
||||||
time.sleep(1)
|
time.sleep(1)
|
||||||
status = self._read()
|
status = self._read()
|
||||||
return status or [RT_MASK_ONLINE]
|
return status
|
||||||
|
|
||||||
def is_online(self):
|
def is_online(self):
|
||||||
""" Queries the printer its online status.
|
""" Queries the printer its online status.
|
||||||
When online, returns True; False otherwise.
|
When online, returns True; False otherwise.
|
||||||
:rtype: bool: True if online, False if offline."""
|
:rtype: bool: True if online, False if offline."""
|
||||||
return not (self.query_status()[0] & RT_MASK_ONLINE)
|
status = self.query_status(RT_STATUS_ONLINE)
|
||||||
|
if len(status) == 0:
|
||||||
|
return False
|
||||||
|
return not (status & RT_MASK_ONLINE)
|
||||||
|
|
||||||
|
def paper_status(self):
|
||||||
|
""" Queries the printer its paper status.
|
||||||
|
Returns 2 if there is plenty of paper, 1 if the paper has arrived to
|
||||||
|
the near-end sensor and 0 if there is no paper.
|
||||||
|
:rtype: int: 2: Paper is adequate. 1: Paper ending. 0: No paper."""
|
||||||
|
status = self.query_status(RT_STATUS_PAPER)
|
||||||
|
if len(status) == 0:
|
||||||
|
return 2
|
||||||
|
if (status[0] & RT_MASK_NOPAPER == RT_MASK_NOPAPER):
|
||||||
|
return 0
|
||||||
|
if (status[0] & RT_MASK_LOWPAPER == RT_MASK_LOWPAPER):
|
||||||
|
return 1
|
||||||
|
if (status[0] & RT_MASK_PAPER == RT_MASK_PAPER):
|
||||||
|
return 2
|
||||||
|
|
||||||
|
|
||||||
class EscposIO(object):
|
class EscposIO(object):
|
||||||
|
@ -150,7 +150,8 @@ class CashDrawerError(Error):
|
|||||||
|
|
||||||
|
|
||||||
class TabPosError(Error):
|
class TabPosError(Error):
|
||||||
""" Valid tab positions must be in the range 0 to 16.
|
""" Valid tab positions must be set by using from 1 to 32 tabs, and between 1 and 255 tab size values.
|
||||||
|
Both values multiplied must not exceed 255, since it is the maximum tab value.
|
||||||
|
|
||||||
This exception is raised by :py:meth:`escpos.escpos.Escpos.control`.
|
This exception is raised by :py:meth:`escpos.escpos.Escpos.control`.
|
||||||
The returncode for this exception is `70`.
|
The returncode for this exception is `70`.
|
||||||
|
17
test/test_function_cut.py
Normal file
17
test/test_function_cut.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import six
|
||||||
|
|
||||||
|
import escpos.printer as printer
|
||||||
|
from escpos.constants import GS
|
||||||
|
|
||||||
|
|
||||||
|
def test_cut_without_feed():
|
||||||
|
"""Test cut without feeding paper"""
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.cut(feed=False)
|
||||||
|
expected = GS + b'V' + six.int2byte(66) + b'\x00'
|
||||||
|
assert(instance.output == expected)
|
Loading…
x
Reference in New Issue
Block a user