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,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