Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add USB Printer device #40

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
202 changes: 202 additions & 0 deletions USBPrinter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
# USBPrinter.py

# Contains class definitions to implement a simple USB Printer
# such as a thermal receipt printer.
# Ubuntu Linux 18.04 creates /dev/usb/lp1 in response to this.
# echo "Hello" >/dev/usb/lp1

import facedancer

from facedancer.USB import *
from facedancer.USBDevice import *
from facedancer.USBConfiguration import *
from facedancer.USBInterface import *
from facedancer.USBEndpoint import *
from facedancer.USBVendor import *


class USBPrinterClass(USBClass):
""" USB Printer Class """
name = "USB Printer class"

PRINTER_CLASS_NUMBER = 7
DESCRIPTOR_TYPE_NUMBER = 0

def __init__(self):
super().__init__(self.PRINTER_CLASS_NUMBER, None, self.DESCRIPTOR_TYPE_NUMBER)

def handle_get_device_id(self, req):
""" Printer class request get device ID """
self.interface.configuration.device.send_control_message(b'')

def handle_get_port_status(self, req):
"""
Printer class request get port status returns 1 byte
bit 5=1:Paper Empty, 4=1:Selected, 3=1:No Error
0x18 = Paper not empty, selected, no error
"""
self.interface.configuration.device.send_control_message(b'\x18')

def handle_soft_reset(self, req):
""" Printer class request soft reset """
self.interface.configuration.device.send_control_message(b'')

def setup_request_handlers(self):
self.request_handlers = {
0 : self.handle_get_device_id,
1 : self.handle_get_port_status,
2 : self.handle_soft_reset,
23: self.handle_soft_reset,
}


class USBPrinterUniDirInterface(USBInterface):
"""
Uni Directional Printer Interface
Direction refers to communication between the printer and the host.
It does not refer to the movement of the printer head.
"""
name = "USB Printer Uni Dir interface"

def __init__(self, verbose=0):
descriptors = {}

endpoints = [
USBEndpoint(
1, # endpoint number
USBEndpoint.direction_out,
USBEndpoint.transfer_type_bulk,
USBEndpoint.sync_type_none,
USBEndpoint.usage_type_data,
64, # max packet size
0, # polling interval, see USB 2.0 spec Table 9-13
self.handle_data_available # handler function
)
]

iclass = USBPrinterClass()
USBInterface.__init__(
self,
0, # interface number
0, # alternate setting
iclass, # interface class: Printer
1, # subclass: Printer
1, # protocol: uni directional
0, # string index
verbose,
endpoints,
descriptors
)
self.device_class = iclass
self.device_class.set_interface(self)

def handle_data_available(self, data):
""" Called when data is received from host """
s = data
if self.verbose > 0:
print(self.name, "received string", s)


class USBPrinterBiDirInterface(USBInterface):
"""
Bi Directional Printer Interface
Direction refers to communication between the printer and the host.
It does not refer to the movement of the printer head.
"""
name = "USB Printer Bi Dir interface"

def __init__(self, verbose=0):
descriptors = {}

endpoints = [
USBEndpoint(
1, # endpoint number
USBEndpoint.direction_out,
USBEndpoint.transfer_type_bulk,
USBEndpoint.sync_type_none,
USBEndpoint.usage_type_data,
64, # max packet size
0, # polling interval, see USB 2.0 spec Table 9-13
self.handle_data_available # handler function
),
USBEndpoint(
2, # endpoint number
USBEndpoint.direction_in,
USBEndpoint.transfer_type_bulk,
USBEndpoint.sync_type_none,
USBEndpoint.usage_type_data,
64, # max packet size
0, # polling interval, see USB 2.0 spec Table 9-13
None # handler function
)
]

iclass = USBPrinterClass()
USBInterface.__init__(
self,
0, # interface number
1, # alternate setting
iclass, # interface class: Printer
1, # subclass: Printer
2, # protocol: Bidirectional
0, # string index
verbose,
endpoints,
descriptors
)
self.device_class = iclass
self.device_class.set_interface(self)

def handle_data_available(self, data):
""" Called when data is received from host """
s = data
if self.verbose > 0:
print(self.name, "received string", s)


class USBPrinterDevice(USBDevice):
"""
USB Printer device class
"""
name = "USB Printer device"

def __init__(self, maxusb_app, interface_options=0, verbose=0):

if interface_options == 0:
uni_interface = USBPrinterUniDirInterface(verbose=verbose)
interfaces = [uni_interface]
elif interface_options == 1:
bi_interface = USBPrinterBiDirInterface(verbose=verbose)
interfaces = [bi_interface]
elif interface_options == 2:
uni_interface = USBPrinterUniDirInterface(verbose=verbose)
bi_interface = USBPrinterBiDirInterface(verbose=verbose)
interfaces = [uni_interface, bi_interface]
else:
uni_interface = USBPrinterUniDirInterface(verbose=verbose)
interfaces = [uni_interface]

config = USBConfiguration(
1, # index
"", # string desc
interfaces, # interfaces
0xC0, # self powered
50, # max 100 mA
)

USBDevice.__init__(
self,
maxusb_app,
0, # device class
0, # device subclass
0, # protocol release number
64, # max packet size for endpoint 0
0x0416, # vendor id: Winbond
0x5011, # product id: thermal printer
0x0001, # device revision
"Printer", # manufacturer string
"USB Printer", # product string
"", # serial number string
[config],
verbose=verbose
)
19 changes: 19 additions & 0 deletions facedancer-printer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#!/usr/bin/env python3
#
# facedancer-printer.py

from facedancer import FacedancerUSBApp
from USBPrinter import USBPrinterDevice

u = FacedancerUSBApp(verbose=1)
# 0=uni directional, 1=bi directional, 2=both
interface_options = 2
d = USBPrinterDevice(u, interface_options, verbose=6)

d.connect()

try:
d.run()
# SIGINT raises KeyboardInterrupt
except KeyboardInterrupt:
d.disconnect()