escposify/
device.rs

1use std::fs;
2use std::io;
3use std::net;
4use std::path;
5
6use rusb::Direction;
7use rusb::TransferType;
8use rusb::UsbContext;
9use rusb::{Context, DeviceHandle};
10
11pub struct Usb {
12    _vendor_id: u16,
13    _product_id: u16,
14    connection: DeviceHandle<Context>,
15    endpoint: u8,
16}
17
18pub struct Serial {}
19
20#[derive(Debug)]
21pub struct Network {
22    _host: String,
23    _port: u16,
24    stream: net::TcpStream,
25}
26
27impl Network {
28    pub fn new(host: &str, port: u16) -> io::Result<Network> {
29        let stream = net::TcpStream::connect((host, port))?;
30        Ok(Network {
31            _host: host.to_string(),
32            _port: port,
33            stream,
34        })
35    }
36}
37
38impl io::Write for Network {
39    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
40        self.stream.write(buf)
41    }
42
43    fn flush(&mut self) -> io::Result<()> {
44        self.stream.flush()
45    }
46}
47
48/// File device that can be written to.
49
50#[derive(Debug)]
51pub struct File<W> {
52    fobj: W,
53}
54
55impl<W: io::Write> File<W> {
56    pub fn from_path<P: AsRef<path::Path> + ToString>(path: P) -> io::Result<File<fs::File>> {
57        let fobj = fs::OpenOptions::new()
58            .write(true)
59            .create(true)
60            .truncate(true)
61            .open(&path)?;
62        Ok(File { fobj })
63    }
64
65    /// Create a device::File from a [std::io::Write].
66    /// # Example
67    /// ```rust
68    /// use std::fs::File;
69    /// use tempfile::NamedTempFileOptions;
70    ///
71    /// let tempf = NamedTempFileOptions::new().create().unwrap();
72    /// let fobj = File::options().append(true).open(tempf.path()).unwrap();
73    /// let file = escposify::device::File::from(fobj);
74    /// ```
75    pub fn from(fobj: W) -> File<W> {
76        File { fobj }
77    }
78}
79
80impl<W: io::Write> io::Write for File<W> {
81    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
82        self.fobj.write(buf)
83    }
84
85    fn flush(&mut self) -> io::Result<()> {
86        self.fobj.flush()
87    }
88}
89
90impl Usb {
91    /// Create a new USB device.
92    /// # Example
93    /// ```no_run
94    /// use std::io;
95    /// use escposify::device::Usb;
96    /// use escposify::printer::Printer;
97    ///
98    /// let product_id = 0xa700;
99    /// let vendor_id = 0x0525;
100    /// let usb = Usb::new(vendor_id, product_id).unwrap();
101    /// let mut printer = Printer::new(usb, None, None);
102    /// ```
103    pub fn new(vendor_id: u16, product_id: u16) -> io::Result<Usb> {
104        let context = Context::new().map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
105        let devices = context
106            .devices()
107            .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
108
109        for device in devices.iter() {
110            let device_desc = device
111                .device_descriptor()
112                .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
113
114            if device_desc.vendor_id() == vendor_id && device_desc.product_id() == product_id {
115                let config_descriptor = device
116                    .active_config_descriptor()
117                    .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;
118
119                let endpoint = config_descriptor
120                    .interfaces()
121                    .flat_map(|interface| interface.descriptors())
122                    .flat_map(|descriptor| descriptor.endpoint_descriptors())
123                    .find_map(|endpoint| {
124                        if let (TransferType::Bulk, Direction::Out) =
125                            (endpoint.transfer_type(), endpoint.direction())
126                        {
127                            Some(endpoint.number())
128                        } else {
129                            None
130                        }
131                    })
132                    .ok_or_else(|| {
133                        io::Error::new(io::ErrorKind::Other, "No suitable endpoint found")
134                    })?;
135
136                match device.open() {
137                    Ok(dvc) => {
138                        if let Ok(active) = dvc.kernel_driver_active(0) {
139                            if active {
140                                if let Err(e) = dvc.detach_kernel_driver(0) {
141                                    return Err(io::Error::new(io::ErrorKind::Other, e));
142                                }
143                            }
144                        } else {
145                            return Err(io::Error::new(
146                                io::ErrorKind::Other,
147                                "Error checking kernel driver",
148                            ));
149                        };
150
151                        return dvc
152                            .claim_interface(0)
153                            .map(|_| Usb {
154                                _vendor_id: vendor_id,
155                                _product_id: product_id,
156                                connection: dvc,
157                                endpoint,
158                            })
159                            .map_err(|e| io::Error::new(io::ErrorKind::Other, e));
160                    }
161                    Err(_) => return Err(io::Error::new(io::ErrorKind::Other, "Device busy")),
162                }
163            }
164        }
165
166        Err(io::Error::new(io::ErrorKind::Other, "USB not found"))
167    }
168}
169
170impl io::Write for Usb {
171    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
172        match self
173            .connection
174            .write_bulk(self.endpoint, buf, std::time::Duration::from_secs(5))
175        {
176            Ok(_) => Ok(buf.len()),
177            Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)),
178        }
179    }
180
181    fn flush(&mut self) -> io::Result<()> {
182        Ok(())
183    }
184}