Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 28 Mar 2017 12:00:10 +0000 (UTC)
From:      Tobias Kortkamp <tobik@FreeBSD.org>
To:        ports-committers@freebsd.org, svn-ports-all@freebsd.org, svn-ports-head@freebsd.org
Subject:   svn commit: r437119 - in head/sysutils: . solaar solaar/files
Message-ID:  <201703281200.v2SC0A7e057888@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: tobik
Date: Tue Mar 28 12:00:09 2017
New Revision: 437119
URL: https://svnweb.freebsd.org/changeset/ports/437119

Log:
  New port: sysutils/solaar
  
  Solaar is a device manager for Logitech's Unifying Receiver.  It is
  able to pair/unpair devices to the receiver, and for most devices read
  battery status.
  
  It comes in two flavors, command-line and GUI.  Both are able to list
  the devices paired to a Unifying Receiver, show detailed info for each
  device, and also pair/unpair supported devices with the receiver.
  
  WWW: https://pwr.github.io/Solaar/
  
  Approved by:	mat (mentor)
  Differential Revision:	https://reviews.freebsd.org/D10155

Added:
  head/sysutils/solaar/
  head/sysutils/solaar/Makefile   (contents, props changed)
  head/sysutils/solaar/distinfo   (contents, props changed)
  head/sysutils/solaar/files/
  head/sysutils/solaar/files/hidapi.py   (contents, props changed)
  head/sysutils/solaar/files/patch-setup.py   (contents, props changed)
  head/sysutils/solaar/pkg-descr   (contents, props changed)
Modified:
  head/sysutils/Makefile

Modified: head/sysutils/Makefile
==============================================================================
--- head/sysutils/Makefile	Tue Mar 28 11:03:30 2017	(r437118)
+++ head/sysutils/Makefile	Tue Mar 28 12:00:09 2017	(r437119)
@@ -1076,6 +1076,7 @@
     SUBDIR += snowlog
     SUBDIR += socket
     SUBDIR += socklog
+    SUBDIR += solaar
     SUBDIR += sortu
     SUBDIR += spindown
     SUBDIR += spinner

