diff --git a/src/main/kotlin/com/jetbrains/micropython/devices/Esp32DeviceProvider.kt b/src/main/kotlin/com/jetbrains/micropython/devices/Esp32DeviceProvider.kt new file mode 100644 index 00000000..2fc6bf51 --- /dev/null +++ b/src/main/kotlin/com/jetbrains/micropython/devices/Esp32DeviceProvider.kt @@ -0,0 +1,51 @@ +package com.jetbrains.micropython.devices + +import com.intellij.execution.configurations.CommandLineState +import com.intellij.execution.configurations.GeneralCommandLine +import com.intellij.execution.process.OSProcessHandler +import com.intellij.execution.runners.ExecutionEnvironment +import com.intellij.openapi.projectRoots.Sdk +import com.jetbrains.micropython.run.MicroPythonRunConfiguration +import com.jetbrains.micropython.run.getMicroUploadCommand +import com.jetbrains.micropython.settings.MicroPythonTypeHints +import com.jetbrains.micropython.settings.MicroPythonUsbId +import com.jetbrains.python.packaging.PyPackageManager +import com.jetbrains.python.packaging.PyRequirement + +/** + * @author Gor-Ren + */ +class Esp32DeviceProvider : MicroPythonDeviceProvider { + override val persistentName: String + get() = "ESP32" + + override val documentationURL: String + get() = "https://github.com/vlasovskikh/intellij-micropython/wiki/ESP32" + + override val usbIds: List + get() = listOf(MicroPythonUsbId(0x1A86, 0x7523), + MicroPythonUsbId(0x10C4, 0xEA60), + MicroPythonUsbId(0x0403, 0x6001)) + + override val typeHints: MicroPythonTypeHints by lazy { + MicroPythonTypeHints(listOf("stdlib", "micropython", "esp32")) + } + + override fun getPackageRequirements(sdk: Sdk): List { + val manager = PyPackageManager.getInstance(sdk) + return manager.parseRequirements("""|pyserial>=3.3,<4.0 + |docopt>=0.6.2,<0.7 + |adafruit-ampy>=1.0.5,<1.1""".trimMargin()) + } + + override fun getRunCommandLineState(configuration: MicroPythonRunConfiguration, + environment: ExecutionEnvironment): CommandLineState? { + val module = configuration.module ?: return null + val command = getMicroUploadCommand(configuration.path, module) ?: return null + + return object : CommandLineState(environment) { + override fun startProcess() = + OSProcessHandler(GeneralCommandLine(command)) + } + } +} diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 3b992443..f13c7749 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -72,6 +72,7 @@ + diff --git a/typehints/esp32/esp.pyi b/typehints/esp32/esp.pyi new file mode 100644 index 00000000..5269d73d --- /dev/null +++ b/typehints/esp32/esp.pyi @@ -0,0 +1,70 @@ + +from typing import Optional + +def sleep_type(sleep_type: Optional[int]) -> Optional[int]: + """ + Get or set the sleep type. + + If the sleep_type parameter is provided, sets the sleep type to its value. + If the function is called without parameters, returns the current sleep type. + + The possible sleep types are defined as constants: + + * ``SLEEP_NONE`` – all functions enabled,\n + * ``SLEEP_MODEM`` – modem sleep, shuts down the WiFi Modem circuit.\n + * ``SLEEP_LIGHT`` – light sleep, shuts down the WiFi Modem circuit and suspends the processor periodically.\n + The system enters the set sleep mode automatically when possible. + + :param sleep_type: Sleep type. + :type sleep_type: int + :return: Current sleep type + :rtype: int + """ + +def deepsleep(time: int = 0) -> None: + """ + Enter deep sleep. + + The whole module powers down, except for the RTC clock circuit, which can + be used to restart the module after the specified time if the pin 16 is + connected to the reset pin. Otherwise the module will sleep until manually reset. + + :param time: Amount of time in milliseconds to sleep. + """ + +def set_native_code_location(start: Optional[int], length: Optional[int]) -> None: + """ + Set the location that native code will be placed for execution after it is + compiled. Native code is emitted when the ``@micropython.native``, ``@micropython.viper`` + and ``@micropython.asm_xtensa`` decorators are applied to a function. The + ESP8266 must execute code from either iRAM or the lower 1MByte of flash + (which is memory mapped), and this function controls the location. + + If start and length are both **None** then the native code location is + set to the unused portion of memory at the end of the iRAM1 region. The + size of this unused portion depends on the firmware and is typically + quite small (around 500 bytes), and is enough to store a few very small + functions. The advantage of using this iRAM1 region is that it does not + get worn out by writing to it. + + If neither start nor length are None then they should be integers. start + should specify the byte offset from the beginning of the flash at which + native code should be stored. length specifies how many bytes of flash + from start can be used to store native code. start and length should be + multiples of the sector size (being 4096 bytes). The flash will be + automatically erased before writing to it so be sure to use a region of + flash that is not otherwise used, for example by the firmware or the filesystem. + + When using the flash to store native code *start*+*length* must be less + than or equal to 1MByte. Note that the flash can be worn out if repeated + erasures (and writes) are made so use this feature sparingly. In particular, + native code needs to be recompiled and rewritten to flash on each boot + (including wake from deepsleep). + + In both cases above, using iRAM1 or flash, if there is no more room left in + the specified region then the use of a native decorator on a function will + lead to ``MemoryError`` exception being raised during compilation of that function. + + :param start: Start of native code region. + :param length: End of native code region. + """ \ No newline at end of file diff --git a/typehints/esp32/network.pyi b/typehints/esp32/network.pyi new file mode 100644 index 00000000..7f61fd26 --- /dev/null +++ b/typehints/esp32/network.pyi @@ -0,0 +1,203 @@ +"""network configuration + +This module provides network drivers and routing configuration. To use this +module, a MicroPython variant/build with network capabilities must be installed. +Network drivers for specific hardware are available within this module and are +used to configure hardware network interface(s). Network services provided +by configured interfaces are then available for use via the :mod:`usocket` +module. + +For example:: + + # connect/ show IP config a specific network interface + # see below for examples of specific drivers + import network + import utime + nic = network.Driver(...) + if not nic.isconnected(): + nic.connect() + print("Waiting for connection...") + while not nic.isconnected(): + utime.sleep(1) + print(nic.ifconfig()) + + # now use usocket as usual + import usocket as socket + addr = socket.getaddrinfo('micropython.org', 80)[0][-1] + s = socket.socket() + s.connect(addr) + s.send(b'GET / HTTP/1.1\r\nHost: micropython.org\r\n\r\n') + data = s.recv(1000) + s.close() +""" + +from typing import overload, Optional, List, Tuple, Union, Any + + +@overload +def phy_mode() -> int: + """Get the PHY mode.""" + ... + + +@overload +def phy_mode(mode: int) -> None: + """Set the PHY mode. + + The possible modes are defined as constants: + * ``MODE_11B`` -- IEEE 802.11b, + * ``MODE_11G`` -- IEEE 802.11g, + * ``MODE_11N`` -- IEEE 802.11n. + """ + ... + + +class WLAN: + def __init__(self, interface_id: int) -> None: + """Create a WLAN network interface object. Supported interfaces are + ``network.STA_IF`` (station aka client, connects to upstream WiFi access + points) and ``network.AP_IF`` (access point, allows other WiFi clients to + connect). Availability of the methods below depends on interface type. + For example, only STA interface may `connect()` to an access point. + """ + ... + + @overload + def active(self) -> bool: + """Query current state of the interface.""" + ... + + @overload + def active(self, is_active: bool) -> None: + """Activate ("up") or deactivate ("down") network interface.""" + ... + + def connect(self, ssid: Optional[Union[bytes, str]] = None, + password: Optional[Union[bytes, str]] = None, *, + bssid: Optional[Union[bytes, str]] = None) -> None: + """Connect to the specified wireless network, using the specified password. + If *bssid* is given then the connection will be restricted to the + access-point with that MAC address (the *ssid* must also be specified + in this case). + """ + ... + + def disconnect(self) -> None: + """Disconnect from the currently connected wireless network.""" + ... + + def scan(self) -> List[Tuple[bytes, bytes, int, int, int, int]]: + """Scan for the available wireless networks. + + Scanning is only possible on STA interface. Returns list of tuples with + the information about WiFi access points: + + (ssid, bssid, channel, RSSI, authmode, hidden) + + *bssid* is hardware address of an access point, in binary form, returned as + bytes object. You can use `ubinascii.hexlify()` to convert it to ASCII form. + + There are five values for authmode: + + * 0 -- open + * 1 -- WEP + * 2 -- WPA-PSK + * 3 -- WPA2-PSK + * 4 -- WPA/WPA2-PSK + + and two for hidden: + + * 0 -- visible + * 1 -- hidden + """ + ... + + def status(self) -> int: + """Return the current status of the wireless connection. + + The possible statuses are defined as constants: + + * ``STAT_IDLE`` -- no connection and no activity, + * ``STAT_CONNECTING`` -- connecting in progress, + * ``STAT_WRONG_PASSWORD`` -- failed due to incorrect password, + * ``STAT_NO_AP_FOUND`` -- failed because no access point replied, + * ``STAT_CONNECT_FAIL`` -- failed due to other problems, + * ``STAT_GOT_IP`` -- connection successful. + """ + ... + + def isconnected(self) -> bool: + """In case of STA mode, returns ``True`` if connected to a WiFi access + point and has a valid IP address. In AP mode returns ``True`` when a + station is connected. Returns ``False`` otherwise. + """ + ... + + @overload + def ifconfig(self) -> Tuple[str, str, str, str]: + """Get IP-level network interface parameters: IP address, subnet mask, + gateway and DNS server. + """ + ... + + @overload + def ifconfig(self, ip: str, subnet: str, gateway: str, dns: str) -> None: + """Get/set IP-level network interface parameters: IP address, subnet mask, + gateway and DNS server. + """ + ... + + @overload + def config(self, param: str) -> Any: + """Get general network interface parameters.""" + ... + + @overload + def config(self, **kwargs: Any) -> None: + """Get or set general network interface parameters. These methods allow to work + with additional parameters beyond standard IP configuration (as dealt with by + `wlan.ifconfig()`). These include network-specific and hardware-specific + parameters. For setting parameters, keyword argument syntax should be used, + multiple parameters can be set at once. For querying, parameters name should + be quoted as a string, and only one parameter can be queries at time:: + + # Set WiFi access point name (formally known as ESSID) and WiFi channel + ap.config(essid='My AP', channel=11) + # Query params one by one + print(ap.config('essid')) + print(ap.config('channel')) + + Following are commonly supported parameters (availability of a specific parameter + depends on network technology type, driver, and `MicroPython port`). + + ============= =========== + Parameter Description + ============= =========== + mac MAC address (bytes) + essid WiFi access point name (string) + channel WiFi channel (integer) + hidden Whether ESSID is hidden (boolean) + authmode Authentication mode supported (enumeration, see module constants) + password Access password (string) + dhcp_hostname The DHCP hostname to use + ============= =========== + """ + ... + + +STA_IF: int +AP_IF: int + + +STAT_IDLE: int +STAT_CONNECTING: int +STAT_WRONG_PASSWORD: int +STAT_NO_AP_FOUND: int +STAT_CONNECT_FAIL: int +STAT_GOT_IP: int + + +MODE_11B: int +MODE_11G: int +MODE_11N: int +