2828#~autogen
2929
3030import os
31- import os .path
3231import fnmatch
3332import numbers
3433import platform
3534import fcntl
3635import array
3736import mmap
3837import ctypes
38+ from os .path import abspath
3939from PIL import Image , ImageDraw
4040from 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