Added: head/sysutils/solaar/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sysutils/solaar/Makefile	Tue Mar 28 12:00:09 2017	(r437119)
@@ -0,0 +1,43 @@
+# $FreeBSD$
+
+PORTNAME=	solaar
+PORTVERSION=	g20170327
+CATEGORIES=	sysutils
+
+MAINTAINER=	tobik@FreeBSD.org
+COMMENT=	Device manager for the Logitech Unifying Receiver
+
+LICENSE=	GPLv2+
+LICENSE_FILE=	${WRKSRC}/COPYING
+
+# libhidapi.so is only loaded at runtime via ctypes (dlopen)
+RUN_DEPENDS=	${LOCALBASE}/lib/libhidapi.so:comms/hidapi
+
+USES=	python
+USE_PYTHON=	distutils autoplist
+
+USE_GITHUB=	yes
+GH_ACCOUNT=	pwr
+GH_PROJECT=	Solaar
+# The latest release is from 2013 and there is not going to be a new
+# release for now:
+# https://github.com/pwr/Solaar/issues/288
+# https://github.com/pwr/Solaar/issues/296
+GH_TAGNAME=	53ec751
+
+NO_ARCH=	yes
+
+OPTIONS_DEFINE=	GUI
+GUI_RUN_DEPENDS=	${PYTHON_PKGNAMEPREFIX}gobject3>=0:devel/py${PYTHON_MAJOR_VER:S/2//}-gobject3
+
+post-patch:
+	@${CP} ${FILESDIR}/hidapi.py ${WRKSRC}/lib/hidapi/udev.py
+	@${REINPLACE_CMD} -e '/pyudev/d' \
+		-e 's|python-gi|${PYTHON_PKGNAMEPREFIX}gobject3|' \
+		${WRKSRC}/lib/solaar/gtk.py
+	@${REINPLACE_CMD} 's|receiver\.path\.split.*|receiver.path)|' \
+		${WRKSRC}/lib/logitech_receiver/listener.py
+	@${REINPLACE_CMD} 's|[[:<:]]cmd[[:>:]]|action|' \
+		${WRKSRC}/lib/solaar/cli/__init__.py
+
+.include <bsd.port.mk>

Added: head/sysutils/solaar/distinfo
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sysutils/solaar/distinfo	Tue Mar 28 12:00:09 2017	(r437119)
@@ -0,0 +1,3 @@
+TIMESTAMP = 1490648037
+SHA256 (pwr-Solaar-g20170327-53ec751_GH0.tar.gz) = 0dca927e30c5436215d732a328d72f6d73b2a1878df6efa4ba054b1dbec9310f
+SIZE (pwr-Solaar-g20170327-53ec751_GH0.tar.gz) = 1189828

Added: head/sysutils/solaar/files/hidapi.py
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sysutils/solaar/files/hidapi.py	Tue Mar 28 12:00:09 2017	(r437119)
@@ -0,0 +1,186 @@
+# $FreeBSD$
+# This is based on previous support for libhidapi which was dropped in
+# upstream commit f5d2eba.
+import ctypes as _C
+from struct import pack as _pack
+
+_native = _C.CDLL("libhidapi.so")
+
+class _NativeDeviceInfo(_C.Structure):
+	pass
+_NativeDeviceInfo._fields_ = [
+	('path', _C.c_char_p),
+	('vendor_id', _C.c_ushort),
+	('product_id', _C.c_ushort),
+	('serial', _C.c_wchar_p),
+	('release', _C.c_ushort),
+	('manufacturer', _C.c_wchar_p),
+	('product', _C.c_wchar_p),
+	('usage_page', _C.c_ushort),
+	('usage', _C.c_ushort),
+	('interface', _C.c_int),
+	('next_device', _C.POINTER(_NativeDeviceInfo))
+]
+
+from collections import namedtuple
+DeviceInfo = namedtuple('DeviceInfo', [
+	'path',
+	'vendor_id',
+	'product_id',
+	'serial',
+	'release',
+	'manufacturer',
+	'product',
+	'interface',
+	'driver',
+])
+del namedtuple
+
+def _makeDeviceInfo(native_device_info):
+	return DeviceInfo(
+		path=native_device_info.path.decode('ascii'),
+		vendor_id=hex(native_device_info.vendor_id)[2:].zfill(4),
+		product_id=hex(native_device_info.product_id)[2:].zfill(4),
+		serial=native_device_info.serial if native_device_info.serial else None,
+		release=hex(native_device_info.release)[2:],
+		manufacturer=native_device_info.manufacturer,
+		product=native_device_info.product,
+		interface=native_device_info.interface,
+		driver=None)
+
+_native.hid_init.argtypes = None
+_native.hid_init.restype = _C.c_int
+
+_native.hid_exit.argtypes = None
+_native.hid_exit.restype = _C.c_int
+
+_native.hid_enumerate.argtypes = [_C.c_ushort, _C.c_ushort]
+_native.hid_enumerate.restype = _C.POINTER(_NativeDeviceInfo)
+
+_native.hid_free_enumeration.argtypes = [_C.POINTER(_NativeDeviceInfo)]
+_native.hid_free_enumeration.restype = None
+
+_native.hid_open.argtypes = [_C.c_ushort, _C.c_ushort, _C.c_wchar_p]
+_native.hid_open.restype = _C.c_void_p
+
+_native.hid_open_path.argtypes = [_C.c_char_p]
+_native.hid_open_path.restype = _C.c_void_p
+
+_native.hid_close.argtypes = [_C.c_void_p]
+_native.hid_close.restype = None
+
+_native.hid_write.argtypes = [_C.c_void_p, _C.c_char_p, _C.c_size_t]
+_native.hid_write.restype = _C.c_int
+
+_native.hid_read.argtypes = [_C.c_void_p, _C.c_char_p, _C.c_size_t]
+_native.hid_read.restype = _C.c_int
+
+_native.hid_read_timeout.argtypes = [_C.c_void_p, _C.c_char_p, _C.c_size_t, _C.c_int]
+_native.hid_read_timeout.restype = _C.c_int
+
+_native.hid_set_nonblocking.argtypes = [_C.c_void_p, _C.c_int]
+_native.hid_set_nonblocking.restype = _C.c_int
+
+_native.hid_send_feature_report.argtypes = [_C.c_void_p, _C.c_char_p, _C.c_size_t]
+_native.hid_send_feature_report.restype = _C.c_int
+
+_native.hid_get_feature_report.argtypes = [_C.c_void_p, _C.c_char_p, _C.c_size_t]
+_native.hid_get_feature_report.restype = _C.c_int
+
+_native.hid_get_manufacturer_string.argtypes = [_C.c_void_p, _C.c_wchar_p, _C.c_size_t]
+_native.hid_get_manufacturer_string.restype = _C.c_int
+
+_native.hid_get_product_string.argtypes = [_C.c_void_p, _C.c_wchar_p, _C.c_size_t]
+_native.hid_get_product_string.restype = _C.c_int
+
+_native.hid_get_serial_number_string.argtypes = [_C.c_void_p, _C.c_wchar_p, _C.c_size_t]
+_native.hid_get_serial_number_string.restype = _C.c_int
+
+_native.hid_get_indexed_string.argtypes = [_C.c_void_p, _C.c_int, _C.c_wchar_p, _C.c_size_t]
+_native.hid_get_indexed_string.restype = _C.c_int
+
+_native.hid_error.argtypes = [_C.c_void_p]
+_native.hid_error.restype = _C.c_wchar_p
+
+def init():
+	return _native.hid_init() == 0
+
+def exit():
+	return _native.hid_exit() == 0
+
+def monitor_glib(callback, *device_filters):
+	pass
+
+def enumerate(vendor_id=None, product_id=None, interface_number=None, hid_driver=None):
+	devices = _native.hid_enumerate(vendor_id, product_id)
+	d = devices
+	while d:
+		if interface_number is None or interface_number == d.contents.interface:
+			yield _makeDeviceInfo(d.contents)
+		d = d.contents.next_device
+
+	if devices:
+		_native.hid_free_enumeration(devices)
+
+def open(vendor_id, product_id, serial=None):
+	return _native.hid_open(vendor_id, product_id, serial) or None
+
+def open_path(device_path):
+	if type(device_path) == str:
+		device_path = device_path.encode('ascii')
+	return _native.hid_open_path(device_path) or None
+
+def close(device_handle):
+	_native.hid_close(device_handle)
+
+def write(device_handle, data):
+	bytes_written = _native.hid_write(device_handle, _C.c_char_p(data), len(data))
+	if bytes_written != len(data):
+		raise IOError(_errno.EIO, 'written %d bytes out of expected %d' % (bytes_written, len(data)))
+
+def read(device_handle, bytes_count, timeout_ms=-1):
+	out_buffer = _C.create_string_buffer(b'\x00' * (bytes_count + 1))
+	bytes_read = _native.hid_read_timeout(device_handle, out_buffer, bytes_count, timeout_ms)
+	if bytes_read == -1:
+		return None
+	if bytes_read == 0:
+		return b''
+	return out_buffer[:bytes_read]
+
+def send_feature_report(device_handle, data, report_number=None):
+	if report_number is not None:
+		data = _pack(b'!B', report_number) + data
+	bytes_written = _native.hid_send_feature_report(device_handle, _C.c_char_p(data), len(data))
+	return bytes_written > -1
+
+def get_feature_report(device_handle, bytes_count, report_number=None):
+	out_buffer = _C.create_string_buffer('\x00' * (bytes_count + 2))
+	if report_number is not None:
+		out_buffer[0] = _pack(b'!B', report_number)
+	bytes_read = _native.hid_get_feature_report(device_handle, out_buffer, bytes_count)
+	if bytes_read > -1:
+		return out_buffer[:bytes_read]
+
+def _read_wchar(func, device_handle, index=None):
+	_BUFFER_SIZE = 64
+	buf = _C.create_unicode_buffer('\x00' * _BUFFER_SIZE)
+	if index is None:
+		ok = func(device_handle, buf, _BUFFER_SIZE)
+	else:
+		ok = func(device_handle, index, buf, _BUFFER_SIZE)
+	if ok == 0:
+		return buf.value
+
+def get_manufacturer(device_handle):
+	return _read_wchar(_native.hid_get_manufacturer_string, device_handle)
+
+def get_product(device_handle):
+	return _read_wchar(_native.hid_get_product_string, device_handle)
+
+def get_serial(device_handle):
+	serial = _read_wchar(_native.hid_get_serial_number_string, device_handle)
+	if serial is not None:
+		return ''.join(hex(ord(c)) for c in serial)
+
+def get_indexed_string(device_handle, index):
+	return _read_wchar(_native.hid_get_indexed_string, device_handle, index)

Added: head/sysutils/solaar/files/patch-setup.py
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sysutils/solaar/files/patch-setup.py	Tue Mar 28 12:00:09 2017	(r437119)
@@ -0,0 +1,32 @@
+--- setup.py.orig	2017-03-20 23:07:26 UTC
++++ setup.py
+@@ -6,10 +6,8 @@ from distutils.core import setup
+ autostart_path = '/etc/xdg/autostart'
+ 
+ import sys
+-backup_path_0 = sys.path[0]
+-sys.path[0] = backup_path_0 + '/lib'
+-from solaar import NAME, __version__
+-sys.path[0] = backup_path_0
++NAME = 'Solaar'
++__version__ = '0.9.2'
+ 
+ if 'install' in sys.argv:
+ 	# naively guess where the autostart .desktop file should be installed
+@@ -22,7 +20,7 @@ if 'install' in sys.argv:
+ 		autostart_path = path.join(xdg_config_home, 'autostart')
+ 		del environ, path, xdg_config_home
+ 
+-del sys, backup_path_0
++del sys
+ 
+ 
+ def _data_files():
+@@ -36,7 +34,6 @@ def _data_files():
+ 		yield _dirname(mo), [mo]
+ 
+ 	yield 'share/applications', ['share/applications/solaar.desktop']
+-	yield autostart_path, ['share/applications/solaar.desktop']
+ 
+ 	del _dirname
+ 

Added: head/sysutils/solaar/pkg-descr
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sysutils/solaar/pkg-descr	Tue Mar 28 12:00:09 2017	(r437119)
@@ -0,0 +1,9 @@
+Solaar is a device manager for Logitech's Unifying Receiver.  It is
+able to pair/unpair devices to the receiver, and for most devices read
+battery status.
+
+It comes in two flavors, command-line and GUI.  Both are able to list
+the devices paired to a Unifying Receiver, show detailed info for each
+device, and also pair/unpair supported devices with the receiver.
+
+WWW: https://pwr.github.io/Solaar/



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201703281200.v2SC0A7e057888>