Skip to content

Commit 00ed242

Browse files
committed
First shot at universal file cache
1 parent 0bd0033 commit 00ed242

File tree

1 file changed

+60
-50
lines changed

1 file changed

+60
-50
lines changed

ev3dev.py

Lines changed: 60 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,54 @@ 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 file_handle( self, path, mode, reopen=False ):
60+
"""Manages the file handle cache and opening the files in the correct mode"""
61+
62+
if path not in self._cache:
63+
f = open( path, mode )
64+
self._cache[path] = f
65+
elif reopen == True:
66+
self._cache[path].close()
67+
f = open( path, mode )
68+
self._cache[path] = f
69+
else:
70+
f = self._cache[path]
71+
f.seek(0)
72+
73+
return f
74+
75+
def read(self, path, size=None):
76+
f = self.file_handle(path, 'r')
77+
78+
try:
79+
value = f.read(size)
80+
except IOError:
81+
f = self.file_handle( path, 'w+', reopen=True )
82+
value = f.read(size)
83+
84+
if size is None:
85+
return value.strip()
86+
else:
87+
return value
88+
89+
def write(self, path, value):
90+
f = self.file_handle( path, 'w' )
91+
92+
try:
93+
f.write( value )
94+
f.flush()
95+
except IOError:
96+
f = self.file_handle( path, 'w+', reopen=True )
97+
f.write( value )
98+
f.flush()
99+
100+
53101
#------------------------------------------------------------------------------
54102
# Define the base class from which all other ev3dev classes are defined.
55103

@@ -80,12 +128,12 @@ def __init__(self, class_name, name='*', **kwargs ):
80128
When connected succesfully, the `connected` attribute is set to True.
81129
"""
82130

83-
classpath = os.path.abspath( Device.DEVICE_ROOT_PATH + '/' + class_name )
84-
self.filehandle_cache = {}
131+
classpath = abspath( Device.DEVICE_ROOT_PATH + '/' + class_name )
132+
self._attribute_cache = FileCache()
85133

86134
for file in os.listdir( classpath ):
87135
if fnmatch.fnmatch(file, name):
88-
self._path = os.path.abspath( classpath + '/' + file )
136+
self._path = abspath( classpath + '/' + file )
89137

90138
# See if requested attributes match:
91139
if all([self._matches(k, kwargs[k]) for k in kwargs]):
@@ -106,44 +154,13 @@ def _matches(self, attribute, pattern):
106154
else:
107155
return value.find(pattern) >= 0
108156

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 ):
157+
def _get_attribute( self, attribute, size=None ):
126158
"""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()
159+
return self._attribute_cache.read(abspath(self._path + '/' + attribute), size)
135160

136161
def _set_attribute( self, attribute, value ):
137162
"""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()
163+
self._attribute_cache.write( abspath(self._path + '/' + attribute), value )
147164

148165
def get_attr_int( self, attribute ):
149166
return int( self._get_attribute( attribute ) )
@@ -1271,9 +1288,7 @@ def bin_data(self, fmt=None):
12711288
"float": 4
12721289
}.get(self.bin_data_format, 1) * self.num_values
12731290

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

12781293
if fmt is None: return raw
12791294

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

18241839
def __init__(self):
1825-
self.buffer_cache = {}
1826-
self.filehandle_cache = {}
1840+
self._file_cache = FileCache()
1841+
self._buffer_cache = {}
18271842
for b in self._buttons:
18281843
self._button_file( self._buttons[b]['name'] )
18291844
self._button_buffer( self._buttons[b]['name'] )
18301845

18311846
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
1847+
return self._file_cache.file_handle(name, 'r')
18381848

18391849
def _button_buffer(self, name):
18401850
if name not in self.buffer_cache:
@@ -1844,7 +1854,7 @@ def _button_buffer(self, name):
18441854
@property
18451855
def buttons_pressed(self):
18461856
for b in self.buffer_cache:
1847-
fcntl.ioctl(self.filehandle_cache[b], self.EVIOCGKEY, self.buffer_cache[b])
1857+
fcntl.ioctl(self._button_file(b), self.EVIOCGKEY, self.buffer_cache[b])
18481858

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

0 commit comments

Comments
 (0)