@@ -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' ), alvik = self )
3132 self .right_wheel = _ArduinoAlvikWheel (self ._packeter , ord ('R' ), alvik = self )
@@ -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
@@ -584,6 +598,9 @@ def _update(self, delay_=1):
584598 :param delay_: while loop delay (ms)
585599 :return:
586600 """
601+
602+ self .i2c .set_main_thread (_thread .get_ident ())
603+
587604 while True :
588605 if not self .is_on ():
589606 print ("Alvik is off" )
@@ -1254,6 +1271,177 @@ def _stop_events_thread(cls):
12541271 cls ._events_thread_running = False
12551272
12561273
1274+ class _ArduinoAlvikI2C :
1275+
1276+ _main_thread_id = None
1277+
1278+ def __init__ (self , sda : int , scl : int ):
1279+ """
1280+ Alvik I2C wrapper
1281+ :param sda:
1282+ :param scl:
1283+ """
1284+ self ._lock = _thread .allocate_lock ()
1285+
1286+ self ._is_single_thread = False
1287+
1288+ self .sda = sda
1289+ self .scl = scl
1290+
1291+ def set_main_thread (self , thread_id : int ):
1292+ """
1293+ Sets the main thread of control. It will be the only thread allowed if set_single_thread is True
1294+ """
1295+ with self ._lock :
1296+ self .__class__ ._main_thread_id = thread_id
1297+
1298+ def set_single_thread (self , value ):
1299+ """
1300+ Sets the single thread mode on/off.
1301+ In single mode only the main thread is allowed to access the bus
1302+ """
1303+ self ._is_single_thread = value
1304+
1305+ def is_accessible (self ):
1306+ """
1307+ Returns True if bus is accessible by the current thread
1308+ """
1309+ return not self ._is_single_thread or _thread .get_ident () == self .__class__ ._main_thread_id
1310+
1311+ def start (self ):
1312+ """
1313+ Bitbanging start condition
1314+ :return:
1315+ """
1316+ _SDA = Pin (self .sda , Pin .OUT )
1317+ _SDA .value (1 )
1318+ sleep_ms (100 )
1319+ _SDA .value (0 )
1320+
1321+ def init (self , scl , sda , freq = 400_000 ) -> None :
1322+ """
1323+ init method just for call compatibility
1324+ """
1325+ print ("AlvikWarning:: init Unsupported. Alvik defines/initializes its own I2C bus" )
1326+
1327+ def deinit (self ):
1328+ """
1329+ deinit method just for call compatibility
1330+ """
1331+ print ("AlvikWarning:: deinit Unsupported. Alvik defines/initializes its own I2C bus" )
1332+
1333+ def stop (self ):
1334+ """ Bitbanging stop condition (untested)
1335+ :return:
1336+ """
1337+ _SDA = Pin (self .sda , Pin .OUT )
1338+ _SDA .value (0 )
1339+ sleep_ms (100 )
1340+ _SDA .value (1 )
1341+
1342+ def scan (self ) -> list [int ]:
1343+ """
1344+ I2C scan method
1345+ :return:
1346+ """
1347+ if not self .is_accessible ():
1348+ return []
1349+ with self ._lock :
1350+ i2c = I2C (0 , scl = Pin (self .scl , Pin .OUT ), sda = Pin (self .sda , Pin .OUT ))
1351+ return i2c .scan ()
1352+
1353+ def readfrom (self , addr , nbytes , stop = True ) -> bytes :
1354+ """
1355+ Wrapping i2c readfrom
1356+ """
1357+ if not self .is_accessible ():
1358+ return bytes (nbytes )
1359+ with self ._lock :
1360+ i2c = I2C (0 , scl = Pin (self .scl , Pin .OUT ), sda = Pin (self .sda , Pin .OUT ))
1361+ return i2c .readfrom (addr , nbytes , stop )
1362+
1363+ def writeto (self , addr , buf , stop = True ) -> int :
1364+ """
1365+ Wrapping i2c writeto
1366+ """
1367+ if not self .is_accessible ():
1368+ return 0
1369+ with self ._lock :
1370+ i2c = I2C (0 , scl = Pin (self .scl , Pin .OUT ), sda = Pin (self .sda , Pin .OUT ))
1371+ return i2c .writeto (addr , buf , stop )
1372+
1373+ def readinto (self , buf , nack = True ) -> None :
1374+ """
1375+ Wrapping i2c readinto
1376+ """
1377+ if not self .is_accessible ():
1378+ return
1379+ with self ._lock :
1380+ i2c = I2C (0 , scl = Pin (self .scl , Pin .OUT ), sda = Pin (self .sda , Pin .OUT ))
1381+ return i2c .readinto (buf , nack )
1382+
1383+ def write (self , buf ) -> int :
1384+ """
1385+ Wrapping i2c write
1386+ """
1387+ if not self .is_accessible ():
1388+ return 0
1389+ with self ._lock :
1390+ i2c = I2C (0 , scl = Pin (self .scl , Pin .OUT ), sda = Pin (self .sda , Pin .OUT ))
1391+ return i2c .write (buf )
1392+
1393+ def readfrom_into (self , addr , buf , stop = True ) -> None :
1394+ """
1395+ Wrapping i2c readfrom_into
1396+ """
1397+ if not self .is_accessible ():
1398+ return
1399+ with self ._lock :
1400+ i2c = I2C (0 , scl = Pin (self .scl , Pin .OUT ), sda = Pin (self .sda , Pin .OUT ))
1401+ return i2c .readfrom_into (addr , buf , stop )
1402+
1403+ def writevto (self , addr , vector , stop = True ) -> int :
1404+ """
1405+ Wrapping i2c writevto
1406+ """
1407+ if not self .is_accessible ():
1408+ return 0
1409+ with self ._lock :
1410+ i2c = I2C (0 , scl = Pin (self .scl , Pin .OUT ), sda = Pin (self .sda , Pin .OUT ))
1411+ return i2c .writevto (addr , vector , stop )
1412+
1413+ def readfrom_mem (self , addr , memaddr , nbytes , addrsize = 8 ) -> bytes :
1414+ """
1415+ Wrapping i2c readfrom_mem
1416+ """
1417+ if not self .is_accessible ():
1418+ return bytes (nbytes )
1419+ with self ._lock :
1420+ i2c = I2C (0 , scl = Pin (self .scl , Pin .OUT ), sda = Pin (self .sda , Pin .OUT ))
1421+ return i2c .readfrom_mem (addr , memaddr , nbytes , addrsize = addrsize )
1422+
1423+ def readfrom_mem_into (self , addr , memaddr , buf , addrsize = 8 ) -> None :
1424+ """
1425+ Wrapping i2c readfrom_mem_into
1426+ """
1427+ if not self .is_accessible ():
1428+ return
1429+ with self ._lock :
1430+ i2c = I2C (0 , scl = Pin (self .scl , Pin .OUT ), sda = Pin (self .sda , Pin .OUT ))
1431+ return i2c .readfrom_mem_into (addr , memaddr , buf , addrsize = addrsize )
1432+
1433+ def writeto_mem (self , addr , memaddr , buf , addrsize = 8 ) -> None :
1434+ """
1435+ Wrapping i2c writeto_mem
1436+ """
1437+ if not self .is_accessible ():
1438+ return
1439+ with self ._lock :
1440+ i2c = I2C (0 , scl = Pin (self .scl , Pin .OUT ), sda = Pin (self .sda , Pin .OUT ))
1441+ return i2c .writeto_mem (addr , memaddr , buf , addrsize = addrsize )
1442+
1443+
1444+
12571445class _ArduinoAlvikServo :
12581446
12591447 def __init__ (self , packeter : ucPack , label : str , servo_id : int , position : list [int | None ]):
0 commit comments