Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion external_samples/color_range_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
# @author alan@porpoiseful.com (Alan Smith)

from component import Component, PortType, InvalidPortException
from typing import Protocol
from typing import Protocol, Self

class DistanceCallable(Protocol):
def __call__(self, distance : float) -> None:
Expand Down Expand Up @@ -52,7 +52,13 @@ def get_connection_port_type(self) -> list[PortType]:
def periodic(self) -> None:
pass

# Alternative constructor to create an instance from an i2c port
@classmethod
def from_i2c_port(cls: type[Self], i2c_port: int) -> Self:
return cls([(PortType.I2C_PORT, i2c_port)])

# Component specific methods

def get_color_rgb(self) -> tuple[int, int, int]:
'''gets the color in rgb (red, green, blue)'''
pass
Expand Down
11 changes: 10 additions & 1 deletion external_samples/rev_touch_sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
# @fileoverview This is a sample for a touch sensor
# @author alan@porpoiseful.com (Alan Smith)

from typing import Self
from component import Component, PortType, InvalidPortException, EmptyCallable

class RevTouchSensor(Component):
Expand Down Expand Up @@ -51,6 +52,14 @@ def periodic(self) -> None:
self.pressed_callback()
elif old and self.released_callback:
self.released_callback()

# Alternative constructor to create an instance from a smart io port
@classmethod
def from_smart_io_port(cls: type[Self], smart_io_port: int) -> Self:
return cls([(PortType.SMART_IO_PORT, smart_io_port)])

# Component specific methods

def _read_hardware(self):
# here read hardware to get the current value of the sensor and set self.is_pressed
pass
Expand All @@ -67,4 +76,4 @@ def register_when_pressed(self, callback: EmptyCallable) -> None:

def register_when_released(self, callback: EmptyCallable) -> None:
'''Event when touch sensor is released (after being pressed)'''
self.released_callback = callback
self.released_callback = callback
10 changes: 7 additions & 3 deletions external_samples/servo.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
# @fileoverview This is a sample for a servo
# @author alan@porpoiseful.com (Alan Smith)

from typing import Self
from component import Component, PortType, InvalidPortException

class Servo(Component):
Expand Down Expand Up @@ -44,14 +45,17 @@ def get_connection_port_type(self) -> list[PortType]:
def periodic(self) -> None:
pass

# Alternative constructor to create an instance from an servo port
@classmethod
def from_servo_port(cls: type[Self], servo_port: int) -> Self:
return cls([(PortType.SERVO_PORT, servo_port)])

# Component specific methods

def set_position(self, pos: float) -> None:
'''Set the servo to a position between 0 and 1'''
# sends to the hardware the position of the servo
pass
def set_angle_degrees(self, angle: float) -> None:
'''Set the servo to an angle between 0 and 270'''
self.set_position(angle / 270.0)



11 changes: 9 additions & 2 deletions external_samples/smart_motor.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@

# @fileoverview This is a sample for a smart motor
# @author alan@porpoiseful.com (Alan Smith)

from typing import Self
from component import Component, PortType, InvalidPortException

class SmartMotor(Component):
class SmartMotor(Component):
def __init__(self, ports : list[tuple[PortType, int]]):
portType, port = ports[0]
if portType != PortType.SMART_MOTOR_PORT:
Expand All @@ -43,7 +45,13 @@ def get_connection_port_type(self) -> list[PortType]:
def periodic(self) -> None:
pass

# Alternative constructor to create an instance from a smart motor port
@classmethod
def from_smart_motor_port(cls: type[Self], smart_motor_port: int) -> Self:
return cls([(PortType.SMART_MOTOR_PORT, smart_motor_port)])

# Component specific methods

def set_speed(self, speed: float) -> None:
'''Set the motor to a speed between -1 and 1'''
# TODO: send to the hardware the speed of the motor
Expand All @@ -64,4 +72,3 @@ def get_angle_degrees(self) -> float:
def reset_relative_encoder(self) -> None:
'''Reset the relative encoder value to 0'''
pass

8 changes: 6 additions & 2 deletions external_samples/spark_mini.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

__author__ = "lizlooney@google.com (Liz Looney)"

from typing import Self
from component import Component, PortType, InvalidPortException
import wpilib
import wpimath
Expand All @@ -32,8 +33,6 @@ def __init__(self, ports : list[tuple[PortType, int]]):
raise InvalidPortException
self.spark_mini = wpilib.SparkMini(port)

