1148 [], |
1183 [], |
1149 self.tr("CircuitPython does not support reporting of connected clients."), |
1184 self.tr("CircuitPython does not support reporting of connected clients."), |
1150 ) |
1185 ) |
1151 |
1186 |
1152 ################################################################## |
1187 ################################################################## |
|
1188 ## Methods below implement Ethernet related methods |
|
1189 ################################################################## |
|
1190 |
|
1191 def hasEthernet(self): |
|
1192 """ |
|
1193 Public method to check the availability of Ethernet. |
|
1194 |
|
1195 @return tuple containing a flag indicating the availability of Ethernet |
|
1196 and the Ethernet type |
|
1197 @rtype tuple of (bool, str) |
|
1198 @exception OSError raised to indicate an issue with the device |
|
1199 """ |
|
1200 command = """ |
|
1201 def has_eth(): |
|
1202 try: |
|
1203 from adafruit_wiznet5k import adafruit_wiznet5k |
|
1204 if hasattr(adafruit_wiznet5k, 'WIZNET5K'): |
|
1205 return True, 'cpypicowiz' |
|
1206 except ImportError: |
|
1207 pass |
|
1208 |
|
1209 return False, '' |
|
1210 |
|
1211 print(has_eth()) |
|
1212 del has_eth |
|
1213 """ |
|
1214 |
|
1215 out, err = self._interface.execute( |
|
1216 command, mode=self._submitMode, timeout=10000 |
|
1217 ) |
|
1218 if err: |
|
1219 raise OSError(self._shortError(err)) |
|
1220 |
|
1221 return ast.literal_eval(out.decode("utf-8")) |
|
1222 |
|
1223 def getEthernetStatus(self): |
|
1224 """ |
|
1225 Public method to get Ethernet status data of the connected board. |
|
1226 |
|
1227 @return list of tuples containing the translated status data label and |
|
1228 the associated value |
|
1229 @rtype list of tuples of (str, str) |
|
1230 @exception OSError raised to indicate an issue with the device |
|
1231 """ |
|
1232 command = """{0} |
|
1233 def ethernet_status(): |
|
1234 import binascii |
|
1235 import json |
|
1236 |
|
1237 w5x00_init() |
|
1238 |
|
1239 res = {{ |
|
1240 'active': nic.link_status != 0, |
|
1241 'connected': nic.link_status == 1 and nic.ifconfig[0] != b'\x00\x00\x00\x00', |
|
1242 'ifconfig': ( |
|
1243 nic.pretty_ip(nic.ifconfig[0]), |
|
1244 nic.pretty_ip(nic.ifconfig[1]), |
|
1245 nic.pretty_ip(nic.ifconfig[2]), |
|
1246 nic.pretty_ip(nic.ifconfig[3]), |
|
1247 ), |
|
1248 'mac': binascii.hexlify(nic.mac_address, ':').decode(), |
|
1249 'chip': nic.chip, |
|
1250 'max_sockets': nic.max_sockets, |
|
1251 }} |
|
1252 print(json.dumps(res)) |
|
1253 |
|
1254 ethernet_status() |
|
1255 del ethernet_status, w5x00_init |
|
1256 """.format( |
|
1257 WiznetUtilities.cpyWiznetInit() |
|
1258 ) |
|
1259 |
|
1260 out, err = self._interface.execute( |
|
1261 command, mode=self._submitMode, timeout=10000 |
|
1262 ) |
|
1263 if err: |
|
1264 raise OSError(self._shortError(err)) |
|
1265 |
|
1266 status = [] |
|
1267 ethStatus = json.loads(out.decode("utf-8")) |
|
1268 status.append((self.tr("Active"), self.bool2str(ethStatus["active"]))) |
|
1269 status.append((self.tr("Connected"), self.bool2str(ethStatus["connected"]))) |
|
1270 status.append((self.tr("IPv4 Address"), ethStatus["ifconfig"][0])) |
|
1271 status.append((self.tr("Netmask"), ethStatus["ifconfig"][1])) |
|
1272 status.append((self.tr("Gateway"), ethStatus["ifconfig"][2])) |
|
1273 status.append((self.tr("DNS"), ethStatus["ifconfig"][3])) |
|
1274 status.append((self.tr("MAC-Address"), ethStatus["mac"])) |
|
1275 status.append((self.tr("Chip Type"), ethStatus["chip"])) |
|
1276 status.append((self.tr("max. Sockets"), ethStatus["max_sockets"])) |
|
1277 |
|
1278 return status |
|
1279 |
|
1280 def connectToLan(self, config): |
|
1281 """ |
|
1282 Public method to connect the connected device to the LAN. |
|
1283 |
|
1284 Note: The MAC address of the interface is configured with the WIZ |
|
1285 |
|
1286 @param config configuration for the connection (either the string 'dhcp' |
|
1287 for a dynamic address or a tuple of four strings with the IPv4 parameters. |
|
1288 @type str or tuple of (str, str, str, str) |
|
1289 @return tuple containing a flag indicating success and an error message |
|
1290 @rtype tuple of (bool, str) |
|
1291 """ |
|
1292 command = """{0} |
|
1293 def connect_lan(config): |
|
1294 from adafruit_wiznet5k import adafruit_wiznet5k |
|
1295 |
|
1296 w5x00_init() |
|
1297 |
|
1298 nic.mac_address = adafruit_wiznet5k._DEFAULT_MAC |
|
1299 if config == 'dhcp': |
|
1300 nic.set_dhcp(response_timeout=14) |
|
1301 else: |
|
1302 nic.ifconfig = ( |
|
1303 nic.unpretty_ip(config[0]), |
|
1304 nic.unpretty_ip(config[1]), |
|
1305 nic.unpretty_ip(config[2]), |
|
1306 tuple(int(a) for a in config[3].split('.')), |
|
1307 ) |
|
1308 print(nic.ifconfig[0] != b'\x00\x00\x00\x00') |
|
1309 |
|
1310 connect_lan({1}) |
|
1311 del connect_lan, w5x00_init |
|
1312 """.format( |
|
1313 WiznetUtilities.cpyWiznetInit(), "'dhcp'" if config == "dhcp" else config |
|
1314 ) |
|
1315 |
|
1316 with EricOverrideCursor(): |
|
1317 out, err = self._interface.execute( |
|
1318 command, mode=self._submitMode, timeout=15000 |
|
1319 ) |
|
1320 if err: |
|
1321 return False, err |
|
1322 |
|
1323 return out.strip() == b"True", "" |
|
1324 |
|
1325 def disconnectFromLan(self): |
|
1326 """ |
|
1327 Public method to disconnect from the LAN. |
|
1328 |
|
1329 @return tuple containing a flag indicating success and an error message |
|
1330 @rtype tuple of (bool, str) |
|
1331 """ |
|
1332 command = """{0} |
|
1333 def disconnect_lan(): |
|
1334 import time |
|
1335 |
|
1336 w5x00_init() |
|
1337 |
|
1338 nic.sw_reset() |
|
1339 time.sleep(1) |
|
1340 print(nic.ifconfig[0] == b'\x00\x00\x00\x00') |
|
1341 |
|
1342 disconnect_lan() |
|
1343 del disconnect_lan, w5x00_init |
|
1344 """.format( |
|
1345 WiznetUtilities.cpyWiznetInit(), |
|
1346 ) |
|
1347 |
|
1348 with EricOverrideCursor(): |
|
1349 out, err = self._interface.execute( |
|
1350 command, mode=self._submitMode, timeout=15000 |
|
1351 ) |
|
1352 if err: |
|
1353 return False, err |
|
1354 |
|
1355 return out.strip() == b"True", "" |
|
1356 |
|
1357 def checkInternetViaLan(self): |
|
1358 """ |
|
1359 Public method to check, if the internet can be reached (LAN variant). |
|
1360 |
|
1361 @return tuple containing a flag indicating reachability and an error string |
|
1362 @rtype tuple of (bool, str) |
|
1363 """ |
|
1364 command = """{0} |
|
1365 def check_internet(): |
|
1366 w5x00_init() |
|
1367 |
|
1368 if nic.ifconfig[0] != b'\x00\x00\x00\x00': |
|
1369 sock = nic.get_socket() |
|
1370 try: |
|
1371 nic.socket_connect(sock, nic.get_host_by_name('quad9.net'), 80) |
|
1372 nic.socket_disconnect(sock) |
|
1373 print(True) |
|
1374 except: |
|
1375 print(False) |
|
1376 nic.socket_close(sock) |
|
1377 else: |
|
1378 print(False) |
|
1379 |
|
1380 check_internet() |
|
1381 del check_internet, w5x00_init |
|
1382 """.format( |
|
1383 WiznetUtilities.cpyWiznetInit(), |
|
1384 ) |
|
1385 |
|
1386 out, err = self._interface.execute( |
|
1387 command, mode=self._submitMode, timeout=15000 |
|
1388 ) |
|
1389 if err: |
|
1390 return False, err |
|
1391 |
|
1392 return out.strip() == b"True", "" |
|
1393 |
|
1394 def deactivateEthernet(self): |
|
1395 """ |
|
1396 Public method to deactivate the Ethernet interface of the connected device. |
|
1397 |
|
1398 @return tuple containg a flag indicating success and an error message |
|
1399 @rtype tuple of (bool, str) |
|
1400 """ |
|
1401 # The WIZnet 5x00 interface cannot be switched off explicitly. That means, |
|
1402 # disconnect from the LAN is all we can do. |
|
1403 |
|
1404 return self.disconnectFromLan() |
|
1405 |
|
1406 def writeLanAutoConnect(self, config): |
|
1407 """ |
|
1408 Public method to generate a script and associated configuration to connect the |
|
1409 device to the LAN during boot time. |
|
1410 |
|
1411 @param config configuration for the connection (either the string 'dhcp' |
|
1412 for a dynamic address or a tuple of four strings with the IPv4 parameters. |
|
1413 @type str or tuple of (str, str, str, str) |
|
1414 @return tuple containing a flag indicating success and an error message |
|
1415 @rtype tuple of (bool, str) |
|
1416 """ |
|
1417 if not self.__deviceVolumeMounted(): |
|
1418 return False, self.tr("The device volume is not available.") |
|
1419 |
|
1420 workspace = self.getWorkspace() |
|
1421 |
|
1422 if Globals.versionToTuple(self._deviceData["release"]) >= (8, 0, 0): |
|
1423 # CircuitPython >= 8.0.0: generate 'settings.toml' file |
|
1424 newConfig = ( |
|
1425 { |
|
1426 "WIZNET_IFCONFIG_0": '"dhcp"', |
|
1427 "WIZNET_IFCONFIG_1": "", |
|
1428 "WIZNET_IFCONFIG_2": "", |
|
1429 "WIZNET_IFCONFIG_3": "", |
|
1430 } |
|
1431 if config == "dhcp" |
|
1432 else { |
|
1433 "WIZNET_IFCONFIG_0": '"{0}"'.format(config[0]), |
|
1434 "WIZNET_IFCONFIG_1": '"{0}"'.format(config[1]), |
|
1435 "WIZNET_IFCONFIG_2": '"{0}"'.format(config[2]), |
|
1436 "WIZNET_IFCONFIG_3": '"{0}"'.format(config[3]), |
|
1437 } |
|
1438 ) |
|
1439 ok, err = self.__modifySettings(newConfig) |
|
1440 if not ok: |
|
1441 return False, err |
|
1442 |
|
1443 scriptFile = os.path.join( |
|
1444 os.path.dirname(__file__), "MCUScripts", "picoWiznetConnectCpy8.py" |
|
1445 ) |
|
1446 |
|
1447 else: |
|
1448 # step 1: generate the wiznet_config.py file |
|
1449 ifconfig = "ifconfig = {0}\n".format( |
|
1450 "'dhcp'" if config == "dhcp" else config |
|
1451 ) |
|
1452 filename = os.path.join(workspace, "wiznet_config.py") |
|
1453 if os.path.exists(filename): |
|
1454 ok = EricMessageBox.yesNo( |
|
1455 None, |
|
1456 self.tr("Write Connect Script"), |
|
1457 self.tr( |
|
1458 """<p>The file <b>{0}</b> exists already. Shall it be""" |
|
1459 """ replaced?</p>""" |
|
1460 ).format(filename), |
|
1461 icon=EricMessageBox.Warning, |
|
1462 ) |
|
1463 if not ok: |
|
1464 return False, self.tr("Aborted") |
|
1465 try: |
|
1466 with open(filename, "w") as f: |
|
1467 f.write(ifconfig) |
|
1468 except OSError as err: |
|
1469 return False, str(err) |
|
1470 |
|
1471 scriptFile = os.path.join( |
|
1472 os.path.dirname(__file__), "MCUScripts", "picoWiznetConnectCpy7.py" |
|
1473 ) |
|
1474 |
|
1475 # step 2: create the auto-connect script (wiznet_connect.py) |
|
1476 targetFile = os.path.join(workspace, "wiznet_connect.py") |
|
1477 try: |
|
1478 shutil.copy2(scriptFile, targetFile) |
|
1479 except OSError as err: |
|
1480 return False, str(err) |
|
1481 # Note: code.py will not be modified because the connection will be |
|
1482 # reset anyway |
|
1483 return True, "" |
|
1484 |
|
1485 def removeLanAutoConnect(self): |
|
1486 """ |
|
1487 Public method to remove the saved IPv4 parameters from the connected device. |
|
1488 |
|
1489 Note: This disables the LAN auto-connect feature. |
|
1490 |
|
1491 @return tuple containing a flag indicating success and an error message |
|
1492 @rtype tuple of (bool, str) |
|
1493 """ |
|
1494 if not self.__deviceVolumeMounted(): |
|
1495 return False, self.tr("The device volume is not available.") |
|
1496 |
|
1497 workspace = self.getWorkspace() |
|
1498 |
|
1499 if Globals.versionToTuple(self._deviceData["release"]) >= (8, 0, 0): |
|
1500 # CircuitPython >= 8.0.0: generate 'settings.toml' file |
|
1501 newConfig = { |
|
1502 "WIZNET_IFCONFIG_0": "", |
|
1503 "WIZNET_IFCONFIG_1": "", |
|
1504 "WIZNET_IFCONFIG_2": "", |
|
1505 "WIZNET_IFCONFIG_3": "", |
|
1506 } |
|
1507 self.__modifySettings(newConfig) |
|
1508 |
|
1509 for name in ("wiznet_config.py", "wiznet_connect.py"): |
|
1510 filename = os.path.join(workspace, name) |
|
1511 if os.path.exists(filename): |
|
1512 os.remove(filename) |
|
1513 |
|
1514 return True, "" |
|
1515 # TODO: not implemented yet |
|
1516 |
|
1517 ################################################################## |
1153 ## Methods below implement Bluetooth related methods |
1518 ## Methods below implement Bluetooth related methods |
1154 ################################################################## |
1519 ################################################################## |
1155 |
1520 |
1156 def hasBluetooth(self): |
1521 def hasBluetooth(self): |
1157 """ |
1522 """ |
1443 'result': False, |
1851 'result': False, |
1444 'error': str(err), |
1852 'error': str(err), |
1445 }}) |
1853 }}) |
1446 del set_ntp_time |
1854 del set_ntp_time |
1447 """.format( |
1855 """.format( |
1448 repr(server), tzOffset, timeout |
1856 repr(server), tzOffset, timeout |
1449 ) |
1857 ) |
|
1858 |
1450 out, err = self._interface.execute( |
1859 out, err = self._interface.execute( |
1451 command, mode=self._submitMode, timeout=(timeout + 2) * 1000 |
1860 command, mode=self._submitMode, timeout=(timeout + 2) * 1000 |
1452 ) |
1861 ) |
1453 if err: |
1862 if err: |
1454 return False, err |
1863 return False, err |
1455 else: |
1864 else: |
1456 res = ast.literal_eval(out.decode("utf-8")) |
1865 res = ast.literal_eval(out.decode("utf-8")) |
1457 return res["result"], res["error"] |
1866 return res["result"], res["error"] |
|
1867 |
|
1868 ################################################################## |
|
1869 ## Methods below implement some utility methods |
|
1870 ################################################################## |
|
1871 |
|
1872 def __modifySettings(self, changedEntries): |
|
1873 """ |
|
1874 Private method to modify the 'settings.toml' file as of CircuitPython 8.0.0. |
|
1875 |
|
1876 @param changedEntries dictionary containing the TOML entries to be changed |
|
1877 @type dict of {str: str} |
|
1878 @return tuple containing a success flag and an error message |
|
1879 @rtype tuple of (bool, str) |
|
1880 """ |
|
1881 workspace = self.getWorkspace() |
|
1882 filename = os.path.join(workspace, "settings.toml") |
|
1883 if os.path.exists(filename): |
|
1884 try: |
|
1885 with open(filename, "r") as f: |
|
1886 lines = f.read().splitlines() |
|
1887 except OSError as err: |
|
1888 return False, str(err) |
|
1889 else: |
|
1890 lines = [] |
|
1891 |
|
1892 for key, value in changedEntries.items(): |
|
1893 newLine = "{0} = {1}".format(key, value) |
|
1894 for row in range(len(lines)): |
|
1895 if lines[row].split("=")[0].strip() == key: |
|
1896 if value == "": |
|
1897 del lines[row] |
|
1898 else: |
|
1899 lines[row] = newLine |
|
1900 break |
|
1901 else: |
|
1902 if value != "": |
|
1903 lines.append(newLine) |
|
1904 |
|
1905 try: |
|
1906 with open(filename, "w") as f: |
|
1907 f.write("\n".join(lines)) |
|
1908 except OSError as err: |
|
1909 return False, str(err) |
|
1910 |
|
1911 return True, "" |
1458 |
1912 |
1459 |
1913 |
1460 def createDevice(microPythonWidget, deviceType, vid, pid, boardName, serialNumber): |
1914 def createDevice(microPythonWidget, deviceType, vid, pid, boardName, serialNumber): |
1461 """ |
1915 """ |
1462 Function to instantiate a MicroPython device object. |
1916 Function to instantiate a MicroPython device object. |