@@ -26,6 +26,7 @@ def __new__(cls):
2626 return cls ._instance
2727
2828 def __init__ (self ):
29+ self .i2c = _ArduinoAlvikI2C (A4 , A5 )
2930 self ._packeter = ucPack (200 )
3031 self .left_wheel = _ArduinoAlvikWheel (self ._packeter , ord ('L' ))
3132 self .right_wheel = _ArduinoAlvikWheel (self ._packeter , ord ('R' ))
@@ -100,54 +101,66 @@ def _progress_bar(percentage: float) -> None:
100101 word = marks_str + f" { percentage } % \t "
101102 sys .stdout .write (bytes ((word .encode ('utf-8' ))))
102103
103- def _idle (self , delay_ = 1 , check_on_thread = False ) -> None :
104+ def _lenghty_op (self , iterations = 10000000 ) -> int :
105+ result = 0
106+ for i in range (1 , iterations ):
107+ result += i * i
108+ return result
109+
110+ def _idle (self , delay_ = 1 , check_on_thread = False , blocking = False ) -> None :
104111 """
105112 Alvik's idle mode behaviour
106113 :return:
107114 """
108-
109115 NANO_CHK .value (1 )
110- sleep_ms (500 )
116+ self .i2c .set_single_thread (True )
117+
118+ if blocking :
119+ self ._lenghty_op (50000 )
120+ else :
121+ sleep_ms (500 )
111122 led_val = 0
112123
113124 try :
114125 while not self .is_on ():
126+
115127 if check_on_thread and not self .__class__ ._update_thread_running :
116128 break
117- _ESP32_SDA = Pin (A4 , Pin .OUT )
118- _ESP32_SCL = Pin (A5 , Pin .OUT )
119- _ESP32_SCL .value (1 )
120- _ESP32_SDA .value (1 )
121- sleep_ms (100 )
122- _ESP32_SCL .value (0 )
123- _ESP32_SDA .value (0 )
124129
125130 cmd = bytearray (1 )
126131 cmd [0 ] = 0x06
127- i2c = I2C (0 , scl = ESP32_SCL , sda = ESP32_SDA )
128- i2c .writeto (0x36 , cmd )
129- soc_raw = struct .unpack ('h' , i2c .readfrom (0x36 , 2 ))[0 ]
132+
133+ self .i2c .start ()
134+ self .i2c .writeto (0x36 , cmd )
135+
136+ soc_raw = struct .unpack ('h' , self .i2c .readfrom (0x36 , 2 ))[0 ]
130137 soc_perc = soc_raw * 0.00390625
131138 self ._progress_bar (round (soc_perc ))
132- sleep_ms (delay_ )
139+ if blocking :
140+ self ._lenghty_op (10000 )
141+ else :
142+ sleep_ms (delay_ )
133143 if soc_perc > 97 :
134144 LEDG .value (0 )
135145 LEDR .value (1 )
136146 else :
137147 LEDR .value (led_val )
138148 LEDG .value (1 )
139149 led_val = (led_val + 1 ) % 2
140- print ("********** Alvik is on **********" )
150+ self .i2c .set_single_thread (False )
151+ if self .is_on ():
152+ print ("********** Alvik is on **********" )
141153 except KeyboardInterrupt :
142154 self .stop ()
143155 sys .exit ()
144156 except Exception as e :
145157 pass
146- # print(f'Unable to read SOC: {e}')
158+ print (f'Unable to read SOC: { e } ' )
147159 finally :
148160 LEDR .value (1 )
149161 LEDG .value (1 )
150162 NANO_CHK .value (0 )
163+ self .i2c .set_single_thread (False )
151164
152165 @staticmethod
153166 def _snake_robot (duration : int = 1000 ):
@@ -184,6 +197,7 @@ def begin(self) -> int:
184197 if not self .is_on ():
185198 print ("\n ********** Please turn on your Arduino Alvik! **********\n " )
186199 sleep_ms (1000 )
200+ self .i2c .set_main_thread (_thread .get_ident ())
187201 self ._idle (1000 )
188202 self ._begin_update_thread ()
189203
@@ -579,6 +593,9 @@ def _update(self, delay_=1):
579593 :param delay_: while loop delay (ms)
580594 :return:
581595 """
596+
597+ self .i2c .set_main_thread (_thread .get_ident ())
598+
582599 while True :
583600 if not self .is_on ():
584601 print ("Alvik is off" )
@@ -1249,6 +1266,177 @@ def _stop_events_thread(cls):
12491266 cls ._events_thread_running = False
12501267
12511268
1269+ class _ArduinoAlvikI2C :
1270+
1271+ _main_thread_id = None
1272+
1273+ def __init__ (self , sda : int , scl : int ):
1274+ """
1275+ Alvik I2C wrapper
1276+ :param sda:
1277+ :param scl:
1278+ """
1279+ self ._lock = _thread .allocate_lock ()
1280+
1281+ self ._is_single_thread = False
1282+
1283+ self .sda = sda
1284+ self .scl = scl
1285+
1286+ def set_main_thread (self , thread_id : int ):
1287+ """
1288+ Sets the main thread of control. It will be the only thread allowed if set_single_thread is True
1289+ """
1290+ with self ._lock :
1291+ self .__class__ ._main_thread_id = thread_id
1292+
1293+ def set_single_thread (self , value ):
1294+ """
1295+ Sets the single thread mode on/off.
1296+ In single mode only the main thread is allowed to access the bus
1297+ """
1298+ self ._is_single_thread = value
1299+
1300+ def is_accessible (self ):
1301+ """
1302+ Returns True if bus is accessible by the current thread
1303+ """
1304+ return not self ._is_single_thread or _thread .get_ident () == self .__class__ ._main_thread_id
1305+
1306+ def start (self ):
1307+ """
1308+ Bitbanging start condition
1309+ :return:
1310+ """
1311+ _SDA = Pin (self .sda , Pin .OUT )
1312+ _SDA .value (1 )
1313+ sleep_ms (100 )
1314+ _SDA .value (0 )
1315+
1316+ def init (self , scl , sda , freq = 400_000 ) -> None :
1317+ """
1318+ init method just for call compatibility
1319+ """
1320+ print ("AlvikWarning:: init Unsupported. Alvik defines/initializes its own I2C bus" )
1321+
1322+ def deinit (self ):
1323+ """
1324+ deinit method just for call compatibility
1325+ """
1326+ print ("AlvikWarning:: deinit Unsupported. Alvik defines/initializes its own I2C bus" )
1327+
1328+ def stop (self ):
1329+ """ Bitbanging stop condition (untested)
1330+ :return:
1331+ """
1332+ _SDA = Pin (self .sda , Pin .OUT )
1333+ _SDA .value (0 )
1334+ sleep_ms (100 )
1335+ _SDA .value (1 )
1336+
1337+ def scan (self ) -> list [int ]:
1338+ """
1339+ I2C scan method
1340+ :return:
1341+ """
1342+ if not self .is_accessible ():
1343+ return []
1344+ with self ._lock :
1345+ i2c = I2C (0 , scl = Pin (self .scl , Pin .OUT ), sda = Pin (self .sda , Pin .OUT ))
1346+ return i2c .scan ()
1347+
1348+ def readfrom (self , addr , nbytes , stop = True ) -> bytes :
1349+ """
1350+ Wrapping i2c readfrom
1351+ """
1352+ if not self .is_accessible ():
1353+ return bytes (nbytes )
1354+ with self ._lock :
1355+ i2c = I2C (0 , scl = Pin (self .scl , Pin .OUT ), sda = Pin (self .sda , Pin .OUT ))
1356+ return i2c .readfrom (addr , nbytes , stop )
1357+
1358+ def writeto (self , addr , buf , stop = True ) -> int :
1359+ """
1360+ Wrapping i2c writeto
1361+ """
1362+ if not self .is_accessible ():
1363+ return 0
1364+ with self ._lock :
1365+ i2c = I2C (0 , scl = Pin (self .scl , Pin .OUT ), sda = Pin (self .sda , Pin .OUT ))
1366+ return i2c .writeto (addr , buf , stop )
1367+
1368+ def readinto (self , buf , nack = True ) -> None :
1369+ """
1370+ Wrapping i2c readinto
1371+ """
1372+ if not self .is_accessible ():
1373+ return
1374+ with self ._lock :
1375+ i2c = I2C (0 , scl = Pin (self .scl , Pin .OUT ), sda = Pin (self .sda , Pin .OUT ))
1376+ return i2c .readinto (buf , nack )
1377+
1378+ def write (self , buf ) -> int :
1379+ """
1380+ Wrapping i2c write
1381+ """
1382+ if not self .is_accessible ():
1383+ return 0
1384+ with self ._lock :
1385+ i2c = I2C (0 , scl = Pin (self .scl , Pin .OUT ), sda = Pin (self .sda , Pin .OUT ))
1386+ return i2c .write (buf )
1387+
1388+ def readfrom_into (self , addr , buf , stop = True ) -> None :
1389+ """
1390+ Wrapping i2c readfrom_into
1391+ """
1392+ if not self .is_accessible ():
1393+ return
1394+ with self ._lock :
1395+ i2c = I2C (0 , scl = Pin (self .scl , Pin .OUT ), sda = Pin (self .sda , Pin .OUT ))
1396+ return i2c .readfrom_into (addr , buf , stop )
1397+
1398+ def writevto (self , addr , vector , stop = True ) -> int :
1399+ """
1400+ Wrapping i2c writevto
1401+ """
1402+ if not self .is_accessible ():
1403+ return 0
1404+ with self ._lock :
1405+ i2c = I2C (0 , scl = Pin (self .scl , Pin .OUT ), sda = Pin (self .sda , Pin .OUT ))
1406+ return i2c .writevto (addr , vector , stop )
1407+
1408+ def readfrom_mem (self , addr , memaddr , nbytes , addrsize = 8 ) -> bytes :
1409+ """
1410+ Wrapping i2c readfrom_mem
1411+ """
1412+ if not self .is_accessible ():
1413+ return bytes (nbytes )
1414+ with self ._lock :
1415+ i2c = I2C (0 , scl = Pin (self .scl , Pin .OUT ), sda = Pin (self .sda , Pin .OUT ))
1416+ return i2c .readfrom_mem (addr , memaddr , nbytes , addrsize = addrsize )
1417+
1418+ def readfrom_mem_into (self , addr , memaddr , buf , addrsize = 8 ) -> None :
1419+ """
1420+ Wrapping i2c readfrom_mem_into
1421+ """
1422+ if not self .is_accessible ():
1423+ return
1424+ with self ._lock :
1425+ i2c = I2C (0 , scl = Pin (self .scl , Pin .OUT ), sda = Pin (self .sda , Pin .OUT ))
1426+ return i2c .readfrom_mem_into (addr , memaddr , buf , addrsize = addrsize )
1427+
1428+ def writeto_mem (self , addr , memaddr , buf , addrsize = 8 ) -> None :
1429+ """
1430+ Wrapping i2c writeto_mem
1431+ """
1432+ if not self .is_accessible ():
1433+ return
1434+ with self ._lock :
1435+ i2c = I2C (0 , scl = Pin (self .scl , Pin .OUT ), sda = Pin (self .sda , Pin .OUT ))
1436+ return i2c .writeto_mem (addr , memaddr , buf , addrsize = addrsize )
1437+
1438+
1439+
12521440class _ArduinoAlvikServo :
12531441
12541442 def __init__ (self , packeter : ucPack , label : str , servo_id : int , position : list [int | None ]):
0 commit comments