Porting Chameleon package to chrome os devices
This primarily includes the following tasks:
- Deploy a chameleond config file as an upstart service.
Do not use update-rc.d on chrome os devices.
- Detect if the machine is already in USB host mode.
No need to enable USB OTG driver in that case.
- In the fpga_tio driver, the instantiation of various devices is
performed in a lazy manner according to the platform, chromeos
or fpga.
- The memory singletons are instantiated in a lazy manner too.
Otherwise, the system may crash due to the incompatibility of
different platforms.
BUG=chromium:859796
TEST=Perform the following steps.
Install "make" on the chrome os device as "make" is required to
setup the package on the device.
(cr) $ emerge-${BOARD} make
where ${BOARD} represents the chromeos board replacing
chameleon board.
(cr) $ cros deploy "$CHROMEOS_IP" make
where ${CHROMEOS_IP} represents the IP address of the
chrome os device replacing chameleon board.
Next step is to make a tarball of the chameleon package and
install it on the chrome os device. This will install a few more
packages at the first time, including setuptools, pip, and wheel.
(cr) $ make
(cr) $ make remote-install CHAMELEON_HOST="$CHROMEOS_IP"
Run a bluetooth test to verify that the package is installed properly.
Remember to insert an RN42 kit to the chrome os device.
(cr) test_that --autotest_dir ~/trunk/src/third_party/autotest/files/
--args "chameleon_host=${CHROMEOS_IP}" "${DUT_IP}"
bluetooth_AdapterPairing.mouse
where DUT_IP is the chromebook under test.
Also verify that the patch works well on a chameleon board.
Change-Id: Ia5dd9aecf02be1bb2aefe4135311f19e04d86057
Reviewed-on: https://chromium-review.googlesource.com/1125650
Commit-Ready: Shyh-In Hwang <josephsih@chromium.org>
Tested-by: Shyh-In Hwang <josephsih@chromium.org>
Reviewed-by: Wai-Hong Tam <waihong@google.com>
diff --git a/MANIFEST.in b/MANIFEST.in
index 25af1d7..1f47e69 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -3,6 +3,7 @@
include bin/*
include deploy/deploy
include deploy/deploy_pip
+include deploy/init/chameleond.conf
include deploy/init.d/chameleond
include deploy/init.d/displayd
include deploy/init.d/scheduler
diff --git a/Makefile b/Makefile
index 9df5b51..287f0a6 100644
--- a/Makefile
+++ b/Makefile
@@ -11,9 +11,13 @@
BINDIR := ./bin
SRCDIR := ./src
DISTDIR := ./dist
+CONFDIR := /etc/init
+INITDIR := ./deploy/init
EGGDIR := ./chameleond.egg-info
STREAM_SRCS = $(wildcard $(SRCDIR)/stream_server/*.c)
STREAM_OBJS = $(patsubst $(SRCDIR)/stream_server/*.c,$(BINDIR)/%.o,$(STREAM_SRCS))
+CONFFILES = chameleond.conf
+IDENTITY_FILE := ~/trunk/src/scripts/mod_for_test_scripts/ssh_keys/testing_rsa
TARGETS = directories chameleond
@@ -52,6 +56,11 @@
# Get current time from the host.
HOST_NOW := `date "+%Y-%m-%d %H:%M:%S"`
+# Check if this is a Chrome OS platform.
+# The '$' symbol in awk has to be doubled in Makefile.
+PLATFORM = $(shell awk -F= '/CHROMEOS_RELEASE_NAME/ {print $$2}' \
+ /etc/lsb-release 2>/dev/null)
+
.PHONY: install
install:
@mkdir -p $(DESTDIR)
@@ -64,8 +73,16 @@
@NOW="`chameleond/utils/server_time`" deploy/deploy_pip
endif
@python setup.py install -f
+
+ifeq ($(PLATFORM), Chrome OS)
+ @cp -f $(INITDIR)/$(CONFFILES) $(CONFDIR)
+ @echo Installing chameleon package on chrome os platform is completed.
+ @echo Please do \"\$ start chameleond\" or \"\$ restart chameleond\".
+else
@BUNDLE_VERSION=$(BUNDLE_VERSION) CHAMELEON_BOARD=$(CHAMELEON_BOARD) \
- deploy/deploy
+ deploy/deploy
+ @echo Installing chameleon package on fpga platform is completed.
+endif
CHAMELEON_USER ?= root
BUNDLE = chameleond-$(VERSION).tar.gz
@@ -78,8 +95,10 @@
@echo "Current host time: $(HOST_NOW)"
ifdef CHAMELEON_HOST
@scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
+ -i $(IDENTITY_FILE) \
$(DISTDIR)/$(BUNDLE) $(CHAMELEON_USER)@$(CHAMELEON_HOST):/tmp
@ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
+ -i $(IDENTITY_FILE) \
$(CHAMELEON_USER)@$(CHAMELEON_HOST) \
"cd /tmp && rm -rf $(BUNDLEDIR) && tar zxf $(BUNDLE) &&" \
"cd $(BUNDLEDIR) && find -exec touch -c {} \; &&" \
diff --git a/chameleond/devices/bluetooth_hid_flow.py b/chameleond/devices/bluetooth_hid_flow.py
index 9766f94..32b9a00 100644
--- a/chameleond/devices/bluetooth_hid_flow.py
+++ b/chameleond/devices/bluetooth_hid_flow.py
@@ -1,13 +1,16 @@
+# -*- coding: utf-8 -*-
# Copyright 2016 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.
"""The control interface of Bluetooth HID flow module driver."""
import logging
+import subprocess
from chameleond.devices import chameleon_device
from chameleond.utils import common
from chameleond.utils import serial_utils
+from chameleond.utils import system_tools
from chameleond.utils.bluetooth_bluefruitle import BluefruitLE
from chameleond.utils.bluetooth_hid import BluetoothHIDMouse
from chameleond.utils.bluetooth_peripheral_kit import PeripheralKit
@@ -55,14 +58,34 @@
driver_name=self.DRIVER)
return self._tty
+ def IsUSBHostMode(self):
+ """Check if the platform is in USB host mode.
+
+ Returns:
+ True if the platform is in USB host mode; otherwise, False.
+ """
+ try:
+ pci_info = system_tools.SystemTools.Output('lspci', '-v')
+ except subprocess.CalledProcessError:
+ logging.info('Failed to use lspci')
+ return False
+
+ for line in pci_info.splitlines():
+ if 'xhci_hcd' in line:
+ logging.info('USB host mode: %s', line)
+ return True
+
+ logging.info('Not in USB host mode')
+ return False
def IsDetected(self):
"""Returns if the device can be detected."""
# Enables Bluetooth HID port controller.
- # Enables USB port device mode controller so USB host on the other side will
- # not get confused when trying to enumerate this USB device.
- self._usb_ctrl.EnableUSBOTGDriver()
+ # If the platform is 'chromeos' which always acts in the USB host mode,
+ # there is no need to enable the USB OTG driver.
+ if not self.IsUSBHostMode():
+ self._usb_ctrl.EnableUSBOTGDriver()
self._usb_ctrl.EnableDriver()
# Our Bluetooth HID flow differs substantially from other flows.
# Everything needed for IsDetected does the job of InitDevice:
diff --git a/chameleond/drivers/fpga_tio.py b/chameleond/drivers/fpga_tio.py
index c991b3e..da0b919 100644
--- a/chameleond/drivers/fpga_tio.py
+++ b/chameleond/drivers/fpga_tio.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
# Copyright (c) 2014 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.
@@ -30,6 +31,7 @@
from chameleond.utils import system_tools
from chameleond.utils import usb
from chameleond.utils import usb_printer_control
+from chameleond.utils.common import lazy
class DriverError(Exception):
@@ -72,55 +74,41 @@
def __init__(self, *args, **kwargs):
super(ChameleondDriver, self).__init__(*args, **kwargs)
+
+ # The default platform is 'fpga', and could be 'chromeos' if specified.
+ platform = kwargs.get('platform', 'fpga')
self._captured_params = {}
self._process = None
- main_bus = i2c.I2cBus(self._I2C_BUS_MAIN)
- ext_board_bus = i2c.I2cBus(self._I2C_BUS_EXT_BOARD)
- audio_codec_bus = i2c.I2cBus(self._I2C_BUS_AUDIO_CODEC)
- fpga_ctrl = fpga.FpgaController()
- usb_audio_ctrl = usb.USBAudioController()
- usb_hid_ctrl = usb.USBController('g_hid')
- usb_printer_ctrl = usb_printer_control.USBPrinterController()
- bluetooth_hid_ctrl = usb.USBController(
+ logging.info("platform: %s", platform)
+
+ # waihong@chromium.org suggests to use a lazy wrapper which instantiates
+ # the following control objects when requested at the first time.
+ self._main_bus = lazy(i2c.I2cBus)(self._I2C_BUS_MAIN)
+ self._ext_board_bus = lazy(i2c.I2cBus)(self._I2C_BUS_EXT_BOARD)
+ self._audio_codec_bus = lazy(i2c.I2cBus)(self._I2C_BUS_AUDIO_CODEC)
+ self._fpga_ctrl = lazy(fpga.FpgaController)()
+ self._usb_audio_ctrl = lazy(usb.USBAudioController)()
+ self._usb_hid_ctrl = lazy(usb.USBController)('g_hid')
+ self._usb_printer_ctrl = lazy(usb_printer_control.USBPrinterController)()
+ self._bluetooth_hid_ctrl = lazy(usb.USBController)(
bluetooth_hid_flow.BluetoothHIDMouseFlow.DRIVER)
- bluetooth_hog_ctrl = usb.USBController(
+ self._bluetooth_hog_ctrl = lazy(usb.USBController)(
bluetooth_hid_flow.BluetoothHOGMouseFlow.DRIVER)
- self._devices = {
- ids.DP1: input_flow.DpInputFlow(ids.DP1, main_bus, fpga_ctrl),
- ids.DP2: input_flow.DpInputFlow(ids.DP2, main_bus, fpga_ctrl),
- ids.HDMI: input_flow.HdmiInputFlow(ids.HDMI, main_bus, fpga_ctrl),
- ids.VGA: input_flow.VgaInputFlow(ids.VGA, main_bus, fpga_ctrl),
- ids.MIC: codec_flow.InputCodecFlow(ids.MIC, audio_codec_bus, fpga_ctrl),
- ids.LINEIN: codec_flow.InputCodecFlow(
- ids.LINEIN, audio_codec_bus, fpga_ctrl),
- ids.LINEOUT: codec_flow.OutputCodecFlow(
- ids.LINEOUT, audio_codec_bus, fpga_ctrl),
- ids.USB_AUDIO_IN: usb_audio_flow.InputUSBAudioFlow(
- ids.USB_AUDIO_IN, usb_audio_ctrl),
- ids.USB_AUDIO_OUT: usb_audio_flow.OutputUSBAudioFlow(
- ids.USB_AUDIO_OUT, usb_audio_ctrl),
- ids.USB_KEYBOARD: usb_hid_flow.KeyboardUSBHIDFlow(
- ids.USB_KEYBOARD, usb_hid_ctrl),
- ids.USB_TOUCH: usb_hid_flow.TouchUSBHIDFlow(
- ids.USB_TOUCH, usb_hid_ctrl),
- ids.BLUETOOTH_HID_MOUSE: bluetooth_hid_flow.BluetoothHIDMouseFlow(
- ids.BLUETOOTH_HID_MOUSE, bluetooth_hid_ctrl),
- ids.BLUETOOTH_HOG_MOUSE: bluetooth_hid_flow.BluetoothHOGMouseFlow(
- ids.BLUETOOTH_HOG_MOUSE, bluetooth_hog_ctrl),
- ids.AVSYNC_PROBE: avsync_probe.AVSyncProbe(ids.AVSYNC_PROBE),
- ids.AUDIO_BOARD: audio_board.AudioBoard(ext_board_bus),
- ids.MOTOR_BOARD: motor_board.MotorBoard(ext_board_bus),
- ids.USB_PRINTER: usb_printer_device.USBPrinter(usb_printer_ctrl),
- }
+ if platform == 'chromeos':
+ self._devices = self.init_devices_for_chromeos()
+ else:
+ self._devices = self.init_devices_for_fpga()
self._device_manager = device_manager.DeviceManager(self._devices)
self._device_manager.Init()
self._flows = self._device_manager.GetDetectedFlows()
- # Allow to accees the methods through object.
+ # Allow to access the methods through object.
# Hence, there is no need to export the methods in ChameleondDriver.
+ # An object in the following would be None if it is not instantiated
+ # in self._devices above.
self.audio_board = self._device_manager.GetChameleonDevice(ids.AUDIO_BOARD)
self.bluetooth_mouse = self._device_manager.GetChameleonDevice(
ids.BLUETOOTH_HID_MOUSE)
@@ -135,6 +123,51 @@
self.Reset()
+ def init_devices_for_chromeos(self):
+ devices = {
+ ids.BLUETOOTH_HID_MOUSE:
+ bluetooth_hid_flow.BluetoothHIDMouseFlow(
+ ids.BLUETOOTH_HID_MOUSE, self._bluetooth_hid_ctrl),
+ ids.BLUETOOTH_HOG_MOUSE:
+ bluetooth_hid_flow.BluetoothHOGMouseFlow(
+ ids.BLUETOOTH_HOG_MOUSE, self._bluetooth_hog_ctrl),
+ }
+ return devices
+
+ def init_devices_for_fpga(self):
+ devices = {
+ ids.DP1: input_flow.DpInputFlow(
+ ids.DP1, self._main_bus, self._fpga_ctrl),
+ ids.DP2: input_flow.DpInputFlow(
+ ids.DP2, self._main_bus, self._fpga_ctrl),
+ ids.HDMI: input_flow.HdmiInputFlow(
+ ids.HDMI, self._main_bus, self._fpga_ctrl),
+ ids.VGA: input_flow.VgaInputFlow(
+ ids.VGA, self._main_bus, self._fpga_ctrl),
+ ids.MIC: codec_flow.InputCodecFlow(
+ ids.MIC, self._audio_codec_bus, self._fpga_ctrl),
+ ids.LINEIN: codec_flow.InputCodecFlow(
+ ids.LINEIN, self._audio_codec_bus, self._fpga_ctrl),
+ ids.LINEOUT: codec_flow.OutputCodecFlow(
+ ids.LINEOUT, self._audio_codec_bus, self._fpga_ctrl),
+ ids.USB_AUDIO_IN: usb_audio_flow.InputUSBAudioFlow(
+ ids.USB_AUDIO_IN, self._usb_audio_ctrl),
+ ids.USB_AUDIO_OUT: usb_audio_flow.OutputUSBAudioFlow(
+ ids.USB_AUDIO_OUT, self._usb_audio_ctrl),
+ ids.USB_KEYBOARD: usb_hid_flow.KeyboardUSBHIDFlow(
+ ids.USB_KEYBOARD, self._usb_hid_ctrl),
+ ids.USB_TOUCH: usb_hid_flow.TouchUSBHIDFlow(
+ ids.USB_TOUCH, self._usb_hid_ctrl),
+ ids.AVSYNC_PROBE: avsync_probe.AVSyncProbe(ids.AVSYNC_PROBE),
+ ids.AUDIO_BOARD: audio_board.AudioBoard(self._ext_board_bus),
+ ids.MOTOR_BOARD: motor_board.MotorBoard(self._ext_board_bus),
+ ids.USB_PRINTER: usb_printer_device.USBPrinter(self._usb_printer_ctrl),
+ }
+
+ # The fpga board also supports all devices of chrome os.
+ devices.update(self.init_devices_for_chromeos())
+ return devices
+
def Reset(self):
"""Resets Chameleon board."""
logging.info('Execute the reset process')
diff --git a/chameleond/utils/common.py b/chameleond/utils/common.py
index 41d3f80..c9a2081 100644
--- a/chameleond/utils/common.py
+++ b/chameleond/utils/common.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
# Copyright (c) 2014 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.
@@ -36,3 +37,56 @@
(func.__name__, str(value)))
logging.warn(message)
raise TimeoutError(message)
+
+
+def lazy(original_class):
+ """lazy instantiation of the original_class.
+
+ The original_class would be instantiated when any method or
+ data member is accessed at the first time.
+
+ Usage:
+ Assume that the orignal instantiation is as follows:
+
+ o = original_class(*args, **kwargs)
+
+ To use lazy instantiation, it would be something like
+
+ o = lazy(original_class)(*args, **kwargs)
+
+ Note:
+ - The following assignment statement would not instantiate the object.
+
+ oo = o
+
+ - However, the following statement would instantiate the object.
+
+ print o
+
+ since it invokes o.__str__()
+
+ Args:
+ original_class: the original class to be instantiated in the lazy way.
+ """
+
+ class LazyInstantiation(object):
+ """The lazy wrapper class."""
+
+ def __init__(self, *args, **kargs):
+ self._args = args
+ self._kargs = kargs
+ self._class = original_class
+ self._obj = None
+ self._loaded = False
+
+ def _load(self):
+ self._obj = self._class(*self._args, **self._kargs)
+ self._loaded = True
+
+ def __getattr__(self, name):
+ if not self._loaded:
+ logging.info('Load %s to access %s.', self._class.__name__, name)
+ self._load()
+ return getattr(self._obj, name)
+
+ return LazyInstantiation
diff --git a/chameleond/utils/mem.py b/chameleond/utils/mem.py
index 4741d6e..e1beb27 100644
--- a/chameleond/utils/mem.py
+++ b/chameleond/utils/mem.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
# Copyright (c) 2014 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.
@@ -15,6 +16,9 @@
import ctypes
import time
+import chameleon_common # pylint: disable=W0611
+from chameleond.utils.common import lazy
+
class _Memory(object):
"""A class to abstract the memory access for IO."""
@@ -156,7 +160,10 @@
_MMAP_START_HPS = 0xfc000000
_MMAP_SIZE_HPS = 0x4000000
-# Singleton
-MemoryForController = _Memory(_MMAP_START_CONTROLLER, _MMAP_SIZE_CONTROLLER)
-MemoryForDumper = _Memory(_MMAP_START_DUMPER, _MMAP_SIZE_DUMPER)
-MemoryForHPS = _Memory(_MMAP_START_HPS, _MMAP_SIZE_HPS)
+
+# Lazy instantiation of the memory singletons since they are not supported
+# on a platform such as chromeos.
+MemoryForController = lazy(_Memory)(
+ _MMAP_START_CONTROLLER, _MMAP_SIZE_CONTROLLER)
+MemoryForDumper = lazy(_Memory)(_MMAP_START_DUMPER, _MMAP_SIZE_DUMPER)
+MemoryForHPS = lazy(_Memory)(_MMAP_START_HPS, _MMAP_SIZE_HPS)
diff --git a/chameleond/utils/system_tools.py b/chameleond/utils/system_tools.py
index 03f2d4e..153325a 100644
--- a/chameleond/utils/system_tools.py
+++ b/chameleond/utils/system_tools.py
@@ -1,8 +1,10 @@
+# -*- coding: utf-8 -*-
# Copyright (c) 2014 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.
"""System tools required for Chameleond execution."""
+import logging
import os
import subprocess
import threading
@@ -17,16 +19,17 @@
'avsync': '/usr/bin/avsync',
'chameleond': '/etc/init.d/chameleond',
'date': '/bin/date',
+ 'histogram': '/usr/bin/histogram',
+ 'hpd_control': '/usr/bin/hpd_control',
'i2cdump': '/usr/local/sbin/i2cdump',
'i2cget': '/usr/local/sbin/i2cget',
'i2cset': '/usr/local/sbin/i2cset',
- 'hpd_control': '/usr/bin/hpd_control',
'lsmod': '/sbin/lsmod',
+ 'lspci': 'lspci',
'memtool': '/usr/bin/memtool',
'modinfo': '/sbin/modinfo',
'modprobe': '/sbin/modprobe',
'reboot': '/sbin/reboot',
- 'histogram': '/usr/bin/histogram',
'pixeldump': '/usr/bin/pixeldump',
'printer': '/usr/bin/printer',
'wget': '/usr/bin/wget',
@@ -44,7 +47,8 @@
"""
for path in self._TOOL_PATHS.itervalues():
if not os.path.isfile(path):
- raise IOError('Required tool %s not existed' % path)
+ # It is okay that some tools may not exist in a particular platform.
+ logging.warning('IOError: Required tool %s not existed', path)
def _MakeCommand(self, name, args):
"""Combines the system tool and its parameters into a list.
diff --git a/deploy/init/chameleond.conf b/deploy/init/chameleond.conf
new file mode 100644
index 0000000..599890d
--- /dev/null
+++ b/deploy/init/chameleond.conf
@@ -0,0 +1,16 @@
+# Copyright 2018 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.
+
+description "Start the chameleon daemon"
+author "chromium-os-dev@chromium.org"
+
+start on started system-services
+stop on stopping system-services
+
+respawn
+
+script
+ exec /usr/local/bin/run_chameleond --driver fpga_tio \
+ platform=chromeos >> /var/log/chameleond_init 2>&1
+end script