summaryrefslogtreecommitdiffstats
path: root/common/recipes-utils/openbmc-gpio/files/openbmc_gpio.py
blob: 9e9232471eb1abec3538b8a538889f987890684c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# Copyright 2015-present Facebook. All rights reserved.
#
# This program file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; version 2 of the License.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program in a file named COPYING; if not, write to the
# Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301 USA
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

import logging
import os
import string


_gpio_shadow = '/tmp/gpionames'


def setup_shadow(shadow=None):
    global _gpio_shadow
    if shadow is not None:
        _gpio_shadow = shadow
    if not os.path.exists(_gpio_shadow):
        os.makedirs(_gpio_shadow)


def gpio_name2value(name):
    name = str(name).lower()
    if name.startswith('gpio'):
        name = name[4:]
    try:
        return int(name)
    except:
        # it is not just value, try treat it as name like 'A0'
        pass
    val = 0
    try:
        if len(name) != 2 and len(name) != 3:
            raise
        for idx in range(0, len(name)):
            ch = name[idx]
            if ch in string.ascii_lowercase:
                # letter cannot be the last character
                if idx == len(name) - 1:
                    raise
                tmp = ord(ch) - ord('a') + 1
                val = val * 26 + tmp
            elif ch in string.digits:
                # digit must be the last character
                if idx != len(name) - 1:
                    raise
                # the digit must be 0-7
                tmp = ord(ch) - ord('0')
                if tmp > 7:
                    raise
                # 'A4' is value 4
                if val > 0:
                    val -= 1
                val = val * 8 + tmp
            else:
                raise
    except:
        logging.exception('Invalid GPIO name "%s"' % name)
    return val


def gpio_dir(name, check_shadow=True):
    GPIODIR_FMT = '/sys/class/gpio/gpio{gpio}'
    if check_shadow:
        shadowdir = os.path.join(_gpio_shadow, name)
        if os.path.isdir(shadowdir):
            return shadowdir
    val = gpio_name2value(name)
    return GPIODIR_FMT.format(gpio=val)


def gpio_get_shadow(name):
    path = gpio_dir(name, check_shadow=False)
    for child in os.listdir(_gpio_shadow):
        try:
            child = os.path.join(_gpio_shadow, child)
            if os.readlink(child) == path:
                return child
        except:
            pass
    return None


def gpio_export(name, shadow=None):
    GPIOEXPORT = '/sys/class/gpio/export'
    if shadow is not None or shadow != '':
        shadowdir = os.path.join(_gpio_shadow, shadow)
        if os.path.exists(shadowdir):
            raise Exception('Shadow "%s" exists already' % shadowdir)
        old_shadow = gpio_get_shadow(name)
        if old_shadow is not None:
            raise Exception('Shadow "%s" already exists for %s'
                            % (old_shadow, name))

    val = gpio_name2value(name)
    try:
        with open(GPIOEXPORT, 'w') as f:
            f.write('%d\n' % val)
    except:
        # in case the GPIO has been exported already
        pass
    if shadow is not None:
        gpiodir = gpio_dir(val, check_shadow=False)
        os.symlink(gpiodir, shadowdir)


def gpio_get(name, change_direction=True):
    path = gpio_dir(name)
    if change_direction:
        with open(os.path.join(path, 'direction'), 'w') as f:
            f.write('in\n')
    with open(os.path.join(path, 'value'), 'r') as f:
        val = int(f.read().rstrip('\n'))
    return val


def gpio_set(name, value, change_direction=True):
    path = gpio_dir(name)
    with open(os.path.join(path, 'value'), 'w') as f:
        f.write('%d\n' % (1 if value else 0))
    if change_direction:
        with open(os.path.join(path, 'direction'), 'w') as f:
            f.write('out\n')


def gpio_info(name):
    res = {}
    # first check if name is shadow
    path = None
    shadow = os.path.join(_gpio_shadow, name)
    if os.path.exists(shadow):
        if not os.path.islink(shadow) or not os.path.isdir(shadow):
            raise Exception('Path "%s" is not a valid shadow path' % shadow)
        path = os.readlink(shadow)
    else:
        path = gpio_dir(name, check_shadow=False)
        shadow = gpio_get_shadow(name)
    res['path'] = path
    res['shadow'] = shadow
    if os.path.isdir(path):
        with open(os.path.join(path, 'direction'), 'r') as f:
            res['direction'] = f.read().rstrip('\n')
        with open(os.path.join(path, 'value'), 'r') as f:
            res['value'] = int(f.read().rstrip('\n'))
    else:
        res['direction'] = None
        res['value'] = None
    return res
OpenPOWER on IntegriCloud