blob: 02701c49dc323a53cdfa3b87cbface364064c6be [file] [log] [blame]
# Copyright 2015 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""A class to control Ginkgo USB-GPIO adapters.
A Ginkgo USB-GPIO adapter could be used to communicate between PC USB bus and
GPIO interface. It could be configured as GPIO/I2C/SPI/CAN. This is an ideal
device if all you need is simple GPIOs while Arduino or Beaglebone is an
overkill.
Refer to the following web site for its user manual:
http://www.viewtool.com/index.php?option=com_content&view=article&id=212:driver-down&catid=39:softdownload&Itemid=18&lang=en
"""
from ctypes import byref, cdll, c_int, c_ubyte, c_ushort
import os
GPIO_DIRECTION_IN = 'in'
GPIO_DIRECTION_OUT = 'out'
GPIO_LOW = 0
GPIO_HIGH = 1
class UsbGpioError(Exception):
pass
class UsbGpioGinkgo(object):
"""A USB to GPIO control device class.
It is possible to connect multiple Ginkgo adapters to a single host by
assigning a proper device index.
"""
# Definition of legal GPIO port range
MIN_GPIO_PORT = 0
MAX_GPIO_PORT = 15
# Definition of device types
VGI_USBGPIO = 1
VII_USBI2C = 1
VAI_USBADC = 1
VSI_USBSPI = 2
VPI_USBPWM = 2
VCI_USBCAN1 = 3
VCI_USBCAN2 = 4
# Error code
ERR_SUCCESS = 0
# Ginkgo driver
GINGKO_DRIVER = 'libGinkgo_Driver.so'
def __init__(self, device_index=0):
self.device_index = device_index
self._LoadDriver()
# Scan the device
need_init = 1
ret = self.ginkgo_lib.VGI_ScanDevice(c_ubyte(need_init))
if ret <= 0:
raise UsbGpioError('scan device error!')
# Open the device
reserved = 0
ret = self.ginkgo_lib.VGI_OpenDevice(c_int(self.VGI_USBGPIO),
c_int(self.device_index),
c_int(reserved))
if ret != self.ERR_SUCCESS:
raise UsbGpioError('open device error!')
def _LoadDriver(self):
"""Load the Ginkgo driver."""
# Try to locate the path of the ginkgo driver from possible paths.
ld_library_paths = os.environ.get('LD_LIBRARY_PATH', '').split(':')
lib_paths = ['/usr/local/lib64', '/usr/lib64', '/usr/local/lib', '/usr/lib']
all_lib_paths = ld_library_paths + lib_paths
for path in all_lib_paths:
ginkgo_lib_path = os.path.join(path, self.GINGKO_DRIVER)
if os.path.isfile(ginkgo_lib_path):
break
else:
raise UsbGpioError('Cannot find %s in %s.' %
(self.GINGKO_DRIVER, all_lib_paths))
# Try to load the driver.
# ginkgo_lib_path = '/usr/lib64/libGinkgo_Driver.so'
try:
self.ginkgo_lib = cdll.LoadLibrary(ginkgo_lib_path)
except Exception as e:
raise UsbGpioError('load %s (%s)' % (ginkgo_lib_path, e))
def _GetGPIOPin(self, gpio_port):
"""Convert the GPIO port number to the physical GPIO pin number."""
# Check the validity of the gpio_port.
if gpio_port < self.MIN_GPIO_PORT or gpio_port > self.MAX_GPIO_PORT:
raise UsbGpioError('invalid gpio port %d' % gpio_port)
gpio_pin = 1 << gpio_port
return gpio_pin
def SetDirection(self, gpio_port, direction):
"""Set the direction of the GPIO port."""
gpio_pin = self._GetGPIOPin(gpio_port)
if direction == 'in':
ret = self.ginkgo_lib.VGI_SetInput(c_int(self.VGI_USBGPIO),
c_int(self.device_index),
c_ushort(gpio_pin))
elif direction == 'out':
ret = self.ginkgo_lib.VGI_SetOutput(c_int(self.VGI_USBGPIO),
c_int(self.device_index),
c_ushort(gpio_pin))
else:
raise UsbGpioError('invalid direction %s' % direction)
if ret != self.ERR_SUCCESS:
raise UsbGpioError('set gpio_%d to %s' % (gpio_port, direction))
def WriteValue(self, gpio_port, value):
"""Write the value to the GPIO port."""
gpio_pin = self._GetGPIOPin(gpio_port)
if value == GPIO_HIGH:
ret = self.ginkgo_lib.VGI_SetPins(c_int(self.VGI_USBGPIO),
c_int(self.device_index),
c_ushort(gpio_pin))
elif value == GPIO_LOW:
ret = self.ginkgo_lib.VGI_ResetPins(c_int(self.VGI_USBGPIO),
c_int(self.device_index),
c_ushort(gpio_pin))
else:
raise UsbGpioError('WriteValue: invalid value: %d' % value)
if ret != self.ERR_SUCCESS:
raise UsbGpioError('set gpio_%d to %d' % (gpio_port, value))
def ReadValue(self, gpio_port):
"""Read the value of the GPIO port."""
gpio_pin = self._GetGPIOPin(gpio_port)
pin_value = c_ushort(0)
ret = self.ginkgo_lib.VGI_ReadDatas(c_int(self.VGI_USBGPIO),
c_int(self.device_index),
c_ushort(gpio_pin),
byref(pin_value))
if ret != self.ERR_SUCCESS:
raise UsbGpioError('read gpio_%d' % gpio_port)
return GPIO_HIGH if (pin_value.value & gpio_pin) != 0 else GPIO_LOW
def Close(self):
"""Close the device."""
ret = self.ginkgo_lib.VGI_CloseDevice(c_int(self.VGI_USBGPIO),
c_int(self.device_index))
if ret != self.ERR_SUCCESS:
raise UsbGpioError('close device')