# Component methods

def get_manufacturer(self) -> str:
return "REV Robotics"

Expand Down Expand Up @@ -62,6 +61,11 @@ def get_connection_port_type(self) -> list[PortType]:
def periodic(self) -> None:
pass

# Alternative constructor to create an instance from a smart motor port
@classmethod
def from_smart_motor_port(cls: type[Self], smart_motor_port: int) -> Self:
return cls([(PortType.SMART_MOTOR_PORT, smart_motor_port)])

# Component specific methods

# Methods from wpilib.PWMMotorController
Expand Down
8 changes: 6 additions & 2 deletions external_samples/sparkfun_led_stick.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

__author__ = "lizlooney@google.com (Liz Looney)"

from typing import Self
from component import Component, PortType, InvalidPortException
import wpilib

Expand All @@ -24,8 +25,6 @@ def __init__(self, ports : list[tuple[PortType, int]]):
raise InvalidPortException
self.port = port

# Component methods

def get_manufacturer(self) -> str:
return "SparkFun"

Expand Down Expand Up @@ -53,6 +52,11 @@ def get_connection_port_type(self) -> list[PortType]:
def periodic(self) -> None:
pass

# Alternative constructor to create an instance from an i2c port
@classmethod
def from_i2c_port(cls: type[Self], i2c_port: int) -> Self:
return cls([(PortType.I2C_PORT, i2c_port)])

# SparkFunLEDStick methods

def set_color(self, position: int, color: wpilib.Color) -> None:
Expand Down
72 changes: 37 additions & 35 deletions src/blocks/mrc_call_python_function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@ import { Order } from 'blockly/python';
import { ClassMethodDefExtraState } from './mrc_class_method_def'
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 * as Value from './utils/value';
import * as Variable from './utils/variable';
import { Editor } from '../editor/editor';
import { ExtendedPythonGenerator } from '../editor/extended_python_generator';
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';
import * as ToolboxItems from '../toolbox/items';
import * as CommonStorage from '../storage/common_storage';


