#!/usr/bin/env python
# Copyright (c) 2012 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.

'''Chrome OS device GPIO library

This module provides a convenient way to detect, setup, and access to GPIO
values on a Chrome OS compatible device.

See help(Gpio) for more information.
'''

import os, shutil, sys, tempfile


class Gpio(object):
    '''
    Utility to access GPIO values.

    Usage:
        gpio = Gpio()
        try:
            gpio.setup()
            print gpio.read(gpio.DEVELOPER_SWITCH_CURRENT)
        except:
            print "gpio failed"
    '''

    # GPIO property names (by "crossystem"):
    DEVELOPER_SWITCH_CURRENT = 'devsw_cur'
    RECOVERY_BUTTON_CURRENT = 'recoverysw_cur'
    WRITE_PROTECT_CURRENT = 'wpsw_cur'

    DEVELOPER_SWITCH_BOOT = 'devsw_boot'
    RECOVERY_BUTTON_BOOT = 'recoverysw_boot'
    WRITE_PROTECT_BOOT = 'wpsw_boot'

    def __init__(self, exception_type=IOError):
        self._exception_type = exception_type

        # list of property conversions, usually str2int.
        self._override_map = {
                self.DEVELOPER_SWITCH_CURRENT: int,
                self.DEVELOPER_SWITCH_BOOT: int,
                self.RECOVERY_BUTTON_CURRENT: int,
                self.RECOVERY_BUTTON_BOOT: int,
                self.WRITE_PROTECT_CURRENT: int,
                self.WRITE_PROTECT_BOOT: int,
        }

        # list of legacy (chromeos_acpi) property names.
        self._legacy_map = {
                'developer_switch': self.DEVELOPER_SWITCH_CURRENT,
                'recovery_button': self.RECOVERY_BUTTON_CURRENT,
                'write_protect': self.WRITE_PROTECT_CURRENT,
        }

    def setup(self):
        '''Configures system for processing GPIO.

        Returns:
            Raises an exception if gpio_setup execution failed.
        '''
        # This is the place to do any configuration / system detection.
        # Currently "crossystem" handles everything so we don't need to do
        # anything now.
        pass

    def read(self, name):
        '''Reads a GPIO property value.
           Check "crossystem" command for the list of available property names.

        Parameters:
            name: the name of property to read.

        Returns: current value, or raise exceptions.
        '''
        debug_title = "Gpio.read('%s'): " % name

        # convert legacy names
        if name in self._legacy_map:
            name = self._legacy_map[name]

        temp_fd, temp_file = tempfile.mkstemp()
        os.close(temp_fd)
        command = "crossystem %s 2>%s" % (name, temp_file)
        pipe = os.popen(command, 'r')
        value = pipe.read()
        exit_status = pipe.close()
        if exit_status:
            with open(temp_file, 'r') as temp_handle:
                debug_info = temp_handle.read()
            value = value.strip()
            debug_info = debug_info.strip()
            if value:
                debug_info = value + '\n' + debug_info
            if debug_info:
                debug_info = '\nInformation: ' + debug_info
            raise self._exception_type(
                    debug_title + "Command failed (%d): %s%s" %
                    (exit_status, command, debug_info))
        # convert values
        if name in self._override_map:
            try:
                value = self._override_map[name](value)
            except:
                raise self._exception_type(debug_title +
                                           'Conversion failed: %s' % value)
        return value


def main():
    gpio = Gpio()
    try:
        gpio.setup()
        print ("developer switch current status: %s" %
               gpio.read(gpio.DEVELOPER_SWITCH_CURRENT))
    except Exception, e:
        print "GPIO failed. %s" % e
        sys.exit(1)

if __name__ == '__main__':
    main()