A clone of: https://github.com/nutechsoftware/alarmdecoder This is requires as they dropped support for older firmware releases w/o building in backward compatibility code, and they had previously hardcoded pyserial to a python2 only version.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1051 lines
28 KiB

  1. """
  2. Contains different types of devices belonging to the AD2 family.
  3. .. moduleauthor:: Scott Petersen <scott@nutech.com>
  4. """
  5. import usb.core, usb.util
  6. import time
  7. import threading
  8. import serial, serial.tools.list_ports
  9. import socket
  10. from OpenSSL import SSL, crypto
  11. from pyftdi.pyftdi.ftdi import *
  12. from pyftdi.pyftdi.usbtools import *
  13. from .util import CommError, TimeoutError, NoDeviceError
  14. from .event import event
  15. class Device(object):
  16. """
  17. Generic parent device to all AD2 products.
  18. """
  19. # Generic device events
  20. on_open = event.Event('Called when the device has been opened')
  21. on_close = event.Event('Called when the device has been closed')
  22. on_read = event.Event('Called when a line has been read from the device')
  23. on_write = event.Event('Called when data has been written to the device')
  24. def __init__(self):
  25. """
  26. Constructor
  27. """
  28. self._id = ''
  29. self._buffer = ''
  30. self._device = None
  31. self._running = False
  32. self._read_thread = Device.ReadThread(self)
  33. @property
  34. def id(self):
  35. """
  36. Retrieve the device ID.
  37. :returns: The identification string for the device.
  38. """
  39. return self._id
  40. @id.setter
  41. def id(self, value):
  42. """
  43. Sets the device ID.
  44. :param value: The device identification.
  45. :type value: str
  46. """
  47. self._id = value
  48. def is_reader_alive(self):
  49. """
  50. Indicates whether or not the reader thread is alive.
  51. :returns: Whether or not the reader thread is alive.
  52. """
  53. return self._read_thread.is_alive()
  54. def stop_reader(self):
  55. """
  56. Stops the reader thread.
  57. """
  58. self._read_thread.stop()
  59. def close(self):
  60. """
  61. Closes the device.
  62. """
  63. try:
  64. self._running = False
  65. self._read_thread.stop()
  66. self._device.close()
  67. except:
  68. pass
  69. self.on_close()
  70. class ReadThread(threading.Thread):
  71. """
  72. Reader thread which processes messages from the device.
  73. """
  74. READ_TIMEOUT = 10
  75. """Timeout for the reader thread."""
  76. def __init__(self, device):
  77. """
  78. Constructor
  79. :param device: The device used by the reader thread.
  80. :type device: devices.Device
  81. """
  82. threading.Thread.__init__(self)
  83. self._device = device
  84. self._running = False
  85. def stop(self):
  86. """
  87. Stops the running thread.
  88. """
  89. self._running = False
  90. def run(self):
  91. """
  92. The actual read process.
  93. """
  94. self._running = True
  95. while self._running:
  96. try:
  97. self._device.read_line(timeout=self.READ_TIMEOUT)
  98. except TimeoutError, err:
  99. pass
  100. except Exception, err:
  101. self._running = False
  102. #raise err
  103. time.sleep(0.01)
  104. class USBDevice(Device):
  105. """
  106. AD2USB device exposed with PyFTDI's interface.
  107. """
  108. # Constants
  109. FTDI_VENDOR_ID = 0x0403
  110. """Vendor ID used to recognize AD2USB devices."""
  111. FTDI_PRODUCT_ID = 0x6001
  112. """Product ID used to recognize AD2USB devices."""
  113. BAUDRATE = 115200
  114. """Default baudrate for AD2USB devices."""
  115. __devices = []
  116. @classmethod
  117. def find_all(cls, vid=FTDI_VENDOR_ID, pid=FTDI_PRODUCT_ID):
  118. """
  119. Returns all FTDI devices matching our vendor and product IDs.
  120. :returns: list of devices
  121. :raises: CommError
  122. """
  123. cls.__devices = []
  124. try:
  125. cls.__devices = Ftdi.find_all([(vid, pid)], nocache=True)
  126. except (usb.core.USBError, FtdiError), err:
  127. raise CommError('Error enumerating AD2USB devices: {0}'.format(str(err)), err)
  128. return cls.__devices
  129. @classmethod
  130. def devices(cls):
  131. """
  132. Returns a cached list of AD2USB devices located on the system.
  133. :returns: cached list of devices found.
  134. """
  135. return cls.__devices
  136. @classmethod
  137. def find(cls, device=None):
  138. """
  139. Factory method that returns the requested USBDevice device, or the first device.
  140. :param device: Tuple describing the USB device to open, as returned by find_all().
  141. :type device: tuple
  142. :returns: USBDevice object utilizing the specified device.
  143. :raises: NoDeviceError
  144. """
  145. cls.find_all()
  146. if len(cls.__devices) == 0:
  147. raise NoDeviceError('No AD2USB devices present.')
  148. if device is None:
  149. device = cls.__devices[0]
  150. vendor, product, sernum, ifcount, description = device
  151. return USBDevice(interface=sernum)
  152. @classmethod
  153. def start_detection(cls, on_attached=None, on_detached=None):
  154. """
  155. Starts the device detection thread.
  156. :param on_attached: function to be called when a device is attached.
  157. :type on_attached: function
  158. :param on_detached: function to be called when a device is detached.
  159. :type on_detached: function
  160. """
  161. cls.__detect_thread = USBDevice.DetectThread(on_attached, on_detached)
  162. cls.find_all()
  163. cls.__detect_thread.start()
  164. @classmethod
  165. def stop_detection(cls):
  166. """
  167. Stops the device detection thread.
  168. """
  169. try:
  170. cls.__detect_thread.stop()
  171. except:
  172. pass
  173. @property
  174. def interface(self):
  175. """
  176. Retrieves the interface used to connect to the device.
  177. :returns: the interface used to connect to the device.
  178. """
  179. return self._interface
  180. @interface.setter
  181. def interface(self, value):
  182. """
  183. Sets the interface used to connect to the device.
  184. :param value: May specify either the serial number or the device index.
  185. :type value: str or int
  186. """
  187. self._interface = value
  188. if isinstance(value, int):
  189. self._device_number = value
  190. else:
  191. self._serial_number = value
  192. @property
  193. def serial_number(self):
  194. """
  195. Retrieves the serial number of the device.
  196. :returns: The serial number of the device.
  197. """
  198. return self._serial_number
  199. @serial_number.setter
  200. def serial_number(self, value):
  201. """
  202. Sets the serial number of the device.
  203. :param value: The serial number of the device.
  204. :type value: string
  205. """
  206. self._serial_number = value
  207. @property
  208. def description(self):
  209. """
  210. Retrieves the description of the device.
  211. :returns: The description of the device.
  212. """
  213. return self._description
  214. @description.setter
  215. def description(self, value):
  216. """
  217. Sets the description of the device.
  218. :param value: The description of the device.
  219. :type value: string
  220. """
  221. self._description = value
  222. def __init__(self, interface=0):
  223. """
  224. Constructor
  225. :param interface: May specify either the serial number or the device index.
  226. :type interface: str or int
  227. """
  228. Device.__init__(self)
  229. self._device = Ftdi()
  230. self._device_number = 0
  231. self._serial_number = None
  232. self.interface = interface
  233. self._vendor_id = USBDevice.FTDI_VENDOR_ID
  234. self._product_id = USBDevice.FTDI_PRODUCT_ID
  235. self._endpoint = 0
  236. self._description = None
  237. def open(self, baudrate=BAUDRATE, no_reader_thread=False):
  238. """
  239. Opens the device.
  240. :param baudrate: The baudrate to use.
  241. :type baudrate: int
  242. :param no_reader_thread: Whether or not to automatically start the reader thread.
  243. :type no_reader_thread: bool
  244. :raises: NoDeviceError
  245. """
  246. # Set up defaults
  247. if baudrate is None:
  248. baudrate = USBDevice.BAUDRATE
  249. # Open the device and start up the thread.
  250. try:
  251. self._device.open(self._vendor_id,
  252. self._product_id,
  253. self._endpoint,
  254. self._device_number,
  255. self._serial_number,
  256. self._description)
  257. self._device.set_baudrate(baudrate)
  258. if not self._serial_number:
  259. self._serial_number = self._get_serial_number()
  260. self._id = self._serial_number
  261. except (usb.core.USBError, FtdiError), err:
  262. raise NoDeviceError('Error opening device: {0}'.format(str(err)), err)
  263. else:
  264. self._running = True
  265. if not no_reader_thread:
  266. self._read_thread.start()
  267. self.on_open()
  268. def close(self):
  269. """
  270. Closes the device.
  271. """
  272. try:
  273. Device.close(self)
  274. # HACK: Probably should fork pyftdi and make this call in .close().
  275. self._device.usb_dev.attach_kernel_driver(self._device_number)
  276. except:
  277. pass
  278. def write(self, data):
  279. """
  280. Writes data to the device.
  281. :param data: Data to write
  282. :type data: str
  283. :raises: CommError
  284. """
  285. try:
  286. self._device.write_data(data)
  287. self.on_write(data=data)
  288. except FtdiError, err:
  289. raise CommError('Error writing to device: {0}'.format(str(err)), err)
  290. def read(self):
  291. """
  292. Reads a single character from the device.
  293. :returns: The character read from the device.
  294. :raises: CommError
  295. """
  296. ret = None
  297. try:
  298. ret = self._device.read_data(1)
  299. except (usb.core.USBError, FtdiError), err:
  300. raise CommError('Error reading from device: {0}'.format(str(err)), err)
  301. return ret
  302. def read_line(self, timeout=0.0, purge_buffer=False):
  303. """
  304. Reads a line from the device.
  305. :param timeout: Read timeout
  306. :type timeout: float
  307. :param purge_buffer: Indicates whether to purge the buffer prior to reading.
  308. :type purge_buffer: bool
  309. :returns: The line that was read.
  310. :raises: CommError, TimeoutError
  311. """
  312. if purge_buffer:
  313. self._buffer = ''
  314. def timeout_event():
  315. timeout_event.reading = False
  316. timeout_event.reading = True
  317. got_line = False
  318. ret = None
  319. timer = None
  320. if timeout > 0:
  321. timer = threading.Timer(timeout, timeout_event)
  322. timer.start()
  323. try:
  324. while timeout_event.reading:
  325. buf = self._device.read_data(1)
  326. if buf != '':
  327. self._buffer += buf
  328. if buf == "\n":
  329. if len(self._buffer) > 1:
  330. if self._buffer[-2] == "\r":
  331. self._buffer = self._buffer[:-2]
  332. # ignore if we just got \r\n with nothing else in the buffer.
  333. if len(self._buffer) != 0:
  334. got_line = True
  335. break
  336. else:
  337. self._buffer = self._buffer[:-1]
  338. except (usb.core.USBError, FtdiError), err:
  339. if timer:
  340. timer.cancel()
  341. raise CommError('Error reading from device: {0}'.format(str(err)), err)
  342. else:
  343. if got_line:
  344. ret = self._buffer
  345. self._buffer = ''
  346. self.on_read(data=ret)
  347. if timer:
  348. if timer.is_alive():
  349. timer.cancel()
  350. else:
  351. raise TimeoutError('Timeout while waiting for line terminator.')
  352. return ret
  353. def _get_serial_number(self):
  354. """
  355. Retrieves the FTDI device serial number.
  356. :returns: string containing the device serial number.
  357. """
  358. return usb.util.get_string(self._device.usb_dev, 64, self._device.usb_dev.iSerialNumber)
  359. class DetectThread(threading.Thread):
  360. """
  361. Thread that handles detection of added/removed devices.
  362. """
  363. on_attached = event.Event('Called when an AD2USB device has been detected.')
  364. on_detached = event.Event('Called when an AD2USB device has been removed.')
  365. def __init__(self, on_attached=None, on_detached=None):
  366. """
  367. Constructor
  368. :param factory: AD2Factory object to use with the thread.
  369. :type factory: AD2Factory
  370. """
  371. threading.Thread.__init__(self)
  372. if on_attached:
  373. self.on_attached += on_attached
  374. if on_detached:
  375. self.on_detached += on_detached
  376. self._running = False
  377. def stop(self):
  378. """
  379. Stops the thread.
  380. """
  381. self._running = False
  382. def run(self):
  383. """
  384. The actual detection process.
  385. """
  386. self._running = True
  387. last_devices = set()
  388. while self._running:
  389. try:
  390. current_devices = set(USBDevice.find_all())
  391. new_devices = [d for d in current_devices if d not in last_devices]
  392. removed_devices = [d for d in last_devices if d not in current_devices]
  393. last_devices = current_devices
  394. for d in new_devices:
  395. self.on_attached(device=d)
  396. for d in removed_devices:
  397. self.on_detached(device=d)
  398. except CommError, err:
  399. pass
  400. time.sleep(0.25)
  401. class SerialDevice(Device):
  402. """
  403. AD2USB or AD2SERIAL device exposed with the pyserial interface.
  404. """
  405. # Constants
  406. BAUDRATE = 19200
  407. """Default baudrate for Serial devices."""
  408. @staticmethod
  409. def find_all(pattern=None):
  410. """
  411. Returns all serial ports present.
  412. :param pattern: Pattern to search for when retrieving serial ports.
  413. :type pattern: str
  414. :returns: list of devices
  415. :raises: CommError
  416. """
  417. devices = []
  418. try:
  419. if pattern:
  420. devices = serial.tools.list_ports.grep(pattern)
  421. else:
  422. devices = serial.tools.list_ports.comports()
  423. except SerialException, err:
  424. raise CommError('Error enumerating serial devices: {0}'.format(str(err)), err)
  425. return devices
  426. @property
  427. def interface(self):
  428. """
  429. Retrieves the interface used to connect to the device.
  430. :returns: the interface used to connect to the device.
  431. """
  432. return self._port
  433. @interface.setter
  434. def interface(self, value):
  435. """
  436. Sets the interface used to connect to the device.
  437. :param value: The name of the serial device.
  438. :type value: string
  439. """
  440. self._port = value
  441. def __init__(self, interface=None):
  442. """
  443. Constructor
  444. :param interface: The device to open.
  445. :type interface: str
  446. """
  447. Device.__init__(self)
  448. self._port = interface
  449. self._id = interface
  450. self._device = serial.Serial(timeout=0, writeTimeout=0) # Timeout = non-blocking to match pyftdi.
  451. def open(self, baudrate=BAUDRATE, no_reader_thread=False):
  452. """
  453. Opens the device.
  454. :param baudrate: The baudrate to use with the device.
  455. :type baudrate: int
  456. :param no_reader_thread: Whether or not to automatically start the reader thread.
  457. :type no_reader_thread: bool
  458. :raises: NoDeviceError
  459. """
  460. # Set up the defaults
  461. if baudrate is None:
  462. baudrate = SerialDevice.BAUDRATE
  463. if self._port is None:
  464. raise NoDeviceError('No device interface specified.')
  465. self._device.port = self._port
  466. # Open the device and start up the reader thread.
  467. try:
  468. self._device.open()
  469. self._device.baudrate = baudrate # NOTE: Setting the baudrate before opening the
  470. # port caused issues with Moschip 7840/7820
  471. # USB Serial Driver converter. (mos7840)
  472. #
  473. # Moving it to this point seems to resolve
  474. # all issues with it.
  475. except (serial.SerialException, ValueError), err:
  476. raise NoDeviceError('Error opening device on port {0}.'.format(self._port), err)
  477. else:
  478. self._running = True
  479. self.on_open()
  480. if not no_reader_thread:
  481. self._read_thread.start()
  482. def close(self):
  483. """
  484. Closes the device.
  485. """
  486. try:
  487. Device.close(self)
  488. except:
  489. pass
  490. def write(self, data):
  491. """
  492. Writes data to the device.
  493. :param data: The data to write.
  494. :type data: str
  495. :raises: CommError
  496. """
  497. try:
  498. self._device.write(data)
  499. except serial.SerialTimeoutException, err:
  500. pass
  501. except serial.SerialException, err:
  502. raise CommError('Error writing to device.', err)
  503. else:
  504. self.on_write(data=data)
  505. def read(self):
  506. """
  507. Reads a single character from the device.
  508. :returns: The character read from the device.
  509. :raises: CommError
  510. """
  511. ret = None
  512. try:
  513. ret = self._device.read(1)
  514. except serial.SerialException, err:
  515. raise CommError('Error reading from device: {0}'.format(str(err)), err)
  516. return ret
  517. def read_line(self, timeout=0.0, purge_buffer=False):
  518. """
  519. Reads a line from the device.
  520. :param timeout: The read timeout.
  521. :type timeout: float
  522. :param purge_buffer: Indicates whether to purge the buffer prior to reading.
  523. :type purge_buffer: bool
  524. :returns: The line read.
  525. :raises: CommError, TimeoutError
  526. """
  527. def timeout_event():
  528. timeout_event.reading = False
  529. timeout_event.reading = True
  530. got_line = False
  531. ret = None
  532. timer = None
  533. if timeout > 0:
  534. timer = threading.Timer(timeout, timeout_event)
  535. timer.start()
  536. try:
  537. while timeout_event.reading:
  538. buf = self._device.read(1)
  539. if buf != '' and buf != "\xff": # AD2SERIAL specifically apparently sends down \xFF on boot.
  540. self._buffer += buf
  541. if buf == "\n":
  542. if len(self._buffer) > 1:
  543. if self._buffer[-2] == "\r":
  544. self._buffer = self._buffer[:-2]
  545. # ignore if we just got \r\n with nothing else in the buffer.
  546. if len(self._buffer) != 0:
  547. got_line = True
  548. break
  549. else:
  550. self._buffer = self._buffer[:-1]
  551. except (OSError, serial.SerialException), err:
  552. if timer:
  553. timer.cancel()
  554. raise CommError('Error reading from device: {0}'.format(str(err)), err)
  555. else:
  556. if got_line:
  557. ret = self._buffer
  558. self._buffer = ''
  559. self.on_read(data=ret)
  560. if timer:
  561. if timer.is_alive():
  562. timer.cancel()
  563. else:
  564. raise TimeoutError('Timeout while waiting for line terminator.')
  565. return ret
  566. class SocketDevice(Device):
  567. """
  568. Device that supports communication with an AD2 that is exposed via ser2sock or another
  569. Serial to IP interface.
  570. """
  571. @property
  572. def interface(self):
  573. """
  574. Retrieves the interface used to connect to the device.
  575. :returns: the interface used to connect to the device.
  576. """
  577. return (self._host, self._port)
  578. @interface.setter
  579. def interface(self, value):
  580. """
  581. Sets the interface used to connect to the device.
  582. :param value: Tuple containing the host and port to use.
  583. :type value: tuple
  584. """
  585. self._host = value[0]
  586. self._port = value[1]
  587. @property
  588. def ssl(self):
  589. """
  590. Retrieves whether or not the device is using SSL.
  591. :returns: Whether or not the device is using SSL.
  592. """
  593. return self._use_ssl
  594. @ssl.setter
  595. def ssl(self, value):
  596. """
  597. Sets whether or not SSL communication is in use.
  598. :param value: Whether or not SSL communication is in use.
  599. :type value: bool
  600. """
  601. self._use_ssl = value
  602. @property
  603. def ssl_certificate(self):
  604. """
  605. Retrieves the SSL client certificate path used for authentication.
  606. :returns: The certificate path
  607. """
  608. return self._ssl_certificate
  609. @ssl_certificate.setter
  610. def ssl_certificate(self, value):
  611. """
  612. Sets the SSL client certificate to use for authentication.
  613. :param value: The path to the SSL certificate.
  614. :type value: str
  615. """
  616. self._ssl_certificate = value
  617. @property
  618. def ssl_key(self):
  619. """
  620. Retrieves the SSL client certificate key used for authentication.
  621. :returns: The key path
  622. """
  623. return self._ssl_key
  624. @ssl_key.setter
  625. def ssl_key(self, value):
  626. """
  627. Sets the SSL client certificate key to use for authentication.
  628. :param value: The path to the SSL key.
  629. :type value: str
  630. """
  631. self._ssl_key = value
  632. @property
  633. def ssl_ca(self):
  634. """
  635. Retrieves the SSL Certificate Authority certificate used for authentication.
  636. :returns: The CA path
  637. """
  638. return self._ssl_ca
  639. @ssl_ca.setter
  640. def ssl_ca(self, value):
  641. """
  642. Sets the SSL Certificate Authority certificate used for authentication.
  643. :param value: The path to the SSL CA certificate.
  644. :type value: str
  645. """
  646. self._ssl_ca = value
  647. def __init__(self, interface=("localhost", 10000)):
  648. """
  649. Constructor
  650. :param interface: Tuple containing the hostname and port of our target.
  651. :type interface: tuple
  652. """
  653. Device.__init__(self)
  654. self._host, self._port = interface
  655. self._use_ssl = False
  656. self._ssl_certificate = None
  657. self._ssl_key = None
  658. self._ssl_ca = None
  659. def open(self, baudrate=None, no_reader_thread=False):
  660. """
  661. Opens the device.
  662. :param baudrate: The baudrate to use
  663. :type baudrate: int
  664. :param no_reader_thread: Whether or not to automatically open the reader thread.
  665. :type no_reader_thread: bool
  666. :raises: NoDeviceError, CommError
  667. """
  668. try:
  669. self._device = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  670. if self._use_ssl:
  671. self._init_ssl()
  672. self._device.connect((self._host, self._port))
  673. self._id = '{0}:{1}'.format(self._host, self._port)
  674. except socket.error, err:
  675. raise NoDeviceError('Error opening device at {0}:{1}'.format(self._host, self._port), err)
  676. else:
  677. self._running = True
  678. self.on_open()
  679. if not no_reader_thread:
  680. self._read_thread.start()
  681. def close(self):
  682. """
  683. Closes the device.
  684. """
  685. try:
  686. if self.ssl:
  687. self._device.shutdown()
  688. else:
  689. self._device.shutdown(socket.SHUT_RDWR) # Make sure that it closes immediately.
  690. Device.close(self)
  691. except Exception, ex:
  692. pass
  693. def write(self, data):
  694. """
  695. Writes data to the device.
  696. :param data: The data to write.
  697. :type data: str
  698. :returns: The number of bytes sent.
  699. :raises: CommError
  700. """
  701. data_sent = None
  702. try:
  703. data_sent = self._device.send(data)
  704. if data_sent == 0:
  705. raise CommError('Error writing to device.')
  706. self.on_write(data=data)
  707. except (SSL.Error, socket.error), err:
  708. raise CommError('Error writing to device.', err)
  709. return data_sent
  710. def read(self):
  711. """
  712. Reads a single character from the device.
  713. :returns: The character read from the device.
  714. :raises: CommError
  715. """
  716. data = None
  717. try:
  718. data = self._device.recv(1)
  719. except socket.error, err:
  720. raise CommError('Error while reading from device: {0}'.format(str(err)), err)
  721. return data
  722. def read_line(self, timeout=0.0, purge_buffer=False):
  723. """
  724. Reads a line from the device.
  725. :param timeout: The read timeout.
  726. :type timeout: float
  727. :param purge_buffer: Indicates whether to purge the buffer prior to reading.
  728. :type purge_buffer: bool
  729. :returns: The line read from the device.
  730. :raises: CommError, TimeoutError
  731. """
  732. if purge_buffer:
  733. self._buffer = ''
  734. def timeout_event():
  735. timeout_event.reading = False
  736. timeout_event.reading = True
  737. got_line = False
  738. ret = None
  739. timer = None
  740. if timeout > 0:
  741. timer = threading.Timer(timeout, timeout_event)
  742. timer.start()
  743. try:
  744. while timeout_event.reading:
  745. buf = self._device.recv(1)
  746. if buf != '':
  747. self._buffer += buf
  748. if buf == "\n":
  749. if len(self._buffer) > 1:
  750. if self._buffer[-2] == "\r":
  751. self._buffer = self._buffer[:-2]
  752. # ignore if we just got \r\n with nothing else in the buffer.
  753. if len(self._buffer) != 0:
  754. got_line = True
  755. break
  756. else:
  757. self._buffer = self._buffer[:-1]
  758. except socket.error, err:
  759. if timer:
  760. timer.cancel()
  761. raise CommError('Error reading from device: {0}'.format(str(err)), err)
  762. else:
  763. if got_line:
  764. ret = self._buffer
  765. self._buffer = ''
  766. self.on_read(data=ret)
  767. if timer:
  768. if timer.is_alive():
  769. timer.cancel()
  770. else:
  771. raise TimeoutError('Timeout while waiting for line terminator.')
  772. return ret
  773. def _init_ssl(self):
  774. try:
  775. ctx = SSL.Context(SSL.TLSv1_METHOD)
  776. if isinstance(self.ssl_key, crypto.PKey):
  777. ctx.use_privatekey(self.ssl_key)
  778. else:
  779. ctx.use_privatekey_file(self.ssl_key)
  780. if isinstance(self.ssl_certificate, crypto.X509):
  781. ctx.use_certificate(self.ssl_certificate)
  782. else:
  783. ctx.use_certificate_file(self.ssl_certificate)
  784. if isinstance(self.ssl_ca, crypto.X509):
  785. store = ctx.get_cert_store()
  786. store.add_cert(self.ssl_ca)
  787. else:
  788. ctx.load_verify_locations(self.ssl_ca, None)
  789. ctx.set_verify(SSL.VERIFY_PEER, self._verify_ssl_callback)
  790. self._device = SSL.Connection(ctx, self._device)
  791. except SSL.Error, err:
  792. raise CommError('Error setting up SSL connection.', err)
  793. def _verify_ssl_callback(self, connection, x509, errnum, errdepth, ok):
  794. return ok