Skip to content

Commit b8e7752

Browse files
committed
Merge pull request #31 from ddemidov/file-cache
Implement generic File cache class.
2 parents 5b1aebb + 54a8c32 commit b8e7752

File tree

1 file changed

+64
-50
lines changed

1 file changed

+64
-50
lines changed

ev3dev.py

Lines changed: 64 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,14 @@
2828
#~autogen
2929

3030
import os
31-
import os.path
3231
import fnmatch
3332
import numbers
3433
import platform
3534
import fcntl
3635
import array
3736
import mmap
3837
import ctypes
38+
from os.path import abspath
3939
from PIL import Image, ImageDraw
4040
from struct import pack, unpack
4141

@@ -50,6 +50,58 @@ def current_platform():
5050
else:
5151
return 'unsupported'
5252

53+
#------------------------------------------------------------------------------
54+
# Attribute reader/writer with cached file access
55+
class FileCache(object):
56+
def __init__(self):
57+
self._cache = {}
58+
59+
def __del__(self):
60+
for f in self._cache.values():
61+
f.close()
62+
63+
def file_handle( self, path, mode, reopen=False ):
64+
"""Manages the file handle cache and opening the files in the correct mode"""
65+
66+
if path not in self._cache:
67+
f = open( path, mode )
68+
self._cache[path] = f
69+
elif reopen == True:
70+
self._cache[path].close()
71+
f = open( path, mode )
72+
self._cache[path] = f
73+
else:
74+
f = self._cache[path]
75+
f.seek(0)
76+
77+
return f
78+
79+
def read(self, path, size=-1):
80+
f = self.file_handle(path, 'r')
81+
82+
try:
83+
value = f.read(size)
84+
except IOError:
85+
f = self.file_handle( path, 'w+', reopen=True )
86+
value = f.read(size)
87+
88+
if size < 0:
89+
return value.strip()
90+
else:
91+
return value
92+
93+
def write(self, path, value):
94+
f = self.file_handle( path, 'w' )
95+
96+
try:
97+
f.write( value )
98+
f.flush()
99+
except IOError:
100+
f = self.file_handle( path, 'w+', reopen=True )
101+
f.write( value )
102+
f.flush()
103+
104+
53105
#------------------------------------------------------------------------------
54106
# Define the base class from which all other ev3dev classes are defined.
55107

@@ -80,12 +132,12 @@ def __init__(self, class_name, name='*', **kwargs ):
80132
When connected succesfully, the `connected` attribute is set to True.
81133
"""
82134

83-
classpath = os.path.abspath( Device.DEVICE_ROOT_PATH + '/' + class_name )
84-
self.filehandle_cache = {}
135+
classpath = abspath( Device.DEVICE_ROOT_PATH + '/' + class_name )
136+
self._attribute_cache = FileCache()
85137

86138
for file in os.listdir( classpath ):
87139
if fnmatch.fnmatch(file, name):
88-
self._path = os.path.abspath( classpath + '/' + file )
140+
self._path = abspath( classpath + '/' + file )
89141

90142
# See if requested attributes match:
91143
if all([self._matches(k, kwargs[k]) for k in kwargs]):
@@ -106,44 +158,13 @@ def _matches(self, attribute, pattern):
106158
else:
107159
return value.find(pattern) >= 0
108160

109-
def _attribute_file( self, attribute, mode, reopen=False ):
110-
"""Manages the file handle cache and opening the files in the correct mode"""
111-
112-
attribute_name = os.path.abspath( self._path + '/' + attribute )
113-
114-
if attribute_name not in self.filehandle_cache:
115-
f = open( attribute_name, mode )
116-
self.filehandle_cache[attribute_name] = f
117-
elif reopen == True:
118-
self.filehandle_cache[attribute_name].close()
119-
f = open( attribute_name, mode )
120-
self.filehandle_cache[attribute_name] = f
121-
else:
122-
f = self.filehandle_cache[attribute_name]
123-
return f
124-
125-
def _get_attribute( self, attribute ):
161+
def _get_attribute( self, attribute, size=-1 ):
126162
"""Device attribute getter"""
127-
f = self._attribute_file( attribute, 'r' )
128-
try:
129-
f.seek(0)
130-
value = f.read()
131-
except IOError:
132-
f = self._attribute_file( attribute, 'w+', True )
133-
value = f.read()
134-
return value.strip()
163+
return self._attribute_cache.read(abspath(self._path + '/' + attribute), size)
135164

136165
def _set_attribute( self, attribute, value ):
137166
"""Device attribute setter"""
138-
f = self._attribute_file( attribute, 'w' )
139-
try:
140-
f.seek(0)
141-
f.write( value )
142-
f.flush()
143-
except IOError:
144-
f = self._attribute_file( attribute, 'w+', True )
145-
f.write( value )
146-
f.flush()
167+
self._attribute_cache.write( abspath(self._path + '/' + attribute), value )
147168

148169
def get_attr_int( self, attribute ):
149170
return int( self._get_attribute( attribute ) )
@@ -1271,9 +1292,7 @@ def bin_data(self, fmt=None):
12711292
"float": 4
12721293
}.get(self.bin_data_format, 1) * self.num_values
12731294

1274-
f = self._attribute_file('bin_data', 'rb')
1275-
f.seek(0)
1276-
raw = bytearray(f.read(self._bin_data_size))
1295+
raw = bytearray(self._get_attribute('bin_data', self._bin_data_size))
12771296

12781297
if fmt is None: return raw
12791298

@@ -1822,19 +1841,14 @@ class Button(ButtonBase):
18221841
EVIOCGKEY = (2 << (14 + 8 + 8) | KEY_BUF_LEN << (8 + 8) | ord('E') << 8 | 0x18)
18231842

18241843
def __init__(self):
1825-
self.buffer_cache = {}
1826-
self.filehandle_cache = {}
1844+
self._file_cache = FileCache()
1845+
self._buffer_cache = {}
18271846
for b in self._buttons:
18281847
self._button_file( self._buttons[b]['name'] )
18291848
self._button_buffer( self._buttons[b]['name'] )
18301849

18311850
def _button_file(self, name):
1832-
if name not in self.filehandle_cache:
1833-
f = open( name, 'r' )
1834-
self.filehandle_cache[name] = f
1835-
else:
1836-
f = self.filehandle_cache[name]
1837-
return f
1851+
return self._file_cache.file_handle(name, 'r')
18381852

18391853
def _button_buffer(self, name):
18401854
if name not in self.buffer_cache:
@@ -1844,7 +1858,7 @@ def _button_buffer(self, name):
18441858
@property
18451859
def buttons_pressed(self):
18461860
for b in self.buffer_cache:
1847-
fcntl.ioctl(self.filehandle_cache[b], self.EVIOCGKEY, self.buffer_cache[b])
1861+
fcntl.ioctl(self._button_file(b), self.EVIOCGKEY, self.buffer_cache[b])
18481862

18491863
pressed = []
18501864
for k,v in self._buttons.items():

0 commit comments

Comments
 (0)