From 242acdbc000c638710a66f59f59eb6ad561fb354 Mon Sep 17 00:00:00 2001 From: Kevin Nguyen Date: Tue, 21 Apr 2020 12:03:48 -0700 Subject: [PATCH] Minor update to production (#352) * Add precision to input slider * Fix inverse switch * Refactor * Switch default is false * Modify precision value for cpx and clue * Table of Contents for README (#349) * Slideshow Backwards/Forwards Bug Fix (#350) * slideshow nav fixed * Fixed print() statements for CLUE display in debug mode (#351) * fixed debug_user_code.py to capture print statements * added starting and ending print statements * new release note apr 21 * added a few fixes Co-authored-by: Vandy Liu <33995460+vandyliu@users.noreply.github.com> Co-authored-by: Andrea Mah <31675041+andreamah@users.noreply.github.com> Co-authored-by: andreamah --- README.md | 27 ++++++++- src/clue/adafruit_slideshow.py | 56 +++++++++++------- src/debug_user_code.py | 24 +++++++- src/latest_release_note.ts | 57 ++++++++++++------- src/view/components/cpx/CpxImage.tsx | 2 +- .../toolbar/GenericSliderComponent.tsx | 1 + src/view/components/toolbar/InputSlider.tsx | 11 +++- .../toolbar/clue/ClueSensorProperties.tsx | 23 +++++++- .../toolbar/cpx/CpxSensorProperties.tsx | 7 ++- .../microbit/MicrobitSensorProperties.tsx | 5 ++ src/view/viewUtils.tsx | 1 + 11 files changed, 163 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index f54889b18..0da43101b 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,32 @@ Make without limit! Device Simulator Express, a Microsoft Garage project, allows 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. -## Devices we support: +## Table of Contents + - [Devices we support](#devices-we-support) + - [Prerequisites](#prerequisites) + - [Adafruit Circuit Playground Express (CPX) Simulator](#adafruit-circuit-playground-express-cpx-simulator) + - [Features](#features) + - [Useful Links](#useful-links) + - [Keyboard Shortcuts](#keyboard-shortcuts) + - [BBC micro:bit Simulator](#bbc-microbit-simulator) + - [Features](#features-1) + - [Useful Links](#useful-links-1) + - [Keyboard Shortcuts](#keyboard-shortcuts-1) + - [Adafruit CLUE Simulator](#adafruit-clue-simulator) + - [Features](#features-2) + - [Useful Links](#useful-links-2) + - [Keyboard Shortcuts](#keyboard-shortcuts-2) + - [How to use](#how-to-use) + - [Commands](#commands) + - [Contribute](#contribute) + - [Provide feedback](#provide-feedback) + - [Privacy and Telemetry Notice](#privacy-and-telemetry-notice) + - [Third Party Notice](#third-party-notice) + - [Troubleshooting Tips](#troubleshooting-tips) + - [License](#license) + - [Notes](#notes) + +## Devices we support - [**Adafruit Circuit Playground Express (CPX)**](#adafruit-circuit-playground-express-cpx-simulator) diff --git a/src/clue/adafruit_slideshow.py b/src/clue/adafruit_slideshow.py index 7e5cecd2c..aa1fb6b65 100644 --- a/src/clue/adafruit_slideshow.py +++ b/src/clue/adafruit_slideshow.py @@ -5,7 +5,6 @@ from io import BytesIO from base_circuitpython import base_cp_constants as CONSTANTS import time -import collections from random import shuffle import common import board @@ -165,6 +164,7 @@ def __init__( self._order = order self._curr_img = "" + self._current_image_index = None # load images into main queue self.__load_images() @@ -219,41 +219,57 @@ def update(self): def __get_next_img(self): - # handle empty queue - if not len(self.pic_queue): - if self.loop: - self.__load_images() + if self.direction == PlayBackDirection.FORWARD: + if self._current_image_index == None: + self._current_image_index = 0 else: - return "" + self._current_image_index += 1 + + if self._current_image_index >= len(self.dir_imgs): + + if self.loop: + self._current_image_index = 0 + self.__load_images() + else: + self._current_image_index = len(self.dir_imgs) - 10 + return "" - if self.direction == PlayBackDirection.FORWARD: - return self.pic_queue.popleft() else: - return self.pic_queue.pop() + if self._current_image_index == None: + self._current_image_index = len(self.dir_imgs) - 1 + else: + self._current_image_index -= 1 + + if self._current_image_index < 0: + if self.loop: + self._current_image_index = len(self.dir_imgs) - 1 + self.__load_images() + else: + self._current_image_index = 0 + return "" + + img = self.dir_imgs[self._current_image_index] + return img def __load_images(self): - dir_imgs = [] + self.dir_imgs = [] for d in self.dirs: try: new_path = os.path.join(self.folder, d) # only add bmp imgs - if os.path.splitext(new_path)[1] == CONSTANTS.BMP_IMG_ENDING: - dir_imgs.append(new_path) + if os.path.splitext(new_path)[-1] == CONSTANTS.BMP_IMG_ENDING: + self.dir_imgs.append(new_path) except Image.UnidentifiedImageError as e: continue - if not len(dir_imgs): + if not len(self.dir_imgs): raise RuntimeError(CONSTANTS.NO_VALID_IMGS_ERR) if self._order == PlayBackOrder.RANDOM: - shuffle(dir_imgs) + shuffle(self.dir_imgs) else: - dir_imgs.sort() - - # convert list to queue - # (must be list beforehand for potential randomization) - self.pic_queue = collections.deque(dir_imgs) + self.dir_imgs.sort() def __advance_with_fade(self): if board.DISPLAY.active_group != self: @@ -265,6 +281,7 @@ def __advance_with_fade(self): while not advance_sucessful: new_path = self.__get_next_img() if new_path == "": + self._img_start = time.monotonic() return False try: @@ -323,6 +340,7 @@ def __advance_no_fade(self): while not advance_sucessful: new_path = self.__get_next_img() if new_path == "": + self._img_start = time.monotonic() return False try: diff --git a/src/debug_user_code.py b/src/debug_user_code.py index 7e534f479..8be4792fb 100644 --- a/src/debug_user_code.py +++ b/src/debug_user_code.py @@ -32,9 +32,15 @@ # Insert absolute path to Circuitpython libraries for CLUE into sys.path sys.path.insert(0, os.path.join(abs_path_to_parent_dir, CONSTANTS.CIRCUITPYTHON)) +# get board so we can get terminal handle +import board + # This import must happen after the sys.path is modified from common import debugger_communication_client +# get handle to terminal for clue +curr_terminal = board.DISPLAY.terminal + ## Execute User Code ## # Get user's code path @@ -56,12 +62,26 @@ utils.abs_path_to_user_file = abs_path_to_code_file utils.debug_mode = True +# overriding print function so that it shows on clue terminal +def print_decorator(func): + global curr_terminal + + def wrapped_func(*args, **kwargs): + curr_terminal.add_str_to_terminal("".join(str(e) for e in args)) + return func(*args, **kwargs) + + return wrapped_func + + +print = print_decorator(print) + # Execute the user's code file with open(abs_path_to_code_file, encoding="utf8") as user_code_file: + curr_terminal.add_str_to_terminal(CONSTANTS.CODE_START_MSG_CLUE) user_code = user_code_file.read() try: codeObj = compile(user_code, abs_path_to_code_file, CONSTANTS.EXEC_COMMAND) - exec(codeObj, {}) + exec(codeObj, {"print": print}) sys.stdout.flush() except Exception as e: exc_type, exc_value, exc_traceback = sys.exc_info() @@ -71,3 +91,5 @@ for frameIndex in range(2, len(stackTrace) - 1): errorMessage += "\t" + str(stackTrace[frameIndex]) print(e, errorMessage, file=sys.stderr, flush=True) + curr_terminal.add_str_to_terminal(CONSTANTS.CODE_FINISHED_MSG_CLUE) + board.DISPLAY.show(None) diff --git a/src/latest_release_note.ts b/src/latest_release_note.ts index 65547e1aa..3d9971054 100644 --- a/src/latest_release_note.ts +++ b/src/latest_release_note.ts @@ -1,26 +1,39 @@ // TODO: find a better way of loading html into a string -export const LATEST_RELEASE_NOTE = `

Device Simulator Express Release Notes 📝(April 20, 2020)

-

-

We're back with a full release for the Adafruit CLUE 🐍🔍.

+export const LATEST_RELEASE_NOTE = `

Device Simulator Express Release Notes 🤖

+

Device Simulator Express, a Microsoft Garage project, allows you to code microcontrollers without the hardware on hand! You can program your Adafruit Circuit Playground Express (CPX), your BBC micro:bit or the Adafruit CLUE!

+
+ LIGHTGESTUREPROXIMITY +
+ +

📝 April 21, 2020

+ +

Changes:

+ +

Fixes:

+ -
- LIGHTGESTUREPROXIMITY -
-

-

Changes:

- -

Fixes:

- +

📝 April 20, 2020

+

+

We're back with a full release for the Adafruit CLUE 🐍🔍.

+

+

Changes:

+ +

Fixes:

+ -

+

-

PS: You can read about the DSX team in the article here!

-

Create something wonderful ✨🙌,
-       - The Device Simulator Express Team

`; +

PS: You can read about the DSX team in the article here!

+

Create something wonderful ✨🙌,
+       - The Device Simulator Express Team

`; diff --git a/src/view/components/cpx/CpxImage.tsx b/src/view/components/cpx/CpxImage.tsx index 7163b67c3..48aef4e64 100644 --- a/src/view/components/cpx/CpxImage.tsx +++ b/src/view/components/cpx/CpxImage.tsx @@ -380,7 +380,7 @@ export const updateSwitch = (switchState: boolean): void => { if (switchElement && switchInner) { svg.addClass(switchInner, "sim-slide-switch-inner"); - if (switchState) { + if (!switchState) { svg.addClass(switchInner, "on"); switchInner.setAttribute("transform", "translate(-5,0)"); } else { diff --git a/src/view/components/toolbar/GenericSliderComponent.tsx b/src/view/components/toolbar/GenericSliderComponent.tsx index 48e2ec091..273896621 100644 --- a/src/view/components/toolbar/GenericSliderComponent.tsx +++ b/src/view/components/toolbar/GenericSliderComponent.tsx @@ -29,6 +29,7 @@ export const GenericSliderComponent: React.FC = props => { value={ props.axisValues[sliderProperties.axisLabel] } + step={sliderProperties.step} />
diff --git a/src/view/components/toolbar/InputSlider.tsx b/src/view/components/toolbar/InputSlider.tsx index d98e118cc..9d163aca3 100644 --- a/src/view/components/toolbar/InputSlider.tsx +++ b/src/view/components/toolbar/InputSlider.tsx @@ -21,6 +21,9 @@ class InputSlider extends React.Component { render() { const isInputDisabled = this.context === VIEW_STATE.PAUSE; + + const nbDecimals = + this.props.step.toString().split(".")[1]?.length || 0; return (
{this.props.axisLabel} @@ -31,8 +34,9 @@ class InputSlider extends React.Component { onInput={this.handleOnChange} defaultValue={this.props.minValue.toLocaleString()} pattern={`^-?[0-9]{0,${ - this.props.maxValue.toString().length - }}$`} + (this.props.maxValue / this.props.step).toString() + .length + }}[.]{0,${nbDecimals > 0 ? 1 : 0}}[0-9]{0,${nbDecimals}}$`} onKeyUp={this.handleOnChange} aria-label={`${this.props.type} sensor input ${this.props.axisLabel}`} /> @@ -56,6 +60,7 @@ class InputSlider extends React.Component { aria-label={`${this.props.type} sensor`} defaultValue={this.props.minValue.toLocaleString()} disabled={isInputDisabled} + step={this.props.step} /> {this.props.minLabel} @@ -100,7 +105,7 @@ class InputSlider extends React.Component { }; private validateRange = (valueString: string) => { - let valueInt = parseInt(valueString, 10); + let valueInt = parseFloat(valueString); if (valueInt < this.props.minValue) { valueInt = this.props.minValue; this.setState({ value: valueInt }); diff --git a/src/view/components/toolbar/clue/ClueSensorProperties.tsx b/src/view/components/toolbar/clue/ClueSensorProperties.tsx index 2e2b9975a..e1f124557 100644 --- a/src/view/components/toolbar/clue/ClueSensorProperties.tsx +++ b/src/view/components/toolbar/clue/ClueSensorProperties.tsx @@ -4,28 +4,31 @@ import { ISensorProps, ISliderProps } from "../../../viewUtils"; const CLUE_SLIDER_R: ISliderProps = { axisLabel: "R", maxLabel: "Max", - maxValue: 255, + maxValue: 65535, minLabel: "Min", minValue: 0, type: SENSOR_LIST.LIGHT_R, + step: 1, }; const CLUE_SLIDER_G: ISliderProps = { axisLabel: "G", maxLabel: "Max", - maxValue: 255, + maxValue: 65535, minLabel: "Min", minValue: 0, type: SENSOR_LIST.LIGHT_G, + step: 1, }; const CLUE_SLIDER_B: ISliderProps = { axisLabel: "B", maxLabel: "Max", - maxValue: 255, + maxValue: 65535, minLabel: "Min", minValue: 0, type: SENSOR_LIST.LIGHT_B, + step: 1, }; const CLUE_SLIDER_C: ISliderProps = { axisLabel: "C", @@ -34,6 +37,7 @@ const CLUE_SLIDER_C: ISliderProps = { minLabel: "Min", minValue: 0, type: SENSOR_LIST.LIGHT_C, + step: 1, }; export const CLUE_LIGHT_PROPERTIES: ISensorProps = { @@ -50,6 +54,7 @@ const CLUE_MAGNET_X: ISliderProps = { maxValue: 1000, minValue: -1000, type: SENSOR_LIST.MAGNET_X, + step: 0.1, }; const CLUE_MAGNET_Y: ISliderProps = { axisLabel: "Y", @@ -58,6 +63,7 @@ const CLUE_MAGNET_Y: ISliderProps = { maxValue: 1000, minValue: -1000, type: SENSOR_LIST.MAGNET_Y, + step: 0.1, }; const CLUE_MAGNET_Z: ISliderProps = { axisLabel: "Z", @@ -66,6 +72,7 @@ const CLUE_MAGNET_Z: ISliderProps = { maxValue: 1000, minValue: -1000, type: SENSOR_LIST.MAGNET_Z, + step: 0.1, }; export const CLUE_MAGNET_PROPERTIES: ISensorProps = { @@ -80,6 +87,7 @@ const CLUE_GYRO_X: ISliderProps = { maxValue: 1000, minValue: -1000, type: SENSOR_LIST.GYRO_X, + step: 0.1, }; const CLUE_GYRO_Y: ISliderProps = { axisLabel: "Y", @@ -88,6 +96,7 @@ const CLUE_GYRO_Y: ISliderProps = { maxValue: 1000, minValue: -1000, type: SENSOR_LIST.GYRO_Y, + step: 0.1, }; const CLUE_GYRO_Z: ISliderProps = { axisLabel: "Z", @@ -96,6 +105,7 @@ const CLUE_GYRO_Z: ISliderProps = { maxValue: 1000, minValue: -1000, type: SENSOR_LIST.GYRO_Z, + step: 0.1, }; export const CLUE_GYRO_PROPERTIES: ISensorProps = { @@ -114,6 +124,7 @@ export const CLUE_HUMIDITY_PROPERTIES: ISensorProps = { minLabel: "Min", minValue: 0, type: SENSOR_LIST.HUMIDITY, + step: 0.1, }, ], unitLabel: "%", @@ -128,6 +139,7 @@ export const CLUE__PROXIMITY_PROPERTIES: ISensorProps = { minLabel: "Min", minValue: 0, type: SENSOR_LIST.PROXIMITY, + step: 1, }, ], unitLabel: "", @@ -142,6 +154,7 @@ export const CLUE_PRESSURE_PROPERTIES: ISensorProps = { minLabel: "Min", minValue: 800, type: SENSOR_LIST.PRESSURE, + step: 0.1, }, ], unitLabel: "hPa", @@ -153,6 +166,7 @@ const MOTION_SLIDER_PROPS_X: ISliderProps = { minLabel: "Left", minValue: -1023, type: SENSOR_LIST.MOTION_X, + step: 0.1, }; const MOTION_SLIDER_PROPS_Y: ISliderProps = { @@ -162,6 +176,7 @@ const MOTION_SLIDER_PROPS_Y: ISliderProps = { minLabel: "Back", minValue: -1023, type: SENSOR_LIST.MOTION_Y, + step: 0.1, }; const MOTION_SLIDER_PROPS_Z: ISliderProps = { @@ -171,6 +186,7 @@ const MOTION_SLIDER_PROPS_Z: ISliderProps = { minLabel: "Up", minValue: -1023, type: SENSOR_LIST.MOTION_Z, + step: 0.1, }; export const MOTION_SENSOR_PROPERTIES: ISensorProps = { @@ -190,6 +206,7 @@ const TEMPERATURE_SLIDER_PROPS: ISliderProps = { minLabel: "Cold", minValue: -55, type: SENSOR_LIST.TEMPERATURE, + step: 0.1, }; export const TEMPERATURE_SENSOR_PROPERTIES: ISensorProps = { diff --git a/src/view/components/toolbar/cpx/CpxSensorProperties.tsx b/src/view/components/toolbar/cpx/CpxSensorProperties.tsx index 6a5a9990a..f91f91469 100644 --- a/src/view/components/toolbar/cpx/CpxSensorProperties.tsx +++ b/src/view/components/toolbar/cpx/CpxSensorProperties.tsx @@ -2,12 +2,13 @@ import { SENSOR_LIST } from "../../../constants"; import { ISensorProps, ISliderProps } from "../../../viewUtils"; const LIGHT_SLIDER_PROPS: ISliderProps = { - maxValue: 255, + maxValue: 320, minValue: 0, minLabel: "Dark", maxLabel: "Bright", type: "light", axisLabel: "L", + step: 1, }; export const LIGHT_SENSOR_PROPERTIES: ISensorProps = { @@ -23,6 +24,7 @@ const TEMPERATURE_SLIDER_PROPS: ISliderProps = { minLabel: "Cold", minValue: -55, type: SENSOR_LIST.TEMPERATURE, + step: 0.1, }; export const TEMPERATURE_SENSOR_PROPERTIES: ISensorProps = { LABEL: "Temperature sensor", @@ -37,6 +39,7 @@ const MOTION_SLIDER_PROPS_X: ISliderProps = { minLabel: "Left", minValue: -78, type: SENSOR_LIST.MOTION_X, + step: 1, }; const MOTION_SLIDER_PROPS_Y: ISliderProps = { axisLabel: "Y", @@ -45,6 +48,7 @@ const MOTION_SLIDER_PROPS_Y: ISliderProps = { minLabel: "Back", minValue: -78, type: SENSOR_LIST.MOTION_Y, + step: 1, }; const MOTION_SLIDER_PROPS_Z: ISliderProps = { axisLabel: "Z", @@ -53,6 +57,7 @@ const MOTION_SLIDER_PROPS_Z: ISliderProps = { minLabel: "Up", minValue: -78, type: SENSOR_LIST.MOTION_Z, + step: 1, }; export const MOTION_SENSOR_PROPERTIES: ISensorProps = { diff --git a/src/view/components/toolbar/microbit/MicrobitSensorProperties.tsx b/src/view/components/toolbar/microbit/MicrobitSensorProperties.tsx index 42470ce44..c32b00477 100644 --- a/src/view/components/toolbar/microbit/MicrobitSensorProperties.tsx +++ b/src/view/components/toolbar/microbit/MicrobitSensorProperties.tsx @@ -8,6 +8,7 @@ const LIGHT_SLIDER_PROPS: ISliderProps = { maxLabel: "Bright", type: "light", axisLabel: "L", + step: 1, }; export const LIGHT_SENSOR_PROPERTIES: ISensorProps = { @@ -23,6 +24,7 @@ const MOTION_SLIDER_PROPS_X: ISliderProps = { minLabel: "Left", minValue: -1023, type: SENSOR_LIST.MOTION_X, + step: 1, }; const MOTION_SLIDER_PROPS_Y: ISliderProps = { @@ -32,6 +34,7 @@ const MOTION_SLIDER_PROPS_Y: ISliderProps = { minLabel: "Back", minValue: -1023, type: SENSOR_LIST.MOTION_Y, + step: 1, }; const MOTION_SLIDER_PROPS_Z: ISliderProps = { @@ -41,6 +44,7 @@ const MOTION_SLIDER_PROPS_Z: ISliderProps = { minLabel: "Up", minValue: -1023, type: SENSOR_LIST.MOTION_Z, + step: 1, }; export const MOTION_SENSOR_PROPERTIES: ISensorProps = { @@ -60,6 +64,7 @@ const TEMPERATURE_SLIDER_PROPS: ISliderProps = { minLabel: "Cold", minValue: -55, type: SENSOR_LIST.TEMPERATURE, + step: 1, }; export const TEMPERATURE_SENSOR_PROPERTIES: ISensorProps = { diff --git a/src/view/viewUtils.tsx b/src/view/viewUtils.tsx index cc12abd59..1335d039f 100644 --- a/src/view/viewUtils.tsx +++ b/src/view/viewUtils.tsx @@ -11,6 +11,7 @@ export interface ISliderProps { axisLabel: string; value?: number; onUpdateValue?: (sensor: SENSOR_LIST, value: number) => void; + step: number; } export interface ISensorButtonProps {