diff --git a/external_samples/spark_mini.py b/external_samples/spark_mini.py new file mode 100644 index 00000000..838524b1 --- /dev/null +++ b/external_samples/spark_mini.py @@ -0,0 +1,151 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""This is the spark_mini module. + +This component wraps the RobotPy SparkMini, providing support for the REV +Robotics SPARKMini Motor Controller with PWM control. +""" + +__author__ = "lizlooney@google.com (Liz Looney)" + +from component import Component, PortType, InvalidPortException +import wpilib +import wpimath +import wpiutil + +class SparkMiniComponent(Component): + def __init__(self, ports : list[tuple[PortType, int]]): + portType, port = ports[0] + if portType != PortType.SMART_MOTOR_PORT: + raise InvalidPortException + self.spark_mini = wpilib.SparkMini(port) + + # Component methods + + def get_manufacturer(self) -> str: + return "REV Robotics" + + def get_name(self) -> str: + return "SPARKMini Motor Controller" + + def get_part_number(self) -> str: + return "REV-31-1230" + + def get_url(self) -> str: + return "https://www.revrobotics.com/rev-31-1230" + + def get_version(self) -> tuple[int, int, int]: + return (1, 0, 0) + + def stop(self) -> None: + # send stop command to motor + pass + + def reset(self) -> None: + pass + + def get_connection_port_type(self) -> list[PortType]: + return [PortType.SMART_MOTOR_PORT] + + def periodic(self) -> None: + pass + + # Component specific methods + + # Methods from wpilib.PWMMotorController + + def add_follower(self, follower: wpilib.PWMMotorController) -> None: + '''Make the given PWM motor controller follow the output of this one.\n\n:param follower: The motor controller follower.''' + self.spark_mini.addFollower(follower) + + def disable(self) -> None: + self.spark_mini.disable() + + def enable_deadband_elimination(self, eliminateDeadband: bool) -> None: + '''Optionally eliminate the deadband from a motor controller.\n\n:param eliminateDeadband: If true, set the motor curve on the motor\n controller to eliminate the deadband in the middle\n of the range. Otherwise, keep the full range\n without modifying any values.''' + self.spark_mini.enableDeadbandElimination(eliminateDeadband) + + def get(self) -> float: + '''Get the recently set value of the PWM. This value is affected by the\ninversion property. If you want the value that is sent directly to the\nMotorController, use PWM::GetSpeed() instead.\n\n:returns: The most recently set value for the PWM between -1.0 and 1.0.''' + return self.spark_mini.get() + + def get_channel(self) -> int: + return self.spark_mini.getChannel() + + def get_description(self) -> str: + return self.spark_mini.getDescription() + + def get_inverted(self) -> bool: + return self.spark_mini.getInverted() + + def get_voltage(self) -> wpimath.units.volts: + '''Gets the voltage output of the motor controller, nominally between -12 V\nand 12 V.\n\n:returns: The voltage of the motor controller, nominally between -12 V and 12\n V.''' + return self.spark_mini.getVoltage() + + def set(self, value: float) -> None: + '''Set the PWM value.\n\nThe PWM value is set using a range of -1.0 to 1.0, appropriately scaling\nthe value for the FPGA.\n\n:param value: The speed value between -1.0 and 1.0 to set.''' + self.spark_mini.set(value) + + def set_inverted(self, isInverted: bool) -> None: + self.spark_mini.setInverted(isInverted) + + def set_voltage(self, output: wpimath.units.volts) -> None: + '''Sets the voltage output of the PWMMotorController. Compensates for\nthe current bus voltage to ensure that the desired voltage is output even\nif the battery voltage is below 12V - highly useful when the voltage\noutputs are "meaningful" (e.g. they come from a feedforward calculation).\n\nNOTE: This function *must* be called regularly in order for voltage\ncompensation to work properly - unlike the ordinary set function, it is not\n"set it and forget it."\n\n:param output: The voltage to output.''' + self.spark_mini.setVoltage(output) + + def stop_motor(self) -> None: + self.spark_mini.stopMotor() + + # Methods from wpilib.MotorSafety + + def check(self) -> None: + '''Check if this motor has exceeded its timeout.\n\nThis method is called periodically to determine if this motor has exceeded\nits timeout value. If it has, the stop method is called, and the motor is\nshut down until its value is updated again.''' + self.spark_mini.check(follower) + + # TODO(lizlooney): Decide whether we should expose checkMotors. It seems + # like it isn't intended to be called by users. + def check_motors() -> None: + '''Check the motors to see if any have timed out.\n\nThis static method is called periodically to poll all the motors and stop\nany that have timed out.''' + wpilib.SparkMini.checkMotors() + + def feed(self) -> None: + '''Feed the motor safety object.\n\nResets the timer on this object that is used to do the timeouts.''' + self.spark_mini.feed() + + def get_expiration(self) -> wpimath.units.seconds: + '''Retrieve the timeout value for the corresponding motor safety object.\n\n:returns: the timeout value.''' + return self.spark_mini.getExpiration() + + def is_alive(self) -> bool: + '''Determine if the motor is still operating or has timed out.\n\n:returns: true if the motor is still operating normally and hasn't timed out.''' + return self.spark_mini.isAlive() + + def is_safety_enabled(self) -> bool: + '''Return the state of the motor safety enabled flag.\n\nReturn if the motor safety is currently enabled for this device.\n\n:returns: True if motor safety is enforced for this device.''' + return self.spark_mini.isSafetyEnabled() + + def set_expiration(self, expirationTime: wpimath.units.seconds) -> None: + '''Set the expiration time for the corresponding motor safety object.\n\n:param expirationTime: The timeout value.''' + self.spark_mini.setExpiration(expirationTime) + + def set_safety_enabled(self, enabled: bool) -> None: + '''Enable/disable motor safety for this device.\n\nTurn on and off the motor safety option for this PWM object.\n\n:param enabled: True if motor safety is enforced for this object.''' + self.spark_mini.setSafetyEnabled(enabled) + + # Methods from wpiutil.Sendable + + def init_sendable(self, builder: wpiutil.SendableBuilder) -> None: + '''Initializes this Sendable object.\n\n:param builder: sendable builder''' + self.spark_mini.initSendable(builder) diff --git a/external_samples/sparkfun_led_stick.py b/external_samples/sparkfun_led_stick.py index 7d890f4e..6fc0b6c0 100644 --- a/external_samples/sparkfun_led_stick.py +++ b/external_samples/sparkfun_led_stick.py @@ -30,7 +30,7 @@ def get_manufacturer(self) -> str: return "SparkFun" def get_name(self) -> str: - return "SparkFun Qwiic LED Strip" + return "SparkFun Qwiic LED Stick" def get_part_number(self) -> str: return "COM-18354" diff --git a/src/blocks/mrc_call_python_function.ts b/src/blocks/mrc_call_python_function.ts index 52c6dd72..66dfa2fb 100644 --- a/src/blocks/mrc_call_python_function.ts +++ b/src/blocks/mrc_call_python_function.ts @@ -24,8 +24,8 @@ import * as Blockly from 'blockly'; import { Order } from 'blockly/python'; import { ClassMethodDefExtraState } from './mrc_class_method_def' -import { getAllowedTypesForSetCheck, getOutputCheck } from './utils/python'; -import { FunctionData } from './utils/python_json_types'; +import { getClassData, getAllowedTypesForSetCheck, getOutputCheck } from './utils/python'; +import { FunctionData, findSuperFunctionData } from './utils/python_json_types'; import * as value from './utils/value'; import * as variable from './utils/variable'; import { Editor } from '../editor/editor'; @@ -34,6 +34,7 @@ import { createFieldDropdown } from '../fields/FieldDropdown'; import { createFieldNonEditableText } from '../fields/FieldNonEditableText'; import { MRC_STYLE_FUNCTIONS } from '../themes/styles' import * as toolboxItems from '../toolbox/items'; +import * as commonStorage from '../storage/common_storage'; // A block to call a python function. @@ -217,6 +218,68 @@ function createInstanceMethodBlock( return block; } +export function addInstanceComponentBlocks( + componentType: string, + componentName: string, + contents: toolboxItems.ContentsType[]) { + + const classData = getClassData(componentType); + const functions = classData.instanceMethods; + + const componentClassData = getClassData('component.Component'); + const componentFunctions = componentClassData.instanceMethods; + + for (const functionData of functions) { + // Skip the functions that are also defined in componentFunctions. + if (findSuperFunctionData(functionData, componentFunctions)) { + continue; + } + const block = createInstanceComponentBlock(componentName, functionData); + contents.push(block); + } +} + +function createInstanceComponentBlock( + componentName: string, functionData: FunctionData): toolboxItems.Block { + const extraState: CallPythonFunctionExtraState = { + functionKind: FunctionKind.INSTANCE_COMPONENT, + returnType: functionData.returnType, + args: [], + tooltip: functionData.tooltip, + importModule: '', + componentClassName: functionData.declaringClassName, + componentName: componentName, + }; + const fields: {[key: string]: any} = {}; + fields[FIELD_COMPONENT_NAME] = componentName; + fields[FIELD_FUNCTION_NAME] = functionData.functionName; + const inputs: {[key: string]: any} = {}; + // For INSTANCE_COMPONENT functions, the 0 argument is 'self', but + // self is represented by the FIELD_COMPONENT_NAME field. + // We don't include the arg or input for self. + for (let i = 1; i < functionData.args.length; i++) { + const argData = functionData.args[i]; + let argName = argData.name; + extraState.args.push({ + 'name': argName, + 'type': argData.type, + }); + // Check if we should plug a variable getter block into the argument input socket. + const input = value.valueForFunctionArgInput(argData.type, argData.defaultValue); + if (input) { + // Because we skipped the self argument, use i - 1 when filling the inputs array. + inputs['ARG' + (i - 1)] = input; + } + } + let block = new toolboxItems.Block(BLOCK_NAME, extraState, fields, Object.keys(inputs).length ? inputs : null); + if (functionData.returnType && functionData.returnType != 'None') { + const varName = variable.varNameForType(functionData.returnType); + if (varName) { + block = variable.createVariableSetterBlock(varName, block); + } + } + return block; +} //.............................................................................. @@ -475,7 +538,9 @@ const CALL_PYTHON_FUNCTION = { break; } case FunctionKind.INSTANCE_COMPONENT: { - const componentNames = Editor.getComponentNames(this.workspace, this.mrcComponentClassName); + // TODO: We need the list of component names for this.mrcComponentClassName so we can + // create a dropdown that has the appropriate component names. + const componentNames = []; const componentName = this.getComponentName(); if (!componentNames.includes(componentName)) { componentNames.push(componentName); @@ -612,7 +677,18 @@ export const pythonFromBlock = function( const functionName = callPythonFunctionBlock.mrcActualFunctionName ? callPythonFunctionBlock.mrcActualFunctionName : block.getFieldValue(FIELD_FUNCTION_NAME); - code = 'self.' + componentName + '.' + functionName; + // Generate the correct code depending on the module type. + switch (generator.getModuleType()) { + case commonStorage.MODULE_TYPE_PROJECT: + case commonStorage.MODULE_TYPE_MECHANISM: + code = 'self.'; + break; + case commonStorage.MODULE_TYPE_OPMODE: + default: + code = 'self.robot.'; + break; + } + code += componentName + '.' + functionName; break; } default: diff --git a/src/blocks/utils/external_samples_data.ts b/src/blocks/utils/external_samples_data.ts index 66f7cfd7..3f796aa9 100644 --- a/src/blocks/utils/external_samples_data.ts +++ b/src/blocks/utils/external_samples_data.ts @@ -19,7 +19,7 @@ * @author lizlooney@google.com (Liz Looney) */ -import { PythonData } from './python_json_types'; +import { PythonData, ClassData } from './python_json_types'; import generatedExternalSamplesData from './generated/external_samples_data.json'; export const externalSamplesData = generatedExternalSamplesData as PythonData; diff --git a/src/blocks/utils/generated/external_samples_data.json b/src/blocks/utils/generated/external_samples_data.json index 32fa8d67..c798a301 100644 --- a/src/blocks/utils/generated/external_samples_data.json +++ b/src/blocks/utils/generated/external_samples_data.json @@ -80,7 +80,7 @@ ], "declaringClassName": "color_range_sensor.ColorRangeSensor", "functionName": "get_distance_mm", - "returnType": "", + "returnType": "float", "tooltip": "gets the distance of the object seen" }, { @@ -93,7 +93,7 @@ ], "declaringClassName": "color_range_sensor.ColorRangeSensor", "functionName": "get_manufacturer", - "returnType": "", + "returnType": "str", "tooltip": "" }, { @@ -106,7 +106,7 @@ ], "declaringClassName": "color_range_sensor.ColorRangeSensor", "functionName": "get_name", - "returnType": "", + "returnType": "str", "tooltip": "" }, { @@ -119,7 +119,7 @@ ], "declaringClassName": "color_range_sensor.ColorRangeSensor", "functionName": "get_part_number", - "returnType": "", + "returnType": "str", "tooltip": "" }, { @@ -132,7 +132,7 @@ ], "declaringClassName": "color_range_sensor.ColorRangeSensor", "functionName": "get_url", - "returnType": "", + "returnType": "str", "tooltip": "" }, { @@ -324,7 +324,7 @@ ], "declaringClassName": "component.Component", "functionName": "get_manufacturer", - "returnType": "", + "returnType": "str", "tooltip": "" }, { @@ -337,7 +337,7 @@ ], "declaringClassName": "component.Component", "functionName": "get_name", - "returnType": "", + "returnType": "str", "tooltip": "" }, { @@ -350,7 +350,7 @@ ], "declaringClassName": "component.Component", "functionName": "get_part_number", - "returnType": "", + "returnType": "str", "tooltip": "" }, { @@ -363,7 +363,7 @@ ], "declaringClassName": "component.Component", "functionName": "get_url", - "returnType": "", + "returnType": "str", "tooltip": "" }, { @@ -552,7 +552,7 @@ ], "declaringClassName": "rev_touch_sensor.RevTouchSensor", "functionName": "get_manufacturer", - "returnType": "", + "returnType": "str", "tooltip": "" }, { @@ -565,7 +565,7 @@ ], "declaringClassName": "rev_touch_sensor.RevTouchSensor", "functionName": "get_name", - "returnType": "", + "returnType": "str", "tooltip": "" }, { @@ -578,7 +578,7 @@ ], "declaringClassName": "rev_touch_sensor.RevTouchSensor", "functionName": "get_part_number", - "returnType": "", + "returnType": "str", "tooltip": "" }, { @@ -591,7 +591,7 @@ ], "declaringClassName": "rev_touch_sensor.RevTouchSensor", "functionName": "get_url", - "returnType": "", + "returnType": "str", "tooltip": "" }, { @@ -617,7 +617,7 @@ ], "declaringClassName": "rev_touch_sensor.RevTouchSensor", "functionName": "is_pressed", - "returnType": "", + "returnType": "bool", "tooltip": "Returns if the touch sensor is pressed or not" }, { @@ -743,7 +743,7 @@ ], "declaringClassName": "servo.Servo", "functionName": "get_manufacturer", - "returnType": "", + "returnType": "str", "tooltip": "" }, { @@ -756,7 +756,7 @@ ], "declaringClassName": "servo.Servo", "functionName": "get_name", - "returnType": "", + "returnType": "str", "tooltip": "" }, { @@ -769,7 +769,7 @@ ], "declaringClassName": "servo.Servo", "functionName": "get_part_number", - "returnType": "", + "returnType": "str", "tooltip": "" }, { @@ -782,7 +782,7 @@ ], "declaringClassName": "servo.Servo", "functionName": "get_url", - "returnType": "", + "returnType": "str", "tooltip": "" }, { @@ -908,7 +908,7 @@ ], "declaringClassName": "smart_motor.SmartMotor", "functionName": "get_angle_degrees", - "returnType": "", + "returnType": "float", "tooltip": "Get the angle position of the motor" }, { @@ -934,7 +934,7 @@ ], "declaringClassName": "smart_motor.SmartMotor", "functionName": "get_manufacturer", - "returnType": "", + "returnType": "str", "tooltip": "" }, { @@ -947,7 +947,7 @@ ], "declaringClassName": "smart_motor.SmartMotor", "functionName": "get_name", - "returnType": "", + "returnType": "str", "tooltip": "" }, { @@ -960,7 +960,7 @@ ], "declaringClassName": "smart_motor.SmartMotor", "functionName": "get_num_relative_encoder_ticks", - "returnType": "", + "returnType": "int", "tooltip": "Get the number of relative motor ticks since reset of encoder" }, { @@ -973,7 +973,7 @@ ], "declaringClassName": "smart_motor.SmartMotor", "functionName": "get_part_number", - "returnType": "", + "returnType": "str", "tooltip": "" }, { @@ -986,7 +986,7 @@ ], "declaringClassName": "smart_motor.SmartMotor", "functionName": "get_url", - "returnType": "", + "returnType": "str", "tooltip": "" }, { @@ -1095,6 +1095,456 @@ "moduleName": "smart_motor", "staticMethods": [] }, + { + "className": "spark_mini.SparkMiniComponent", + "classVariables": [], + "constructors": [ + { + "args": [ + { + "defaultValue": null, + "name": "ports", + "type": "list[tuple[component.PortType, int]]" + } + ], + "declaringClassName": "spark_mini.SparkMiniComponent", + "functionName": "__init__", + "returnType": "spark_mini.SparkMiniComponent", + "tooltip": "" + } + ], + "enums": [], + "instanceMethods": [ + { + "args": [ + { + "defaultValue": null, + "name": "self", + "type": "spark_mini.SparkMiniComponent" + }, + { + "defaultValue": null, + "name": "follower", + "type": "wpilib.PWMMotorController" + } + ], + "declaringClassName": "spark_mini.SparkMiniComponent", + "functionName": "add_follower", + "returnType": "None", + "tooltip": "Make the given PWM motor controller follow the output of this one.\n\n:param follower: The motor controller follower." + }, + { + "args": [ + { + "defaultValue": null, + "name": "self", + "type": "spark_mini.SparkMiniComponent" + } + ], + "declaringClassName": "spark_mini.SparkMiniComponent", + "functionName": "check", + "returnType": "None", + "tooltip": "Check if this motor has exceeded its timeout.\n\nThis method is called periodically to determine if this motor has exceeded\nits timeout value. If it has, the stop method is called, and the motor is\nshut down until its value is updated again." + }, + { + "args": [ + { + "defaultValue": null, + "name": "self", + "type": "spark_mini.SparkMiniComponent" + } + ], + "declaringClassName": "spark_mini.SparkMiniComponent", + "functionName": "disable", + "returnType": "None", + "tooltip": "" + }, + { + "args": [ + { + "defaultValue": null, + "name": "self", + "type": "spark_mini.SparkMiniComponent" + }, + { + "defaultValue": null, + "name": "eliminateDeadband", + "type": "bool" + } + ], + "declaringClassName": "spark_mini.SparkMiniComponent", + "functionName": "enable_deadband_elimination", + "returnType": "None", + "tooltip": "Optionally eliminate the deadband from a motor controller.\n\n:param eliminateDeadband: If true, set the motor curve on the motor\n controller to eliminate the deadband in the middle\n of the range. Otherwise, keep the full range\n without modifying any values." + }, + { + "args": [ + { + "defaultValue": null, + "name": "self", + "type": "spark_mini.SparkMiniComponent" + } + ], + "declaringClassName": "spark_mini.SparkMiniComponent", + "functionName": "feed", + "returnType": "None", + "tooltip": "Feed the motor safety object.\n\nResets the timer on this object that is used to do the timeouts." + }, + { + "args": [ + { + "defaultValue": null, + "name": "self", + "type": "spark_mini.SparkMiniComponent" + } + ], + "declaringClassName": "spark_mini.SparkMiniComponent", + "functionName": "get", + "returnType": "float", + "tooltip": "Get the recently set value of the PWM. This value is affected by the\ninversion property. If you want the value that is sent directly to the\nMotorController, use PWM::GetSpeed() instead.\n\n:returns: The most recently set value for the PWM between -1.0 and 1.0." + }, + { + "args": [ + { + "defaultValue": null, + "name": "self", + "type": "spark_mini.SparkMiniComponent" + } + ], + "declaringClassName": "spark_mini.SparkMiniComponent", + "functionName": "get_channel", + "returnType": "int", + "tooltip": "" + }, + { + "args": [ + { + "defaultValue": null, + "name": "self", + "type": "spark_mini.SparkMiniComponent" + } + ], + "declaringClassName": "spark_mini.SparkMiniComponent", + "functionName": "get_connection_port_type", + "returnType": "list[component.PortType]", + "tooltip": "" + }, + { + "args": [ + { + "defaultValue": null, + "name": "self", + "type": "spark_mini.SparkMiniComponent" + } + ], + "declaringClassName": "spark_mini.SparkMiniComponent", + "functionName": "get_description", + "returnType": "str", + "tooltip": "" + }, + { + "args": [ + { + "defaultValue": null, + "name": "self", + "type": "spark_mini.SparkMiniComponent" + } + ], + "declaringClassName": "spark_mini.SparkMiniComponent", + "functionName": "get_expiration", + "returnType": "float", + "tooltip": "Retrieve the timeout value for the corresponding motor safety object.\n\n:returns: the timeout value." + }, + { + "args": [ + { + "defaultValue": null, + "name": "self", + "type": "spark_mini.SparkMiniComponent" + } + ], + "declaringClassName": "spark_mini.SparkMiniComponent", + "functionName": "get_inverted", + "returnType": "bool", + "tooltip": "" + }, + { + "args": [ + { + "defaultValue": null, + "name": "self", + "type": "spark_mini.SparkMiniComponent" + } + ], + "declaringClassName": "spark_mini.SparkMiniComponent", + "functionName": "get_manufacturer", + "returnType": "str", + "tooltip": "" + }, + { + "args": [ + { + "defaultValue": null, + "name": "self", + "type": "spark_mini.SparkMiniComponent" + } + ], + "declaringClassName": "spark_mini.SparkMiniComponent", + "functionName": "get_name", + "returnType": "str", + "tooltip": "" + }, + { + "args": [ + { + "defaultValue": null, + "name": "self", + "type": "spark_mini.SparkMiniComponent" + } + ], + "declaringClassName": "spark_mini.SparkMiniComponent", + "functionName": "get_part_number", + "returnType": "str", + "tooltip": "" + }, + { + "args": [ + { + "defaultValue": null, + "name": "self", + "type": "spark_mini.SparkMiniComponent" + } + ], + "declaringClassName": "spark_mini.SparkMiniComponent", + "functionName": "get_url", + "returnType": "str", + "tooltip": "" + }, + { + "args": [ + { + "defaultValue": null, + "name": "self", + "type": "spark_mini.SparkMiniComponent" + } + ], + "declaringClassName": "spark_mini.SparkMiniComponent", + "functionName": "get_version", + "returnType": "tuple[int, int, int]", + "tooltip": "" + }, + { + "args": [ + { + "defaultValue": null, + "name": "self", + "type": "spark_mini.SparkMiniComponent" + } + ], + "declaringClassName": "spark_mini.SparkMiniComponent", + "functionName": "get_voltage", + "returnType": "float", + "tooltip": "Gets the voltage output of the motor controller, nominally between -12 V\nand 12 V.\n\n:returns: The voltage of the motor controller, nominally between -12 V and 12\n V." + }, + { + "args": [ + { + "defaultValue": null, + "name": "self", + "type": "spark_mini.SparkMiniComponent" + }, + { + "defaultValue": null, + "name": "builder", + "type": "wpiutil.SendableBuilder" + } + ], + "declaringClassName": "spark_mini.SparkMiniComponent", + "functionName": "init_sendable", + "returnType": "None", + "tooltip": "Initializes this Sendable object.\n\n:param builder: sendable builder" + }, + { + "args": [ + { + "defaultValue": null, + "name": "self", + "type": "spark_mini.SparkMiniComponent" + } + ], + "declaringClassName": "spark_mini.SparkMiniComponent", + "functionName": "is_alive", + "returnType": "bool", + "tooltip": "Determine if the motor is still operating or has timed out.\n\n:returns: true if the motor is still operating normally and hasn't timed out." + }, + { + "args": [ + { + "defaultValue": null, + "name": "self", + "type": "spark_mini.SparkMiniComponent" + } + ], + "declaringClassName": "spark_mini.SparkMiniComponent", + "functionName": "is_safety_enabled", + "returnType": "bool", + "tooltip": "Return the state of the motor safety enabled flag.\n\nReturn if the motor safety is currently enabled for this device.\n\n:returns: True if motor safety is enforced for this device." + }, + { + "args": [ + { + "defaultValue": null, + "name": "self", + "type": "spark_mini.SparkMiniComponent" + } + ], + "declaringClassName": "spark_mini.SparkMiniComponent", + "functionName": "periodic", + "returnType": "None", + "tooltip": "" + }, + { + "args": [ + { + "defaultValue": null, + "name": "self", + "type": "spark_mini.SparkMiniComponent" + } + ], + "declaringClassName": "spark_mini.SparkMiniComponent", + "functionName": "reset", + "returnType": "None", + "tooltip": "" + }, + { + "args": [ + { + "defaultValue": null, + "name": "self", + "type": "spark_mini.SparkMiniComponent" + }, + { + "defaultValue": null, + "name": "value", + "type": "float" + } + ], + "declaringClassName": "spark_mini.SparkMiniComponent", + "functionName": "set", + "returnType": "None", + "tooltip": "Set the PWM value.\n\nThe PWM value is set using a range of -1.0 to 1.0, appropriately scaling\nthe value for the FPGA.\n\n:param value: The speed value between -1.0 and 1.0 to set." + }, + { + "args": [ + { + "defaultValue": null, + "name": "self", + "type": "spark_mini.SparkMiniComponent" + }, + { + "defaultValue": null, + "name": "expirationTime", + "type": "float" + } + ], + "declaringClassName": "spark_mini.SparkMiniComponent", + "functionName": "set_expiration", + "returnType": "None", + "tooltip": "Set the expiration time for the corresponding motor safety object.\n\n:param expirationTime: The timeout value." + }, + { + "args": [ + { + "defaultValue": null, + "name": "self", + "type": "spark_mini.SparkMiniComponent" + }, + { + "defaultValue": null, + "name": "isInverted", + "type": "bool" + } + ], + "declaringClassName": "spark_mini.SparkMiniComponent", + "functionName": "set_inverted", + "returnType": "None", + "tooltip": "" + }, + { + "args": [ + { + "defaultValue": null, + "name": "self", + "type": "spark_mini.SparkMiniComponent" + }, + { + "defaultValue": null, + "name": "enabled", + "type": "bool" + } + ], + "declaringClassName": "spark_mini.SparkMiniComponent", + "functionName": "set_safety_enabled", + "returnType": "None", + "tooltip": "Enable/disable motor safety for this device.\n\nTurn on and off the motor safety option for this PWM object.\n\n:param enabled: True if motor safety is enforced for this object." + }, + { + "args": [ + { + "defaultValue": null, + "name": "self", + "type": "spark_mini.SparkMiniComponent" + }, + { + "defaultValue": null, + "name": "output", + "type": "float" + } + ], + "declaringClassName": "spark_mini.SparkMiniComponent", + "functionName": "set_voltage", + "returnType": "None", + "tooltip": "Sets the voltage output of the PWMMotorController. Compensates for\nthe current bus voltage to ensure that the desired voltage is output even\nif the battery voltage is below 12V - highly useful when the voltage\noutputs are \"meaningful\" (e.g. they come from a feedforward calculation).\n\nNOTE: This function *must* be called regularly in order for voltage\ncompensation to work properly - unlike the ordinary set function, it is not\n\"set it and forget it.\"\n\n:param output: The voltage to output." + }, + { + "args": [ + { + "defaultValue": null, + "name": "self", + "type": "spark_mini.SparkMiniComponent" + } + ], + "declaringClassName": "spark_mini.SparkMiniComponent", + "functionName": "stop", + "returnType": "None", + "tooltip": "" + }, + { + "args": [ + { + "defaultValue": null, + "name": "self", + "type": "spark_mini.SparkMiniComponent" + } + ], + "declaringClassName": "spark_mini.SparkMiniComponent", + "functionName": "stop_motor", + "returnType": "None", + "tooltip": "" + } + ], + "instanceVariables": [], + "moduleName": "spark_mini", + "staticMethods": [ + { + "args": [], + "declaringClassName": "spark_mini.SparkMiniComponent", + "functionName": "check_motors", + "returnType": "None", + "tooltip": "Check the motors to see if any have timed out.\n\nThis static method is called periodically to poll all the motors and stop\nany that have timed out." + } + ] + }, { "className": "sparkfun_led_stick.SparkFunLEDStick", "classVariables": [], @@ -1138,7 +1588,7 @@ ], "declaringClassName": "sparkfun_led_stick.SparkFunLEDStick", "functionName": "get_manufacturer", - "returnType": "", + "returnType": "str", "tooltip": "" }, { @@ -1151,7 +1601,7 @@ ], "declaringClassName": "sparkfun_led_stick.SparkFunLEDStick", "functionName": "get_name", - "returnType": "", + "returnType": "str", "tooltip": "" }, { @@ -1164,7 +1614,7 @@ ], "declaringClassName": "sparkfun_led_stick.SparkFunLEDStick", "functionName": "get_part_number", - "returnType": "", + "returnType": "str", "tooltip": "" }, { @@ -1177,7 +1627,7 @@ ], "declaringClassName": "sparkfun_led_stick.SparkFunLEDStick", "functionName": "get_url", - "returnType": "", + "returnType": "str", "tooltip": "" }, { @@ -1336,6 +1786,12 @@ "moduleName": "smart_motor", "moduleVariables": [] }, + { + "enums": [], + "functions": [], + "moduleName": "spark_mini", + "moduleVariables": [] + }, { "enums": [], "functions": [], @@ -1349,6 +1805,7 @@ "rev_touch_sensor.RevTouchSensor", "servo.Servo", "smart_motor.SmartMotor", + "spark_mini.SparkMiniComponent", "sparkfun_led_stick.SparkFunLEDStick" ] } diff --git a/src/blocks/utils/generated/robotpy_data.json b/src/blocks/utils/generated/robotpy_data.json index ee83de5b..451e88d9 100644 --- a/src/blocks/utils/generated/robotpy_data.json +++ b/src/blocks/utils/generated/robotpy_data.json @@ -35508,7 +35508,7 @@ "args": [], "declaringClassName": "wpilib.cameraserver.CameraServer", "functionName": "is_alive", - "returnType": "", + "returnType": "bool", "tooltip": ":returns: True if the CameraServer is still alive" }, { diff --git a/src/blocks/utils/python.ts b/src/blocks/utils/python.ts index 5772d4b0..a8afce86 100644 --- a/src/blocks/utils/python.ts +++ b/src/blocks/utils/python.ts @@ -116,6 +116,17 @@ export function initialize() { } } +// Returns the ClassData for the given class name. +export function getClassData(className: string): ClassData | null { + for (const pythonData of allPythonData) { + for (const classData of pythonData.classes) { + if (classData.className === className) { + return classData; + } + } + } + return null; +} // If the given type is a type alias, returns the value of the type alias. // For example, if type is 'wpimath.units.nanoseconds', this function will return 'float' diff --git a/src/blocks/utils/python_json_types.ts b/src/blocks/utils/python_json_types.ts index 2232a3b8..514c767b 100644 --- a/src/blocks/utils/python_json_types.ts +++ b/src/blocks/utils/python_json_types.ts @@ -100,3 +100,34 @@ export function organizeVarDataByType(vars: VarData[]): {[key: string]: Variable } return varsByType; } + +function isSuperFunction(f1: FunctionData, f2: FunctionData): boolean { + if (f1.functionName !== f2.functionName || + f1.returnType !== f2.returnType || + f1.args.length !== f2.args.length) { + return false; + } + + for (let i = 0; i < f1.args.length; i++) { + if (f1.args[i].name !== f2.args[i].name) { + return false; + } + if (f1.args[i].name === 'self') { + // Don't compare the types of the self arguments. + continue; + } + if (f1.args[i].type !== f2.args[i].type) { + return false; + } + } + return true; +} + +export function findSuperFunctionData(functionData: FunctionData, superClassFunctions: FunctionData): FunctionData | null { + for (const superClassFunctionData of superClassFunctions) { + if (isSuperFunction(superClassFunctionData, functionData)) { + return superClassFunctionData; + } + } + return null; +} diff --git a/src/editor/editor.ts b/src/editor/editor.ts index 48358810..86d6f5a5 100644 --- a/src/editor/editor.ts +++ b/src/editor/editor.ts @@ -244,46 +244,4 @@ export class Editor { throw e; } } - - private getComponentNamesImpl(componentClassName: string): string[] { - if (!this.projectContent) { - throw new Error('getComponentNames: this.projectContent is null.'); - } - const components = commonStorage.extractComponents(this.projectContent); - - // TODO(lizlooney): Remove this fake code after getComponents (above) has been implemented. - components.push({name: 'frontTouch', className: 'rev.TouchSensor'}); - components.push({name: 'backTouch', className: 'rev.TouchSensor'}); - components.push({name: 'leftMotor', className: 'rev.SmartMotor'}); - components.push({name: 'rightMotor', className: 'rev.SmartMotor'}); - components.push({name: 'clawServo', className: 'rev.Servo'}); - components.push({name: 'colorSensor', className: 'rev.ColorRangeSensor'}); - components.push({name: 'ledStick', className: 'sparkfun.LEDStick'}); - // End of fake code - - const componentNames: string[] = []; - components.forEach((component) => { - if (component.className === componentClassName) { - componentNames.push(component.name); - } - }); - return componentNames; - } - - public static getComponentNames( - workspace: Blockly.Workspace, componentClassName: string): string[] { - - let editor: Editor | null = null; - if (workspace.id in Editor.workspaceIdToEditor) { - editor = Editor.workspaceIdToEditor[workspace.id]; - } else { - // If the workspace id was not found, it might be because the workspace is associated with the - // toolbox flyout, not a real workspace. In that case, use the first editor. - const allEditors = Object.values(Editor.workspaceIdToEditor); - if (allEditors.length) { - editor = allEditors[0]; - } - } - return editor ? editor.getComponentNamesImpl(componentClassName) : []; - } } diff --git a/src/editor/extended_python_generator.ts b/src/editor/extended_python_generator.ts index 24013b7b..1812a575 100644 --- a/src/editor/extended_python_generator.ts +++ b/src/editor/extended_python_generator.ts @@ -121,6 +121,13 @@ export class ExtendedPythonGenerator extends PythonGenerator { return code; } + getModuleType(): string | null { + if (this.context && this.context.module) { + return this.context.module.moduleType; + } + return null; + } + /** * Add an import statement for a python module. */ @@ -248,7 +255,7 @@ export class ExtendedPythonGenerator extends PythonGenerator { exportedBlocks.push(callFunctionBlock); } - const allVariables = workspace.getAllVariables(); + const allVariables = workspace.getVariableMap().getAllVariables(); for (const variableModel of allVariables) { // Only variables that are used outside of functions are exported. (I'm not sure if this is // the right choice, since all blockly variables are global variables.) diff --git a/src/toolbox/blocks_components.ts b/src/toolbox/blocks_components.ts index f1e2ec83..f95becf6 100644 --- a/src/toolbox/blocks_components.ts +++ b/src/toolbox/blocks_components.ts @@ -24,13 +24,7 @@ import * as ColorSensor from './hardware_components/color_sensor'; import * as SmartMotor from './hardware_components/smart_motor'; import * as Servo from './hardware_components/servo'; import * as TouchSensor from './hardware_components/touch_sensor'; - -const ALL_COMPONENTS: Record ToolboxItems.ContentsType[]> = { - [ColorSensor.TYPE_NAME]: ColorSensor.getBlocks, - [SmartMotor.TYPE_NAME]: SmartMotor.getBlocks, - [TouchSensor.TYPE_NAME]: TouchSensor.getBlocks, - [Servo.TYPE_NAME]: Servo.getBlocks, -}; +import { addInstanceComponentBlocks } from '../blocks/mrc_call_python_function'; export function getAllPossibleComponents(hideParams: boolean): ToolboxItems.ContentsType[] { return [ @@ -42,9 +36,7 @@ export function getAllPossibleComponents(hideParams: boolean): ToolboxItems.Cont } export function getBlocks(componentType: string, componentName: string): ToolboxItems.ContentsType[] { - const getBlocksFunction = ALL_COMPONENTS[componentType]; - if (getBlocksFunction) { - return getBlocksFunction(componentName); - } - return []; + const contents: ToolboxItems.ContentsType[] = []; + addInstanceComponentBlocks(componentType, componentName, contents); + return contents; } diff --git a/src/toolbox/hardware_category.ts b/src/toolbox/hardware_category.ts index bfe4c538..a19c1a96 100644 --- a/src/toolbox/hardware_category.ts +++ b/src/toolbox/hardware_category.ts @@ -107,7 +107,7 @@ function getRobotMechanismsBlocks(currentModule: commonStorage.Module) { ], tooltip: 'Drive (robot relative)', importModule: '', - componentClassName: 'rev.ColorRangeSensor', + componentClassName: 'DriveRobotRelative', componentName: 'robot.drive', }, fields: { @@ -141,7 +141,7 @@ function getRobotMechanismsBlocks(currentModule: commonStorage.Module) { args: [], tooltip: 'Get the color in rgb (red, green, blue).', importModule: '', - componentClassName: 'rev.ColorRangeSensor', + componentClassName: 'color_range_sensor.ColorRangeSensor', componentName: 'colorSensor', }, fields: { @@ -160,7 +160,7 @@ function getRobotMechanismsBlocks(currentModule: commonStorage.Module) { args: [], tooltip: 'Get the color in hsv (hue, saturation, value).', importModule: '', - componentClassName: 'rev.ColorRangeSensor', + componentClassName: 'color_range_sensor.ColorRangeSensor', componentName: 'colorSensor', }, fields: { @@ -179,7 +179,7 @@ function getRobotMechanismsBlocks(currentModule: commonStorage.Module) { args: [], tooltip: 'Get the distance of the object seen.', importModule: '', - componentClassName: 'rev.ColorRangeSensor', + componentClassName: 'color_range_sensor.ColorRangeSensor', componentName: 'colorSensor', }, fields: { diff --git a/src/toolbox/hardware_components/color_sensor.ts b/src/toolbox/hardware_components/color_sensor.ts index 0213cd79..4c36136c 100644 --- a/src/toolbox/hardware_components/color_sensor.ts +++ b/src/toolbox/hardware_components/color_sensor.ts @@ -22,7 +22,7 @@ import * as ToolboxItems from '../items'; -export const TYPE_NAME = 'ColorRangeSensor'; +export const TYPE_NAME = 'color_range_sensor.ColorRangeSensor'; /** * Returns a component definition block for a color range sensor. @@ -36,7 +36,7 @@ export function getDefinitionBlock(hideParams: boolean): ToolboxItems.ContentsTy TYPE: TYPE_NAME, }, extraState: { - importModule: 'rev_color_range_sensor', + importModule: 'color_range_sensor', params: [{name: 'smartIO_port', type: 'int'}], hideParams, }, @@ -55,68 +55,3 @@ export function getDefinitionBlock(hideParams: boolean): ToolboxItems.ContentsTy }), }; } - -/** - * Returns the blocks available for a color range sensor component. - */ -export function getBlocks(componentName: string): ToolboxItems.ContentsType[] { - return [ - // Method: get_color_rgb() -> tuple[int, int, int] - { - kind: 'block', - type: 'mrc_call_python_function', - extraState: { - functionKind: 'instance_component', - returnType: 'tuple[int, int, int]', - args: [], - tooltip: 'Get the color in rgb (red, green, blue).', - importModule: '', - componentClassName: 'rev.ColorRangeSensor', - componentName : componentName, - }, - fields: { - COMPONENT_NAME: componentName, - FUNC: 'get_color_rgb', - }, - inputs: {}, - }, - // Method: get_color_hsv() -> tuple[int, int, int] - { - kind: 'block', - type: 'mrc_call_python_function', - extraState: { - functionKind: 'instance_component', - returnType: 'tuple[int, int, int]', - args: [], - tooltip: 'Get the color in hsv (hue, saturation, value).', - importModule: '', - componentClassName: 'rev.ColorRangeSensor', - componentName, - }, - fields: { - COMPONENT_NAME: componentName, - FUNC: 'get_color_hsv', - }, - inputs: {}, - }, - // Method: get_distance_mm() -> float - { - kind: 'block', - type: 'mrc_call_python_function', - extraState: { - functionKind: 'instance_component', - returnType: 'float', - args: [], - tooltip: 'Get the distance of the object seen.', - importModule: '', - componentClassName: 'rev.ColorRangeSensor', - componentName, - }, - fields: { - COMPONENT_NAME: componentName, - FUNC: 'get_distance_mm', - }, - inputs: {}, - }, - ]; -} \ No newline at end of file diff --git a/src/toolbox/hardware_components/servo.ts b/src/toolbox/hardware_components/servo.ts index 4274c4b5..df770cd4 100644 --- a/src/toolbox/hardware_components/servo.ts +++ b/src/toolbox/hardware_components/servo.ts @@ -19,9 +19,10 @@ * @fileoverview Servo hardware component definitions. * @author alan@porpoiseful.com (Alan Smith) */ + import * as ToolboxItems from '../items'; -export const TYPE_NAME = 'Servo'; +export const TYPE_NAME = 'servo.Servo'; /** * Returns a component definition block for a servo. @@ -35,7 +36,7 @@ export function getDefinitionBlock(hideParams: boolean): ToolboxItems.ContentsTy TYPE: TYPE_NAME, }, extraState: { - importModule: 'rev_servo', + importModule: 'servo', params: [{name: 'servo_port', type: 'int'}], hideParams, }, @@ -54,77 +55,3 @@ export function getDefinitionBlock(hideParams: boolean): ToolboxItems.ContentsTy }), }; } - -/** - * Returns the blocks available for a servo component. - */ -export function getBlocks(componentName: string): ToolboxItems.ContentsType[] { - return [ - // Method: set_position(pos: float) -> None - { - kind: 'block', - type: 'mrc_call_python_function', - extraState: { - functionKind: 'instance_component', - returnType: 'None', - args: [ - { - name: 'pos', - type: 'float', - }, - ], - tooltip: 'Set the servo to a position between 0 and 1.', - importModule: '', - componentClassName: 'rev.Servo', - componentName, - }, - fields: { - COMPONENT_NAME: componentName, - FUNC: 'set_position', - }, - inputs: { - ARG0: { - block: { - type: 'math_number', - fields: { - NUM: 0.5, - }, - }, - }, - }, - }, - // Method: set_angle_degrees(angle: float) -> None - { - kind: 'block', - type: 'mrc_call_python_function', - extraState: { - functionKind: 'instance_component', - returnType: 'None', - args: [ - { - name: 'angle', - type: 'float', - }, - ], - tooltip: 'Set the servo to an angle between 0 and 270.', - importModule: '', - componentClassName: 'rev.Servo', - componentName, - }, - fields: { - COMPONENT_NAME: componentName, - FUNC: 'set_angle_degrees', - }, - inputs: { - ARG0: { - block: { - type: 'math_number', - fields: { - NUM: 180, - }, - }, - }, - }, - }, - ]; -} diff --git a/src/toolbox/hardware_components/smart_motor.ts b/src/toolbox/hardware_components/smart_motor.ts index abbe1deb..f8d7f766 100644 --- a/src/toolbox/hardware_components/smart_motor.ts +++ b/src/toolbox/hardware_components/smart_motor.ts @@ -22,7 +22,7 @@ import * as ToolboxItems from '../items'; -export const TYPE_NAME = 'SmartMotor'; +export const TYPE_NAME = 'smart_motor.SmartMotor'; /** * Returns a component definition block for a smart motor. @@ -55,149 +55,3 @@ export function getDefinitionBlock(hideParams: boolean): ToolboxItems.ContentsTy }), }; } - -/** - * Returns the blocks available for a smart motor component. - */ -export function getBlocks(componentName: string): ToolboxItems.ContentsType[] { - return [ - // Event: on_stall - { - kind: 'block', - type: 'mrc_event_handler', - extraState: { - tooltip: '', - pathOfSender: '', - typeOfSender: 'component', - params: [], - }, - fields: { - SENDER: componentName, - EVENT_NAME: 'on_stall', - }, - }, - // Method: set_speed(speed: float) -> None - { - kind: 'block', - type: 'mrc_call_python_function', - extraState: { - functionKind: 'instance_component', - returnType: 'None', - args: [ - { - name: 'speed', - type: 'float', - }, - ], - tooltip: 'Set the motor to a speed between -1 and 1.', - importModule: '', - componentClassName: 'rev.SmartMotor', - componentName, - }, - fields: { - COMPONENT_NAME: componentName, - FUNC: 'set_speed', - }, - inputs: { - ARG0: { - block: { - type: 'math_number', - fields: { - NUM: 0.8, - }, - }, - }, - }, - }, - // Method: set_angle_degrees(angle: float) -> None - { - kind: 'block', - type: 'mrc_call_python_function', - extraState: { - functionKind: 'instance_component', - returnType: 'None', - args: [ - { - name: 'angle', - type: 'float', - }, - ], - tooltip: 'Set the motor to an angle between 0 and 360.', - importModule: '', - componentClassName: 'rev.SmartMotor', - componentName, - }, - fields: { - COMPONENT_NAME: componentName, - FUNC: 'set_angle_degrees', - }, - inputs: { - ARG0: { - block: { - type: 'math_number', - fields: { - NUM: 180, - }, - }, - }, - }, - }, - // Method: get_num_relative_encoder_ticks() -> int - { - kind: 'block', - type: 'mrc_call_python_function', - extraState: { - functionKind: 'instance_component', - returnType: 'int', - args: [], - tooltip: 'Get the number of relative motor ticks since reset of encoder.', - importModule: '', - componentClassName: 'rev.SmartMotor', - componentName, - }, - fields: { - COMPONENT_NAME: componentName, - FUNC: 'get_num_relative_encoder_ticks', - }, - inputs: {}, - }, - // Method: get_angle_degrees() -> float - { - kind: 'block', - type: 'mrc_call_python_function', - extraState: { - functionKind: 'instance_component', - returnType: 'float', - args: [], - tooltip: 'Get the angle position of the motor.', - importModule: '', - componentClassName: 'rev.SmartMotor', - componentName, - }, - fields: { - COMPONENT_NAME: componentName, - FUNC: 'get_angle_degrees', - }, - inputs: {}, - }, - // Method: reset_relative_encoder() -> None - { - kind: 'block', - type: 'mrc_call_python_function', - extraState: { - functionKind: 'instance_component', - returnType: 'None', - args: [], - tooltip: 'Reset the relative encoder value to 0.', - importModule: '', - componentClassName: 'rev.SmartMotor', - componentName, - }, - fields: { - COMPONENT_NAME: componentName, - FUNC: 'reset_relative_encoder', - }, - inputs: {}, - }, - ]; -} \ No newline at end of file diff --git a/src/toolbox/hardware_components/touch_sensor.ts b/src/toolbox/hardware_components/touch_sensor.ts index 5b95a8f5..ce7f2d67 100644 --- a/src/toolbox/hardware_components/touch_sensor.ts +++ b/src/toolbox/hardware_components/touch_sensor.ts @@ -22,7 +22,7 @@ import * as ToolboxItems from '../items'; -export const TYPE_NAME = 'TouchSensor'; +export const TYPE_NAME = 'rev_touch_sensor.RevTouchSensor'; /** * Returns a component definition block for a touch sensor. @@ -55,80 +55,3 @@ export function getDefinitionBlock(hideParams: boolean): ToolboxItems.ContentsTy }), }; } - -/** - * Returns the blocks available for a touch sensor component. - */ -export function getBlocks(componentName: string): ToolboxItems.ContentsType[] { - return [ - // Event: pressed - { - kind: 'block', - type: 'mrc_event_handler', - extraState: { - tooltip: '', - pathOfSender: '', - typeOfSender: 'component', - params: [], - }, - fields: { - SENDER: 'my_touch_sensor', - EVENT_NAME: 'pressed', - }, - }, - // Event: released - { - kind: 'block', - type: 'mrc_event_handler', - extraState: { - tooltip: '', - pathOfSender: '', - typeOfSender: 'component', - params: [], - }, - fields: { - SENDER: 'my_touch_sensor', - EVENT_NAME: 'released', - }, - }, - // Event: changed with new_state parameter - { - kind: 'block', - type: 'mrc_event_handler', - extraState: { - tooltip: '', - pathOfSender: '', - typeOfSender: 'component', - params: [ - { - name: 'new_state', - type: 'boolean', - }, - ], - }, - fields: { - SENDER: 'my_touch_sensor', - EVENT_NAME: 'changed', - }, - }, - // Method: is_pressed() -> bool - { - kind: 'block', - type: 'mrc_call_python_function', - extraState: { - functionKind: 'instance_component', - returnType: 'bool', - args: [], - tooltip: 'Return whether the touch sensor is pressed.', - importModule: '', - componentClassName: 'rev.TouchSensor', - componentName, - }, - fields: { - COMPONENT_NAME: componentName, - FUNC: 'is_pressed', - }, - inputs: {}, - }, - ]; -}