// A block to call a python function.
Expand Down Expand Up @@ -67,7 +67,7 @@ export type FunctionArg = {
export function addModuleFunctionBlocks(
moduleName: string,
functions: FunctionData[],
contents: toolboxItems.ContentsType[]) {
contents: ToolboxItems.ContentsType[]) {
for (const functionData of functions) {
const block = createModuleFunctionOrStaticMethodBlock(
FunctionKind.MODULE, moduleName, moduleName, functionData);
Expand All @@ -78,7 +78,7 @@ export function addModuleFunctionBlocks(
export function addStaticMethodBlocks(
importModule: string,
functions: FunctionData[],
contents: toolboxItems.ContentsType[]) {
contents: ToolboxItems.ContentsType[]) {
for (const functionData of functions) {
if (functionData.declaringClassName) {
const block = createModuleFunctionOrStaticMethodBlock(
Expand All @@ -92,7 +92,7 @@ function createModuleFunctionOrStaticMethodBlock(
functionKind: FunctionKind,
importModule: string,
moduleOrClassName: string,
functionData: FunctionData): toolboxItems.Block {
functionData: FunctionData): ToolboxItems.Block {
const extraState: CallPythonFunctionExtraState = {
functionKind: functionKind,
returnType: functionData.returnType,
Expand All @@ -111,16 +111,16 @@ function createModuleFunctionOrStaticMethodBlock(
'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);
const input = Value.valueForFunctionArgInput(argData.type, argData.defaultValue);
if (input) {
inputs['ARG' + i] = input;
}
}
let block = new toolboxItems.Block(BLOCK_NAME, extraState, fields, Object.keys(inputs).length ? inputs : null);
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);
const varName = Variable.varNameForType(functionData.returnType);
if (varName) {
block = variable.createVariableSetterBlock(varName, block);
block = Variable.createVariableSetterBlock(varName, block);
}
}
return block;
Expand All @@ -129,7 +129,7 @@ function createModuleFunctionOrStaticMethodBlock(
export function addConstructorBlocks(
importModule: string,
functions: FunctionData[],
contents: toolboxItems.ContentsType[]) {
contents: ToolboxItems.ContentsType[]) {
for (const functionData of functions) {
const block = createConstructorBlock(importModule, functionData);
contents.push(block);
Expand All @@ -138,7 +138,7 @@ export function addConstructorBlocks(

function createConstructorBlock(
importModule: string,
functionData: FunctionData): toolboxItems.Block {
functionData: FunctionData): ToolboxItems.Block {
const extraState: CallPythonFunctionExtraState = {
functionKind: FunctionKind.CONSTRUCTOR,
returnType: functionData.returnType,
Expand All @@ -156,32 +156,32 @@ function createConstructorBlock(
'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);
const input = Value.valueForFunctionArgInput(argData.type, argData.defaultValue);
if (input) {
inputs['ARG' + i] = input;
}
}
let block = new toolboxItems.Block(BLOCK_NAME, extraState, fields, Object.keys(inputs).length ? inputs : null);
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);
const varName = Variable.varNameForType(functionData.returnType);
if (varName) {
block = variable.createVariableSetterBlock(varName, block);
block = Variable.createVariableSetterBlock(varName, block);
}
}
return block;
}

export function addInstanceMethodBlocks(
functions: FunctionData[],
contents: toolboxItems.ContentsType[]) {
contents: ToolboxItems.ContentsType[]) {
for (const functionData of functions) {
const block = createInstanceMethodBlock(functionData);
contents.push(block);
}
}

function createInstanceMethodBlock(
functionData: FunctionData): toolboxItems.Block {
functionData: FunctionData): ToolboxItems.Block {
const extraState: CallPythonFunctionExtraState = {
functionKind: FunctionKind.INSTANCE,
returnType: functionData.returnType,
Expand All @@ -196,32 +196,32 @@ function createInstanceMethodBlock(
const argData = functionData.args[i];
let argName = argData.name;
if (i === 0 && argName === 'self' && functionData.declaringClassName) {
argName = variable.getSelfArgName(functionData.declaringClassName);
argName = Variable.getSelfArgName(functionData.declaringClassName);
}
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);
const input = Value.valueForFunctionArgInput(argData.type, argData.defaultValue);
if (input) {
inputs['ARG' + i] = input;
}
}
let block = new toolboxItems.Block(BLOCK_NAME, extraState, fields, Object.keys(inputs).length ? inputs : null);
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);
const varName = Variable.varNameForType(functionData.returnType);
if (varName) {
block = variable.createVariableSetterBlock(varName, block);
block = Variable.createVariableSetterBlock(varName, block);
}
}
return block;
}

export function addInstanceComponentBlocks(
export function getInstanceComponentBlocks(
componentType: string,
componentName: string,
contents: toolboxItems.ContentsType[]) {
componentName: string) {
const contents: ToolboxItems.ContentsType[] = [];

const classData = getClassData(componentType);
if (!classData) {
Expand All @@ -243,10 +243,12 @@ export function addInstanceComponentBlocks(
const block = createInstanceComponentBlock(componentName, functionData);
contents.push(block);
}

return contents;
}

function createInstanceComponentBlock(
componentName: string, functionData: FunctionData): toolboxItems.Block {
componentName: string, functionData: FunctionData): ToolboxItems.Block {
const extraState: CallPythonFunctionExtraState = {
functionKind: FunctionKind.INSTANCE_COMPONENT,
returnType: functionData.returnType,
Expand All @@ -271,17 +273,17 @@ function createInstanceComponentBlock(
'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);
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);
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);
const varName = Variable.varNameForType(functionData.returnType);
if (varName) {
block = variable.createVariableSetterBlock(varName, block);
block = Variable.createVariableSetterBlock(varName, block);
}
}
return block;
Expand Down Expand Up @@ -688,11 +690,11 @@ export const pythonFromBlock = function(
: block.getFieldValue(FIELD_FUNCTION_NAME);
// Generate the correct code depending on the module type.
switch (generator.getModuleType()) {
case commonStorage.MODULE_TYPE_ROBOT:
case commonStorage.MODULE_TYPE_MECHANISM:
case CommonStorage.MODULE_TYPE_ROBOT:
case CommonStorage.MODULE_TYPE_MECHANISM:
code = 'self.';
break;
case commonStorage.MODULE_TYPE_OPMODE:
case CommonStorage.MODULE_TYPE_OPMODE:
default:
code = 'self.robot.';
break;
Expand Down
Loading