diff --git a/README.md b/README.md
index d675ab0a5..5580104cc 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,23 @@
# Device Simulator Express, a Microsoft Garage project
+
+
+
+
Make without limit! Device Simulator Express, a Microsoft Garage project, allows you to code microcontrollers without the hardware on hand! You can program your Circuit Playground Express (CPX) or your BBC micro:bit! Test and debug your code on the device simulator and see the same
result when you plug in your actual microcontroller. Curious about the output of the device, the serial
monitor allows you to observe the device output.
+## Build Status
+
+| Branch | Build Status |
+| :------ | :-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
+| dev | [](https://microsoftgarage.visualstudio.com/Intern%20GitHub/_build/latest?definitionId=304&branchName=dev) |
+| staging | [](https://microsoftgarage.visualstudio.com/Intern%20GitHub/_build/latest?definitionId=304&branchName=staging) |
+| master | [](https://microsoftgarage.visualstudio.com/Intern%20GitHub/_build/latest?definitionId=304&branchName=master) |
+
## Prerequisites
@@ -89,7 +101,6 @@ Before deploying the python code to your CPX device, you need to format your dev
1. Download the firmware with the .uf2 file (link: https://learn.adafruit.com/adafruit-circuit-playground-express/circuitpython-quickstart)
2. Download the lastest version of the cpx library (link: https://learn.adafruit.com/welcome-to-circuitpython/circuitpython-libraries).
- **_Note:_** Make sure you name your file `main.py` or `code.py`: the device automatically runs the first file that is likely named. This is the convention for CircuitPython ([source](https://learn.adafruit.com/welcome-to-circuitpython/creating-and-editing-code#naming-your-program-file-7-32)).
Then, if you are on Windows, you will also need to install the Python Pywin32 package. Use the following command in the console: `pip install pywin32`
@@ -98,7 +109,7 @@ Then, if you are on Windows, you will also need to install the Python Pywin32 pa
#### 5. Use the Serial Monitor for your Adafruit CPX device (available on Windows and Mac only)
1. Plug in your CPX device (make sure itβs formatted properly already)
-2. Run the command `"Device Simulator Express: [Circuit Playground Express] Open Serial Monitor"`
+2. Run the command `"Device Simulator Express: Open Serial Monitor"`
3. Select your baud rate for the serial port
4. The print() statements in your code will show in the output console
@@ -123,11 +134,11 @@ Device Simulator Express provides several commands in the Command Palette (F1 or
- `Device Simulator Express: [Circuit Playground Express] New File`: Opens an unsaved .py file with template code, also opens the simulator.
- `Device Simulator Express: [Circuit Playground Express] Open Simulator`: Opens the simulator in the webView
- `Device Simulator Express: [Circuit Playground Express] Run on Simulator`: Runs python code on the simulator
-- `Device Simulator Express: [Circuit Playground Express] Deploy to Device`: Copies & Pastes the code.py or main.py file to CIRCUITPY drive if detected a CPX is plugged in
-- `Device Simulator Express: [Circuit Playground Express] Open Serial Monitor`: Opens the serial monitor in the integrated output window.
-- `Device Simulator Express: [Circuit Playground Express] Close Serial Monitor`: Stops the serial monitor and releases the serial port.
-- `Device Simulator Express: [Circuit Playground Express] Change Baud Rate`: Changes the baud rate of the selected serial port. For Adafruit CPX, the default baud rate is 115200.
-- `Device Simulator Express: [Circuit Playground Express] Select Serial Port`: Changes the current serial port.
+- `Device Simulator Express: [Circuit Playground Express] Deploy to Device`: Copies & Pastes the current file to CIRCUITPY drive if detected a CPX is plugged in
+- `Device Simulator Express: Open Serial Monitor`: Opens the serial monitor in the integrated output window.
+- `Device Simulator Express: Close Serial Monitor`: Stops the serial monitor and releases the serial port.
+- `Device Simulator Express: Change Baud Rate`: Changes the baud rate of the selected serial port. For Adafruit CPX and the BBC micro:bit, the default baud rate is 115200.
+- `Device Simulator Express: Select Serial Port`: Changes the current serial port.
### Keybindings
@@ -148,6 +159,8 @@ In Device Simulator Express, you can use keyboard to interact with the device:
- IntelliSense and syntax highlighting for micro:bit code
- Template file generation
- Integrated Python Debugging for the Simulator
+- Deploy MicroPython code to the physical device
+- Serial monitor (available on Windows and Mac only)
- Simulation of the micro:bit device, including:
- 25 LEDs
- Light sensor
@@ -240,4 +253,3 @@ A `ThirdPartyNotices.txt` file is provided in the extension's source code listin
1. Make sure that when you type _python_ in a terminal, the command is recognized and you have the correct version. The easiest way to do it is to select the "Add to PATH" option directly when you install Python. Otherwise you can search how to insert it manually.
2. You can choose to see the prompt or not by changing the extension configurations.
-3. To be able to run the file on your physical device, it should either be named code.py or main.py.
diff --git a/ThirdPartyNotices.txt b/ThirdPartyNotices.txt
index 26648250b..f062565a7 100644
--- a/ThirdPartyNotices.txt
+++ b/ThirdPartyNotices.txt
@@ -5829,6 +5829,26 @@ The above copyright notice and this permission notice shall be included in all c
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+uflash
+The MIT License (MIT)
+Copyright (c) 2015-2018 Nicholas H.Tollervey and others.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-------------------------------------------------------------------
-------------------------------------------------------------------
diff --git a/docs/how-to-use.md b/docs/how-to-use.md
index 09c497710..d94b4987c 100644
--- a/docs/how-to-use.md
+++ b/docs/how-to-use.md
@@ -9,14 +9,14 @@ Commands are accessible through :
- **Open Simulator** : opens the webview of the simulator.
-- **New File** : opens an unsaved file with links to help you and a code snippet that you can save as `code.py` / `main.py`.
+- **New File** : opens an unsaved file to help you and a code snippet that you can save and play around with.
_(**Note :** will open the simulator webview if it's not open yet)_.
- **Run Simulator** : runs the code you have opened in the simulator (make sure you've clicked on a valid code file).
_(**Note :** will open the simulator webview if it's not open yet)_.
-- **Deploy to Device** : saves the code to a Circuit Playground Express.
- _(**Note :** the board needs to be correctly formatted to a `CIRCUITPY` drive first. If that's not the case check [Installing CircuitPython](https://learn.adafruit.com/welcome-to-circuitpython/installing-circuitpython) to correctly format it)_.
+- **Deploy to Device** : saves the code to the connected device.
+ _(**Note :** For the Circuit Playground Express, the board needs to be correctly formatted to a `CIRCUITPY` drive first. If that's not the case check [Installing CircuitPython](https://learn.adafruit.com/welcome-to-circuitpython/installing-circuitpython) to correctly format it)_.
* **Select Serial Port** : selects the serial port of the board you want the serial monitor to interact with. (2)
_(**Note :** USB detection must be enabled in the extension settings.)_
@@ -82,7 +82,7 @@ Here are the settings you can change in the Device Simulator Express configurati
- The first time you install the extension, you'll need to execute the `run` command at least once in order to access auto-completion.
- While running a code file, if you get an error saying it can't find the file, make sure you've clicked on a valid Python code file before running it.
- To open the output panel again after closing it go to VS Code menu : `View->Output`.
-- If you try to deploy to the device while it's plugged in but you still get an error saying it cannot find the board, make sure your Circuit Playground Express is formatted correctly and that its name matches `CIRCUITPY`.
+- For the Circuit Playground Express, if you try to deploy to the device while it's plugged in but you still get an error saying it cannot find the board, make sure your Circuit Playground Express is formatted correctly and that its name matches `CIRCUITPY`.
- If you can't get the Simulator communication working while debugging, try to open you `Settings` and check the port used under `'Device Simulator Express: Debugger Server Port'`. You can either change it (usually ports above 5000 could work) or try to free it, then start debugging again.
### Notes
diff --git a/gulpfile.js b/gulpfile.js
index e2b15d39b..def76e5c3 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -39,6 +39,7 @@ const pythonToMove = [
"./src/microbit/!(test)/**/*",
"./src/*.py",
"./src/common/*.py",
+ "./src/dev-requirements.txt",
"./src/requirements.txt",
"./src/templates/*.*"
];
diff --git a/locales/en/out/constants.i18n.json b/locales/en/out/constants.i18n.json
index 333d9bf47..d6c6c548a 100644
--- a/locales/en/out/constants.i18n.json
+++ b/locales/en/out/constants.i18n.json
@@ -12,10 +12,6 @@
"dialogResponses.readInstall": "Read installation docs",
"error.debuggerServerInitFailed": "Warning : The Debugger Server cannot be opened. Please try to free the port {0} if it's already in use or select another one in your Settings 'Device Simulator Express: Debugger Server Port' and start another debug session.\n You can still debug your code but you won't be able to use the Simulator.",
"error.debuggingSessionInProgress": "[ERROR] A debugging session is currently in progress, please stop it before running your code. \n",
- "error.incorrectFileNameForDevice": "[ERROR] Can\\'t deploy to your Circuit Playground Express device, please rename your file to \"code.py\" or \"main.py\". \n",
- "error.incorrectFileNameForDevicePopup": "Seems like you have a different file name than what the CPX requires, please rename it to \"code.py\" or \"main.py\".",
- "error.incorrectFileNameForSimulatorPopup": "We want your code to work on your actual board as well. Make sure you name your file \"code.py\" or \"main.py\" to be able to run your code on an actual physical device.",
- "error.invalidFileNameDebug": "The file you tried to debug isn\\'t named \"code.py\" or \"main.py\\. Rename your file if you want your code to work on your actual device.",
"error.noDevice": "No plugged in boards detected. Please double check if your board is connected and/or properly formatted",
"error.noFileToRun": "\n[ERROR] We can't find the .py file to run on simulator. Open up a new .py file, or browse through some examples\n",
"error.noFolderCreated": "In order to use the Serial Monitor, you need to open a folder and reload VS Code.",
diff --git a/locales/en/package.i18n.json b/locales/en/package.i18n.json
index 9afd1a72c..6681f33da 100644
--- a/locales/en/package.i18n.json
+++ b/locales/en/package.i18n.json
@@ -2,18 +2,19 @@
"deviceSimulatorExpressExtension.commands.common.installDependencies": "Install Extension Dependencies",
"deviceSimulatorExpressExtension.commands.common.label": "Device Simulator Express",
"deviceSimulatorExpressExtension.commands.common.runSimulator": "Run Simulator",
- "deviceSimulatorExpressExtension.commands.cpx.changeBaudRate": "[Circuit Playground Express] Change Baud Rate",
- "deviceSimulatorExpressExtension.commands.cpx.closeSerialMonitor": "[Circuit Playground Express] Close Serial Monitor",
- "deviceSimulatorExpressExtension.commands.cpx.openSerialMonitor": "[Circuit Playground Express] Open Serial Monitor",
+ "deviceSimulatorExpressExtension.commands.common.changeBaudRate": "Change Baud Rate",
+ "deviceSimulatorExpressExtension.commands.common.closeSerialMonitor": "Close Serial Monitor",
+ "deviceSimulatorExpressExtension.commands.common.openSerialMonitor": "Open Serial Monitor",
+ "deviceSimulatorExpressExtension.commands.common.selectSerialPort": "Select Serial Port",
"deviceSimulatorExpressExtension.commands.cpx.openSimulator": "[Circuit Playground Express] Open Simulator",
"deviceSimulatorExpressExtension.commands.cpx.newFile": "[Circuit Playground Express] New File",
"deviceSimulatorExpressExtension.commands.cpx.deployToDevice": "[Circuit Playground Express] Deploy to Device",
- "deviceSimulatorExpressExtension.commands.cpx.selectSerialPort": "[Circuit Playground Express] Select Serial Port",
+ "deviceSimulatorExpressExtension.commands.microbit.deployToDevice": "[micro:bit] Deploy to Device",
"deviceSimulatorExpressExtension.commands.microbit.openSimulator": "[micro:bit] Open Simulator",
"deviceSimulatorExpressExtension.commands.microbit.newFile": "[micro:bit] New File",
"deviceSimulatorExpressExtension.configuration.title": "Device Simulator Express configuration",
"deviceSimulatorExpressExtension.configuration.properties.configEnvOnChange": "When you change the Python interpreter, the Device Simulator Express will automatically configure itself for the required dependencies.",
"deviceSimulatorExpressExtension.configuration.properties.debuggerPort": "The port the Server will listen on for communication with the debugger.",
- "deviceSimulatorExpressExtension.configuration.properties.dependencyChecker": "Whether or not to ask if we can download dependencies. If unchecked, the extension will default to never download dependencies, except when automatically creating a virtual environment in the extension files."
+ "deviceSimulatorExpressExtension.configuration.properties.dependencyChecker": "Whether or not to ask if we can download dependencies. If unchecked, the extension will default to never download dependencies, except when automatically creating a virtual environment in the extension files.",
"deviceSimulatorExpressExtension.configuration.properties.previewMode": "Enable this to test out and play with the new micro:bit simulator!"
}
diff --git a/package.json b/package.json
index 0c716c8f6..4c18fe24a 100644
--- a/package.json
+++ b/package.json
@@ -31,12 +31,13 @@
],
"activationEvents": [
"onCommand:deviceSimulatorExpress.common.installDependencies",
+ "onCommand:deviceSimulatorExpress.common.openSerialMonitor",
"onCommand:deviceSimulatorExpress.common.runSimulator",
+ "onCommand:deviceSimulatorExpress.common.selectSerialPort",
"onCommand:deviceSimulatorExpress.cpx.deployToDevice",
"onCommand:deviceSimulatorExpress.cpx.newFile",
- "onCommand:deviceSimulatorExpress.cpx.openSerialMonitor",
"onCommand:deviceSimulatorExpress.cpx.openSimulator",
- "onCommand:deviceSimulatorExpress.cpx.selectSerialPort",
+ "onCommand:deviceSimulatorExpress.microbit.deployToDevice",
"onCommand:deviceSimulatorExpress.microbit.newFile",
"onCommand:deviceSimulatorExpress.microbit.openSimulator",
"onDebug"
@@ -50,18 +51,28 @@
"category": "%deviceSimulatorExpressExtension.commands.common.label%"
},
{
- "command": "deviceSimulatorExpress.common.runSimulator",
- "title": "%deviceSimulatorExpressExtension.commands.common.runSimulator%",
+ "command": "deviceSimulatorExpress.common.changeBaudRate",
+ "title": "%deviceSimulatorExpressExtension.commands.common.changeBaudRate%",
+ "category": "%deviceSimulatorExpressExtension.commands.common.label%"
+ },
+ {
+ "command": "deviceSimulatorExpress.common.closeSerialMonitor",
+ "title": "%deviceSimulatorExpressExtension.commands.common.closeSerialMonitor%",
"category": "%deviceSimulatorExpressExtension.commands.common.label%"
},
{
- "command": "deviceSimulatorExpress.cpx.changeBaudRate",
- "title": "%deviceSimulatorExpressExtension.commands.cpx.changeBaudRate%",
+ "command": "deviceSimulatorExpress.common.openSerialMonitor",
+ "title": "%deviceSimulatorExpressExtension.commands.common.openSerialMonitor%",
"category": "%deviceSimulatorExpressExtension.commands.common.label%"
},
{
- "command": "deviceSimulatorExpress.cpx.closeSerialMonitor",
- "title": "%deviceSimulatorExpressExtension.commands.cpx.closeSerialMonitor%",
+ "command": "deviceSimulatorExpress.common.selectSerialPort",
+ "title": "%deviceSimulatorExpressExtension.commands.common.selectSerialPort%",
+ "category": "%deviceSimulatorExpressExtension.commands.common.label%"
+ },
+ {
+ "command": "deviceSimulatorExpress.common.runSimulator",
+ "title": "%deviceSimulatorExpressExtension.commands.common.runSimulator%",
"category": "%deviceSimulatorExpressExtension.commands.common.label%"
},
{
@@ -74,19 +85,14 @@
"title": "%deviceSimulatorExpressExtension.commands.cpx.newFile%",
"category": "%deviceSimulatorExpressExtension.commands.common.label%"
},
- {
- "command": "deviceSimulatorExpress.cpx.openSerialMonitor",
- "title": "%deviceSimulatorExpressExtension.commands.cpx.openSerialMonitor%",
- "category": "%deviceSimulatorExpressExtension.commands.common.label%"
- },
{
"command": "deviceSimulatorExpress.cpx.openSimulator",
"title": "%deviceSimulatorExpressExtension.commands.cpx.openSimulator%",
"category": "%deviceSimulatorExpressExtension.commands.common.label%"
},
{
- "command": "deviceSimulatorExpress.cpx.selectSerialPort",
- "title": "%deviceSimulatorExpressExtension.commands.cpx.selectSerialPort%",
+ "command": "deviceSimulatorExpress.microbit.deployToDevice",
+ "title": "%deviceSimulatorExpressExtension.commands.microbit.deployToDevice%",
"category": "%deviceSimulatorExpressExtension.commands.common.label%"
},
{
@@ -102,6 +108,12 @@
],
"menus": {
"commandPalette": [
+ {
+ "command": "deviceSimulatorExpress.microbit.deployToDevice",
+ "title": "%deviceSimulatorExpressExtension.commands.microbit.deployToDevice%",
+ "category": "%deviceSimulatorExpressExtension.commands.common.label%",
+ "when": "config.deviceSimulatorExpress.previewMode"
+ },
{
"command": "deviceSimulatorExpress.microbit.openSimulator",
"title": "%deviceSimulatorExpressExtension.commands.microbit.openSimulator%",
diff --git a/package.nls.json b/package.nls.json
index 1092a8d4a..2f574c7eb 100644
--- a/package.nls.json
+++ b/package.nls.json
@@ -2,13 +2,14 @@
"deviceSimulatorExpressExtension.commands.common.installDependencies": "Install Extension Dependencies",
"deviceSimulatorExpressExtension.commands.common.label": "Device Simulator Express",
"deviceSimulatorExpressExtension.commands.common.runSimulator": "Run Simulator",
- "deviceSimulatorExpressExtension.commands.cpx.changeBaudRate": "[Circuit Playground Express] Change Baud Rate",
- "deviceSimulatorExpressExtension.commands.cpx.closeSerialMonitor": "[Circuit Playground Express] Close Serial Monitor",
- "deviceSimulatorExpressExtension.commands.cpx.openSerialMonitor": "[Circuit Playground Express] Open Serial Monitor",
+ "deviceSimulatorExpressExtension.commands.common.changeBaudRate": "Change Baud Rate",
+ "deviceSimulatorExpressExtension.commands.common.closeSerialMonitor": "Close Serial Monitor",
+ "deviceSimulatorExpressExtension.commands.common.openSerialMonitor": "Open Serial Monitor",
+ "deviceSimulatorExpressExtension.commands.common.selectSerialPort": "Select Serial Port",
"deviceSimulatorExpressExtension.commands.cpx.openSimulator": "[Circuit Playground Express] Open Simulator",
"deviceSimulatorExpressExtension.commands.cpx.newFile": "[Circuit Playground Express] New File",
"deviceSimulatorExpressExtension.commands.cpx.deployToDevice": "[Circuit Playground Express] Deploy to Device",
- "deviceSimulatorExpressExtension.commands.cpx.selectSerialPort": "[Circuit Playground Express] Select Serial Port",
+ "deviceSimulatorExpressExtension.commands.microbit.deployToDevice": "[micro:bit] Deploy to Device",
"deviceSimulatorExpressExtension.commands.microbit.openSimulator": "[micro:bit] Open Simulator",
"deviceSimulatorExpressExtension.commands.microbit.newFile": "[micro:bit] New File",
"deviceSimulatorExpressExtension.configuration.title": "Device Simulator Express configuration",
diff --git a/src/adafruit_circuitplayground/test/test_utils.py b/src/adafruit_circuitplayground/test/test_utils.py
index a3c38e1b1..21a8c6296 100644
--- a/src/adafruit_circuitplayground/test/test_utils.py
+++ b/src/adafruit_circuitplayground/test/test_utils.py
@@ -13,16 +13,20 @@ def test_remove_leading_slashes(self):
assert expected == utils.remove_leading_slashes(original)
def test_escape_notOSX(self):
+ _utils_sys = utils.sys
if sys.platform.startswith(CONSTANTS.MAC_OS):
utils.sys = mock.MagicMock()
utils.sys.configure_mock(platform="win32")
original = "a b"
assert original == utils.escape_if_OSX(original)
+ utils.sys = _utils_sys
def test_escape_isOSX(self):
+ _utils_sys = utils.sys
if not sys.platform.startswith(CONSTANTS.MAC_OS):
utils.sys = mock.MagicMock()
utils.sys.configure_mock(platform="darwin")
original = "a b"
expected = "a%20b"
assert expected == utils.escape_if_OSX(original)
+ utils.sys = _utils_sys
diff --git a/src/common/utils.py b/src/common/utils.py
index a468044f7..6a0e6953d 100644
--- a/src/common/utils.py
+++ b/src/common/utils.py
@@ -44,6 +44,6 @@ def remove_leading_slashes(string):
def escape_if_OSX(file_name):
- if sys.platform.startswith(CONSTANTS.MAC_OS):
+ if sys.platform == CONSTANTS.MAC_OS:
file_name = file_name.replace(" ", "%20")
return file_name
diff --git a/src/constants.ts b/src/constants.ts
index 7c537c122..5d30b3602 100644
--- a/src/constants.ts
+++ b/src/constants.ts
@@ -65,18 +65,11 @@ export const CONSTANTS = {
`[ERROR] Failed to open serial port ${port} due to error: ${error}. \n`
);
},
- INCORRECT_FILE_NAME_FOR_DEVICE: localize(
- "error.incorrectFileNameForDevice",
- '[ERROR] Can\'t deploy to your Circuit Playground Express device, please rename your file to "code.py" or "main.py". \n'
- ),
- INCORRECT_FILE_NAME_FOR_DEVICE_POPUP: localize(
- "error.incorrectFileNameForDevicePopup",
- 'Seems like you have a different file name than what CPX requires, please rename it to "code.py" or "main.py".'
- ),
INSTALLATION_ERROR: localize(
"error.installationError",
"Installation Error"
),
+
INVALID_FILE_EXTENSION_DEBUG: localize(
"error.invalidFileExtensionDebug",
"The file you tried to run isn't a Python file."
@@ -85,6 +78,10 @@ export const CONSTANTS = {
"error.invalidPythonPath",
'We found that your selected Python interpreter version is too low to run the extension. Please upgrade to version 3.7+ or select a different interpreter (CTRL+SHIFT+P and type "python.selectInterpreter") and restart the application.'
),
+ LOW_PYTHON_VERSION_FOR_MICROBIT_DEPLOYMENT: localize(
+ "error.lowPythonVersionForMicrobitDeployment",
+ "To deploy your code to the micro:bit, you must be using Python 3.3+"
+ ),
NO_DEVICE: localize(
"error.noDevice",
"No plugged in boards detected. Please double check if your board is connected and/or properly formatted"
@@ -155,11 +152,11 @@ export const CONSTANTS = {
),
DEPLOY_SUCCESS: localize(
"info.deploySuccess",
- "\n[INFO] Code successfully copied! Your Circuit Playground Express should be loading and ready to go shortly.\n"
+ "\n[INFO] Code successfully copied! Your device should be loading and ready to go shortly.\n"
),
EXTENSION_ACTIVATED: localize(
"info.extensionActivated",
- "Congratulations, your extension Adafruit_Simulator is now active!"
+ "Congratulations, your extension Device Simulator Express is now active!"
),
FILE_SELECTED: (filePath: string) => {
return localize(
@@ -171,10 +168,6 @@ export const CONSTANTS = {
"info.firstTimeWebview",
'To reopen the simulator select the command "Open Simulator" from command palette.'
),
- INCORRECT_FILE_NAME_FOR_SIMULATOR_POPUP: localize(
- "info.incorrectFileNameForSimulatorPopup",
- 'We want your code to work on your actual board as well. Make sure you name your file "code.py" or "main.py" to be able to run your code on an actual physical device'
- ),
INSTALLING_PYTHON_VENV: localize(
"info.installingPythonVenv",
"A virtual environment is currently being created. The required Python packages will be installed. You will be prompted a message telling you when the installation is done."
@@ -187,10 +180,6 @@ export const CONSTANTS = {
"info.installPythonVenv",
"Do you want us to try and install this extension's dependencies via virtual environment for you?"
),
- INVALID_FILE_NAME_DEBUG: localize(
- "info.invalidFileNameDebug",
- 'The file you tried to debug isn\'t named "code.py" or "main.py". Rename your file if you want your code to work on your actual device.'
- ),
NEW_FILE: localize(
"info.newFile",
"New to Python or the Circuit Playground Express? We are here to help!"
@@ -327,15 +316,16 @@ export enum TelemetryEventName {
COMMAND_RUN_SIMULATOR_BUTTON = "COMMAND.RUN.SIMULATOR_BUTTON",
COMMAND_RUN_PALETTE = "COMMAND.RUN.PALETTE",
COMMAND_INSTALL_EXTENSION_DEPENDENCIES = "COMMAND.INSTALL.EXTENSION.DEPENDENCIES",
+ COMMAND_SERIAL_MONITOR_CHOOSE_PORT = "COMMAND.SERIAL_MONITOR.CHOOSE_PORT",
+ COMMAND_SERIAL_MONITOR_OPEN = "COMMAND.SERIAL_MONITOR.OPEN",
+ COMMAND_SERIAL_MONITOR_BAUD_RATE = "COMMAND.SERIAL_MONITOR.BAUD_RATE",
+ COMMAND_SERIAL_MONITOR_CLOSE = "COMMAND.SERIAL_MONITOR.CLOSE",
CPX_COMMAND_DEPLOY_DEVICE = "CPX.COMMAND.DEPLOY.DEVICE",
CPX_COMMAND_NEW_FILE = "CPX.COMMAND.NEW.FILE.CPX",
CPX_COMMAND_OPEN_SIMULATOR = "CPX.COMMAND.OPEN.SIMULATOR",
- CPX_COMMAND_SERIAL_MONITOR_CHOOSE_PORT = "CPX.COMMAND.SERIAL_MONITOR.CHOOSE_PORT",
- CPX_COMMAND_SERIAL_MONITOR_OPEN = "CPX.COMMAND.SERIAL_MONITOR.OPEN",
- CPX_COMMAND_SERIAL_MONITOR_BAUD_RATE = "CPX.COMMAND.SERIAL_MONITOR.BAUD_RATE",
- CPX_COMMAND_SERIAL_MONITOR_CLOSE = "CPX.COMMAND.SERIAL_MONITOR.CLOSE",
+ MICROBIT_COMMAND_DEPLOY_DEVICE = "MICROBIT.COMMAND.DEPLOY.DEVICE",
MICROBIT_COMMAND_NEW_FILE = "MICROBIT.COMMAND.NEW.FILE",
MICROBIT_COMMAND_OPEN_SIMULATOR = "MICROBIT.COMMAND.OPEN.SIMULATOR",
@@ -373,14 +363,32 @@ export enum TelemetryEventName {
CPX_SUCCESS_COMMAND_DEPLOY_DEVICE = "CPX.SUCCESS.COMMAND.DEPLOY.DEVICE",
MICROBIT_ERROR_COMMAND_NEW_FILE = "MICROBIT.ERROR.COMMAND.NEW.FILE",
+ MICROBIT_ERROR_DEPLOY_WITHOUT_DEVICE = "MICROBIT.ERROR.DEPLOY.WITHOUT.DEVICE",
+ MICROBIT_ERROR_PYTHON_DEVICE_PROCESS = "MICROBIT.ERROR.PYTHON.DEVICE.PROCESS",
+ MICROBIT_SUCCESS_COMMAND_DEPLOY_DEVICE = "MICROBIT.SUCCESS.COMMAND.DEPLOY.DEVICE",
// Performance
CPX_PERFORMANCE_DEPLOY_DEVICE = "CPX.PERFORMANCE.DEPLOY.DEVICE",
CPX_PERFORMANCE_NEW_FILE = "CPX.PERFORMANCE.NEW.FILE",
CPX_PERFORMANCE_OPEN_SIMULATOR = "CPX.PERFORMANCE.OPEN.SIMULATOR",
+ MICROBIT_PERFORMANCE_DEPLOY_DEVICE = "MICROBIT.PERFORMANCE.DEPLOY.DEVICE",
MICROBIT_PERFORMANCE_NEW_FILE = "MICROBIT.PERFORMANCE.NEW.FILE",
MICROBIT_PERFORMANCE_OPEN_SIMULATOR = "MICROBIT.PERFORMANCE.OPEN.SIMULATOR",
+
+ // Venv options
+ SETUP_VENV_CREATION_ERR = "SETUP.VENV.CREATION.ERR",
+ SETUP_NO_PIP = "SETUP.NO.PIP",
+ SETUP_DEP_INSTALL_FAIL = "SETUP.DEP.INSTALL.FAIL",
+ SETUP_AUTO_RESOLVE_PYTHON_PATH = "SETUP.AUTO.RESOLVE.PYTHON.PATH",
+ SETUP_NO_PYTHON_PATH = "SETUP.NO.PYTHON.PATH",
+ SETUP_DOWNLOAD_PYTHON = "SETUP.DOWNLOAD.PYTHON",
+ SETUP_INVALID_PYTHON_INTERPRETER_PATH = "SETUP.INVALID.PYTHON.INTERPRETER.PATH",
+ SETUP_INVALID_PYTHON_VER = "SETUP.INVALID.PYTHON.VER",
+ SETUP_INSTALL_VENV = "SETUP.INSTALL.VENV",
+ SETUP_ORIGINAL_INTERPRETER_DEP_INSTALL = "SETUP.ORIGINAL.INTERPRETER.DEP.INSTALL",
+ SETUP_HAS_VENV = "SETUP.HAS.VENV",
+ SETUP_NO_DEPS_INSTALLED = "SETUP.NO.DEPS.INSTALLED",
}
export const DEFAULT_DEVICE = CONSTANTS.DEVICE_NAME.CPX;
@@ -450,11 +458,6 @@ export namespace DialogResponses {
export const CPX_CONFIG_FILE = path.join(".vscode", "cpx.json");
-export const USER_CODE_NAMES = {
- CODE_PY: "code.py",
- MAIN_PY: "main.py",
-};
-
export const STATUS_BAR_PRIORITY = {
PORT: 20,
OPEN_PORT: 30,
@@ -477,5 +480,8 @@ export const HELPER_FILES = {
export const GLOBAL_ENV_VARS = {
PYTHON: "python",
};
+export const LANGUAGE_VARS = {
+ PYTHON: { ID: "python", FILE_ENDS: ".py" },
+};
export default CONSTANTS;
diff --git a/src/debug_user_code.py b/src/debug_user_code.py
index c4b3dd2c5..c7110640f 100644
--- a/src/debug_user_code.py
+++ b/src/debug_user_code.py
@@ -51,7 +51,7 @@
mb._MicrobitModel__set_debug_mode(True)
# Execute the user's code file
-with open(abs_path_to_code_file) as user_code_file:
+with open(abs_path_to_code_file, encoding="utf8") as user_code_file:
user_code = user_code_file.read()
try:
codeObj = compile(user_code, abs_path_to_code_file, CONSTANTS.EXEC_COMMAND)
diff --git a/src/dev-requirements.txt b/src/dev-requirements.txt
new file mode 100644
index 000000000..26f334b51
--- /dev/null
+++ b/src/dev-requirements.txt
@@ -0,0 +1,3 @@
+-r ./requirements.txt
+black==19.10b0
+pytest==5.0.1
\ No newline at end of file
diff --git a/src/device.py b/src/device.py
index 60b081b50..cc6e035ff 100644
--- a/src/device.py
+++ b/src/device.py
@@ -5,7 +5,9 @@
import string
import os
import sys
+import shutil
import json
+import uflash
import python_constants as CONSTANTS
if sys.platform == "win32":
@@ -14,11 +16,13 @@
class Device:
- def __init__(self):
+ def __init__(self, name, file_path):
+ self.name = name
+ self.file_path = file_path
self.connected = False
self.error_message = None
- def find_device_directory(self):
+ def find_cpx_directory(self):
"""
Check if the Circuit Playground Express is available/plugged in
"""
@@ -61,22 +65,57 @@ def find_device_directory(self):
self.error_message = None
return found_directory
+ def deployToCPX(self):
+ device_directory = self.find_cpx_directory()
+ if self.error_message:
+ print(
+ "{}:\t{}".format(self.error_message[0], self.error_message[1]),
+ file=sys.stderr,
+ flush=True,
+ )
+ if self.connected:
+ original_file_name = self.file_path.rsplit(os.sep, 1)[-1]
+ if original_file_name == "code.py" or original_file_name == "main.py":
+ dest_path = os.path.join(device_directory, original_file_name)
+ else:
+ dest_path = os.path.join(device_directory, "code.py")
+ shutil.copyfile(self.file_path, dest_path)
+ message = {"type": "complete"}
+ else:
+ message = {"type": "no-device"}
+ return message
-if __name__ == "__main__":
- import shutil
+ def deployToMicrobit(self):
+ # Temporarily redirecting stdout because there are some print statements in uflash library
+ fake_stdout = open(os.devnull, "w")
+ _stdout = sys.stdout
+ sys.stdout = fake_stdout
+
+ try:
+ uflash.flash(path_to_python=self.file_path)
+ message = {"type": "complete"}
+ except RuntimeError:
+ message = {"type": "low-python-version"}
+ except IOError:
+ self.error_message = CONSTANTS.NO_MICROBIT_DETECTED_ERROR_TITLE
+ print(
+ self.error_message, file=sys.stderr, flush=True,
+ )
+ message = {"type": "no-device"}
- cpx = Device()
- device_directory = cpx.find_device_directory()
- if cpx.error_message:
- print(
- "{}:\t{}".format(cpx.error_message[0], cpx.error_message[1]),
- file=sys.stderr,
- flush=True,
- )
- if cpx.connected:
- dest_path = os.path.join(device_directory, sys.argv[1].rsplit(os.sep, 1)[-1])
- shutil.copyfile(sys.argv[1], dest_path)
- message = {"type": "complete"}
- else:
- message = {"type": "no-device"}
+ sys.stdout = _stdout
+ return message
+
+ def deploy(self):
+ if self.name == CONSTANTS.MICROBIT:
+ return self.deployToMicrobit()
+ elif self.name == CONSTANTS.CPX:
+ return self.deployToCPX()
+ else:
+ return {"type": "no-device"}
+
+
+if __name__ == "__main__":
+ device = Device(sys.argv[1], sys.argv[2])
+ message = device.deploy()
print(json.dumps(message), flush=True)
diff --git a/src/extension.ts b/src/extension.ts
index c14532a0a..59d9d87e8 100644
--- a/src/extension.ts
+++ b/src/extension.ts
@@ -3,6 +3,7 @@
import * as cp from "child_process";
import * as fs from "fs";
+import { registerDefaultFontFaces } from "office-ui-fabric-react";
import * as open from "open";
import * as os from "os";
import * as path from "path";
@@ -17,6 +18,7 @@ import {
HELPER_FILES,
SERVER_INFO,
TelemetryEventName,
+ LANGUAGE_VARS,
} from "./constants";
import { CPXWorkspace } from "./cpxWorkspace";
import { DebugAdapterFactory } from "./debugger/debugAdapterFactory";
@@ -24,62 +26,46 @@ import { DebuggerCommunicationServer } from "./debuggerCommunicationServer";
import * as utils from "./extension_utils/utils";
import { SerialMonitor } from "./serialMonitor";
import { DebuggerCommunicationService } from "./service/debuggerCommunicationService";
+import { DeviceSelectionService } from "./service/deviceSelectionService";
+import { FileSelectionService } from "./service/fileSelectionService";
import { MessagingService } from "./service/messagingService";
+import { PopupService } from "./service/PopupService";
+import { SetupService } from "./service/SetupService";
import { SimulatorDebugConfigurationProvider } from "./simulatorDebugConfigurationProvider";
+import getPackageInfo from "./telemetry/getPackageInfo";
import TelemetryAI from "./telemetry/telemetryAI";
import { UsbDetector } from "./usbDetector";
import { VSCODE_MESSAGES_TO_WEBVIEW, WEBVIEW_MESSAGES } from "./view/constants";
-import { PopupService } from "./service/PopupService";
-import getPackageInfo from "./telemetry/getPackageInfo";
-import { registerDefaultFontFaces } from "office-ui-fabric-react";
-let currentFileAbsPath: string = "";
-let currentTextDocument: vscode.TextDocument;
let telemetryAI: TelemetryAI;
let pythonExecutablePath: string = GLOBAL_ENV_VARS.PYTHON;
let configFileCreated: boolean = false;
let inDebugMode: boolean = false;
// Notification booleans
let firstTimeClosed: boolean = true;
-let shouldShowInvalidFileNamePopup: boolean = true;
let shouldShowRunCodePopup: boolean = true;
-const messagingService = new MessagingService();
-const debuggerCommunicationService = new DebuggerCommunicationService();
-let currentActiveDevice: string = DEFAULT_DEVICE;
+let setupService: SetupService;
+const deviceSelectionService = new DeviceSelectionService();
+const messagingService = new MessagingService(deviceSelectionService);
+const debuggerCommunicationService = new DebuggerCommunicationService();
+const fileSelectionService = new FileSelectionService(messagingService);
export let outChannel: vscode.OutputChannel | undefined;
function loadScript(context: vscode.ExtensionContext, scriptPath: string) {
- return ``;
}
-const setPathAndSendMessage = (
- currentPanel: vscode.WebviewPanel,
- newFilePath: string
-) => {
- currentFileAbsPath = newFilePath;
- if (currentPanel) {
- currentPanel.webview.postMessage({
- command: "current-file",
- active_device: currentActiveDevice,
-
- state: {
- running_file: newFilePath,
- },
- });
- }
-};
-
const sendCurrentDeviceMessage = (currentPanel: vscode.WebviewPanel) => {
if (currentPanel) {
currentPanel.webview.postMessage({
command: VSCODE_MESSAGES_TO_WEBVIEW.SET_DEVICE,
- active_device: currentActiveDevice,
+ active_device: deviceSelectionService.getCurrentActiveDevice(),
});
}
};
@@ -88,6 +74,7 @@ export async function activate(context: vscode.ExtensionContext) {
console.info(CONSTANTS.INFO.EXTENSION_ACTIVATED);
telemetryAI = new TelemetryAI(context);
+ setupService = new SetupService(telemetryAI);
let currentPanel: vscode.WebviewPanel | undefined;
let childProcess: cp.ChildProcess | undefined;
let messageListener: vscode.Disposable;
@@ -100,7 +87,7 @@ export async function activate(context: vscode.ExtensionContext) {
// doesn't trigger lint errors
updatePylintArgs(context);
- pythonExecutablePath = await utils.setupEnv(context);
+ pythonExecutablePath = await setupService.setupEnv(context);
try {
utils.generateCPXConfig();
@@ -121,7 +108,7 @@ export async function activate(context: vscode.ExtensionContext) {
vscode.workspace.onDidSaveTextDocument(
async (document: vscode.TextDocument) => {
- await updateCurrentFileIfPython(document, currentPanel);
+ await fileSelectionService.updateCurrentFileFromTextFile(document);
}
);
@@ -138,7 +125,7 @@ export async function activate(context: vscode.ExtensionContext) {
}
const openWebview = () => {
- if (currentPanel) {
+ if (currentPanel && currentPanel.webview) {
messagingService.setWebview(currentPanel.webview);
currentPanel.reveal(vscode.ViewColumn.Beside);
} else {
@@ -186,7 +173,7 @@ export async function activate(context: vscode.ExtensionContext) {
messageListener = currentPanel.webview.onDidReceiveMessage(
message => {
const messageJson = JSON.stringify({
- active_device: currentActiveDevice,
+ active_device: deviceSelectionService.getCurrentActiveDevice(),
state: message.text,
});
switch (message.command) {
@@ -210,18 +197,10 @@ export async function activate(context: vscode.ExtensionContext) {
case WEBVIEW_MESSAGES.TOGGLE_PLAY_STOP:
console.log(`Play button ${messageJson} \n`);
if (message.text.state as boolean) {
- setPathAndSendMessage(
- currentPanel,
+ fileSelectionService.setPathAndSendMessage(
message.text.selected_file
);
- if (currentFileAbsPath) {
- const foundDocument = utils.getActiveEditorFromPath(
- currentFileAbsPath
- );
- if (foundDocument !== undefined) {
- currentTextDocument = foundDocument;
- }
- }
+ fileSelectionService.findCurrentTextDocument();
telemetryAI.trackFeatureUsage(
TelemetryEventName.COMMAND_RUN_SIMULATOR_BUTTON
);
@@ -262,7 +241,9 @@ export async function activate(context: vscode.ExtensionContext) {
handleSensorTelemetry(message.text);
break;
case WEBVIEW_MESSAGES.SWITCH_DEVICE:
- switchDevice(message.text.active_device);
+ deviceSelectionService.setCurrentActiveDevice(
+ message.text.active_device
+ );
killProcessIfRunning();
break;
default:
@@ -309,12 +290,16 @@ export async function activate(context: vscode.ExtensionContext) {
};
const openCPXWebview = () => {
- switchDevice(CONSTANTS.DEVICE_NAME.CPX);
+ deviceSelectionService.setCurrentActiveDevice(
+ CONSTANTS.DEVICE_NAME.CPX
+ );
openWebview();
};
const openMicrobitWebview = () => {
- switchDevice(CONSTANTS.DEVICE_NAME.MICROBIT);
+ deviceSelectionService.setCurrentActiveDevice(
+ CONSTANTS.DEVICE_NAME.MICROBIT
+ );
openWebview();
};
@@ -346,12 +331,16 @@ export async function activate(context: vscode.ExtensionContext) {
);
const openCPXTemplateFile = () => {
- switchDevice(CONSTANTS.DEVICE_NAME.CPX);
+ deviceSelectionService.setCurrentActiveDevice(
+ CONSTANTS.DEVICE_NAME.CPX
+ );
openTemplateFile(CONSTANTS.TEMPLATE.CPX);
};
const openMicrobitTemplateFile = () => {
- switchDevice(CONSTANTS.DEVICE_NAME.MICROBIT);
+ deviceSelectionService.setCurrentActiveDevice(
+ CONSTANTS.DEVICE_NAME.MICROBIT
+ );
openTemplateFile(CONSTANTS.TEMPLATE.MICROBIT);
};
@@ -402,7 +391,10 @@ export async function activate(context: vscode.ExtensionContext) {
// tslint:disable-next-line: ban-comma-operator
vscode.workspace
- .openTextDocument({ content: file, language: "python" })
+ .openTextDocument({
+ content: file,
+ language: LANGUAGE_VARS.PYTHON.ID,
+ })
.then((template: vscode.TextDocument) => {
vscode.window.showTextDocument(template, 1, false).then(() => {
openWebview();
@@ -444,7 +436,7 @@ export async function activate(context: vscode.ExtensionContext) {
const installDependencies: vscode.Disposable = vscode.commands.registerCommand(
"deviceSimulatorExpress.common.installDependencies",
async () => {
- pythonExecutablePath = await utils.setupEnv(context, true);
+ pythonExecutablePath = await setupService.setupEnv(context, true);
telemetryAI.trackFeatureUsage(
TelemetryEventName.COMMAND_INSTALL_EXTENSION_DEPENDENCIES
);
@@ -454,10 +446,9 @@ export async function activate(context: vscode.ExtensionContext) {
const killProcessIfRunning = () => {
if (childProcess !== undefined) {
if (currentPanel) {
- console.info("Sending clearing state command");
currentPanel.webview.postMessage({
command: "reset-state",
- active_device: currentActiveDevice,
+ active_device: deviceSelectionService.getCurrentActiveDevice(),
});
}
// TODO: We need to check the process was correctly killed
@@ -511,12 +502,11 @@ export async function activate(context: vscode.ExtensionContext) {
killProcessIfRunning();
- await updateCurrentFileIfPython(
- vscode.window.activeTextEditor!.document,
- currentPanel
+ await fileSelectionService.updateCurrentFileFromEditor(
+ vscode.window.activeTextEditor
);
- if (currentFileAbsPath === "") {
+ if (fileSelectionService.getCurrentFileAbsPath() === "") {
utils.logToOutputChannel(
outChannel,
CONSTANTS.ERROR.NO_FILE_TO_RUN,
@@ -528,9 +518,13 @@ export async function activate(context: vscode.ExtensionContext) {
);
} else {
// Save on run
- await currentTextDocument.save();
+ await fileSelectionService.getCurrentTextDocument().save();
- if (!currentTextDocument.fileName.endsWith(".py")) {
+ if (
+ !fileSelectionService
+ .getCurrentTextDocument()
+ .fileName.endsWith(LANGUAGE_VARS.PYTHON.FILE_ENDS)
+ ) {
utils.logToOutputChannel(
outChannel,
CONSTANTS.ERROR.NO_FILE_TO_RUN,
@@ -540,34 +534,15 @@ export async function activate(context: vscode.ExtensionContext) {
}
utils.logToOutputChannel(
outChannel,
- CONSTANTS.INFO.FILE_SELECTED(currentFileAbsPath)
+ CONSTANTS.INFO.FILE_SELECTED(
+ fileSelectionService.getCurrentFileAbsPath()
+ )
);
- if (
- !utils.validCodeFileName(currentFileAbsPath) &&
- shouldShowInvalidFileNamePopup
- ) {
- // to the popup
- vscode.window
- .showInformationMessage(
- CONSTANTS.INFO.INCORRECT_FILE_NAME_FOR_SIMULATOR_POPUP,
- DialogResponses.DONT_SHOW,
- DialogResponses.MESSAGE_UNDERSTOOD
- )
- .then((selection: vscode.MessageItem | undefined) => {
- if (selection === DialogResponses.DONT_SHOW) {
- shouldShowInvalidFileNamePopup = false;
- telemetryAI.trackFeatureUsage(
- TelemetryEventName.CPX_CLICK_DIALOG_DONT_SHOW
- );
- }
- });
- }
-
// Activate the run webview button
currentPanel.webview.postMessage({
command: "activate-play",
- active_device: currentActiveDevice,
+ active_device: deviceSelectionService.getCurrentActiveDevice(),
});
childProcess = cp.spawn(pythonExecutablePath, [
@@ -576,7 +551,7 @@ export async function activate(context: vscode.ExtensionContext) {
CONSTANTS.FILESYSTEM.OUTPUT_DIRECTORY,
HELPER_FILES.PROCESS_USER_CODE_PY
),
- currentFileAbsPath,
+ fileSelectionService.getCurrentFileAbsPath(),
JSON.stringify({ enable_telemetry: utils.getTelemetryState() }),
]);
@@ -610,10 +585,10 @@ export async function activate(context: vscode.ExtensionContext) {
);
if (
messageData.device_name ===
- currentActiveDevice
+ deviceSelectionService.getCurrentActiveDevice()
) {
currentPanel.webview.postMessage({
- active_device: currentActiveDevice,
+ active_device: deviceSelectionService.getCurrentActiveDevice(),
command: "set-state",
state: messageData,
});
@@ -660,9 +635,8 @@ export async function activate(context: vscode.ExtensionContext) {
true
);
if (currentPanel) {
- console.log("Sending clearing state command");
currentPanel.webview.postMessage({
- active_device: currentActiveDevice,
+ active_device: deviceSelectionService.getCurrentActiveDevice(),
command: "reset-state",
});
}
@@ -686,21 +660,18 @@ export async function activate(context: vscode.ExtensionContext) {
}
);
- const cpxDeployCodeToDevice = async () => {
- console.info("Sending code to device");
-
+ const deployCode = async (device: string) => {
utils.logToOutputChannel(
outChannel,
CONSTANTS.INFO.DEPLOY_DEVICE,
true
);
- await updateCurrentFileIfPython(
- vscode.window.activeTextEditor!.document,
- currentPanel
+ await fileSelectionService.updateCurrentFileFromEditor(
+ vscode.window.activeTextEditor
);
- if (currentFileAbsPath === "") {
+ if (fileSelectionService.getCurrentFileAbsPath() === "") {
utils.logToOutputChannel(
outChannel,
CONSTANTS.ERROR.NO_FILE_TO_RUN,
@@ -710,23 +681,12 @@ export async function activate(context: vscode.ExtensionContext) {
CONSTANTS.ERROR.NO_FILE_TO_RUN,
DialogResponses.MESSAGE_UNDERSTOOD
);
- } else if (!utils.validCodeFileName(currentFileAbsPath)) {
- // Save on run
- await currentTextDocument.save();
- // Output panel
- utils.logToOutputChannel(
- outChannel,
- CONSTANTS.ERROR.INCORRECT_FILE_NAME_FOR_DEVICE,
- true
- );
- // Popup
- vscode.window.showErrorMessage(
- CONSTANTS.ERROR.INCORRECT_FILE_NAME_FOR_DEVICE_POPUP
- );
} else {
utils.logToOutputChannel(
outChannel,
- CONSTANTS.INFO.FILE_SELECTED(currentFileAbsPath)
+ CONSTANTS.INFO.FILE_SELECTED(
+ fileSelectionService.getCurrentFileAbsPath()
+ )
);
const deviceProcess = cp.spawn(pythonExecutablePath, [
@@ -735,7 +695,8 @@ export async function activate(context: vscode.ExtensionContext) {
CONSTANTS.FILESYSTEM.OUTPUT_DIRECTORY,
HELPER_FILES.DEVICE_PY
),
- currentFileAbsPath,
+ device,
+ fileSelectionService.getCurrentFileAbsPath(),
]);
let dataFromTheProcess = "";
@@ -747,58 +708,14 @@ export async function activate(context: vscode.ExtensionContext) {
let messageToWebview;
try {
messageToWebview = JSON.parse(dataFromTheProcess);
- // Check the JSON is a state
- switch (messageToWebview.type) {
- case "complete":
- telemetryAI.trackFeatureUsage(
- TelemetryEventName.CPX_SUCCESS_COMMAND_DEPLOY_DEVICE
- );
- utils.logToOutputChannel(
- outChannel,
- CONSTANTS.INFO.DEPLOY_SUCCESS
- );
- break;
-
- case "no-device":
- telemetryAI.trackFeatureUsage(
- TelemetryEventName.CPX_ERROR_DEPLOY_WITHOUT_DEVICE
- );
- vscode.window
- .showErrorMessage(
- CONSTANTS.ERROR.NO_DEVICE,
- DialogResponses.HELP
- )
- .then(
- (
- selection:
- | vscode.MessageItem
- | undefined
- ) => {
- if (
- selection === DialogResponses.HELP
- ) {
- const okAction = () => {
- open(CONSTANTS.LINKS.HELP);
- telemetryAI.trackFeatureUsage(
- TelemetryEventName.CPX_CLICK_DIALOG_HELP_DEPLOY_TO_DEVICE
- );
- };
- utils.showPrivacyModal(
- okAction,
- CONSTANTS.INFO
- .THIRD_PARTY_WEBSITE_ADAFRUIT
- );
- }
- }
- );
- break;
-
- default:
- console.log(
- `Non-state JSON output from the process : ${messageToWebview}`
- );
- break;
+ if (messageToWebview.type === "complete") {
+ utils.logToOutputChannel(
+ outChannel,
+ CONSTANTS.INFO.DEPLOY_SUCCESS,
+ true
+ );
}
+ handleDeployToDeviceTelemetry(messageToWebview, device);
} catch (err) {
console.log(
`Non-JSON output from the process : ${dataFromTheProcess}`
@@ -808,10 +725,7 @@ export async function activate(context: vscode.ExtensionContext) {
// Std error output
deviceProcess.stderr.on("data", data => {
- telemetryAI.trackFeatureUsage(
- TelemetryEventName.CPX_ERROR_PYTHON_DEVICE_PROCESS,
- { error: `${data}` }
- );
+ handleDeployToDeviceErrorTelemetry(data, device);
console.error(
`Error from the Python device process through stderr: ${data}`
);
@@ -829,6 +743,86 @@ export async function activate(context: vscode.ExtensionContext) {
}
};
+ const handleDeployToDeviceErrorTelemetry = (
+ data: string,
+ device: string
+ ) => {
+ let telemetryErrorName: string;
+ if (device === CONSTANTS.DEVICE_NAME.CPX) {
+ telemetryErrorName =
+ TelemetryEventName.CPX_ERROR_PYTHON_DEVICE_PROCESS;
+ } else if (device === CONSTANTS.DEVICE_NAME.MICROBIT) {
+ telemetryErrorName =
+ TelemetryEventName.MICROBIT_ERROR_PYTHON_DEVICE_PROCESS;
+ }
+ telemetryAI.trackFeatureUsage(telemetryErrorName, { error: `${data}` });
+ };
+
+ const handleDeployToDeviceTelemetry = (message: any, device: string) => {
+ let successCommandDeployDevice: string;
+ let errorCommandDeployWithoutDevice: string;
+ if (device === CONSTANTS.DEVICE_NAME.CPX) {
+ successCommandDeployDevice =
+ TelemetryEventName.CPX_SUCCESS_COMMAND_DEPLOY_DEVICE;
+ errorCommandDeployWithoutDevice =
+ TelemetryEventName.CPX_ERROR_DEPLOY_WITHOUT_DEVICE;
+ } else if (device === CONSTANTS.DEVICE_NAME.MICROBIT) {
+ successCommandDeployDevice =
+ TelemetryEventName.MICROBIT_SUCCESS_COMMAND_DEPLOY_DEVICE;
+ errorCommandDeployWithoutDevice =
+ TelemetryEventName.MICROBIT_ERROR_DEPLOY_WITHOUT_DEVICE;
+ }
+ switch (message.type) {
+ case "complete":
+ telemetryAI.trackFeatureUsage(successCommandDeployDevice);
+ break;
+ case "no-device":
+ telemetryAI.trackFeatureUsage(errorCommandDeployWithoutDevice);
+ if (device === CONSTANTS.DEVICE_NAME.CPX) {
+ vscode.window
+ .showErrorMessage(
+ CONSTANTS.ERROR.NO_DEVICE,
+ DialogResponses.HELP
+ )
+ .then((selection: vscode.MessageItem | undefined) => {
+ if (selection === DialogResponses.HELP) {
+ const okAction = () => {
+ open(CONSTANTS.LINKS.HELP);
+ telemetryAI.trackFeatureUsage(
+ TelemetryEventName.CPX_CLICK_DIALOG_HELP_DEPLOY_TO_DEVICE
+ );
+ };
+ utils.showPrivacyModal(
+ okAction,
+ CONSTANTS.INFO.THIRD_PARTY_WEBSITE_ADAFRUIT
+ );
+ }
+ });
+ } else if (device === CONSTANTS.DEVICE_NAME.MICROBIT) {
+ vscode.window.showErrorMessage(CONSTANTS.ERROR.NO_DEVICE);
+ }
+ break;
+ case "low-python-version":
+ vscode.window.showErrorMessage(
+ CONSTANTS.ERROR.LOW_PYTHON_VERSION_FOR_MICROBIT_DEPLOYMENT
+ );
+ break;
+ default:
+ console.log(
+ `Non-state JSON output from the process : ${message}`
+ );
+ break;
+ }
+ };
+
+ const cpxDeployCodeToDevice = () => {
+ deployCode(CONSTANTS.DEVICE_NAME.CPX);
+ };
+
+ const microbitDeployCodeToDevice = () => {
+ deployCode(CONSTANTS.DEVICE_NAME.MICROBIT);
+ };
+
const cpxDeployToDevice: vscode.Disposable = vscode.commands.registerCommand(
"deviceSimulatorExpress.cpx.deployToDevice",
() => {
@@ -842,19 +836,32 @@ export async function activate(context: vscode.ExtensionContext) {
}
);
+ const microbitDeployToDevice: vscode.Disposable = vscode.commands.registerCommand(
+ "deviceSimulatorExpress.microbit.deployToDevice",
+ () => {
+ telemetryAI.trackFeatureUsage(
+ TelemetryEventName.MICROBIT_COMMAND_DEPLOY_DEVICE
+ );
+ telemetryAI.runWithLatencyMeasure(
+ microbitDeployCodeToDevice,
+ TelemetryEventName.MICROBIT_PERFORMANCE_DEPLOY_DEVICE
+ );
+ }
+ );
+
let serialMonitor: SerialMonitor | undefined;
if (configFileCreated) {
serialMonitor = SerialMonitor.getInstance();
context.subscriptions.push(serialMonitor);
}
- const cpxSelectSerialPort: vscode.Disposable = vscode.commands.registerCommand(
- "deviceSimulatorExpress.cpx.selectSerialPort",
+ const selectSerialPort: vscode.Disposable = vscode.commands.registerCommand(
+ "deviceSimulatorExpress.common.selectSerialPort",
() => {
if (serialMonitor) {
telemetryAI.runWithLatencyMeasure(() => {
serialMonitor.selectSerialPort(null, null);
- }, TelemetryEventName.CPX_COMMAND_SERIAL_MONITOR_CHOOSE_PORT);
+ }, TelemetryEventName.COMMAND_SERIAL_MONITOR_CHOOSE_PORT);
} else {
vscode.window.showErrorMessage(
CONSTANTS.ERROR.NO_FOLDER_OPENED
@@ -864,13 +871,13 @@ export async function activate(context: vscode.ExtensionContext) {
}
);
- const cpxOpenSerialMonitor: vscode.Disposable = vscode.commands.registerCommand(
- "deviceSimulatorExpress.cpx.openSerialMonitor",
+ const openSerialMonitor: vscode.Disposable = vscode.commands.registerCommand(
+ "deviceSimulatorExpress.common.openSerialMonitor",
() => {
if (serialMonitor) {
telemetryAI.runWithLatencyMeasure(
serialMonitor.openSerialMonitor.bind(serialMonitor),
- TelemetryEventName.CPX_COMMAND_SERIAL_MONITOR_OPEN
+ TelemetryEventName.COMMAND_SERIAL_MONITOR_OPEN
);
} else {
vscode.window.showErrorMessage(
@@ -881,13 +888,13 @@ export async function activate(context: vscode.ExtensionContext) {
}
);
- const cpxChangeBaudRate: vscode.Disposable = vscode.commands.registerCommand(
- "deviceSimulatorExpress.cpx.changeBaudRate",
+ const changeBaudRate: vscode.Disposable = vscode.commands.registerCommand(
+ "deviceSimulatorExpress.common.changeBaudRate",
() => {
if (serialMonitor) {
telemetryAI.runWithLatencyMeasure(
serialMonitor.changeBaudRate.bind(serialMonitor),
- TelemetryEventName.CPX_COMMAND_SERIAL_MONITOR_BAUD_RATE
+ TelemetryEventName.COMMAND_SERIAL_MONITOR_BAUD_RATE
);
} else {
vscode.window.showErrorMessage(
@@ -898,13 +905,13 @@ export async function activate(context: vscode.ExtensionContext) {
}
);
- const cpxCloseSerialMonitor: vscode.Disposable = vscode.commands.registerCommand(
- "deviceSimulatorExpress.cpx.closeSerialMonitor",
+ const closeSerialMonitor: vscode.Disposable = vscode.commands.registerCommand(
+ "deviceSimulatorExpress.common.closeSerialMonitor",
(port, showWarning = true) => {
if (serialMonitor) {
telemetryAI.runWithLatencyMeasure(() => {
serialMonitor.closeSerialMonitor(port, showWarning);
- }, TelemetryEventName.CPX_COMMAND_SERIAL_MONITOR_CLOSE);
+ }, TelemetryEventName.COMMAND_SERIAL_MONITOR_CLOSE);
} else {
vscode.window.showErrorMessage(
CONSTANTS.ERROR.NO_FOLDER_OPENED
@@ -920,7 +927,7 @@ export async function activate(context: vscode.ExtensionContext) {
if (serialMonitor) {
telemetryAI.runWithLatencyMeasure(() => {
serialMonitor.closeSerialMonitor(port, showWarning);
- }, TelemetryEventName.CPX_COMMAND_SERIAL_MONITOR_CLOSE);
+ }, TelemetryEventName.COMMAND_SERIAL_MONITOR_CLOSE);
} else {
vscode.window.showErrorMessage(
CONSTANTS.ERROR.NO_FOLDER_OPENED
@@ -958,7 +965,7 @@ export async function activate(context: vscode.ExtensionContext) {
debuggerCommunicationService
);
vscode.debug.registerDebugAdapterTrackerFactory(
- "python",
+ LANGUAGE_VARS.PYTHON.ID,
debugAdapterFactory
);
// On Debug Session Start: Init comunication
@@ -978,7 +985,7 @@ export async function activate(context: vscode.ExtensionContext) {
new DebuggerCommunicationServer(
currentPanel,
utils.getServerPortConfig(),
- currentActiveDevice
+ deviceSelectionService.getCurrentActiveDevice()
)
);
@@ -990,7 +997,7 @@ export async function activate(context: vscode.ExtensionContext) {
.getCurrentDebuggerServer()
.setWebview(currentPanel);
currentPanel.webview.postMessage({
- currentActiveDevice,
+ active_device: deviceSelectionService.getCurrentActiveDevice(),
command: "activate-play",
});
}
@@ -1023,7 +1030,7 @@ export async function activate(context: vscode.ExtensionContext) {
if (currentPanel) {
currentPanel.webview.postMessage({
command: "reset-state",
- active_device: currentActiveDevice,
+ active_device: deviceSelectionService.getCurrentActiveDevice(),
});
}
}
@@ -1032,7 +1039,7 @@ export async function activate(context: vscode.ExtensionContext) {
const configsChanged = vscode.workspace.onDidChangeConfiguration(
async () => {
if (utils.checkConfig(CONFIG.CONFIG_ENV_ON_SWITCH)) {
- pythonExecutablePath = await utils.setupEnv(context);
+ pythonExecutablePath = await setupService.setupEnv(context);
}
}
);
@@ -1040,15 +1047,16 @@ export async function activate(context: vscode.ExtensionContext) {
context.subscriptions.push(
installDependencies,
runSimulator,
- cpxChangeBaudRate,
- cpxCloseSerialMonitor,
+ changeBaudRate,
+ closeSerialMonitor,
cpxDeployToDevice,
cpxNewFile,
- cpxOpenSerialMonitor,
+ openSerialMonitor,
cpxOpenSimulator,
- cpxSelectSerialPort,
+ selectSerialPort,
microbitOpenSimulator,
microbitNewFile,
+ microbitDeployToDevice,
vscode.debug.registerDebugConfigurationProvider(
CONSTANTS.DEBUG_CONFIGURATION_TYPE,
simulatorDebugConfiguration
@@ -1059,41 +1067,8 @@ export async function activate(context: vscode.ExtensionContext) {
);
}
-const getActivePythonFile = () => {
- const editors: vscode.TextEditor[] = vscode.window.visibleTextEditors;
- const activeEditor = editors.find(
- editor => editor.document.languageId === "python"
- );
- if (activeEditor) {
- currentTextDocument = activeEditor.document;
- }
- return activeEditor ? activeEditor.document.fileName : "";
-};
-
-const updateCurrentFileIfPython = async (
- activeTextDocument: vscode.TextDocument | undefined,
- currentPanel: vscode.WebviewPanel
-) => {
- if (activeTextDocument && activeTextDocument.languageId === "python") {
- setPathAndSendMessage(currentPanel, activeTextDocument.fileName);
- currentTextDocument = activeTextDocument;
- } else if (currentFileAbsPath === "") {
- setPathAndSendMessage(currentPanel, getActivePythonFile() || "");
- }
- if (
- currentTextDocument &&
- utils.getActiveEditorFromPath(currentTextDocument.fileName) ===
- undefined
- ) {
- await vscode.window.showTextDocument(
- currentTextDocument,
- vscode.ViewColumn.One
- );
- }
-};
-
const handleDebuggerTelemetry = () => {
- switch (currentActiveDevice) {
+ switch (deviceSelectionService.getCurrentActiveDevice()) {
case CONSTANTS.DEVICE_NAME.CPX:
telemetryAI.trackFeatureUsage(
TelemetryEventName.CPX_DEBUGGER_INIT_SUCCESS
@@ -1110,7 +1085,7 @@ const handleDebuggerTelemetry = () => {
};
const handleDebuggerFailTelemetry = () => {
- switch (currentActiveDevice) {
+ switch (deviceSelectionService.getCurrentActiveDevice()) {
case CONSTANTS.DEVICE_NAME.CPX:
telemetryAI.trackFeatureUsage(
TelemetryEventName.CPX_DEBUGGER_INIT_FAIL
@@ -1127,7 +1102,7 @@ const handleDebuggerFailTelemetry = () => {
};
const handleButtonPressTelemetry = (buttonState: any) => {
- switch (currentActiveDevice) {
+ switch (deviceSelectionService.getCurrentActiveDevice()) {
case CONSTANTS.DEVICE_NAME.CPX:
handleCPXButtonPressTelemetry(buttonState);
break;
@@ -1140,7 +1115,7 @@ const handleButtonPressTelemetry = (buttonState: any) => {
};
const handleGestureTelemetry = (sensorState: any) => {
- switch (currentActiveDevice) {
+ switch (deviceSelectionService.getCurrentActiveDevice()) {
case CONSTANTS.DEVICE_NAME.CPX:
handleCPXGestureTelemetry(sensorState);
break;
@@ -1152,7 +1127,7 @@ const handleGestureTelemetry = (sensorState: any) => {
};
const handleSensorTelemetry = (sensor: string) => {
- switch (currentActiveDevice) {
+ switch (deviceSelectionService.getCurrentActiveDevice()) {
case CONSTANTS.DEVICE_NAME.CPX:
handleCPXSensorTelemetry(sensor);
break;
@@ -1277,7 +1252,7 @@ const handleMicrobitSensorTelemetry = (sensor: string) => {
};
const handleNewFileErrorTelemetry = () => {
- switch (currentActiveDevice) {
+ switch (deviceSelectionService.getCurrentActiveDevice()) {
case CONSTANTS.DEVICE_NAME.CPX:
telemetryAI.trackFeatureUsage(
TelemetryEventName.CPX_ERROR_COMMAND_NEW_FILE
@@ -1353,9 +1328,6 @@ function getWebviewContent(context: vscode.ExtensionContext) {